Skip to content

[Performance]Improvements #825

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Draft
wants to merge 13 commits into
base: develop
Choose a base branch
from
Draft

Conversation

ipavlidakis
Copy link
Contributor

@ipavlidakis ipavlidakis commented May 27, 2025

🔗 Issue Links

Resolves https://linear.app/stream/issue/IOS-650/videoinvestigate-performance-on-lower-end-devices

🎯 Goal

Improve performance, battery drain and thermal degradation during call.

🛠 Implementation

🧪 Manual Testing Notes

Given When Then
🟠 In a call alone I enable the camera The camera has a flipping animation
🟠 In a call I rotate the device The app freezes and then kills the phone
🟠 In a call I set a background filter My video track gets stuck and I get disconnected, but UI is frozen
🟢 In a call with 4+ participants I raise a hand It does not show for me, but it does for web participants
🟠 In a call with >2 participants I move app to background and then foreground All video tracks appear frozen
🟠 In a call with >2 participants I move app to background and then foreground Camera and mic buttons do not work

✅ Call Test Summary

Scenario

1:1 call for 5 minutes

  • noise-cancellation: active
  • background-filter: inactive
  • profiler: connected
  • debugger: disconnected

🧵 Tasks

Created Average Active Average Alive
29309 3 13,000

🌡️ Thermal State Degradation

Start End Thermal State
00:00.000 00:55.710 Nominal thermal state
00:55.710 01:25.708 Fair thermal state
01:25.708 05:16.416 Serious thermal state

☑️ Contributor Checklist

  • I have signed the Stream CLA (required)
  • This change follows zero ⚠️ policy (required)
  • This change should receive manual QA
  • Changelog is updated with client-facing changes
  • New code is covered by unit tests
  • Comparison screenshots added for visual changes
  • Affected documentation updated (tutorial, CMS)

@ipavlidakis ipavlidakis self-assigned this May 27, 2025
@ipavlidakis ipavlidakis added bug Something isn't working enhancement New feature or request labels May 27, 2025
Copy link

Public Interface

🚀 No changes affecting the public interface.

Copy link

1 Message
📖 Skipping Danger since the Pull Request is classed as Draft/Work In Progress

Generated by 🚫 Danger

@Stream-SDK-Bot
Copy link
Collaborator

Stream-SDK-Bot commented May 27, 2025

SDK Size

title develop branch diff status
StreamVideo 7.89 MB 7.99 MB +104 KB 🟢
StreamVideoSwiftUI 2.26 MB 2.26 MB 0 KB 🟢
StreamVideoUIKit 2.38 MB 2.38 MB -1 KB 🚀
StreamWebRTC 9.85 MB 9.85 MB 0 KB 🟢

Copy link

Public Interface

+ public protocol TimerProviding

+ extension ScreenPropertiesAdapter: InjectionKey  
+ 
+   public nonisolated static var currentValue: ScreenPropertiesAdapter

+ public final class ScreenPropertiesAdapter: @unchecked Sendable  
+ 
+   public private var preferredFramesPerSecond: Int
+   public private var refreshRate: TimeInterval
+   public private var scale: CGFloat



Copy link

Public Interface

+ public final class ScreenPropertiesAdapter: @unchecked Sendable  
+ 
+   public private var preferredFramesPerSecond: Int
+   public private var refreshRate: TimeInterval
+   public private var scale: CGFloat

+ public protocol TimerProviding

+ extension ScreenPropertiesAdapter: InjectionKey  
+ 
+   public nonisolated static var currentValue: ScreenPropertiesAdapter



 public class StreamVideo: ObservableObject, @unchecked Sendable  
-   public var state: State
+   case ringEventReceived
-   public let videoConfig: VideoConfig
+   
-   public var user: User
+ 
-   public var isHardwareAccelerationAvailable: Bool
+   public var state: State
-   public lazy var rejectionReasonProvider: RejectionReasonProviding
+   public let videoConfig: VideoConfig
-   
+   public var user: User
- 
+   public var isHardwareAccelerationAvailable: Bool
-   public convenience init(apiKey: String,user: User,token: UserToken,videoConfig: VideoConfig = VideoConfig(),pushNotificationsConfig: PushNotificationsConfig = .default,tokenProvider: UserTokenProvider? = nil)
+   public lazy var rejectionReasonProvider: RejectionReasonProviding
-   public func connect()async throws 
+   public convenience init(apiKey: String,user: User,token: UserToken,videoConfig: VideoConfig = VideoConfig(),pushNotificationsConfig: PushNotificationsConfig = .default,tokenProvider: UserTokenProvider? = nil)
-   public func call(callType: String,callId: String,callSettings: CallSettings? = nil)-> Call
+   
-   public func makeCallsController(callsQuery: CallsQuery)-> CallsController
+ 
-   @discardableResult public func setDevice(id: String)async throws -> ModelResponse
+   public func connect()async throws 
-   @discardableResult public func setVoipDevice(id: String)async throws -> ModelResponse
+   public func call(callType: String,callId: String,callSettings: CallSettings? = nil)-> Call
-   @discardableResult public func deleteDevice(id: String)async throws -> ModelResponse
+   public func makeCallsController(callsQuery: CallsQuery)-> CallsController
-   public func listDevices()async throws -> [Device]
+   @discardableResult public func setDevice(id: String)async throws -> ModelResponse
-   public func disconnect()async 
+   @discardableResult public func setVoipDevice(id: String)async throws -> ModelResponse
-   public func subscribe()-> AsyncStream<VideoEvent>
+   @discardableResult public func deleteDevice(id: String)async throws -> ModelResponse
-   public func subscribe(for event: WSEvent.Type)-> AsyncStream<WSEvent>
+   public func listDevices()async throws -> [Device]
-   public func queryCalls(next: String? = nil,watch: Bool = false)async throws -> (calls: [Call], next: String?)
+   public func disconnect()async 
-   public func queryCalls(filters: [String: RawJSON]?,sort: [SortParamRequest] = [SortParamRequest.descending("created_at")],limit: Int? = 25,watch: Bool = false)async throws -> (calls: [Call], next: String?)
+   public func eventPublisher()-> AnyPublisher<VideoEvent, Never>
-   
+   public func eventPublisher(for event: WSEvent.Type)-> AnyPublisher<WSEvent, Never>
- 
+   public func subscribe()-> AsyncStream<VideoEvent>
-   public final class State: ObservableObject, @unchecked Sendable  
+   public func subscribe(for event: WSEvent.Type)-> AsyncStream<WSEvent>
-   
+   public func queryCalls(next: String? = nil,watch: Bool = false)async throws -> (calls: [Call], next: String?)
-     @Published public internal var connection: ConnectionStatus
+   public func queryCalls(filters: [String: RawJSON]?,sort: [SortParamRequest] = [SortParamRequest.descending("created_at")],limit: Int? = 25,watch: Bool = false)async throws -> (calls: [Call], next: String?)
-     @Published public internal var user: User
+   
-     @Published public internal var activeCall: Call?
+ 
-     @Published public internal var ringingCall: Call?
+   public final class State: ObservableObject, @unchecked Sendable  
+   
+     @Published public internal var connection: ConnectionStatus
+     @Published public internal var user: User
+     @Published public internal var activeCall: Call?
+     @Published public internal var ringingCall: Call?

Copy link

github-actions bot commented Jun 1, 2025

Public Interface

+ public actor SerialActorQueue  
+ 
+   nonisolated public var unownedExecutor: UnownedSerialExecutor
+   
+ 
+   public init(file: StaticString = #file)
+   
+ 
+   @discardableResult public nonisolated func async(file: StaticString = #file,function: StaticString = #function,line: UInt = #line,@_inheritActorContext operation: @escaping Operation)-> QueueTask
+   @discardableResult public nonisolated func async(file: StaticString = #file,function: StaticString = #function,line: UInt = #line,@_inheritActorContext operation: @escaping @Sendable() async -> Void)-> QueueTask
+   @discardableResult public nonisolated func sync(@_inheritActorContext operation: @escaping @Sendable() async throws -> Output)async throws -> Output
+   @discardableResult public nonisolated func async(file: StaticString = #file,function: StaticString = #function,line: UInt = #line,@_inheritActorContext operation: sending @escaping @Sendable @isolated(any) () async throws (Failure) -> Void)-> QueueTask
+   @discardableResult public nonisolated func sync(@_inheritActorContext operation: sending @escaping @Sendable @isolated(any) () async throws (Failure) -> Output)async throws -> Output
+   public nonisolated func cancelAll()
+   
+ 
+   public final class QueueTask: @unchecked Sendable

+ extension ScreenPropertiesAdapter: InjectionKey  
+ 
+   public nonisolated static var currentValue: ScreenPropertiesAdapter

+ public protocol TimerProviding

+ public final class ScreenPropertiesAdapter: @unchecked Sendable  
+ 
+   public private var preferredFramesPerSecond: Int
+   public private var refreshRate: TimeInterval
+   public private var scale: CGFloat

- public final class SerialActorQueue: Sendable  
- 
-   public init()
-   
- 
-   public func cancelAll()
-   public func async(file: StaticString = #file,functionName: StaticString = #function,line: UInt = #line,_ block: @Sendable @escaping () async throws -> Void)
-   public func sync(_ block: @Sendable @escaping () async throws -> T)async throws -> T

 extension Task  
-   public func store(in disposableBag: DisposableBag,key: String = UUID().uuidString)
+   @discardableResult public init(disposableBag: DisposableBag,identifier: String = UUIDProviderKey.currentValue.get().uuidString,priority: TaskPriority? = .background,@_inheritActorContext block: @Sendable @escaping () async -> Success)
+   @discardableResult public init(disposableBag: DisposableBag,identifier: String = UUIDProviderKey.currentValue.get().uuidString,priority: TaskPriority? = .background,@_inheritActorContext block: @Sendable @escaping () async throws -> Success)
+   
+ 
+   public func store(in disposableBag: DisposableBag,identifier: String = UUID().uuidString)

 public class StreamVideo: ObservableObject, @unchecked Sendable  
-   public var state: State
+   case ringEventReceived
-   public let videoConfig: VideoConfig
+   
-   public var user: User
+ 
-   public var isHardwareAccelerationAvailable: Bool
+   public var state: State
-   public lazy var rejectionReasonProvider: RejectionReasonProviding
+   public let videoConfig: VideoConfig
-   
+   public var user: User
- 
+   public var isHardwareAccelerationAvailable: Bool
-   public convenience init(apiKey: String,user: User,token: UserToken,videoConfig: VideoConfig = VideoConfig(),pushNotificationsConfig: PushNotificationsConfig = .default,tokenProvider: UserTokenProvider? = nil)
+   public lazy var rejectionReasonProvider: RejectionReasonProviding
-   public func connect()async throws 
+   public convenience init(apiKey: String,user: User,token: UserToken,videoConfig: VideoConfig = VideoConfig(),pushNotificationsConfig: PushNotificationsConfig = .default,tokenProvider: UserTokenProvider? = nil)
-   public func call(callType: String,callId: String,callSettings: CallSettings? = nil)-> Call
+   
-   public func makeCallsController(callsQuery: CallsQuery)-> CallsController
+ 
-   @discardableResult public func setDevice(id: String)async throws -> ModelResponse
+   public func connect()async throws 
-   @discardableResult public func setVoipDevice(id: String)async throws -> ModelResponse
+   public func call(callType: String,callId: String,callSettings: CallSettings? = nil)-> Call
-   @discardableResult public func deleteDevice(id: String)async throws -> ModelResponse
+   public func makeCallsController(callsQuery: CallsQuery)-> CallsController
-   public func listDevices()async throws -> [Device]
+   @discardableResult public func setDevice(id: String)async throws -> ModelResponse
-   public func disconnect()async 
+   @discardableResult public func setVoipDevice(id: String)async throws -> ModelResponse
-   public func subscribe()-> AsyncStream<VideoEvent>
+   @discardableResult public func deleteDevice(id: String)async throws -> ModelResponse
-   public func subscribe(for event: WSEvent.Type)-> AsyncStream<WSEvent>
+   public func listDevices()async throws -> [Device]
-   public func queryCalls(next: String? = nil,watch: Bool = false)async throws -> (calls: [Call], next: String?)
+   public func disconnect()async 
-   public func queryCalls(filters: [String: RawJSON]?,sort: [SortParamRequest] = [SortParamRequest.descending("created_at")],limit: Int? = 25,watch: Bool = false)async throws -> (calls: [Call], next: String?)
+   public func eventPublisher()-> AnyPublisher<VideoEvent, Never>
-   
+   public func eventPublisher(for event: WSEvent.Type)-> AnyPublisher<WSEvent, Never>
- 
+   public func subscribe()-> AsyncStream<VideoEvent>
-   public final class State: ObservableObject, @unchecked Sendable  
+   public func subscribe(for event: WSEvent.Type)-> AsyncStream<WSEvent>
-   
+   public func queryCalls(next: String? = nil,watch: Bool = false)async throws -> (calls: [Call], next: String?)
-     @Published public internal var connection: ConnectionStatus
+   public func queryCalls(filters: [String: RawJSON]?,sort: [SortParamRequest] = [SortParamRequest.descending("created_at")],limit: Int? = 25,watch: Bool = false)async throws -> (calls: [Call], next: String?)
-     @Published public internal var user: User
+   
-     @Published public internal var activeCall: Call?
+ 
-     @Published public internal var ringingCall: Call?
+   public final class State: ObservableObject, @unchecked Sendable  
+   
+     @Published public internal var connection: ConnectionStatus
+     @Published public internal var user: User
+     @Published public internal var activeCall: Call?
+     @Published public internal var ringingCall: Call?

- public enum CallingState: Equatable, CustomStringConvertible  
+ public enum CallingState: Equatable, CustomStringConvertible, Sendable  

 public final class DisposableBag: @unchecked Sendable  
+   public func completed(_ key: String)

 extension Publisher  
-   public func sinkTask(storeIn disposableBag: DisposableBag? = nil,identifier: String? = nil,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable
+   public func sinkTask(storeIn disposableBag: DisposableBag,identifier: String = UUIDProviderKey.currentValue.get().uuidString,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable
-   public func sinkTask(queue: SerialActorQueue,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable
+   public func sinkTask(queue: SerialActorQueue,file: StaticString = #file,function: StaticString = #function,line: UInt = #line,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable

Copy link

sonarqubecloud bot commented Jun 1, 2025

Copy link

Public Interface

+ public final class ScreenPropertiesAdapter: @unchecked Sendable  
+ 
+   public private var preferredFramesPerSecond: Int
+   public private var refreshRate: TimeInterval
+   public private var scale: CGFloat

+ public actor SerialActorQueue  
+ 
+   nonisolated public var unownedExecutor: UnownedSerialExecutor
+   
+ 
+   public init(file: StaticString = #file)
+   
+ 
+   @discardableResult public nonisolated func async(file: StaticString = #file,function: StaticString = #function,line: UInt = #line,@_inheritActorContext operation: @escaping Operation)-> QueueTask
+   @discardableResult public nonisolated func async(file: StaticString = #file,function: StaticString = #function,line: UInt = #line,@_inheritActorContext operation: @escaping @Sendable() async -> Void)-> QueueTask
+   @discardableResult public nonisolated func sync(@_inheritActorContext operation: @escaping @Sendable() async throws -> Output)async throws -> Output
+   @discardableResult public nonisolated func async(file: StaticString = #file,function: StaticString = #function,line: UInt = #line,@_inheritActorContext operation: sending @escaping @Sendable @isolated(any) () async throws (Failure) -> Void)-> QueueTask
+   @discardableResult public nonisolated func sync(@_inheritActorContext operation: sending @escaping @Sendable @isolated(any) () async throws (Failure) -> Output)async throws -> Output
+   public nonisolated func cancelAll()
+   
+ 
+   public final class QueueTask: @unchecked Sendable

+ extension ScreenPropertiesAdapter: InjectionKey  
+ 
+   public nonisolated static var currentValue: ScreenPropertiesAdapter

+ public protocol TimerProviding

- public final class SerialActorQueue: Sendable  
- 
-   public init()
-   
- 
-   public func cancelAll()
-   public func async(file: StaticString = #file,functionName: StaticString = #function,line: UInt = #line,_ block: @Sendable @escaping () async throws -> Void)
-   public func sync(_ block: @Sendable @escaping () async throws -> T)async throws -> T

 public final class DisposableBag: @unchecked Sendable  
+   public func completed(_ key: String)

 extension Task  
-   public func store(in disposableBag: DisposableBag,key: String = UUID().uuidString)
+   @discardableResult public init(disposableBag: DisposableBag,identifier: String = UUIDProviderKey.currentValue.get().uuidString,priority: TaskPriority? = .background,@_inheritActorContext block: @Sendable @escaping () async -> Success)
+   @discardableResult public init(disposableBag: DisposableBag,identifier: String = UUIDProviderKey.currentValue.get().uuidString,priority: TaskPriority? = .background,@_inheritActorContext block: @Sendable @escaping () async throws -> Success)
+   
+ 
+   public func store(in disposableBag: DisposableBag,identifier: String = UUID().uuidString)

 extension Publisher  
-   public func sinkTask(storeIn disposableBag: DisposableBag? = nil,identifier: String? = nil,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable
+   public func sinkTask(storeIn disposableBag: DisposableBag,identifier: String = UUIDProviderKey.currentValue.get().uuidString,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable
-   public func sinkTask(queue: SerialActorQueue,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable
+   public func sinkTask(queue: SerialActorQueue,file: StaticString = #file,function: StaticString = #function,line: UInt = #line,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable

- public enum CallingState: Equatable, CustomStringConvertible  
+ public enum CallingState: Equatable, CustomStringConvertible, Sendable  

 public final class MicrophoneChecker: ObservableObject  
-   
- 
-   public func startListening(ignoreActiveCall: Bool = false)async 
-   public func stopListening()async

 public class StreamVideo: ObservableObject, @unchecked Sendable  
-   public var state: State
+   case ringEventReceived
-   public let videoConfig: VideoConfig
+   
-   public var user: User
+ 
-   public var isHardwareAccelerationAvailable: Bool
+   public var state: State
-   public lazy var rejectionReasonProvider: RejectionReasonProviding
+   public let videoConfig: VideoConfig
-   
+   public var user: User
- 
+   public var isHardwareAccelerationAvailable: Bool
-   public convenience init(apiKey: String,user: User,token: UserToken,videoConfig: VideoConfig = VideoConfig(),pushNotificationsConfig: PushNotificationsConfig = .default,tokenProvider: UserTokenProvider? = nil)
+   public lazy var rejectionReasonProvider: RejectionReasonProviding
-   public func connect()async throws 
+   public convenience init(apiKey: String,user: User,token: UserToken,videoConfig: VideoConfig = VideoConfig(),pushNotificationsConfig: PushNotificationsConfig = .default,tokenProvider: UserTokenProvider? = nil)
-   public func call(callType: String,callId: String,callSettings: CallSettings? = nil)-> Call
+   
-   public func makeCallsController(callsQuery: CallsQuery)-> CallsController
+ 
-   @discardableResult public func setDevice(id: String)async throws -> ModelResponse
+   public func connect()async throws 
-   @discardableResult public func setVoipDevice(id: String)async throws -> ModelResponse
+   public func call(callType: String,callId: String,callSettings: CallSettings? = nil)-> Call
-   @discardableResult public func deleteDevice(id: String)async throws -> ModelResponse
+   public func makeCallsController(callsQuery: CallsQuery)-> CallsController
-   public func listDevices()async throws -> [Device]
+   @discardableResult public func setDevice(id: String)async throws -> ModelResponse
-   public func disconnect()async 
+   @discardableResult public func setVoipDevice(id: String)async throws -> ModelResponse
-   public func subscribe()-> AsyncStream<VideoEvent>
+   @discardableResult public func deleteDevice(id: String)async throws -> ModelResponse
-   public func subscribe(for event: WSEvent.Type)-> AsyncStream<WSEvent>
+   public func listDevices()async throws -> [Device]
-   public func queryCalls(next: String? = nil,watch: Bool = false)async throws -> (calls: [Call], next: String?)
+   public func disconnect()async 
-   public func queryCalls(filters: [String: RawJSON]?,sort: [SortParamRequest] = [SortParamRequest.descending("created_at")],limit: Int? = 25,watch: Bool = false)async throws -> (calls: [Call], next: String?)
+   public func eventPublisher()-> AnyPublisher<VideoEvent, Never>
-   
+   public func eventPublisher(for event: WSEvent.Type)-> AnyPublisher<WSEvent, Never>
- 
+   public func subscribe()-> AsyncStream<VideoEvent>
-   public final class State: ObservableObject, @unchecked Sendable  
+   public func subscribe(for event: WSEvent.Type)-> AsyncStream<WSEvent>
-   
+   public func queryCalls(next: String? = nil,watch: Bool = false)async throws -> (calls: [Call], next: String?)
-     @Published public internal var connection: ConnectionStatus
+   public func queryCalls(filters: [String: RawJSON]?,sort: [SortParamRequest] = [SortParamRequest.descending("created_at")],limit: Int? = 25,watch: Bool = false)async throws -> (calls: [Call], next: String?)
-     @Published public internal var user: User
+   
-     @Published public internal var activeCall: Call?
+ 
-     @Published public internal var ringingCall: Call?
+   public final class State: ObservableObject, @unchecked Sendable  
+   
+     @Published public internal var connection: ConnectionStatus
+     @Published public internal var user: User
+     @Published public internal var activeCall: Call?
+     @Published public internal var ringingCall: Call?

@ipavlidakis ipavlidakis force-pushed the fix/performance-improvements branch from 5563d5d to 35d2404 Compare June 17, 2025 08:41
Copy link

Public Interface

+ public protocol TimerProviding

+ public final class ScreenPropertiesAdapter: @unchecked Sendable  
+ 
+   public private var preferredFramesPerSecond: Int
+   public private var refreshRate: TimeInterval
+   public private var scale: CGFloat

+ public actor SerialActorQueue  
+ 
+   nonisolated public var unownedExecutor: UnownedSerialExecutor
+   
+ 
+   public init(file: StaticString = #file)
+   
+ 
+   @discardableResult public nonisolated func async(file: StaticString = #file,function: StaticString = #function,line: UInt = #line,@_inheritActorContext operation: @escaping Operation)-> QueueTask
+   @discardableResult public nonisolated func async(file: StaticString = #file,function: StaticString = #function,line: UInt = #line,@_inheritActorContext operation: @escaping @Sendable() async -> Void)-> QueueTask
+   @discardableResult public nonisolated func sync(@_inheritActorContext operation: @escaping @Sendable() async throws -> Output)async throws -> Output
+   @discardableResult public nonisolated func async(file: StaticString = #file,function: StaticString = #function,line: UInt = #line,@_inheritActorContext operation: sending @escaping @Sendable @isolated(any) () async throws (Failure) -> Void)-> QueueTask
+   @discardableResult public nonisolated func sync(@_inheritActorContext operation: sending @escaping @Sendable @isolated(any) () async throws (Failure) -> Output)async throws -> Output
+   public nonisolated func cancelAll()
+   
+ 
+   public final class QueueTask: @unchecked Sendable

+ extension ScreenPropertiesAdapter: InjectionKey  
+ 
+   public nonisolated static var currentValue: ScreenPropertiesAdapter

- public final class SerialActorQueue: Sendable  
- 
-   public init()
-   
- 
-   public func cancelAll()
-   public func async(file: StaticString = #file,functionName: StaticString = #function,line: UInt = #line,_ block: @Sendable @escaping () async throws -> Void)
-   public func sync(_ block: @Sendable @escaping () async throws -> T)async throws -> T

 extension Task  
-   public func store(in disposableBag: DisposableBag,key: String = UUID().uuidString)
+   @discardableResult public init(disposableBag: DisposableBag,identifier: String = UUIDProviderKey.currentValue.get().uuidString,priority: TaskPriority? = .background,@_inheritActorContext block: @Sendable @escaping () async -> Success)
+   @discardableResult public init(disposableBag: DisposableBag,identifier: String = UUIDProviderKey.currentValue.get().uuidString,priority: TaskPriority? = .background,@_inheritActorContext block: @Sendable @escaping () async throws -> Success)
+   
+ 
+   public func store(in disposableBag: DisposableBag,identifier: String = UUID().uuidString)

- public enum CallingState: Equatable, CustomStringConvertible  
+ public enum CallingState: Equatable, CustomStringConvertible, Sendable  

 public final class MicrophoneChecker: ObservableObject  
-   
- 
-   public func startListening(ignoreActiveCall: Bool = false)async 
-   public func stopListening()async

 public class StreamVideo: ObservableObject, @unchecked Sendable  
-   public var state: State
+   case ringEventReceived
-   public let videoConfig: VideoConfig
+   
-   public var user: User
+ 
-   public var isHardwareAccelerationAvailable: Bool
+   public var state: State
-   public lazy var rejectionReasonProvider: RejectionReasonProviding
+   public let videoConfig: VideoConfig
-   
+   public var user: User
- 
+   public var isHardwareAccelerationAvailable: Bool
-   public convenience init(apiKey: String,user: User,token: UserToken,videoConfig: VideoConfig = VideoConfig(),pushNotificationsConfig: PushNotificationsConfig = .default,tokenProvider: UserTokenProvider? = nil)
+   public lazy var rejectionReasonProvider: RejectionReasonProviding
-   public func connect()async throws 
+   public convenience init(apiKey: String,user: User,token: UserToken,videoConfig: VideoConfig = VideoConfig(),pushNotificationsConfig: PushNotificationsConfig = .default,tokenProvider: UserTokenProvider? = nil)
-   public func call(callType: String,callId: String,callSettings: CallSettings? = nil)-> Call
+   
-   public func makeCallsController(callsQuery: CallsQuery)-> CallsController
+ 
-   @discardableResult public func setDevice(id: String)async throws -> ModelResponse
+   public func connect()async throws 
-   @discardableResult public func setVoipDevice(id: String)async throws -> ModelResponse
+   public func call(callType: String,callId: String,callSettings: CallSettings? = nil)-> Call
-   @discardableResult public func deleteDevice(id: String)async throws -> ModelResponse
+   public func makeCallsController(callsQuery: CallsQuery)-> CallsController
-   public func listDevices()async throws -> [Device]
+   @discardableResult public func setDevice(id: String)async throws -> ModelResponse
-   public func disconnect()async 
+   @discardableResult public func setVoipDevice(id: String)async throws -> ModelResponse
-   public func subscribe()-> AsyncStream<VideoEvent>
+   @discardableResult public func deleteDevice(id: String)async throws -> ModelResponse
-   public func subscribe(for event: WSEvent.Type)-> AsyncStream<WSEvent>
+   public func listDevices()async throws -> [Device]
-   public func queryCalls(next: String? = nil,watch: Bool = false)async throws -> (calls: [Call], next: String?)
+   public func disconnect()async 
-   public func queryCalls(filters: [String: RawJSON]?,sort: [SortParamRequest] = [SortParamRequest.descending("created_at")],limit: Int? = 25,watch: Bool = false)async throws -> (calls: [Call], next: String?)
+   public func eventPublisher()-> AnyPublisher<VideoEvent, Never>
-   
+   public func eventPublisher(for event: WSEvent.Type)-> AnyPublisher<WSEvent, Never>
- 
+   public func subscribe()-> AsyncStream<VideoEvent>
-   public final class State: ObservableObject, @unchecked Sendable  
+   public func subscribe(for event: WSEvent.Type)-> AsyncStream<WSEvent>
-   
+   public func queryCalls(next: String? = nil,watch: Bool = false)async throws -> (calls: [Call], next: String?)
-     @Published public internal var connection: ConnectionStatus
+   public func queryCalls(filters: [String: RawJSON]?,sort: [SortParamRequest] = [SortParamRequest.descending("created_at")],limit: Int? = 25,watch: Bool = false)async throws -> (calls: [Call], next: String?)
-     @Published public internal var user: User
+   
-     @Published public internal var activeCall: Call?
+ 
-     @Published public internal var ringingCall: Call?
+   public final class State: ObservableObject, @unchecked Sendable  
+   
+     @Published public internal var connection: ConnectionStatus
+     @Published public internal var user: User
+     @Published public internal var activeCall: Call?
+     @Published public internal var ringingCall: Call?

 public final class DisposableBag: @unchecked Sendable  
+   public func completed(_ key: String)

 extension Publisher  
-   public func sinkTask(storeIn disposableBag: DisposableBag? = nil,identifier: String? = nil,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable
+   public func sinkTask(storeIn disposableBag: DisposableBag,identifier: String = UUIDProviderKey.currentValue.get().uuidString,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable
-   public func sinkTask(queue: SerialActorQueue,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable
+   public func sinkTask(queue: SerialActorQueue,file: StaticString = #file,function: StaticString = #function,line: UInt = #line,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable

@ipavlidakis ipavlidakis force-pushed the fix/performance-improvements branch from 35d2404 to cad930d Compare June 17, 2025 23:43
Copy link

Public Interface

+ public final class ScreenPropertiesAdapter: @unchecked Sendable  
+ 
+   public private var preferredFramesPerSecond: Int
+   public private var refreshRate: TimeInterval
+   public private var scale: CGFloat

+ public actor SerialActorQueue  
+ 
+   nonisolated public var unownedExecutor: UnownedSerialExecutor
+   
+ 
+   public init(file: StaticString = #file)
+   
+ 
+   @discardableResult public nonisolated func async(file: StaticString = #file,function: StaticString = #function,line: UInt = #line,@_inheritActorContext operation: @escaping Operation)-> QueueTask
+   @discardableResult public nonisolated func async(file: StaticString = #file,function: StaticString = #function,line: UInt = #line,@_inheritActorContext operation: @escaping @Sendable() async -> Void)-> QueueTask
+   @discardableResult public nonisolated func sync(@_inheritActorContext operation: @escaping @Sendable() async throws -> Output)async throws -> Output
+   @discardableResult public nonisolated func async(file: StaticString = #file,function: StaticString = #function,line: UInt = #line,@_inheritActorContext operation: sending @escaping @Sendable @isolated(any) () async throws (Failure) -> Void)-> QueueTask
+   @discardableResult public nonisolated func sync(@_inheritActorContext operation: sending @escaping @Sendable @isolated(any) () async throws (Failure) -> Output)async throws -> Output
+   public nonisolated func cancelAll()
+   
+ 
+   public final class QueueTask: @unchecked Sendable

+ public protocol TimerProviding

+ extension ScreenPropertiesAdapter: InjectionKey  
+ 
+   public nonisolated static var currentValue: ScreenPropertiesAdapter

- public final class SerialActorQueue: Sendable  
- 
-   public init()
-   
- 
-   public func cancelAll()
-   public func async(file: StaticString = #file,functionName: StaticString = #function,line: UInt = #line,_ block: @Sendable @escaping () async throws -> Void)
-   public func sync(_ block: @Sendable @escaping () async throws -> T)async throws -> T

 extension Task  
-   public func store(in disposableBag: DisposableBag,key: String = UUID().uuidString)
+   @discardableResult public init(disposableBag: DisposableBag,identifier: String = UUIDProviderKey.currentValue.get().uuidString,priority: TaskPriority? = .background,@_inheritActorContext block: @Sendable @escaping () async -> Success)
+   @discardableResult public init(disposableBag: DisposableBag,identifier: String = UUIDProviderKey.currentValue.get().uuidString,priority: TaskPriority? = .background,@_inheritActorContext block: @Sendable @escaping () async throws -> Success)
+   
+ 
+   public func store(in disposableBag: DisposableBag,identifier: String = UUID().uuidString)

 extension Publisher  
-   public func sinkTask(storeIn disposableBag: DisposableBag? = nil,identifier: String? = nil,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable
+   public func sinkTask(storeIn disposableBag: DisposableBag,identifier: String = UUIDProviderKey.currentValue.get().uuidString,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable
-   public func sinkTask(queue: SerialActorQueue,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable
+   public func sinkTask(queue: SerialActorQueue,file: StaticString = #file,function: StaticString = #function,line: UInt = #line,receiveCompletion: @escaping (@Sendable(Subscribers.Completion<Failure>) -> Void) = { _ in },receiveValue: @escaping (@Sendable(Output) async throws -> Void))-> AnyCancellable

 public final class DisposableBag: @unchecked Sendable  
+   public func completed(_ key: String)

 public final class MicrophoneChecker: ObservableObject  
-   
- 
-   public func startListening(ignoreActiveCall: Bool = false)async 
-   public func stopListening()async

 public class StreamVideo: ObservableObject, @unchecked Sendable  
-   public var state: State
+   case ringEventReceived
-   public let videoConfig: VideoConfig
+   
-   public var user: User
+ 
-   public var isHardwareAccelerationAvailable: Bool
+   public var state: State
-   public lazy var rejectionReasonProvider: RejectionReasonProviding
+   public let videoConfig: VideoConfig
-   
+   public var user: User
- 
+   public var isHardwareAccelerationAvailable: Bool
-   public convenience init(apiKey: String,user: User,token: UserToken,videoConfig: VideoConfig = VideoConfig(),pushNotificationsConfig: PushNotificationsConfig = .default,tokenProvider: UserTokenProvider? = nil)
+   public lazy var rejectionReasonProvider: RejectionReasonProviding
-   public func connect()async throws 
+   public convenience init(apiKey: String,user: User,token: UserToken,videoConfig: VideoConfig = VideoConfig(),pushNotificationsConfig: PushNotificationsConfig = .default,tokenProvider: UserTokenProvider? = nil)
-   public func call(callType: String,callId: String,callSettings: CallSettings? = nil)-> Call
+   
-   public func makeCallsController(callsQuery: CallsQuery)-> CallsController
+ 
-   @discardableResult public func setDevice(id: String)async throws -> ModelResponse
+   public func connect()async throws 
-   @discardableResult public func setVoipDevice(id: String)async throws -> ModelResponse
+   public func call(callType: String,callId: String,callSettings: CallSettings? = nil)-> Call
-   @discardableResult public func deleteDevice(id: String)async throws -> ModelResponse
+   public func makeCallsController(callsQuery: CallsQuery)-> CallsController
-   public func listDevices()async throws -> [Device]
+   @discardableResult public func setDevice(id: String)async throws -> ModelResponse
-   public func disconnect()async 
+   @discardableResult public func setVoipDevice(id: String)async throws -> ModelResponse
-   public func subscribe()-> AsyncStream<VideoEvent>
+   @discardableResult public func deleteDevice(id: String)async throws -> ModelResponse
-   public func subscribe(for event: WSEvent.Type)-> AsyncStream<WSEvent>
+   public func listDevices()async throws -> [Device]
-   public func queryCalls(next: String? = nil,watch: Bool = false)async throws -> (calls: [Call], next: String?)
+   public func disconnect()async 
-   public func queryCalls(filters: [String: RawJSON]?,sort: [SortParamRequest] = [SortParamRequest.descending("created_at")],limit: Int? = 25,watch: Bool = false)async throws -> (calls: [Call], next: String?)
+   public func eventPublisher()-> AnyPublisher<VideoEvent, Never>
-   
+   public func eventPublisher(for event: WSEvent.Type)-> AnyPublisher<WSEvent, Never>
- 
+   public func subscribe()-> AsyncStream<VideoEvent>
-   public final class State: ObservableObject, @unchecked Sendable  
+   public func subscribe(for event: WSEvent.Type)-> AsyncStream<WSEvent>
-   
+   public func queryCalls(next: String? = nil,watch: Bool = false)async throws -> (calls: [Call], next: String?)
-     @Published public internal var connection: ConnectionStatus
+   public func queryCalls(filters: [String: RawJSON]?,sort: [SortParamRequest] = [SortParamRequest.descending("created_at")],limit: Int? = 25,watch: Bool = false)async throws -> (calls: [Call], next: String?)
-     @Published public internal var user: User
+   
-     @Published public internal var activeCall: Call?
+ 
-     @Published public internal var ringingCall: Call?
+   public final class State: ObservableObject, @unchecked Sendable  
+   
+     @Published public internal var connection: ConnectionStatus
+     @Published public internal var user: User
+     @Published public internal var activeCall: Call?
+     @Published public internal var ringingCall: Call?

- public enum CallingState: Equatable, CustomStringConvertible  
+ public enum CallingState: Equatable, CustomStringConvertible, Sendable  

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants