mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-06 04:18:31 +00:00
Element Call: Send rtc.decline event when incoming call is declined (#4499)
This commit is contained in:
@@ -8997,6 +8997,76 @@ class JoinedRoomProxyMock: JoinedRoomProxyProtocol, @unchecked Sendable {
|
|||||||
return elementCallWidgetDriverDeviceIDReturnValue
|
return elementCallWidgetDriverDeviceIDReturnValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//MARK: - declineCall
|
||||||
|
|
||||||
|
var declineCallNotificationIDUnderlyingCallsCount = 0
|
||||||
|
var declineCallNotificationIDCallsCount: Int {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return declineCallNotificationIDUnderlyingCallsCount
|
||||||
|
} else {
|
||||||
|
var returnValue: Int? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = declineCallNotificationIDUnderlyingCallsCount
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
declineCallNotificationIDUnderlyingCallsCount = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
declineCallNotificationIDUnderlyingCallsCount = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var declineCallNotificationIDCalled: Bool {
|
||||||
|
return declineCallNotificationIDCallsCount > 0
|
||||||
|
}
|
||||||
|
var declineCallNotificationIDReceivedNotificationID: String?
|
||||||
|
var declineCallNotificationIDReceivedInvocations: [String] = []
|
||||||
|
|
||||||
|
var declineCallNotificationIDUnderlyingReturnValue: Result<Void, RoomProxyError>!
|
||||||
|
var declineCallNotificationIDReturnValue: Result<Void, RoomProxyError>! {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return declineCallNotificationIDUnderlyingReturnValue
|
||||||
|
} else {
|
||||||
|
var returnValue: Result<Void, RoomProxyError>? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = declineCallNotificationIDUnderlyingReturnValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
declineCallNotificationIDUnderlyingReturnValue = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
declineCallNotificationIDUnderlyingReturnValue = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var declineCallNotificationIDClosure: ((String) async -> Result<Void, RoomProxyError>)?
|
||||||
|
|
||||||
|
func declineCall(notificationID: String) async -> Result<Void, RoomProxyError> {
|
||||||
|
declineCallNotificationIDCallsCount += 1
|
||||||
|
declineCallNotificationIDReceivedNotificationID = notificationID
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.declineCallNotificationIDReceivedInvocations.append(notificationID)
|
||||||
|
}
|
||||||
|
if let declineCallNotificationIDClosure = declineCallNotificationIDClosure {
|
||||||
|
return await declineCallNotificationIDClosure(notificationID)
|
||||||
|
} else {
|
||||||
|
return declineCallNotificationIDReturnValue
|
||||||
|
}
|
||||||
|
}
|
||||||
//MARK: - matrixToPermalink
|
//MARK: - matrixToPermalink
|
||||||
|
|
||||||
var matrixToPermalinkUnderlyingCallsCount = 0
|
var matrixToPermalinkUnderlyingCallsCount = 0
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
|
|||||||
private struct CallID: Equatable {
|
private struct CallID: Equatable {
|
||||||
let callKitID: UUID
|
let callKitID: UUID
|
||||||
let roomID: String
|
let roomID: String
|
||||||
|
let rtcNotificationID: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
private let pushRegistry: PKPushRegistry
|
private let pushRegistry: PKPushRegistry
|
||||||
@@ -93,7 +94,7 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
|
|||||||
let callID = if let incomingCallID, incomingCallID.roomID == roomID {
|
let callID = if let incomingCallID, incomingCallID.roomID == roomID {
|
||||||
incomingCallID
|
incomingCallID
|
||||||
} else {
|
} else {
|
||||||
CallID(callKitID: UUID(), roomID: roomID)
|
CallID(callKitID: UUID(), roomID: roomID, rtcNotificationID: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
incomingCallID = nil
|
incomingCallID = nil
|
||||||
@@ -146,12 +147,17 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guard let rtcNotificationID = payload.dictionaryPayload[ElementCallServiceNotificationKey.rtcNotifyEventID.rawValue] as? String else {
|
||||||
|
MXLog.error("Something went wrong, missing rtc notification event identifier for incoming voip call: \(payload)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
guard ongoingCallID?.roomID != roomID else {
|
guard ongoingCallID?.roomID != roomID else {
|
||||||
MXLog.warning("Call already ongoing for room \(roomID), ignoring incoming push")
|
MXLog.warning("Call already ongoing for room \(roomID), ignoring incoming push")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let callID = CallID(callKitID: UUID(), roomID: roomID)
|
let callID = CallID(callKitID: UUID(), roomID: roomID, rtcNotificationID: rtcNotificationID)
|
||||||
incomingCallID = callID
|
incomingCallID = callID
|
||||||
|
|
||||||
let roomDisplayName = payload.dictionaryPayload[ElementCallServiceNotificationKey.roomDisplayName.rawValue] as? String
|
let roomDisplayName = payload.dictionaryPayload[ElementCallServiceNotificationKey.roomDisplayName.rawValue] as? String
|
||||||
@@ -253,6 +259,12 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
|
|||||||
actionsSubject.send(.endCall(roomID: ongoingCallID.roomID))
|
actionsSubject.send(.endCall(roomID: ongoingCallID.roomID))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let incomingCallID {
|
||||||
|
Task {
|
||||||
|
await sendDeclineCallEvent(incomingCallID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tearDownCallSession(sendEndCallAction: false)
|
tearDownCallSession(sendEndCallAction: false)
|
||||||
|
|
||||||
action.fulfill()
|
action.fulfill()
|
||||||
@@ -274,6 +286,25 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
|
|||||||
ongoingCallID = nil
|
ongoingCallID = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func sendDeclineCallEvent(_ incomingCallID: CallID) async {
|
||||||
|
guard let rtcNotificationID = incomingCallID.rtcNotificationID else {
|
||||||
|
MXLog.info("No rtc notification event to decline.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let clientProxy else {
|
||||||
|
MXLog.warning("A ClientProxy is needed to fetch the room.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard case let .joined(roomProxy) = await clientProxy.roomForIdentifier(incomingCallID.roomID) else {
|
||||||
|
MXLog.warning("Failed to fetch a joined room for the incoming call.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = await roomProxy.declineCall(notificationID: rtcNotificationID)
|
||||||
|
}
|
||||||
|
|
||||||
private func observeIncomingCallRoomInfo() async {
|
private func observeIncomingCallRoomInfo() async {
|
||||||
incomingCallRoomInfoCancellable = nil
|
incomingCallRoomInfoCancellable = nil
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import Foundation
|
|||||||
enum ElementCallServiceNotificationKey: String {
|
enum ElementCallServiceNotificationKey: String {
|
||||||
case roomID
|
case roomID
|
||||||
case roomDisplayName
|
case roomDisplayName
|
||||||
|
/// When an incoming call is set to ring, there will be a `m.rtc.notification`event (MSC4075).
|
||||||
|
/// Keep the notification event id as it is needed to decline calls (MSC4310).
|
||||||
|
case rtcNotifyEventID
|
||||||
}
|
}
|
||||||
|
|
||||||
let ElementCallServiceNotificationDiscardDelta = 15.0
|
let ElementCallServiceNotificationDiscardDelta = 15.0
|
||||||
|
|||||||
@@ -639,6 +639,16 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
|||||||
ElementCallWidgetDriver(room: room, deviceID: deviceID)
|
ElementCallWidgetDriver(room: room, deviceID: deviceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func declineCall(notificationID: String) async -> Result<Void, RoomProxyError> {
|
||||||
|
do {
|
||||||
|
try await room.declineCall(rtcNotificationEventId: notificationID)
|
||||||
|
return .success(())
|
||||||
|
} catch {
|
||||||
|
MXLog.error("Failed to decline rtc notification \(notificationID) with error: \(error)")
|
||||||
|
return .failure(.sdkError(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Permalinks
|
// MARK: - Permalinks
|
||||||
|
|
||||||
func matrixToPermalink() async -> Result<URL, RoomProxyError> {
|
func matrixToPermalink() async -> Result<URL, RoomProxyError> {
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
|
|||||||
// MARK: - Element Call
|
// MARK: - Element Call
|
||||||
|
|
||||||
func elementCallWidgetDriver(deviceID: String) -> ElementCallWidgetDriverProtocol
|
func elementCallWidgetDriver(deviceID: String) -> ElementCallWidgetDriverProtocol
|
||||||
|
func declineCall(notificationID: String) async -> Result<Void, RoomProxyError>
|
||||||
|
|
||||||
// MARK: - Permalinks
|
// MARK: - Permalinks
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ class NotificationHandler {
|
|||||||
return .processedShouldDiscard
|
return .processedShouldDiscard
|
||||||
case .callNotify(let notifyType):
|
case .callNotify(let notifyType):
|
||||||
return await handleCallNotification(notifyType: notifyType,
|
return await handleCallNotification(notifyType: notifyType,
|
||||||
|
rtcNotifyEventID: event.eventId(),
|
||||||
timestamp: event.timestamp(),
|
timestamp: event.timestamp(),
|
||||||
roomID: itemProxy.roomID,
|
roomID: itemProxy.roomID,
|
||||||
roomDisplayName: itemProxy.roomDisplayName)
|
roomDisplayName: itemProxy.roomDisplayName)
|
||||||
@@ -153,6 +154,7 @@ class NotificationHandler {
|
|||||||
/// Handle incoming call notifications.
|
/// Handle incoming call notifications.
|
||||||
/// - Returns: A boolean indicating whether the notification was handled and should now be discarded.
|
/// - Returns: A boolean indicating whether the notification was handled and should now be discarded.
|
||||||
private func handleCallNotification(notifyType: NotifyType,
|
private func handleCallNotification(notifyType: NotifyType,
|
||||||
|
rtcNotifyEventID: String,
|
||||||
timestamp: Timestamp,
|
timestamp: Timestamp,
|
||||||
roomID: String,
|
roomID: String,
|
||||||
roomDisplayName: String) async -> NotificationProcessingResult {
|
roomDisplayName: String) async -> NotificationProcessingResult {
|
||||||
@@ -206,7 +208,8 @@ class NotificationHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let payload = [ElementCallServiceNotificationKey.roomID.rawValue: roomID,
|
let payload = [ElementCallServiceNotificationKey.roomID.rawValue: roomID,
|
||||||
ElementCallServiceNotificationKey.roomDisplayName.rawValue: roomDisplayName]
|
ElementCallServiceNotificationKey.roomDisplayName.rawValue: roomDisplayName,
|
||||||
|
ElementCallServiceNotificationKey.rtcNotifyEventID.rawValue: rtcNotifyEventID]
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try await CXProvider.reportNewIncomingVoIPPushPayload(payload)
|
try await CXProvider.reportNewIncomingVoIPPushPayload(payload)
|
||||||
|
|||||||
Reference in New Issue
Block a user