diff --git a/Classes/Swift/CallManager.swift b/Classes/Swift/CallManager.swift index 8d94b317e..c85e86ca5 100644 --- a/Classes/Swift/CallManager.swift +++ b/Classes/Swift/CallManager.swift @@ -49,6 +49,7 @@ import AVFoundation var actionsToPerformOnceWhenCoreIsOn : [(()->Void)] = [] var conference: Conference? var callkitAudioSessionActivated : Bool? = nil // if "nil", ignore. + var actionToFulFill : CXCallAction? = nil; var backgroundContextCall : Call? @objc var backgroundContextCameraIsEnabled : Bool = false @@ -556,7 +557,7 @@ import AVFoundation switch cstate { case .IncomingReceived: let addr = call.remoteAddress - var displayName = incomingDisplayName(call: call) + var displayName = incomingDisplayName(call: call) if (CallManager.callKitEnabled()) { let isConference = isConferenceCall(call: call) @@ -608,7 +609,13 @@ import AVFoundation CallManager.instance().speakerBeforePause = false CallManager.instance().changeRouteToSpeaker() } + actionToFulFill?.fulfill() + actionToFulFill = nil break + case .Paused: + actionToFulFill?.fulfill() + actionToFulFill = nil + break case .OutgoingInit, .OutgoingProgress, .OutgoingRinging, diff --git a/Classes/Swift/ProviderDelegate.swift b/Classes/Swift/ProviderDelegate.swift index 38692b7ee..80eb69a81 100644 --- a/Classes/Swift/ProviderDelegate.swift +++ b/Classes/Swift/ProviderDelegate.swift @@ -205,8 +205,10 @@ extension ProviderDelegate: CXProviderDelegate { let uuid = action.callUUID let callId = callInfos[uuid]?.callId let call = CallManager.instance().callByCallId(callId: callId) - action.fulfill() + if (call == nil) { + Log.directLog(BCTBX_LOG_ERROR, text: "CXSetHeldCallAction: no call !") + action.fail() return } @@ -215,33 +217,46 @@ extension ProviderDelegate: CXProviderDelegate { try CallManager.instance().lc?.leaveConference() Log.directLog(BCTBX_LOG_DEBUG, text: "CallKit: call-id: [\(String(describing: callId))] leaving conference") NotificationCenter.default.post(name: Notification.Name("LinphoneCallUpdate"), object: self) - return - } - - let state = action.isOnHold ? "Paused" : "Resumed" - Log.directLog(BCTBX_LOG_DEBUG, text: "CallKit: Call with call-id: [\(String(describing: callId))] and UUID: [\(uuid)] paused status changed to: [\(state)]") - if (action.isOnHold) { - if (call!.params?.localConferenceMode ?? false) { - return - } - CallManager.instance().speakerBeforePause = CallManager.instance().isSpeakerEnabled() - try call!.pause() - } else { - if (CallManager.instance().lc?.conference != nil && CallManager.instance().lc?.callsNb ?? 0 > 1) { - try CallManager.instance().lc?.enterConference() - NotificationCenter.default.post(name: Notification.Name("LinphoneCallUpdate"), object: self) + action.fulfill() + }else{ + let state = action.isOnHold ? "Paused" : "Resumed" + Log.directLog(BCTBX_LOG_DEBUG, text: "CallKit: Call with call-id: [\(String(describing: callId))] and UUID: [\(uuid)] paused status changed to: [\(state)]") + if (action.isOnHold) { + CallManager.instance().speakerBeforePause = CallManager.instance().isSpeakerEnabled() + try call!.pause() + CallManager.instance().actionToFulFill = action; } else { - try call!.resume() + if (CallManager.instance().lc?.conference != nil && CallManager.instance().lc?.callsNb ?? 0 > 1) { + try CallManager.instance().lc?.enterConference() + action.fulfill() + NotificationCenter.default.post(name: Notification.Name("LinphoneCallUpdate"), object: self) + } else { + try call!.resume() + CallManager.instance().actionToFulFill = action; + // HORRIBLE HACK HERE - PLEASE APPLE FIX THIS !! + // When resuming a SIP call after a native call has ended remotely, didActivate: audioSession + // is never called. + // It looks like in this case, it is implicit. + // As a result we have to notify the Core that the AudioSession is active. + // The SpeakerBox demo application written by Apple exhibits this behavior. + // https://developer.apple.com/documentation/callkit/making_and_receiving_voip_calls_with_callkit + // We can clearly see there that startAudio() is called immediately in the CXSetHeldCallAction + // handler, while it is called from didActivate: audioSession otherwise. + // Callkit's design is not consistent, or its documentation imcomplete, wich is somewhat disapointing. + // + Log.directLog(BCTBX_LOG_DEBUG, text: "Assuming AudioSession is active when executing a CXSetHeldCallAction with isOnHold=false.") + CallManager.instance().lc?.activateAudioSession(actived: true) + CallManager.instance().callkitAudioSessionActivated = true + } } } } catch { Log.directLog(BCTBX_LOG_ERROR, text: "CallKit: Call set held (paused or resumed) \(uuid) failed because \(error)") + action.fail() } } func provider(_ provider: CXProvider, perform action: CXStartCallAction) { - - do { let uuid = action.callUUID