Fixes #3042 - Cancel ElementCall ringing as soon as the call ends

This commit is contained in:
Stefan Ceriu
2024-07-16 17:09:16 +03:00
committed by Stefan Ceriu
parent d16ba9f3ef
commit 239afeb662
9 changed files with 188 additions and 18 deletions
@@ -44,7 +44,17 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
return CXProvider(configuration: configuration)
}()
private var incomingCallID: CallID?
private weak var clientProxy: ClientProxyProtocol?
private var cancellables = Set<AnyCancellable>()
private var incomingCallID: CallID? {
didSet {
Task {
await observeIncomingCallRoomStateUpdates()
}
}
}
private var endUnansweredCallTask: Task<Void, Never>?
private var ongoingCallID: CallID?
@@ -65,6 +75,10 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
callProvider.setDelegate(self, queue: nil)
}
func setClientProxy(_ clientProxy: any ClientProxyProtocol) {
self.clientProxy = clientProxy
}
func setupCallSession(roomID: String, roomDisplayName: String) async {
// Drop any ongoing calls when starting a new one
if ongoingCallID != nil {
@@ -221,4 +235,46 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
ongoingCallID = nil
}
func observeIncomingCallRoomStateUpdates() async {
cancellables.removeAll()
guard let clientProxy, let incomingCallID else {
return
}
guard let roomProxy = await clientProxy.roomForIdentifier(incomingCallID.roomID) else {
return
}
roomProxy.subscribeToRoomInfoUpdates()
// There's no incoming event for call cancellations so try to infer
// it from what we have. If the call is running before subscribing then wait
// for it to change to `false` otherwise wait for it to turn `true` before
// changing to `false`
let isCallOngoing = roomProxy.hasOngoingCall
roomProxy
.actionsPublisher
.map { action in
switch action {
case .roomInfoUpdate:
return roomProxy.hasOngoingCall
}
}
.removeDuplicates()
.dropFirst(isCallOngoing ? 0 : 1)
.sink { [weak self] hasOngoingCall in
guard let self else { return }
if !hasOngoingCall {
MXLog.info("Call has been cancelled")
cancellables.removeAll()
endUnansweredCallTask?.cancel()
callProvider.reportCall(with: incomingCallID.callKitID, endedAt: nil, reason: .remoteEnded)
}
}
.store(in: &cancellables)
}
}