Skip to content

Commit

Permalink
Various tweaks following code review
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanceriu committed Jun 26, 2024
1 parent 57761ba commit 0a701a7
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 45 deletions.
2 changes: 1 addition & 1 deletion ElementX/Sources/Application/AppCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions ElementX/Sources/Application/Navigation/AppRoutes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
22 changes: 15 additions & 7 deletions ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -573,7 +581,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
presentCallScreen(roomProxy: roomProxy)
}

private func dismissCallScreen() {
private func dismissCallScreenIfNeeded() {
guard navigationSplitCoordinator.sheetCoordinator is CallScreenCoordinator else {
return
}
Expand Down
67 changes: 32 additions & 35 deletions ElementX/Sources/Services/ElementCall/ElementCallService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<Void, Never>?

private var ongoingCallID: CallID?

private let actionsSubject: PassthroughSubject<ElementCallServiceAction, Never> = .init()
var actions: AnyPublisher<ElementCallServiceAction, Never> {
actionsSubject.eraseToAnyPublisher()
Expand All @@ -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)
Expand All @@ -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

Expand All @@ -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)
}
}
}
Expand All @@ -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()
}
Expand All @@ -162,30 +166,23 @@ 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()
}

// 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 {
Expand All @@ -194,6 +191,6 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
}
}

self.ongoingCallID = nil
ongoingCallID = nil
}
}

0 comments on commit 0a701a7

Please sign in to comment.