From 0a701a77d1b3db885c6a2ae19626b63227cff009 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Wed, 26 Jun 2024 08:23:11 +0300 Subject: [PATCH] Various tweaks following code review --- .../Sources/Application/AppCoordinator.swift | 2 +- .../Application/Navigation/AppRoutes.swift | 4 +- .../UserSessionFlowCoordinator.swift | 22 ++++-- .../ElementCall/ElementCallService.swift | 67 +++++++++---------- 4 files changed, 50 insertions(+), 45 deletions(-) diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index fe3a6bfdb6..f70687641b 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -152,7 +152,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg case .startCall(let roomID): self?.handleAppRoute(.call(roomID: roomID)) case .endCall: - self?.handleAppRoute(.call(roomID: nil)) + break // Handled internally in the UserSessionFlowCoordinator } } .store(in: &cancellables) diff --git a/ElementX/Sources/Application/Navigation/AppRoutes.swift b/ElementX/Sources/Application/Navigation/AppRoutes.swift index 64f2d77864..2e6aec080b 100644 --- a/ElementX/Sources/Application/Navigation/AppRoutes.swift +++ b/ElementX/Sources/Application/Navigation/AppRoutes.swift @@ -44,8 +44,8 @@ enum AppRoute: Equatable { case childEventOnRoomAlias(eventID: String, alias: String) /// The profile of a matrix user (outside of a room). case userProfile(userID: String) - /// An Element Call running in a particular room. Nil if having to end the call - case call(roomID: String?) + /// An Element Call running in a particular room + case call(roomID: String) /// An Element Call link generated outside of a chat room. case genericCallLink(url: URL) /// The settings screen. diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index 18fedd00da..04bbceb546 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -168,6 +168,18 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { } } .store(in: &cancellables) + + elementCallService.actions + .receive(on: DispatchQueue.main) + .sink { [weak self] action in + switch action { + case .startCall: + break + case .endCall: + self?.dismissCallScreenIfNeeded() + } + } + .store(in: &cancellables) } func start() { @@ -251,12 +263,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { case .userProfile(let userID): stateMachine.processEvent(.showUserProfileScreen(userID: userID), userInfo: .init(animated: animated)) case .call(let roomID): - if let roomID { - Task { - await presentCallScreen(roomID: roomID) - } - } else { - dismissCallScreen() + Task { + await presentCallScreen(roomID: roomID) } case .genericCallLink(let url): navigationSplitCoordinator.setSheetCoordinator(GenericCallLinkCoordinator(parameters: .init(url: url)), animated: animated) @@ -573,7 +581,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { presentCallScreen(roomProxy: roomProxy) } - private func dismissCallScreen() { + private func dismissCallScreenIfNeeded() { guard navigationSplitCoordinator.sheetCoordinator is CallScreenCoordinator else { return } diff --git a/ElementX/Sources/Services/ElementCall/ElementCallService.swift b/ElementX/Sources/Services/ElementCall/ElementCallService.swift index 465fc8e358..5a690deb27 100644 --- a/ElementX/Sources/Services/ElementCall/ElementCallService.swift +++ b/ElementX/Sources/Services/ElementCall/ElementCallService.swift @@ -41,9 +41,11 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe return CXProvider(configuration: configuration) }() - private var ongoingCallID: CallID? + private var incomingCallID: CallID? private var endUnansweredCallTask: Task? + private var ongoingCallID: CallID? + private let actionsSubject: PassthroughSubject = .init() var actions: AnyPublisher { actionsSubject.eraseToAnyPublisher() @@ -57,16 +59,24 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe pushRegistry.delegate = self pushRegistry.desiredPushTypes = [.voIP] - callProvider.setDelegate(self, queue: DispatchQueue.main) + callProvider.setDelegate(self, queue: nil) } func setupCallSession(roomID: String, roomDisplayName: String) async { - let callID = if let ongoingCallID { - ongoingCallID + // Drop any ongoing calls when starting a new one + if ongoingCallID != nil { + tearDownCallSession() + } + + // If this starting from a ring reuse those identifiers + // Make sure the roomID matches + let callID = if let incomingCallID, incomingCallID.roomID == roomID { + incomingCallID } else { CallID(callKitID: UUID(), roomID: roomID) } + incomingCallID = nil ongoingCallID = callID let handle = CXHandle(type: .generic, value: roomDisplayName) @@ -93,7 +103,7 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe } let callID = CallID(callKitID: UUID(), roomID: roomID) - ongoingCallID = callID + incomingCallID = callID let roomDisplayName = payload.dictionaryPayload[ElementCallServiceNotificationKey.roomDisplayName.rawValue] as? String @@ -118,8 +128,8 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe return } - if let ongoingCallID, ongoingCallID.callKitID == callID.callKitID { - callProvider.reportCall(with: ongoingCallID.callKitID, endedAt: .now, reason: .unanswered) + if let incomingCallID, incomingCallID.callKitID == callID.callKitID { + callProvider.reportCall(with: incomingCallID.callKitID, endedAt: .now, reason: .unanswered) } } } @@ -131,28 +141,22 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe } func provider(_ provider: CXProvider, perform action: CXStartCallAction) { - guard let ongoingCallID else { + if let ongoingCallID { + provider.reportOutgoingCall(with: ongoingCallID.callKitID, connectedAt: .now) + } else { MXLog.error("Failed starting call, missing ongoingCallID") - tearDownCallSession() - return } - - provider.reportOutgoingCall(with: ongoingCallID.callKitID, connectedAt: .now) - + action.fulfill() } func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) { - guard let ongoingCallID else { - MXLog.error("Failed answering incoming call, missing ongoingCallID") - tearDownCallSession() - return + if let incomingCallID { + actionsSubject.send(.startCall(roomID: incomingCallID.roomID)) + endUnansweredCallTask?.cancel() + } else { + MXLog.error("Failed answering incoming call, missing incomingCallID") } - - // Dispatch to next run loop so it doesn't conflict with `setupCallSession` - actionsSubject.send(.startCall(roomID: ongoingCallID.roomID)) - - endUnansweredCallTask?.cancel() action.fulfill() } @@ -162,16 +166,13 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe } func provider(_ provider: CXProvider, perform action: CXEndCallAction) { - defer { - tearDownCallSession(sendEndCallAction: false) - } - - guard let ongoingCallID else { + if let ongoingCallID { + actionsSubject.send(.endCall(roomID: ongoingCallID.roomID)) + } else { MXLog.error("Failed declining incoming call, missing ongoingCallID") - return } - actionsSubject.send(.endCall(roomID: ongoingCallID.roomID)) + tearDownCallSession(sendEndCallAction: false) action.fulfill() } @@ -179,13 +180,9 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe // MARK: - Private func tearDownCallSession(sendEndCallAction: Bool = true) { - guard let ongoingCallID else { - return - } - try? AVAudioSession.sharedInstance().setActive(false) - if sendEndCallAction { + if sendEndCallAction, let ongoingCallID { let transaction = CXTransaction(action: CXEndCallAction(call: ongoingCallID.callKitID)) callController.request(transaction) { error in if let error { @@ -194,6 +191,6 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe } } - self.ongoingCallID = nil + ongoingCallID = nil } }