Skip to content

Commit 19004bb

Browse files
committed
EC: Send rtc.decline event when incoming call is declined
1 parent 3891ca7 commit 19004bb

File tree

6 files changed

+121
-3
lines changed

6 files changed

+121
-3
lines changed

ElementX/Sources/Mocks/Generated/GeneratedMocks.swift

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8997,6 +8997,76 @@ class JoinedRoomProxyMock: JoinedRoomProxyProtocol, @unchecked Sendable {
89978997
return elementCallWidgetDriverDeviceIDReturnValue
89988998
}
89998999
}
9000+
//MARK: - declineCall
9001+
9002+
var declineCallNotificationIdUnderlyingCallsCount = 0
9003+
var declineCallNotificationIdCallsCount: Int {
9004+
get {
9005+
if Thread.isMainThread {
9006+
return declineCallNotificationIdUnderlyingCallsCount
9007+
} else {
9008+
var returnValue: Int? = nil
9009+
DispatchQueue.main.sync {
9010+
returnValue = declineCallNotificationIdUnderlyingCallsCount
9011+
}
9012+
9013+
return returnValue!
9014+
}
9015+
}
9016+
set {
9017+
if Thread.isMainThread {
9018+
declineCallNotificationIdUnderlyingCallsCount = newValue
9019+
} else {
9020+
DispatchQueue.main.sync {
9021+
declineCallNotificationIdUnderlyingCallsCount = newValue
9022+
}
9023+
}
9024+
}
9025+
}
9026+
var declineCallNotificationIdCalled: Bool {
9027+
return declineCallNotificationIdCallsCount > 0
9028+
}
9029+
var declineCallNotificationIdReceivedNotificationId: String?
9030+
var declineCallNotificationIdReceivedInvocations: [String] = []
9031+
9032+
var declineCallNotificationIdUnderlyingReturnValue: Result<Void, RoomProxyError>!
9033+
var declineCallNotificationIdReturnValue: Result<Void, RoomProxyError>! {
9034+
get {
9035+
if Thread.isMainThread {
9036+
return declineCallNotificationIdUnderlyingReturnValue
9037+
} else {
9038+
var returnValue: Result<Void, RoomProxyError>? = nil
9039+
DispatchQueue.main.sync {
9040+
returnValue = declineCallNotificationIdUnderlyingReturnValue
9041+
}
9042+
9043+
return returnValue!
9044+
}
9045+
}
9046+
set {
9047+
if Thread.isMainThread {
9048+
declineCallNotificationIdUnderlyingReturnValue = newValue
9049+
} else {
9050+
DispatchQueue.main.sync {
9051+
declineCallNotificationIdUnderlyingReturnValue = newValue
9052+
}
9053+
}
9054+
}
9055+
}
9056+
var declineCallNotificationIdClosure: ((String) async -> Result<Void, RoomProxyError>)?
9057+
9058+
func declineCall(notificationId: String) async -> Result<Void, RoomProxyError> {
9059+
declineCallNotificationIdCallsCount += 1
9060+
declineCallNotificationIdReceivedNotificationId = notificationId
9061+
DispatchQueue.main.async {
9062+
self.declineCallNotificationIdReceivedInvocations.append(notificationId)
9063+
}
9064+
if let declineCallNotificationIdClosure = declineCallNotificationIdClosure {
9065+
return await declineCallNotificationIdClosure(notificationId)
9066+
} else {
9067+
return declineCallNotificationIdReturnValue
9068+
}
9069+
}
90009070
//MARK: - matrixToPermalink
90019071

90029072
var matrixToPermalinkUnderlyingCallsCount = 0

ElementX/Sources/Services/ElementCall/ElementCallService.swift

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
1616
private struct CallID: Equatable {
1717
let callKitID: UUID
1818
let roomID: String
19+
let rtcNotificationId: String?
1920
}
2021

2122
private let pushRegistry: PKPushRegistry
@@ -93,7 +94,7 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
9394
let callID = if let incomingCallID, incomingCallID.roomID == roomID {
9495
incomingCallID
9596
} else {
96-
CallID(callKitID: UUID(), roomID: roomID)
97+
CallID(callKitID: UUID(), roomID: roomID, rtcNotificationId: nil)
9798
}
9899

99100
incomingCallID = nil
@@ -146,12 +147,17 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
146147
return
147148
}
148149

150+
guard let rtcNotificationId = payload.dictionaryPayload[ElementCallServiceNotificationKey.rtcNotifyEventId.rawValue] as? String else {
151+
MXLog.error("Something went wrong, missing rtc notification event identifier for incoming voip call: \(payload)")
152+
return
153+
}
154+
149155
guard ongoingCallID?.roomID != roomID else {
150156
MXLog.warning("Call already ongoing for room \(roomID), ignoring incoming push")
151157
return
152158
}
153159

154-
let callID = CallID(callKitID: UUID(), roomID: roomID)
160+
let callID = CallID(callKitID: UUID(), roomID: roomID, rtcNotificationId: rtcNotificationId)
155161
incomingCallID = callID
156162

157163
let roomDisplayName = payload.dictionaryPayload[ElementCallServiceNotificationKey.roomDisplayName.rawValue] as? String
@@ -253,6 +259,12 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
253259
actionsSubject.send(.endCall(roomID: ongoingCallID.roomID))
254260
}
255261

262+
if let incomingCallID {
263+
Task {
264+
await sendDeclineCallEvent(incomingCallID)
265+
}
266+
}
267+
256268
tearDownCallSession(sendEndCallAction: false)
257269

258270
action.fulfill()
@@ -274,6 +286,25 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
274286
ongoingCallID = nil
275287
}
276288

289+
private func sendDeclineCallEvent(_ incomingCallID: CallID) async {
290+
guard let rtcNotificationId = incomingCallID.rtcNotificationId else {
291+
MXLog.info("No rtc notification event to decline.")
292+
return
293+
}
294+
295+
guard let clientProxy else {
296+
MXLog.warning("A ClientProxy is needed to fetch the room.")
297+
return
298+
}
299+
300+
guard case let .joined(roomProxy) = await clientProxy.roomForIdentifier(incomingCallID.roomID) else {
301+
MXLog.warning("Failed to fetch a joined room for the incoming call.")
302+
return
303+
}
304+
305+
_ = await roomProxy.declineCall(notificationId: rtcNotificationId)
306+
}
307+
277308
private func observeIncomingCallRoomInfo() async {
278309
incomingCallRoomInfoCancellable = nil
279310

ElementX/Sources/Services/ElementCall/ElementCallServiceConstants.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import Foundation
1010
enum ElementCallServiceNotificationKey: String {
1111
case roomID
1212
case roomDisplayName
13+
/// When an incoming call is set to ring, there will be a `m.rtc.notification`event (MSC4075).
14+
/// Keep the notification event id as it is needed to decline calls (MSC4310).
15+
case rtcNotifyEventId
1316
}
1417

1518
let ElementCallServiceNotificationDiscardDelta = 15.0

ElementX/Sources/Services/Room/JoinedRoomProxy.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,16 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
639639
ElementCallWidgetDriver(room: room, deviceID: deviceID)
640640
}
641641

642+
func declineCall(notificationId: String) async -> Result<Void, RoomProxyError> {
643+
do {
644+
try await room.declineCall(rtcNotificationEventId: notificationId)
645+
return .success(())
646+
} catch {
647+
MXLog.error("Failed to decline rtc notification \(notificationId) with error: \(error)")
648+
return .failure(.sdkError(error))
649+
}
650+
}
651+
642652
// MARK: - Permalinks
643653

644654
func matrixToPermalink() async -> Result<URL, RoomProxyError> {

ElementX/Sources/Services/Room/RoomProxyProtocol.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
169169
// MARK: - Element Call
170170

171171
func elementCallWidgetDriver(deviceID: String) -> ElementCallWidgetDriverProtocol
172+
func declineCall(notificationId: String) async -> Result<Void, RoomProxyError>
172173

173174
// MARK: - Permalinks
174175

NSE/Sources/NotificationHandler.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ class NotificationHandler {
126126
return .processedShouldDiscard
127127
case .callNotify(let notifyType):
128128
return await handleCallNotification(notifyType: notifyType,
129+
rtcNotifyEventId: event.eventId(),
129130
timestamp: event.timestamp(),
130131
roomID: itemProxy.roomID,
131132
roomDisplayName: itemProxy.roomDisplayName)
@@ -153,6 +154,7 @@ class NotificationHandler {
153154
/// Handle incoming call notifications.
154155
/// - Returns: A boolean indicating whether the notification was handled and should now be discarded.
155156
private func handleCallNotification(notifyType: NotifyType,
157+
rtcNotifyEventId: String,
156158
timestamp: Timestamp,
157159
roomID: String,
158160
roomDisplayName: String) async -> NotificationProcessingResult {
@@ -206,7 +208,8 @@ class NotificationHandler {
206208
}
207209

208210
let payload = [ElementCallServiceNotificationKey.roomID.rawValue: roomID,
209-
ElementCallServiceNotificationKey.roomDisplayName.rawValue: roomDisplayName]
211+
ElementCallServiceNotificationKey.roomDisplayName.rawValue: roomDisplayName,
212+
ElementCallServiceNotificationKey.rtcNotifyEventId.rawValue: rtcNotifyEventId]
210213

211214
do {
212215
try await CXProvider.reportNewIncomingVoIPPushPayload(payload)

0 commit comments

Comments
 (0)