diff --git a/src/ios/SignalRingRTC/SignalRingRTC/Assertions.swift b/src/ios/SignalRingRTC/SignalRingRTC/Assertions.swift index f446ca7e..0c2bdc32 100644 --- a/src/ios/SignalRingRTC/SignalRingRTC/Assertions.swift +++ b/src/ios/SignalRingRTC/SignalRingRTC/Assertions.swift @@ -28,13 +28,3 @@ internal func failDebug( Logger.error(message, file: file, function: function, line: UInt32(line)) assertionFailure(message, file: file, line: UInt(line)) } - -internal func AssertIsOnMainThread( - file: StaticString = #fileID, - function: StaticString = #function, - line: Int = #line -) { - if !Thread.isMainThread { - failDebug("Must be on main thread.", file: file, function: function, line: line) - } -} diff --git a/src/ios/SignalRingRTC/SignalRingRTC/CallManager.swift b/src/ios/SignalRingRTC/SignalRingRTC/CallManager.swift index 1d9b5e42..31405f3f 100644 --- a/src/ios/SignalRingRTC/SignalRingRTC/CallManager.swift +++ b/src/ios/SignalRingRTC/SignalRingRTC/CallManager.swift @@ -194,20 +194,20 @@ public protocol CallManagerDelegate: AnyObject { /** * A call, either outgoing or incoming, should be started by the application. - * Invoked on the main thread, asynchronously. */ + @MainActor func callManager(_ callManager: CallManager, shouldStartCall call: CallManagerDelegateCallType, callId: UInt64, isOutgoing: Bool, callMediaType: CallMediaType) /** * onEvent will be invoked in response to Call Manager library operations. - * Invoked on the main thread, asynchronously. */ + @MainActor func callManager(_ callManager: CallManager, onEvent call: CallManagerDelegateCallType, event: CallManagerEvent) /** * onNetworkRouteChangedFor will be invoked when changes to the network routing (e.g. wifi/cellular) are detected. - * Invoked on the main thread, asynchronously. */ + @MainActor func callManager(_ callManager: CallManager, onNetworkRouteChangedFor call: CallManagerDelegateCallType, networkRoute: NetworkRoute) /** @@ -219,54 +219,54 @@ public protocol CallManagerDelegate: AnyObject { /** * onLowBandwidthForVideoFor will be invoked when the estimated upload * bandwidth is too low to send video reliably. - * Invoked on the main thread, asynchronously. * * When this is first called, recovered will be false. The second call (if * any) will have recovered set to true and will be called when the upload * bandwidth is high enough to send video reliably. */ + @MainActor func callManager(_ callManager: CallManager, onLowBandwidthForVideoFor call: CallManagerDelegateCallType, recovered: Bool) /** * An Offer message should be sent to the given remote. - * Invoked on the main thread, asynchronously. * If there is any error, the UI can reset UI state and invoke the reset() API. */ + @MainActor func callManager(_ callManager: CallManager, shouldSendOffer callId: UInt64, call: CallManagerDelegateCallType, destinationDeviceId: UInt32?, opaque: Data, callMediaType: CallMediaType) /** * An Answer message should be sent to the given remote. - * Invoked on the main thread, asynchronously. * If there is any error, the UI can reset UI state and invoke the reset() API. */ + @MainActor func callManager(_ callManager: CallManager, shouldSendAnswer callId: UInt64, call: CallManagerDelegateCallType, destinationDeviceId: UInt32?, opaque: Data) /** * An Ice Candidate message should be sent to the given remote. - * Invoked on the main thread, asynchronously. * If there is any error, the UI can reset UI state and invoke the reset() API. */ + @MainActor func callManager(_ callManager: CallManager, shouldSendIceCandidates callId: UInt64, call: CallManagerDelegateCallType, destinationDeviceId: UInt32?, candidates: [Data]) /** * A Hangup message should be sent to the given remote. - * Invoked on the main thread, asynchronously. * If there is any error, the UI can reset UI state and invoke the reset() API. */ + @MainActor func callManager(_ callManager: CallManager, shouldSendHangup callId: UInt64, call: CallManagerDelegateCallType, destinationDeviceId: UInt32?, hangupType: HangupType, deviceId: UInt32) /** * A Busy message should be sent to the given remote. - * Invoked on the main thread, asynchronously. * If there is any error, the UI can reset UI state and invoke the reset() API. */ + @MainActor func callManager(_ callManager: CallManager, shouldSendBusy callId: UInt64, call: CallManagerDelegateCallType, destinationDeviceId: UInt32?) /** * Send a generic call message to the given remote recipient. - * Invoked on the main thread, asynchronously. * If there is any error, the UI can reset UI state and invoke the reset() API. */ + @MainActor func callManager(_ callManager: CallManager, shouldSendCallMessage recipientUuid: UUID, message: Data, urgency: CallMessageUrgency) /** @@ -274,9 +274,9 @@ public protocol CallManagerDelegate: AnyObject { * or, if overrideRecipients is not empty, send to the given subset of members * using multi-recipient sealed sender. If the sealed sender request fails, * clients should provide a fallback mechanism. - * Invoked on the main thread, asynchronously. * If there is any error, the UI can reset UI state and invoke the reset() API. */ + @MainActor func callManager(_ callManager: CallManager, shouldSendCallMessageToGroup groupId: Data, message: Data, urgency: CallMessageUrgency, overrideRecipients: [UUID]) /** @@ -289,24 +289,23 @@ public protocol CallManagerDelegate: AnyObject { /** * The local video track has been enabled and can be connected to the * UI's display surface/view for the outgoing media. - * Invoked on the main thread, asynchronously. */ + @MainActor func callManager(_ callManager: CallManager, onUpdateLocalVideoSession call: CallManagerDelegateCallType, session: AVCaptureSession?) /** * The remote peer has connected and their video track can be connected to the * UI's display surface/view for the incoming media. - * Invoked on the main thread, asynchronously. */ + @MainActor func callManager(_ callManager: CallManager, onAddRemoteVideoTrack call: CallManagerDelegateCallType, track: RTCVideoTrack) /** * An update from `sender` has come in for the ring in `groupId` identified by `ringId`. * * `sender` will be the current user's ID if the update came from another device. - * - * Invoked on the main thread, asynchronously. */ + @MainActor func callManager(_ callManager: CallManager, didUpdateRingForGroup groupId: Data, ringId: Int64, sender: UUID, update: RingUpdate) } @@ -368,8 +367,8 @@ public class CallManager: CallManagerInterfac Logger.debug("object! CallManager created... \(ObjectIdentifier(self))") } + @MainActor public func setSelfUuid(_ uuid: UUID) { - AssertIsOnMainThread() Logger.debug("setSelfUuid") let uuidSlice = allocatedAppByteSliceFromData(maybe_data: uuid.data) @@ -399,8 +398,8 @@ public class CallManager: CallManagerInterfac /// - call: The application call context /// - callMediaType: The type of call to place (audio or video) /// - localDevice: The local device ID of the client (must be valid for lifetime of the call) + @MainActor public func placeCall(call: CallType, callMediaType: CallMediaType, localDevice: UInt32) throws { - AssertIsOnMainThread() Logger.debug("call") let unmanagedCall: Unmanaged = Unmanaged.passUnretained(call) @@ -414,8 +413,8 @@ public class CallManager: CallManagerInterfac _ = unmanagedCall.retain() } + @MainActor public func accept(callId: UInt64) throws { - AssertIsOnMainThread() Logger.debug("accept") let retPtr = ringrtcAccept(ringRtcCallManager, callId) @@ -424,8 +423,8 @@ public class CallManager: CallManagerInterfac } } + @MainActor public func hangup() throws { - AssertIsOnMainThread() Logger.debug("hangup") let retPtr = ringrtcHangup(ringRtcCallManager) @@ -434,8 +433,8 @@ public class CallManager: CallManagerInterfac } } + @MainActor public func cancelGroupRing(groupId: Data, ringId: Int64, reason: RingCancelReason?) throws { - AssertIsOnMainThread() Logger.debug("cancelGroupRing") let groupId = allocatedAppByteSliceFromData(maybe_data: groupId) @@ -458,8 +457,8 @@ public class CallManager: CallManagerInterfac /// - videoCaptureController: UI provided capturer interface /// - dataMode: The desired data mode to start the session with /// - audioLevelsIntervalMillis: If non-zero, the desired interval between audio level events (in milliseconds) + @MainActor public func proceed(callId: UInt64, iceServers: [RTCIceServer], hideIp: Bool, videoCaptureController: VideoCaptureController, dataMode: DataMode, audioLevelsIntervalMillis: UInt64?) throws { - AssertIsOnMainThread() Logger.info("proceed(): callId: 0x\(String(callId, radix: 16)), hideIp: \(hideIp)") for iceServer in iceServers { for url in iceServer.urlStrings { @@ -499,8 +498,8 @@ public class CallManager: CallManagerInterfac } } + @MainActor public func drop(callId: UInt64) { - AssertIsOnMainThread() Logger.debug("drop") let retPtr = ringrtcDrop(ringRtcCallManager, callId) @@ -509,8 +508,8 @@ public class CallManager: CallManagerInterfac } } + @MainActor public func signalingMessageDidSend(callId: UInt64) throws { - AssertIsOnMainThread() Logger.debug("signalingMessageDidSend") let retPtr = ringrtcMessageSent(ringRtcCallManager, callId) @@ -519,8 +518,8 @@ public class CallManager: CallManagerInterfac } } + @MainActor public func signalingMessageDidFail(callId: UInt64) { - AssertIsOnMainThread() Logger.debug("signalingMessageDidFail") let retPtr = ringrtcMessageSendFailure(ringRtcCallManager, callId) @@ -529,8 +528,8 @@ public class CallManager: CallManagerInterfac } } + @MainActor public func reset() { - AssertIsOnMainThread() Logger.debug("reset") let retPtr = ringrtcReset(ringRtcCallManager) @@ -539,8 +538,8 @@ public class CallManager: CallManagerInterfac } } + @MainActor public func setLocalAudioEnabled(enabled: Bool) { - AssertIsOnMainThread() Logger.info("#outgoing_audio_enabled: \(enabled)") let retPtr = ringrtcGetActiveCallContext(ringRtcCallManager) @@ -562,8 +561,8 @@ public class CallManager: CallManagerInterfac isAudioEnabled = enabled } + @MainActor public func setLocalVideoEnabled(enabled: Bool, call: CallType) { - AssertIsOnMainThread() Logger.debug("setLocalVideoEnabled(\(enabled))") let retPtr = ringrtcGetActiveCallContext(ringRtcCallManager) @@ -586,7 +585,7 @@ public class CallManager: CallManagerInterfac return } - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("setLocalVideoEnabled - main async") guard let delegate = self.delegate else { return } @@ -600,16 +599,17 @@ public class CallManager: CallManagerInterfac } } + @MainActor public func updateDataMode(dataMode: DataMode) { - AssertIsOnMainThread() Logger.debug("updateDataMode(\(dataMode))") ringrtcUpdateDataMode(ringRtcCallManager, dataMode.rawValue) } // MARK: - Signaling API - public func receivedOffer(call: CallType, sourceDevice: UInt32, callId: UInt64, opaque: Data, messageAgeSec: UInt64, callMediaType: CallMediaType, localDevice: UInt32, isLocalDevicePrimary: Bool, senderIdentityKey: Data, receiverIdentityKey: Data) throws { - AssertIsOnMainThread() + + @MainActor + public func receivedOffer(call: CallType, sourceDevice: UInt32, callId: UInt64, opaque: Data, messageAgeSec: UInt64, callMediaType: CallMediaType, localDevice: UInt32, isLocalDevicePrimary: Bool, senderIdentityKey: Data, receiverIdentityKey: Data) throws { Logger.debug("receivedOffer") let opaqueSlice = allocatedAppByteSliceFromData(maybe_data: opaque) @@ -641,8 +641,8 @@ public class CallManager: CallManagerInterfac _ = unmanagedRemote.retain() } + @MainActor public func receivedAnswer(sourceDevice: UInt32, callId: UInt64, opaque: Data, senderIdentityKey: Data, receiverIdentityKey: Data) throws { - AssertIsOnMainThread() Logger.debug("receivedAnswer") let opaqueSlice = allocatedAppByteSliceFromData(maybe_data: opaque) @@ -670,8 +670,8 @@ public class CallManager: CallManagerInterfac } } + @MainActor public func receivedIceCandidates(sourceDevice: UInt32, callId: UInt64, candidates: [Data]) throws { - AssertIsOnMainThread() Logger.debug("receivedIceCandidates") let appIceCandidates: [AppByteSlice] = candidates.map { candidate in @@ -702,8 +702,8 @@ public class CallManager: CallManagerInterfac } } + @MainActor public func receivedHangup(sourceDevice: UInt32, callId: UInt64, hangupType: HangupType, deviceId: UInt32) throws { - AssertIsOnMainThread() Logger.debug("receivedHangup") let retPtr = ringrtcReceivedHangup(ringRtcCallManager, callId, sourceDevice, hangupType.rawValue, deviceId) @@ -712,8 +712,8 @@ public class CallManager: CallManagerInterfac } } + @MainActor public func receivedBusy(sourceDevice: UInt32, callId: UInt64) throws { - AssertIsOnMainThread() Logger.debug("receivedBusy") let retPtr = ringrtcReceivedBusy(ringRtcCallManager, callId, sourceDevice) @@ -722,8 +722,8 @@ public class CallManager: CallManagerInterfac } } + @MainActor public func receivedCallMessage(senderUuid: UUID, senderDeviceId: UInt32, localDeviceId: UInt32, message: Data, messageAgeSec: UInt64) { - AssertIsOnMainThread() Logger.debug("receivedCallMessage") let senderUuidSlice = allocatedAppByteSliceFromData(maybe_data: senderUuid.data) @@ -746,8 +746,8 @@ public class CallManager: CallManagerInterfac // MARK: - Group Call + @MainActor public func createGroupCall(groupId: Data, sfuUrl: String, hkdfExtraInfo: Data, audioLevelsIntervalMillis: UInt64?, videoCaptureController: VideoCaptureController) -> GroupCall? { - AssertIsOnMainThread() Logger.debug("createGroupCall") guard let factory = self.factory else { @@ -759,8 +759,8 @@ public class CallManager: CallManagerInterfac return groupCall } + @MainActor public func createCallLinkCall(sfuUrl: String, authCredentialPresentation: [UInt8], linkRootKey: CallLinkRootKey, adminPasskey: Data?, hkdfExtraInfo: Data, audioLevelsIntervalMillis: UInt64?, videoCaptureController: VideoCaptureController) -> GroupCall? { - AssertIsOnMainThread() Logger.debug("createCallLinkCall") guard let factory = self.factory else { @@ -777,7 +777,7 @@ public class CallManager: CallManagerInterfac func onStartCall(remote: UnsafeRawPointer, callId: UInt64, isOutgoing: Bool, callMediaType: CallMediaType) { Logger.debug("onStartCall") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("onStartCall - main.async") guard let delegate = self.delegate else { return } @@ -790,7 +790,7 @@ public class CallManager: CallManagerInterfac func onEvent(remote: UnsafeRawPointer, event: CallManagerEvent) { Logger.debug("onEvent") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("onEvent - main.async") guard let delegate = self.delegate else { return } @@ -808,7 +808,7 @@ public class CallManager: CallManagerInterfac func onNetworkRouteChangedFor(remote: UnsafeRawPointer, networkRoute: NetworkRoute) { Logger.debug("onNetworkRouteChanged") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("onNetworkRouteChanged - main.async") guard let delegate = self.delegate else { return } @@ -831,7 +831,7 @@ public class CallManager: CallManagerInterfac func onLowBandwidthForVideoFor(remote: UnsafeRawPointer, recovered: Bool) { Logger.debug("onLowBandwidthForVideo") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("onLowBandwidthForVideo - main.async") guard let delegate = self.delegate else { return } @@ -846,7 +846,7 @@ public class CallManager: CallManagerInterfac func onSendOffer(callId: UInt64, remote: UnsafeRawPointer, destinationDeviceId: UInt32?, opaque: Data, callMediaType: CallMediaType) { Logger.debug("onSendOffer") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("onSendOffer - main.async") guard let delegate = self.delegate else { return } @@ -859,7 +859,7 @@ public class CallManager: CallManagerInterfac func onSendAnswer(callId: UInt64, remote: UnsafeRawPointer, destinationDeviceId: UInt32?, opaque: Data) { Logger.debug("onSendAnswer") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("onSendAnswer - main.async") guard let delegate = self.delegate else { return } @@ -872,7 +872,7 @@ public class CallManager: CallManagerInterfac func onSendIceCandidates(callId: UInt64, remote: UnsafeRawPointer, destinationDeviceId: UInt32?, candidates: [Data]) { Logger.debug("onSendIceCandidates") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("onSendIceCandidates - main.async") guard let delegate = self.delegate else { return } @@ -885,7 +885,7 @@ public class CallManager: CallManagerInterfac func onSendHangup(callId: UInt64, remote: UnsafeRawPointer, destinationDeviceId: UInt32?, hangupType: HangupType, deviceId: UInt32) { Logger.debug("onSendHangup") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("onSendHangup - main.async") guard let delegate = self.delegate else { return } @@ -898,7 +898,7 @@ public class CallManager: CallManagerInterfac func onSendBusy(callId: UInt64, remote: UnsafeRawPointer, destinationDeviceId: UInt32?) { Logger.debug("onSendBusy") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("onSendBusy - main.async") guard let delegate = self.delegate else { return } @@ -911,7 +911,7 @@ public class CallManager: CallManagerInterfac func sendCallMessage(recipientUuid: UUID, message: Data, urgency: CallMessageUrgency) { Logger.debug("sendCallMessage") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("sendCallMessage - main.async") guard let delegate = self.delegate else { return } @@ -923,7 +923,7 @@ public class CallManager: CallManagerInterfac func sendCallMessageToGroup(groupId: Data, message: Data, urgency: CallMessageUrgency, overrideRecipients: [UUID]) { Logger.debug("sendCallMessageToGroup") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("sendCallMessageToGroup - main.async") guard let delegate = self.delegate else { return } @@ -935,7 +935,7 @@ public class CallManager: CallManagerInterfac func groupCallRingUpdate(groupId: Data, ringId: Int64, sender: UUID, update: RingUpdate) { Logger.debug("onSendHttpRequest") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("onSendHttpRequest - main.async") self.delegate?.callManager(self, didUpdateRingForGroup: groupId, ringId: ringId, sender: sender, update: update) @@ -1001,7 +1001,7 @@ public class CallManager: CallManagerInterfac return } - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("onConnectMedia - main async") guard let delegate = self.delegate else { return } @@ -1028,7 +1028,7 @@ public class CallManager: CallManagerInterfac func onCallConcluded(remote: UnsafeRawPointer) { Logger.debug("onCallConcluded") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("onCallConcluded - main.async") let unmanagedRemote: Unmanaged = Unmanaged.fromOpaque(remote) @@ -1043,7 +1043,7 @@ public class CallManager: CallManagerInterfac func requestMembershipProof(clientId: UInt32) { Logger.debug("requestMembershipProof") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("requestMembershipProof - main.async") guard let groupCall = self.groupCallByClientId[clientId] else { @@ -1057,7 +1057,7 @@ public class CallManager: CallManagerInterfac func requestGroupMembers(clientId: UInt32) { Logger.debug("requestGroupMembers") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("requestGroupMembers - main.async") guard let groupCall = self.groupCallByClientId[clientId] else { @@ -1071,7 +1071,7 @@ public class CallManager: CallManagerInterfac func handleConnectionStateChanged(clientId: UInt32, connectionState: ConnectionState) { Logger.debug("handleConnectionStateChanged") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("handleConnectionStateChanged - main.async") guard let groupCall = self.groupCallByClientId[clientId] else { @@ -1085,7 +1085,7 @@ public class CallManager: CallManagerInterfac func handleNetworkRouteChanged(clientId: UInt32, networkRoute: NetworkRoute) { Logger.debug("handleNetworkRouteChanged") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("handleNetworkRouteChanged - main.async") guard let groupCall = self.groupCallByClientId[clientId] else { @@ -1097,7 +1097,7 @@ public class CallManager: CallManagerInterfac } func handleAudioLevels(clientId: UInt32, capturedLevel: UInt16, receivedLevels: [ReceivedAudioLevel]) { - DispatchQueue.main.async { + Task { @MainActor in guard let groupCall = self.groupCallByClientId[clientId] else { return } @@ -1109,7 +1109,7 @@ public class CallManager: CallManagerInterfac func handleLowBandwidthForVideo(clientId: UInt32, recovered: Bool) { Logger.debug("handleLowBandwidthForVideo") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("handleLowBandwidthForVideo - main.async") guard let groupCall = self.groupCallByClientId[clientId] else { @@ -1123,7 +1123,7 @@ public class CallManager: CallManagerInterfac func handleReactions(clientId: UInt32, reactions: [Reaction]) { Logger.debug("handleReactions") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("handleReactions - main.async") guard let groupCall = self.groupCallByClientId[clientId] else { @@ -1137,7 +1137,7 @@ public class CallManager: CallManagerInterfac func handleRaisedHands(clientId: UInt32, raisedHands: [UInt32]) { Logger.debug("handleRaisedHands") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("handleRaisedHands - main.async") guard let groupCall = self.groupCallByClientId[clientId] else { @@ -1151,7 +1151,7 @@ public class CallManager: CallManagerInterfac func handleJoinStateChanged(clientId: UInt32, joinState: JoinState, demuxId: UInt32?) { Logger.debug("handleJoinStateChanged") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("handleJoinStateChanged - main.async") guard let groupCall = self.groupCallByClientId[clientId] else { @@ -1165,7 +1165,7 @@ public class CallManager: CallManagerInterfac func handleRemoteDevicesChanged(clientId: UInt32, remoteDeviceStates: [RemoteDeviceState]) { Logger.debug("handleRemoteDevicesChanged") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("handleRemoteDevicesChanged - main.async") guard let groupCall = self.groupCallByClientId[clientId] else { @@ -1192,7 +1192,7 @@ public class CallManager: CallManagerInterfac // This takes a borrowed RC. let videoTrack = factory.videoTrack(fromNativeTrack: nativeVideoTrackBorrowedRc) - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("handleIncomingVideoTrack - main.async") guard let groupCall = self.groupCallByClientId[clientId] else { @@ -1206,7 +1206,7 @@ public class CallManager: CallManagerInterfac func handlePeekChanged(clientId: UInt32, peekInfo: PeekInfo) { Logger.debug("handlePeekChanged") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("handlePeekChanged - main.async") guard let groupCall = self.groupCallByClientId[clientId] else { @@ -1220,7 +1220,7 @@ public class CallManager: CallManagerInterfac func handleEnded(clientId: UInt32, reason: GroupCallEndReason) { Logger.debug("handleEnded") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("handleEnded - main.async") guard let groupCall = self.groupCallByClientId[clientId] else { diff --git a/src/ios/SignalRingRTC/SignalRingRTC/GroupCall.swift b/src/ios/SignalRingRTC/SignalRingRTC/GroupCall.swift index a771f290..6c0e79a3 100644 --- a/src/ios/SignalRingRTC/SignalRingRTC/GroupCall.swift +++ b/src/ios/SignalRingRTC/SignalRingRTC/GroupCall.swift @@ -176,29 +176,34 @@ public protocol GroupCallDelegate: AnyObject { * Indication that the application should provide an updated proof of membership * for the group call. */ + @MainActor func groupCall(requestMembershipProof groupCall: GroupCall) /** * Indication that the application should provide the list of group members that * belong to the group for the purposes of the group call. */ + @MainActor func groupCall(requestGroupMembers groupCall: GroupCall) /** * Indication that the application should retrieve the latest local device * state from the group call and refresh the presentation. */ + @MainActor func groupCall(onLocalDeviceStateChanged groupCall: GroupCall) /** * Indication that the application should retrieve the latest remote device * states from the group call and refresh the presentation. */ + @MainActor func groupCall(onRemoteDeviceStatesChanged groupCall: GroupCall) /** * Indication that the application should draw audio levels. */ + @MainActor func groupCall(onAudioLevels groupCall: GroupCall) /** @@ -209,30 +214,35 @@ public protocol GroupCallDelegate: AnyObject { * any) will have recovered set to true and will be called when the upload * bandwidth is high enough to send video reliably. */ + @MainActor func groupCall(onLowBandwidthForVideo groupCall: GroupCall, recovered: Bool) /** * Indication that the application should notify the user that one or more reactions * were received. */ + @MainActor func groupCall(onReactions groupCall: GroupCall, reactions: [Reaction]) /** * Indication that the application should notify the user that raised hands * changed. */ + @MainActor func groupCall(onRaisedHands groupCall: GroupCall, raisedHands: [UInt32]) /** * Indication that the application can retrieve an updated PeekInfo which * includes a list of users that are actively in the group call. */ + @MainActor func groupCall(onPeekChanged groupCall: GroupCall) /** * Indication that group call ended due to a reason other than the user choosing * to disconnect from it. */ + @MainActor func groupCall(onEnded groupCall: GroupCall, reason: GroupCallEndReason) } @@ -273,9 +283,8 @@ public class GroupCall { var audioTrack: RTCAudioTrack? var videoTrack: RTCVideoTrack? + @MainActor internal init(ringRtcCallManager: UnsafeMutableRawPointer, factory: RTCPeerConnectionFactory, groupCallByClientId: GroupCallByClientId, groupId: Data, sfuUrl: String, hkdfExtraInfo: Data, audioLevelsIntervalMillis: UInt64?, videoCaptureController: VideoCaptureController) { - AssertIsOnMainThread() - self.ringRtcCallManager = ringRtcCallManager self.factory = factory self.groupCallByClientId = groupCallByClientId @@ -292,9 +301,8 @@ public class GroupCall { Logger.debug("object! GroupCall created... \(ObjectIdentifier(self))") } + @MainActor internal init(ringRtcCallManager: UnsafeMutableRawPointer, factory: RTCPeerConnectionFactory, groupCallByClientId: GroupCallByClientId, sfuUrl: String, authCredentialPresentation: [UInt8], linkRootKey: CallLinkRootKey, adminPasskey: Data?, hkdfExtraInfo: Data, audioLevelsIntervalMillis: UInt64?, videoCaptureController: VideoCaptureController) { - AssertIsOnMainThread() - self.ringRtcCallManager = ringRtcCallManager self.factory = factory self.groupCallByClientId = groupCallByClientId @@ -326,8 +334,8 @@ public class GroupCall { /// Connect to a group call, creating a client if one does not already exist. /// Return true if successful. + @MainActor public func connect() -> Bool { - AssertIsOnMainThread() Logger.debug("connect") if self.clientId == nil { @@ -419,8 +427,8 @@ public class GroupCall { return true } + @MainActor public func join() { - AssertIsOnMainThread() Logger.debug("join") guard let clientId = self.clientId else { @@ -431,8 +439,8 @@ public class GroupCall { ringrtcJoin(self.ringRtcCallManager, clientId) } + @MainActor public func leave() { - AssertIsOnMainThread() Logger.debug("leave") guard let clientId = self.clientId else { @@ -447,8 +455,8 @@ public class GroupCall { ringrtcLeave(self.ringRtcCallManager, clientId) } + @MainActor public func disconnect() { - AssertIsOnMainThread() Logger.debug("disconnect") guard let clientId = self.clientId else { @@ -463,8 +471,8 @@ public class GroupCall { ringrtcDisconnect(self.ringRtcCallManager, clientId) } + @MainActor public func react(value: String) { - AssertIsOnMainThread() Logger.debug("react") guard let clientId = self.clientId else { @@ -478,8 +486,8 @@ public class GroupCall { ringrtcReact(self.ringRtcCallManager, clientId, valueSlice) } + @MainActor public func raiseHand(raise: Bool) { - AssertIsOnMainThread() Logger.debug("raiseHand") guard let clientId = self.clientId else { @@ -491,13 +499,12 @@ public class GroupCall { } private var _isOutgoingAudioMuted = false + @MainActor public var isOutgoingAudioMuted: Bool { get { - AssertIsOnMainThread() return _isOutgoingAudioMuted } set { - AssertIsOnMainThread() Logger.debug("setOutgoingAudioMuted") _isOutgoingAudioMuted = newValue @@ -513,13 +520,12 @@ public class GroupCall { } private var _isOutgoingVideoMuted = false + @MainActor public var isOutgoingVideoMuted: Bool { get { - AssertIsOnMainThread() return _isOutgoingVideoMuted } set { - AssertIsOnMainThread() Logger.debug("setOutgoingVideoMuted") _isOutgoingVideoMuted = newValue @@ -534,8 +540,8 @@ public class GroupCall { } } + @MainActor public func ringAll() { - AssertIsOnMainThread() Logger.debug("ring") guard let clientId = self.clientId else { @@ -546,8 +552,8 @@ public class GroupCall { ringrtcGroupRing(self.ringRtcCallManager, clientId, AppByteSlice(bytes: nil, len: 0)) } + @MainActor public func resendMediaKeys() { - AssertIsOnMainThread() Logger.debug("resendMediaKeys") guard let clientId = self.clientId else { @@ -559,8 +565,8 @@ public class GroupCall { } /// Sets a data mode, allowing the client to limit the media bandwidth used. + @MainActor public func updateDataMode(dataMode: DataMode) { - AssertIsOnMainThread() Logger.debug("updateDataMode") guard let clientId = self.clientId else { @@ -578,8 +584,8 @@ public class GroupCall { /// /// - parameter resolutions: the VideoRequest objects for each user rendered on the screen /// - parameter activeSpeakerHeight: the height of the view for the active speaker, in pixels + @MainActor public func updateVideoRequests(resolutions: [VideoRequest], activeSpeakerHeight: UInt16) { - AssertIsOnMainThread() Logger.debug("updateVideoRequests") guard let clientId = self.clientId else { @@ -608,8 +614,8 @@ public class GroupCall { ringrtcRequestVideo(self.ringRtcCallManager, clientId, &appResolutionArray, activeSpeakerHeight) } + @MainActor public func approveUser(_ userId: UUID) { - AssertIsOnMainThread() Logger.debug("approveUser") guard let clientId = self.clientId else { @@ -623,8 +629,8 @@ public class GroupCall { ringrtcApproveUser(self.ringRtcCallManager, clientId, userIdSlice) } + @MainActor public func denyUser(_ userId: UUID) { - AssertIsOnMainThread() Logger.debug("denyUser") guard let clientId = self.clientId else { @@ -638,8 +644,8 @@ public class GroupCall { ringrtcDenyUser(self.ringRtcCallManager, clientId, userIdSlice) } + @MainActor public func removeClient(demuxId otherClientDemuxId: UInt32) { - AssertIsOnMainThread() Logger.debug("removeClient") guard let clientId = self.clientId else { @@ -650,8 +656,8 @@ public class GroupCall { ringrtcRemoveClient(self.ringRtcCallManager, clientId, otherClientDemuxId) } + @MainActor public func blockClient(demuxId otherClientDemuxId: UInt32) { - AssertIsOnMainThread() Logger.debug("blockClient") guard let clientId = self.clientId else { @@ -662,8 +668,8 @@ public class GroupCall { ringrtcBlockClient(self.ringRtcCallManager, clientId, otherClientDemuxId) } + @MainActor public func updateGroupMembers(members: [GroupMember]) { - AssertIsOnMainThread() Logger.debug("updateGroupMembers") guard let clientId = self.clientId else { @@ -702,8 +708,8 @@ public class GroupCall { ringrtcSetGroupMembers(self.ringRtcCallManager, clientId, &appGroupMemberInfoArray) } + @MainActor public func updateMembershipProof(proof: Data) { - AssertIsOnMainThread() Logger.debug("updateMembershipProof") guard let clientId = self.clientId else { @@ -727,37 +733,32 @@ public class GroupCall { // MARK: - Internal Callback Handlers + @MainActor func requestMembershipProof() { - AssertIsOnMainThread() - self.delegate?.groupCall(requestMembershipProof: self) } + @MainActor func requestGroupMembers() { - AssertIsOnMainThread() - self.delegate?.groupCall(requestGroupMembers: self) } + @MainActor func handleConnectionStateChanged(connectionState: ConnectionState) { - AssertIsOnMainThread() - self.localDeviceState.connectionState = connectionState self.delegate?.groupCall(onLocalDeviceStateChanged: self) } + @MainActor func handleNetworkRouteChanged(networkRoute: NetworkRoute) { - AssertIsOnMainThread() - self.localDeviceState.networkRoute = networkRoute; self.delegate?.groupCall(onLocalDeviceStateChanged: self) } + @MainActor func handleAudioLevels(capturedLevel: UInt16, receivedLevels: [ReceivedAudioLevel]) { - AssertIsOnMainThread() - self.localDeviceState.audioLevel = capturedLevel; for received in receivedLevels { let remoteDeviceState = self.remoteDeviceStates[received.demuxId] @@ -769,35 +770,31 @@ public class GroupCall { self.delegate?.groupCall(onAudioLevels: self) } + @MainActor func handleLowBandwidthForVideo(recovered: Bool) { - AssertIsOnMainThread() - self.delegate?.groupCall(onLowBandwidthForVideo: self, recovered: recovered) } + @MainActor func handleReactions(reactions: [Reaction]) { - AssertIsOnMainThread() - self.delegate?.groupCall(onReactions: self, reactions: reactions) } + @MainActor func handleRaisedHands(raisedHands: [UInt32]) { - AssertIsOnMainThread() - self.delegate?.groupCall(onRaisedHands: self, raisedHands: raisedHands) } + @MainActor func handleJoinStateChanged(joinState: JoinState, demuxId: UInt32?) { - AssertIsOnMainThread() - self.localDeviceState.joinState = joinState self.localDeviceState.demuxId = demuxId self.delegate?.groupCall(onLocalDeviceStateChanged: self) } + @MainActor func handleRemoteDevicesChanged(remoteDeviceStates: [RemoteDeviceState]) { - AssertIsOnMainThread() Logger.debug("handleRemoteDevicesChanged() count: \(remoteDeviceStates.count)") var remoteDeviceByDemuxId: [UInt32: RemoteDeviceState] = [:] @@ -818,8 +815,8 @@ public class GroupCall { self.delegate?.groupCall(onRemoteDeviceStatesChanged: self) } + @MainActor func handleIncomingVideoTrack(remoteDemuxId: UInt32, videoTrack: RTCVideoTrack) { - AssertIsOnMainThread() Logger.debug("handleIncomingVideoTrack() for remoteDemuxId: 0x\(String(remoteDemuxId, radix: 16))") guard let remoteDeviceState = self.remoteDeviceStates[remoteDemuxId] else { @@ -832,17 +829,15 @@ public class GroupCall { self.delegate?.groupCall(onRemoteDeviceStatesChanged: self) } + @MainActor func handlePeekChanged(peekInfo: PeekInfo) { - AssertIsOnMainThread() - self.peekInfo = peekInfo self.delegate?.groupCall(onPeekChanged: self) } + @MainActor func handleEnded(reason: GroupCallEndReason) { - AssertIsOnMainThread() - guard let clientId = self.clientId else { Logger.error("no clientId defined for groupCall") return diff --git a/src/ios/SignalRingRTC/SignalRingRTC/HTTP.swift b/src/ios/SignalRingRTC/SignalRingRTC/HTTP.swift index 34ed07e4..91963137 100644 --- a/src/ios/SignalRingRTC/SignalRingRTC/HTTP.swift +++ b/src/ios/SignalRingRTC/SignalRingRTC/HTTP.swift @@ -92,7 +92,7 @@ public protocol HTTPDelegate: AnyObject { // An HTTP request should be sent to the given url. // The HTTP response should be returned by calling the HttpClient.receivedResponse(requestId, ...). // or HttpClient.requestFailed(requestId) if the request failed to get a response. - // Invoked on the main thread, asynchronously. + @MainActor func sendRequest(requestId: UInt32, request: HTTPRequest) } @@ -124,8 +124,8 @@ public class HTTPClient { } } + @MainActor public func receivedResponse(requestId: UInt32, response: HTTPResponse) { - AssertIsOnMainThread() Logger.debug("HttpClient.receivedResponse") let rtcResponse = rtc_http_Response.allocate(from: response) @@ -135,8 +135,8 @@ public class HTTPClient { rtc_http_Client_received_response(self.rtcClient, requestId, rtcResponse) } + @MainActor public func httpRequestFailed(requestId: UInt32) { - AssertIsOnMainThread() Logger.debug("httpRequestFailed") rtc_http_Client_request_failed(self.rtcClient, requestId) @@ -189,7 +189,7 @@ private class HTTPDelegateWrapper { } Logger.debug("HTTPDelegate.sendRequest") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("HTTPDelegate.sendRequest (on main.async)") guard let delegate = wrapper.delegate else { diff --git a/src/ios/SignalRingRTC/SignalRingRTC/SFU.swift b/src/ios/SignalRingRTC/SignalRingRTC/SFU.swift index 298133dc..04a06d10 100644 --- a/src/ios/SignalRingRTC/SignalRingRTC/SFU.swift +++ b/src/ios/SignalRingRTC/SignalRingRTC/SFU.swift @@ -206,6 +206,7 @@ public class SFUClient { } } + @MainActor func handlePeekResponse(requestId: UInt32, response: PeekResponse) { let resolved = self.peekRequests.resolve(id: requestId, response: response); if !resolved { @@ -213,6 +214,7 @@ public class SFUClient { } } + @MainActor func handleCallLinkResponse(requestId: UInt32, response: SFUResult) { let resolved = self.callLinkRequests.resolve(id: requestId, response: response) if !resolved { @@ -220,6 +222,7 @@ public class SFUClient { } } + @MainActor func handleEmptyResponse(requestId: UInt32, response: SFUResult<()>) { let resolved = self.emptyRequests.resolve(id: requestId, response: response) if !resolved { @@ -453,7 +456,7 @@ private class SFUDelegateWrapper { Logger.debug("SFUDelegateWrapper.handlePeekResponse") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("SFUDelegateWrapper.handlePeekResponse - main.async") guard let delegate = wrapper.delegate else { @@ -492,7 +495,7 @@ private class SFUDelegateWrapper { Logger.debug("SFUDelegateWrapper.handleResponse") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("SFUDelegateWrapper.handleResponse - main.async") guard let delegate = wrapper.delegate else { @@ -531,7 +534,7 @@ private class SFUDelegateWrapper { Logger.debug("SFUDelegateWrapper.handleEmptyResponse") - DispatchQueue.main.async { + Task { @MainActor in Logger.debug("SFUDelegateWrapper.handleEmptyResponse - main.async") guard let delegate = wrapper.delegate else { diff --git a/src/ios/SignalRingRTC/SignalRingRTCTests/CallLinkTests.swift b/src/ios/SignalRingRTC/SignalRingRTCTests/CallLinkTests.swift index 3d1c9a7d..da03bce3 100644 --- a/src/ios/SignalRingRTC/SignalRingRTCTests/CallLinkTests.swift +++ b/src/ios/SignalRingRTC/SignalRingRTCTests/CallLinkTests.swift @@ -24,6 +24,7 @@ final class CallLinkTests: XCTestCase { XCTAssertEqual(String(describing: Self.EXAMPLE_KEY), "bcdf-ghkm-npqr-stxz-bcdf-ghkm-npqr-stxz") } + @MainActor func testCreateSuccess() async throws { let delegate = TestDelegate() let httpClient = HTTPClient(delegate: delegate) @@ -44,6 +45,7 @@ final class CallLinkTests: XCTestCase { } } + @MainActor func testCreateFailure() async throws { let delegate = TestDelegate() let httpClient = HTTPClient(delegate: delegate) @@ -64,6 +66,7 @@ final class CallLinkTests: XCTestCase { } } + @MainActor func testReadSuccess() async throws { let delegate = TestDelegate() let httpClient = HTTPClient(delegate: delegate) @@ -84,6 +87,7 @@ final class CallLinkTests: XCTestCase { } } + @MainActor func testReadFailure() async throws { let delegate = TestDelegate() let httpClient = HTTPClient(delegate: delegate) @@ -104,6 +108,7 @@ final class CallLinkTests: XCTestCase { } } + @MainActor func testUpdateNameSuccess() async throws { let delegate = TestDelegate() let httpClient = HTTPClient(delegate: delegate) @@ -126,6 +131,7 @@ final class CallLinkTests: XCTestCase { } } + @MainActor func testUpdateNameFailure() async throws { let delegate = TestDelegate() let httpClient = HTTPClient(delegate: delegate) @@ -146,6 +152,7 @@ final class CallLinkTests: XCTestCase { } } + @MainActor func testUpdateNameEmptySuccess() async throws { let delegate = TestDelegate() let httpClient = HTTPClient(delegate: delegate) @@ -167,6 +174,7 @@ final class CallLinkTests: XCTestCase { } } + @MainActor func testUpdateRestrictionsSuccess() async throws { let delegate = TestDelegate() let httpClient = HTTPClient(delegate: delegate) @@ -188,7 +196,7 @@ final class CallLinkTests: XCTestCase { } } - + @MainActor func testDeleteCallLinkSuccess() async throws { let delegate = TestDelegate() let httpClient = HTTPClient(delegate: delegate) @@ -210,6 +218,7 @@ final class CallLinkTests: XCTestCase { } } + @MainActor func testPeekNoActiveCall() async throws { let delegate = TestDelegate() let httpClient = HTTPClient(delegate: delegate) @@ -228,6 +237,7 @@ final class CallLinkTests: XCTestCase { XCTAssertEqual(0, result.peekInfo.deviceCountExcludingPendingDevices) } + @MainActor func testPeekExpiredLink() async throws { let delegate = TestDelegate() let httpClient = HTTPClient(delegate: delegate) @@ -246,6 +256,7 @@ final class CallLinkTests: XCTestCase { XCTAssertEqual(0, result.peekInfo.deviceCountExcludingPendingDevices) } + @MainActor func testPeekInvalidLink() async throws { let delegate = TestDelegate() let httpClient = HTTPClient(delegate: delegate) @@ -264,6 +275,7 @@ final class CallLinkTests: XCTestCase { XCTAssertEqual(0, result.peekInfo.deviceCountExcludingPendingDevices) } + @MainActor func testConnectWithNoResponse() throws { let delegate = TestDelegate() let callManager = createCallManager(delegate)! diff --git a/src/ios/SignalRingRTC/SignalRingRTCTests/SignalRingRTCTests.swift b/src/ios/SignalRingRTC/SignalRingRTCTests/SignalRingRTCTests.swift index ca00deb0..a21a8003 100644 --- a/src/ios/SignalRingRTC/SignalRingRTCTests/SignalRingRTCTests.swift +++ b/src/ios/SignalRingRTC/SignalRingRTCTests/SignalRingRTCTests.swift @@ -426,6 +426,7 @@ final class TestDelegate: CallManagerDelegate & HTTPDelegate { shouldSendIceCandidatesInvoked = false } + @MainActor func tryToSendIceCandidates(callId: UInt64, destinationDeviceId: UInt32?, candidates: [Data]) { if destinationDeviceId != nil { Logger.debug("callId: \(callId) destinationDeviceId: \(destinationDeviceId ?? 0) candidates.count: \(candidates.count)") @@ -796,6 +797,7 @@ class SignalRingRTCTests: XCTestCase { delay(interval: 0.1) } + @MainActor func outgoingTesting(dataMode: DataMode) { Logger.debug("Test: Outgoing Call...") @@ -895,14 +897,17 @@ class SignalRingRTCTests: XCTestCase { Logger.debug("Test: Exiting test function...") } + @MainActor func testOutgoingNormal() { outgoingTesting(dataMode: .normal) } + @MainActor func testOutgoingLow() { outgoingTesting(dataMode: .low) } + @MainActor func testOutgoingSendOfferFail() { Logger.debug("Test: Outgoing Call Send Offer Fail...") @@ -967,6 +972,7 @@ class SignalRingRTCTests: XCTestCase { Logger.debug("Test: Exiting test function...") } + @MainActor func testIncoming() { Logger.debug("Test: Incoming Call...") @@ -1054,6 +1060,7 @@ class SignalRingRTCTests: XCTestCase { Logger.debug("Test: Exiting test function...") } + @MainActor func testOutgoingMultiHangupMin() { Logger.debug("Test: MultiHangup Minimum...") @@ -1101,6 +1108,7 @@ class SignalRingRTCTests: XCTestCase { Logger.debug("Test: Exiting test function...") } + @MainActor func testOutgoingMultiHangup() { Logger.debug("Test: MultiHangup...") @@ -1151,6 +1159,7 @@ class SignalRingRTCTests: XCTestCase { Logger.debug("Test: Exiting test function...") } + @MainActor func testOutgoingMultiHangupProceed() { Logger.debug("Test: MultiHangup with Proceed...") @@ -1225,6 +1234,7 @@ class SignalRingRTCTests: XCTestCase { Logger.debug("Test: Exiting test function...") } + @MainActor func testOutgoingMultiHangupProceedOffer() { Logger.debug("Test: MultiHangup with Proceed until offer sent...") @@ -1300,6 +1310,7 @@ class SignalRingRTCTests: XCTestCase { Logger.debug("Test: Exiting test function...") } + @MainActor func testIncomingQuickHangupNoDelay() { Logger.debug("Test: Incoming Call Offer with quick Hangup No Delay...") @@ -1360,6 +1371,7 @@ class SignalRingRTCTests: XCTestCase { Logger.debug("Test: Exiting test function...") } + @MainActor func testIncomingQuickHangupWithDelay() { Logger.debug("Test: Incoming Call Offer with quick Hangup with Delay...") @@ -1426,6 +1438,7 @@ class SignalRingRTCTests: XCTestCase { Logger.debug("Test: Exiting test function...") } + @MainActor func multiCallTesting(loopIterations: Int) { Logger.debug("Test: MultiCall...") @@ -1600,10 +1613,12 @@ class SignalRingRTCTests: XCTestCase { Logger.debug("Test: Exiting test function...") } + @MainActor func testMultiCallOpaque() { multiCallTesting(loopIterations: 2) } + @MainActor func testMultiCallFastIceCheck() { Logger.debug("Test: MultiCall check that immediate ICE message is handled...") @@ -1764,6 +1779,7 @@ class SignalRingRTCTests: XCTestCase { case equal } + @MainActor func glareTesting(scenario: GlareScenario, condition: GlareCondition) { Logger.debug("Test: Testing glare for scenario: \(scenario) and condition: \(condition)...") @@ -1925,26 +1941,32 @@ class SignalRingRTCTests: XCTestCase { Logger.debug("Test: Exiting test function...") } + @MainActor func testGlareWinnerBeforeProceed() { glareTesting(scenario: .beforeProceed, condition: .winner) } + @MainActor func testGlareWinnerAfterProceed() { glareTesting(scenario: .afterProceed, condition: .winner) } + @MainActor func testGlareLoserBeforeProceed() { glareTesting(scenario: .beforeProceed, condition: .loser) } + @MainActor func testGlareLoserAfterProceed() { glareTesting(scenario: .afterProceed, condition: .loser) } + @MainActor func testGlareEqualBeforeProceed() { glareTesting(scenario: .beforeProceed, condition: .equal) } + @MainActor func testGlareEqualAfterProceed() { glareTesting(scenario: .afterProceed, condition: .equal) } @@ -1955,6 +1977,7 @@ class SignalRingRTCTests: XCTestCase { case calleeReconnecting } + @MainActor func reCallTesting(scenario: ReCallScenario) { Logger.debug("Test: Testing ReCall for scenario: \(scenario)...") @@ -2157,10 +2180,12 @@ class SignalRingRTCTests: XCTestCase { Logger.debug("Test: Exiting test function...") } + @MainActor func testRecallStillInCall() { reCallTesting(scenario: .calleeStillInCall) } + @MainActor func testRecallReconnecting() { reCallTesting(scenario: .calleeReconnecting) } @@ -2172,6 +2197,7 @@ class SignalRingRTCTests: XCTestCase { case calleeAccepts /// Caller rings multiple callee devices, one callee accepts and gets in to call, all other callees stop ringing. } + @MainActor func multiRingTesting(calleeDeviceCount: Int, loopIterations: Int, scenario: MultiRingScenario) { Logger.debug("Test: Testing multi-ring for scenario: \(scenario)...") @@ -2649,18 +2675,22 @@ class SignalRingRTCTests: XCTestCase { Logger.debug("Test: Exiting test function...") } + @MainActor func testMultiRing() { multiRingTesting(calleeDeviceCount: 2, loopIterations: 1, scenario: .callerEnds) } + @MainActor func testMultiRingDeclined() { multiRingTesting(calleeDeviceCount: 2, loopIterations: 1, scenario: .calleeDeclines) } + @MainActor func testMultiRingBusy() { multiRingTesting(calleeDeviceCount: 2, loopIterations: 1, scenario: .calleeBusy) } + @MainActor func testMultiRingAccepted() { multiRingTesting(calleeDeviceCount: 2, loopIterations: 1, scenario: .calleeAccepts) } @@ -2672,6 +2702,7 @@ class SignalRingRTCTests: XCTestCase { case differentDevice /// A1 is in call with B1; A2 calls B, should ring on B2 } + @MainActor func multiRingGlareTesting(scenario: MultiRingGlareScenario) { Logger.debug("Test: Testing multi-ring glare for scenario: \(scenario)...") @@ -3220,22 +3251,27 @@ class SignalRingRTCTests: XCTestCase { Logger.debug("Test: Exiting test function...") } + @MainActor func testMultiRingGlarePrimaryWinner() { multiRingGlareTesting(scenario: .primaryWinner) } + @MainActor func testMultiRingGlarePrimaryLoser() { multiRingGlareTesting(scenario: .primaryLoser) } + @MainActor func testMultiRingGlarePrimaryEqual() { multiRingGlareTesting(scenario: .primaryEqual) } + @MainActor func testMultiRingGlareDifferentDevice() { multiRingGlareTesting(scenario: .differentDevice) } + @MainActor func testCallIdFromEra() { let fromHex = callIdFromEra("1122334455667788") XCTAssertEqual(fromHex, 0x1122334455667788) @@ -3256,6 +3292,7 @@ class SignalRingRTCTests: XCTestCase { } } + @MainActor func testPeekWithPendingClients() async throws { let delegate = TestDelegate() let httpClient = HTTPClient(delegate: delegate)