mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
merge CallKitProviderDelegate into CallKitCallUIAdaptee
There was not a clear distinction in responsibilities and mostly the Adaptee was just delegating to the CKProviderDelegate
This commit is contained in:
parent
ce3780e44a
commit
9e248168b9
4 changed files with 272 additions and 339 deletions
|
@ -101,8 +101,6 @@
|
|||
45F659731E1BD99C00444429 /* CallKitCallUIAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F659721E1BD99C00444429 /* CallKitCallUIAdaptee.swift */; };
|
||||
45F659821E1BE77000444429 /* NonCallKitCallUIAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F659811E1BE77000444429 /* NonCallKitCallUIAdaptee.swift */; };
|
||||
45F659831E1BE77000444429 /* NonCallKitCallUIAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F659811E1BE77000444429 /* NonCallKitCallUIAdaptee.swift */; };
|
||||
45FBC5C01DF8575700E9B410 /* CallKitProviderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45FBC5951DF8575700E9B410 /* CallKitProviderDelegate.swift */; };
|
||||
45FBC5C11DF8575700E9B410 /* CallKitProviderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45FBC5951DF8575700E9B410 /* CallKitProviderDelegate.swift */; };
|
||||
45FBC5C81DF8575700E9B410 /* CallKitCallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */; };
|
||||
45FBC5C91DF8575700E9B410 /* CallKitCallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */; };
|
||||
45FBC5D11DF8592E00E9B410 /* SignalCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45FBC5D01DF8592E00E9B410 /* SignalCall.swift */; };
|
||||
|
@ -687,7 +685,6 @@
|
|||
45F3AEB51DFDE7900080CE33 /* AvatarImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarImageView.swift; sourceTree = "<group>"; };
|
||||
45F659721E1BD99C00444429 /* CallKitCallUIAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitCallUIAdaptee.swift; sourceTree = "<group>"; };
|
||||
45F659811E1BE77000444429 /* NonCallKitCallUIAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NonCallKitCallUIAdaptee.swift; sourceTree = "<group>"; };
|
||||
45FBC5951DF8575700E9B410 /* CallKitProviderDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitProviderDelegate.swift; sourceTree = "<group>"; };
|
||||
45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitCallManager.swift; sourceTree = "<group>"; };
|
||||
45FBC5D01DF8592E00E9B410 /* SignalCall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalCall.swift; sourceTree = "<group>"; };
|
||||
4CE0E3751B95453C007210CF /* TSAnimatedAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSAnimatedAdapter.h; sourceTree = "<group>"; };
|
||||
|
@ -1411,7 +1408,6 @@
|
|||
45FBC57A1DF8575700E9B410 /* CallKit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
45FBC5951DF8575700E9B410 /* CallKitProviderDelegate.swift */,
|
||||
45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */,
|
||||
45F659721E1BD99C00444429 /* CallKitCallUIAdaptee.swift */,
|
||||
);
|
||||
|
@ -3033,7 +3029,6 @@
|
|||
B6A3EB4B1A423B3800B2236B /* TSPhotoAdapter.m in Sources */,
|
||||
4509E79C1DD6545B0025A59F /* CallViewController.swift in Sources */,
|
||||
76EB063A18170B33006006FC /* FunctionalUtil.m in Sources */,
|
||||
45FBC5C01DF8575700E9B410 /* CallKitProviderDelegate.swift in Sources */,
|
||||
76EB060A18170B33006006FC /* SignalUtil.m in Sources */,
|
||||
E197B61718BBEC1A00F073E5 /* AnonymousAudioCallbackHandler.m in Sources */,
|
||||
76EB05BC18170B33006006FC /* ConfirmAckPacket.m in Sources */,
|
||||
|
@ -3320,7 +3315,6 @@
|
|||
B660F7581C29988E00687D6E /* RPAccountManager.m in Sources */,
|
||||
B660F7591C29988E00687D6E /* CallController.m in Sources */,
|
||||
B660F75A1C29988E00687D6E /* CallFailedServerMessage.m in Sources */,
|
||||
45FBC5C11DF8575700E9B410 /* CallKitProviderDelegate.swift in Sources */,
|
||||
B660F75B1C29988E00687D6E /* CallProgress.m in Sources */,
|
||||
B660F75C1C29988E00687D6E /* CallState.m in Sources */,
|
||||
B660F75D1C29988E00687D6E /* CallTermination.m in Sources */,
|
||||
|
|
|
@ -1,62 +1,290 @@
|
|||
// Created by Michael Kirk on 1/3/17.
|
||||
// Copyright © 2017 Open Whisper Systems. All rights reserved.
|
||||
// Created by Michael Kirk on 12/23/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import CallKit
|
||||
import AVFoundation
|
||||
|
||||
/**
|
||||
* CallKit backed implementation of UI Activity related to Signal Calls
|
||||
* TODO: Code Cleanup: It might be more straight forward to roll this into the CallKitProviderDelegate.
|
||||
* Connects user interface to the CallService usin CallKit.
|
||||
*
|
||||
* User interface is mapped to CXCall action requests, and if the CXProvider accepts them,
|
||||
* their corresponding consequences are requested via the CallService
|
||||
*/
|
||||
@available(iOS 10.0, *)
|
||||
class CallKitCallUIAdaptee: CallUIAdaptee {
|
||||
final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
|
||||
|
||||
let TAG = "[CallKitCallUIAdaptee]"
|
||||
let providerDelegate: CallKitProviderDelegate
|
||||
let callManager: CallKitCallManager
|
||||
let notificationsAdapter: CallNotificationsAdapter
|
||||
|
||||
init(callService: CallService, notificationsAdapter: CallNotificationsAdapter) {
|
||||
self.callManager = CallKitCallManager()
|
||||
self.providerDelegate = CallKitProviderDelegate(callService: callService, notificationsAdapter: notificationsAdapter)
|
||||
self.notificationsAdapter = notificationsAdapter
|
||||
private let callManager: CallKitCallManager
|
||||
private let callService: CallService
|
||||
internal let notificationsAdapter: CallNotificationsAdapter
|
||||
private let provider: CXProvider
|
||||
|
||||
// FIXME - I might be thinking about this the wrong way.
|
||||
// It seems like the provider delegate wants to stop/start the audio recording
|
||||
// process, but the ProviderDelegate is an app singleton
|
||||
// and the audio recording process is currently controlled (I think) by
|
||||
// the PeerConnectionClient instance, which is one per call (NOT a singleton).
|
||||
// It seems like a mess to reconcile this difference in cardinality. But... here we are.
|
||||
var audioManager: SignalCallAudioManager?
|
||||
|
||||
/// The app's provider configuration, representing its CallKit capabilities
|
||||
static var providerConfiguration: CXProviderConfiguration {
|
||||
let localizedName = NSLocalizedString("APPLICATION_NAME", comment: "Name of application")
|
||||
let providerConfiguration = CXProviderConfiguration(localizedName: localizedName)
|
||||
|
||||
providerConfiguration.supportsVideo = true
|
||||
|
||||
providerConfiguration.maximumCallsPerCallGroup = 1
|
||||
|
||||
providerConfiguration.supportedHandleTypes = [.phoneNumber]
|
||||
|
||||
if let iconMaskImage = UIImage(named: "IconMask") {
|
||||
providerConfiguration.iconTemplateImageData = UIImagePNGRepresentation(iconMaskImage)
|
||||
}
|
||||
|
||||
providerConfiguration.ringtoneSound = "r.caf"
|
||||
|
||||
return providerConfiguration
|
||||
}
|
||||
|
||||
public func startOutgoingCall(_ call: SignalCall) {
|
||||
init(callService: CallService, notificationsAdapter: CallNotificationsAdapter) {
|
||||
self.callManager = CallKitCallManager()
|
||||
self.callService = callService
|
||||
self.notificationsAdapter = notificationsAdapter
|
||||
self.provider = CXProvider(configuration: type(of: self).providerConfiguration)
|
||||
|
||||
super.init()
|
||||
|
||||
self.provider.setDelegate(self, queue: nil)
|
||||
}
|
||||
|
||||
// MARK: CallUIAdaptee
|
||||
|
||||
internal func startOutgoingCall(_ call: SignalCall) {
|
||||
// Add the new outgoing call to the app's list of calls.
|
||||
// So we can find it in the provider delegate callbacks.
|
||||
// self.callManager.addCall(call)
|
||||
// providerDelegate.callManager.startCall(call)
|
||||
callManager.addCall(call)
|
||||
callManager.startCall(call)
|
||||
}
|
||||
|
||||
public func reportIncomingCall(_ call: SignalCall, callerName: String, audioManager: SignalCallAudioManager) {
|
||||
// FIXME weird to pass the audio manager in here.
|
||||
// Crux is, the peerconnectionclient is what controls the audio channel.
|
||||
// But a peerconnectionclient is per call.
|
||||
// While this providerDelegate is an app singleton.
|
||||
// providerDelegate.audioManager = audioManager
|
||||
//
|
||||
// providerDelegate.reportIncomingCall(call) { error in
|
||||
// if error == nil {
|
||||
// Logger.debug("\(self.TAG) successfully reported incoming call.")
|
||||
// } else {
|
||||
// Logger.error("\(self.TAG) providerDelegate.reportIncomingCall failed with error: \(error)")
|
||||
// }
|
||||
// }
|
||||
// TODO CodeCleanup: remove unused audiomanager
|
||||
internal func reportIncomingCall(_ call: SignalCall, callerName: String, audioManager: SignalCallAudioManager) {
|
||||
// Construct a CXCallUpdate describing the incoming call, including the caller.
|
||||
let update = CXCallUpdate()
|
||||
update.remoteHandle = CXHandle(type: .phoneNumber, value: call.remotePhoneNumber)
|
||||
update.hasVideo = call.hasVideo
|
||||
|
||||
// Report the incoming call to the system
|
||||
provider.reportNewIncomingCall(with: call.localId, update: update) { error in
|
||||
/*
|
||||
Only add incoming call to the app's list of calls if the call was allowed (i.e. there was no error)
|
||||
since calls may be "denied" for various legitimate reasons. See CXErrorCodeIncomingCallError.
|
||||
*/
|
||||
guard error == nil else {
|
||||
Logger.error("\(self.TAG) failed to report new incoming call")
|
||||
return
|
||||
}
|
||||
|
||||
self.callManager.addCall(call)
|
||||
}
|
||||
}
|
||||
|
||||
public func reportMissedCall(_ call: SignalCall, callerName: String) {
|
||||
notificationsAdapter.presentMissedCall(call, callerName: callerName)
|
||||
}
|
||||
|
||||
func answerCall(_ call: SignalCall) {
|
||||
internal func answerCall(_ call: SignalCall) {
|
||||
showCall(call)
|
||||
}
|
||||
|
||||
public func declineCall(_ call: SignalCall) {
|
||||
internal func declineCall(_ call: SignalCall) {
|
||||
callManager.end(call: call)
|
||||
}
|
||||
|
||||
func endCall(_ call: SignalCall) {
|
||||
internal func endCall(_ call: SignalCall) {
|
||||
callManager.end(call: call)
|
||||
}
|
||||
|
||||
// MARK: CXProviderDelegate
|
||||
|
||||
func providerDidReset(_ provider: CXProvider) {
|
||||
Logger.debug("\(TAG) in \(#function)")
|
||||
|
||||
stopAudio()
|
||||
|
||||
/*
|
||||
End any ongoing calls if the provider resets, and remove them from the app's list of calls,
|
||||
since they are no longer valid.
|
||||
*/
|
||||
// This is a little goofy because CallKit assumes multiple calls (maybe some are held, or group calls?)
|
||||
// but CallService currently just has one call at a time.
|
||||
for call in callManager.calls {
|
||||
callService.handleFailedCall(error: .providerReset)
|
||||
}
|
||||
|
||||
// Remove all calls from the app's list of calls.
|
||||
callManager.removeAllCalls()
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
|
||||
Logger.debug("\(TAG) in \(#function) CXStartCallAction")
|
||||
|
||||
/*
|
||||
Configure the audio session, but do not start call audio here, since it must be done once
|
||||
the audio session has been activated by the system after having its priority elevated.
|
||||
*/
|
||||
configureAudioSession()
|
||||
|
||||
// TODO does this work when `action.handle.value` is not in e164 format, e.g. if called via intent?
|
||||
guard let call = callManager.callWithLocalId(action.callUUID) else {
|
||||
Logger.error("\(TAG) unable to find call in \(#function)")
|
||||
return
|
||||
}
|
||||
|
||||
CallService.signalingQueue.async {
|
||||
self.callService.handleOutgoingCall(call).then {
|
||||
action.fulfill()
|
||||
}.catch { error in
|
||||
self.callManager.removeCall(call)
|
||||
action.fail()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO FIXME
|
||||
// /*
|
||||
// Set callback blocks for significant events in the call's lifecycle, so that the CXProvider may be updated
|
||||
// to reflect the updated state.
|
||||
// */
|
||||
// call.hasStartedConnectingDidChange = { [weak self] in
|
||||
// self?.provider.reportOutgoingCall(with: call.uuid, startedConnectingAt: call.connectingDate)
|
||||
// }
|
||||
// call.hasConnectedDidChange = { [weak self] in
|
||||
// self?.provider.reportOutgoingCall(with: call.uuid, connectedAt: call.connectDate)
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
||||
Logger.debug("\(TAG) Received \(#function) CXAnswerCallAction")
|
||||
// Retrieve the SpeakerboxCall instance corresponding to the action's call UUID
|
||||
guard let call = callManager.callWithLocalId(action.callUUID) else {
|
||||
action.fail()
|
||||
return
|
||||
}
|
||||
|
||||
// Original Speakerbox implementation
|
||||
// /*
|
||||
// Configure the audio session, but do not start call audio here, since it must be done once
|
||||
// the audio session has been activated by the system after having its priority elevated.
|
||||
// */
|
||||
// configureAudioSession()
|
||||
//
|
||||
// // Trigger the call to be answered via the underlying network service.
|
||||
// call.answerSpeakerboxCall()
|
||||
|
||||
// Synchronous to ensure work is done before call is displayed as "answered"
|
||||
CallService.signalingQueue.sync {
|
||||
self.callService.handleAnswerCall(call)
|
||||
}
|
||||
|
||||
// Signal to the system that the action has been successfully performed.
|
||||
action.fulfill()
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
|
||||
Logger.debug("\(TAG) Received \(#function) CXEndCallAction")
|
||||
guard let call = callManager.callWithLocalId(action.callUUID) else {
|
||||
action.fail()
|
||||
return
|
||||
}
|
||||
|
||||
// Original Speakerbox implementation
|
||||
// // Stop call audio whenever ending the call.
|
||||
// stopAudio()
|
||||
// // Trigger the call to be ended via the underlying network service.
|
||||
// call.endSpeakerboxCall()
|
||||
|
||||
// Synchronous to ensure call is terminated before call is displayed as "ended"
|
||||
CallService.signalingQueue.sync {
|
||||
self.callService.handleLocalHungupCall(call)
|
||||
}
|
||||
|
||||
// Signal to the system that the action has been successfully performed.
|
||||
action.fulfill()
|
||||
|
||||
// Remove the ended call from the app's list of calls.
|
||||
callManager.removeCall(call)
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {
|
||||
Logger.debug("\(TAG) Received \(#function) CXSetHeldCallAction")
|
||||
guard let call = callManager.callWithLocalId(action.callUUID) else {
|
||||
action.fail()
|
||||
return
|
||||
}
|
||||
Logger.warn("TODO, set held call: \(call)")
|
||||
|
||||
// TODO FIXME
|
||||
// // Update the SpeakerboxCall's underlying hold state.
|
||||
// call.isOnHold = action.isOnHold
|
||||
//
|
||||
// // Stop or start audio in response to holding or unholding the call.
|
||||
// if call.isOnHold {
|
||||
// stopAudio()
|
||||
// } else {
|
||||
// startAudio()
|
||||
// }
|
||||
|
||||
// Signal to the system that the action has been successfully performed.
|
||||
action.fulfill()
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {
|
||||
Logger.debug("\(TAG) Timed out \(#function)")
|
||||
|
||||
// React to the action timeout if necessary, such as showing an error UI.
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
|
||||
Logger.debug("\(TAG) Received \(#function)")
|
||||
|
||||
startAudio()
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
|
||||
Logger.debug("\(TAG) Received \(#function)")
|
||||
|
||||
/*
|
||||
Restart any non-call related audio now that the app's audio session has been
|
||||
de-activated after having its priority restored to normal.
|
||||
*/
|
||||
}
|
||||
|
||||
// MARK: - Audio
|
||||
|
||||
func startAudio() {
|
||||
guard let audioManager = self.audioManager else {
|
||||
Logger.error("\(TAG) audioManager was unexpectedly nil while tryign to start audio")
|
||||
return
|
||||
}
|
||||
|
||||
audioManager.startAudio()
|
||||
}
|
||||
|
||||
func stopAudio() {
|
||||
guard let audioManager = self.audioManager else {
|
||||
Logger.error("\(TAG) audioManager was unexpectedly nil while tryign to stop audio")
|
||||
return
|
||||
}
|
||||
|
||||
audioManager.stopAudio()
|
||||
}
|
||||
|
||||
func configureAudioSession() {
|
||||
guard let audioManager = self.audioManager else {
|
||||
Logger.error("\(TAG) audioManager was unexpectedly nil while trying to: \(#function)")
|
||||
return
|
||||
}
|
||||
|
||||
audioManager.configureAudioSession()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,289 +0,0 @@
|
|||
// Created by Michael Kirk on 12/23/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import CallKit
|
||||
import AVFoundation
|
||||
|
||||
/**
|
||||
* Connects requests for CallKit actions (CXActions) with their corresponding consequences in CallService
|
||||
*
|
||||
* TODO: Code cleanup: The responsibilities largely overlap with the CallKitCallUIAdapter. Maybe they should be merged.
|
||||
*/
|
||||
@available(iOS 10.0, *)
|
||||
final class CallKitProviderDelegate: NSObject, CallUIAdaptee, CXProviderDelegate {
|
||||
|
||||
let TAG = "[CallKitProviderDelegate]"
|
||||
|
||||
private let callManager: CallKitCallManager
|
||||
private let callService: CallService
|
||||
internal let notificationsAdapter: CallNotificationsAdapter
|
||||
private let provider: CXProvider
|
||||
|
||||
// FIXME - I might be thinking about this the wrong way.
|
||||
// It seems like the provider delegate wants to stop/start the audio recording
|
||||
// process, but the ProviderDelegate is an app singleton
|
||||
// and the audio recording process is currently controlled (I think) by
|
||||
// the PeerConnectionClient instance, which is one per call (NOT a singleton).
|
||||
// It seems like a mess to reconcile this difference in cardinality. But... here we are.
|
||||
var audioManager: SignalCallAudioManager?
|
||||
|
||||
/// The app's provider configuration, representing its CallKit capabilities
|
||||
static var providerConfiguration: CXProviderConfiguration {
|
||||
let localizedName = NSLocalizedString("APPLICATION_NAME", comment: "Name of application")
|
||||
let providerConfiguration = CXProviderConfiguration(localizedName: localizedName)
|
||||
|
||||
providerConfiguration.supportsVideo = true
|
||||
|
||||
providerConfiguration.maximumCallsPerCallGroup = 1
|
||||
|
||||
providerConfiguration.supportedHandleTypes = [.phoneNumber]
|
||||
|
||||
if let iconMaskImage = UIImage(named: "IconMask") {
|
||||
providerConfiguration.iconTemplateImageData = UIImagePNGRepresentation(iconMaskImage)
|
||||
}
|
||||
|
||||
providerConfiguration.ringtoneSound = "r.caf"
|
||||
|
||||
return providerConfiguration
|
||||
}
|
||||
|
||||
init(callService: CallService, notificationsAdapter: CallNotificationsAdapter) {
|
||||
self.callManager = CallKitCallManager()
|
||||
self.callService = callService
|
||||
self.notificationsAdapter = notificationsAdapter
|
||||
self.provider = CXProvider(configuration: type(of: self).providerConfiguration)
|
||||
|
||||
super.init()
|
||||
|
||||
self.provider.setDelegate(self, queue: nil)
|
||||
}
|
||||
|
||||
// MARK: CallUIAdaptee
|
||||
|
||||
internal func startOutgoingCall(_ call: SignalCall) {
|
||||
// Add the new outgoing call to the app's list of calls.
|
||||
// So we can find it in the provider delegate callbacks.
|
||||
callManager.addCall(call)
|
||||
callManager.startCall(call)
|
||||
}
|
||||
|
||||
// TODO CodeCleanup: remove unused audiomanager
|
||||
internal func reportIncomingCall(_ call: SignalCall, callerName: String, audioManager: SignalCallAudioManager) {
|
||||
// Construct a CXCallUpdate describing the incoming call, including the caller.
|
||||
let update = CXCallUpdate()
|
||||
update.remoteHandle = CXHandle(type: .phoneNumber, value: call.remotePhoneNumber)
|
||||
update.hasVideo = call.hasVideo
|
||||
|
||||
// Report the incoming call to the system
|
||||
provider.reportNewIncomingCall(with: call.localId, update: update) { error in
|
||||
/*
|
||||
Only add incoming call to the app's list of calls if the call was allowed (i.e. there was no error)
|
||||
since calls may be "denied" for various legitimate reasons. See CXErrorCodeIncomingCallError.
|
||||
*/
|
||||
guard error == nil else {
|
||||
Logger.error("\(self.TAG) failed to report new incoming call")
|
||||
return
|
||||
}
|
||||
|
||||
self.callManager.addCall(call)
|
||||
}
|
||||
}
|
||||
|
||||
internal func answerCall(_ call: SignalCall) {
|
||||
showCall(call)
|
||||
}
|
||||
|
||||
internal func declineCall(_ call: SignalCall) {
|
||||
callManager.end(call: call)
|
||||
}
|
||||
|
||||
internal func endCall(_ call: SignalCall) {
|
||||
callManager.end(call: call)
|
||||
}
|
||||
|
||||
// MARK: CXProviderDelegate
|
||||
|
||||
func providerDidReset(_ provider: CXProvider) {
|
||||
Logger.debug("\(TAG) in \(#function)")
|
||||
|
||||
stopAudio()
|
||||
|
||||
/*
|
||||
End any ongoing calls if the provider resets, and remove them from the app's list of calls,
|
||||
since they are no longer valid.
|
||||
*/
|
||||
// This is a little goofy because CallKit assumes multiple calls (maybe some are held, or group calls?)
|
||||
// but CallService currently just has one call at a time.
|
||||
for call in callManager.calls {
|
||||
callService.handleFailedCall(error: .providerReset)
|
||||
}
|
||||
|
||||
// Remove all calls from the app's list of calls.
|
||||
callManager.removeAllCalls()
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
|
||||
Logger.debug("\(TAG) in \(#function) CXStartCallAction")
|
||||
|
||||
/*
|
||||
Configure the audio session, but do not start call audio here, since it must be done once
|
||||
the audio session has been activated by the system after having its priority elevated.
|
||||
*/
|
||||
configureAudioSession()
|
||||
|
||||
// TODO does this work when `action.handle.value` is not in e164 format, e.g. if called via intent?
|
||||
guard let call = callManager.callWithLocalId(action.callUUID) else {
|
||||
Logger.error("\(TAG) unable to find call in \(#function)")
|
||||
return
|
||||
}
|
||||
|
||||
CallService.signalingQueue.async {
|
||||
self.callService.handleOutgoingCall(call).then {
|
||||
action.fulfill()
|
||||
}.catch { error in
|
||||
self.callManager.removeCall(call)
|
||||
action.fail()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO FIXME
|
||||
// /*
|
||||
// Set callback blocks for significant events in the call's lifecycle, so that the CXProvider may be updated
|
||||
// to reflect the updated state.
|
||||
// */
|
||||
// call.hasStartedConnectingDidChange = { [weak self] in
|
||||
// self?.provider.reportOutgoingCall(with: call.uuid, startedConnectingAt: call.connectingDate)
|
||||
// }
|
||||
// call.hasConnectedDidChange = { [weak self] in
|
||||
// self?.provider.reportOutgoingCall(with: call.uuid, connectedAt: call.connectDate)
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
||||
Logger.debug("\(TAG) Received \(#function) CXAnswerCallAction")
|
||||
// Retrieve the SpeakerboxCall instance corresponding to the action's call UUID
|
||||
guard let call = callManager.callWithLocalId(action.callUUID) else {
|
||||
action.fail()
|
||||
return
|
||||
}
|
||||
|
||||
// Original Speakerbox implementation
|
||||
// /*
|
||||
// Configure the audio session, but do not start call audio here, since it must be done once
|
||||
// the audio session has been activated by the system after having its priority elevated.
|
||||
// */
|
||||
// configureAudioSession()
|
||||
//
|
||||
// // Trigger the call to be answered via the underlying network service.
|
||||
// call.answerSpeakerboxCall()
|
||||
|
||||
// Synchronous to ensure work is done before call is displayed as "answered"
|
||||
CallService.signalingQueue.sync {
|
||||
self.callService.handleAnswerCall(call)
|
||||
}
|
||||
|
||||
// Signal to the system that the action has been successfully performed.
|
||||
action.fulfill()
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
|
||||
Logger.debug("\(TAG) Received \(#function) CXEndCallAction")
|
||||
guard let call = callManager.callWithLocalId(action.callUUID) else {
|
||||
action.fail()
|
||||
return
|
||||
}
|
||||
|
||||
// Original Speakerbox implementation
|
||||
// // Stop call audio whenever ending the call.
|
||||
// stopAudio()
|
||||
// // Trigger the call to be ended via the underlying network service.
|
||||
// call.endSpeakerboxCall()
|
||||
|
||||
// Synchronous to ensure call is terminated before call is displayed as "ended"
|
||||
CallService.signalingQueue.sync {
|
||||
self.callService.handleLocalHungupCall(call)
|
||||
}
|
||||
|
||||
// Signal to the system that the action has been successfully performed.
|
||||
action.fulfill()
|
||||
|
||||
// Remove the ended call from the app's list of calls.
|
||||
callManager.removeCall(call)
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {
|
||||
Logger.debug("\(TAG) Received \(#function) CXSetHeldCallAction")
|
||||
guard let call = callManager.callWithLocalId(action.callUUID) else {
|
||||
action.fail()
|
||||
return
|
||||
}
|
||||
Logger.warn("TODO, set held call: \(call)")
|
||||
|
||||
// TODO FIXME
|
||||
// // Update the SpeakerboxCall's underlying hold state.
|
||||
// call.isOnHold = action.isOnHold
|
||||
//
|
||||
// // Stop or start audio in response to holding or unholding the call.
|
||||
// if call.isOnHold {
|
||||
// stopAudio()
|
||||
// } else {
|
||||
// startAudio()
|
||||
// }
|
||||
|
||||
// Signal to the system that the action has been successfully performed.
|
||||
action.fulfill()
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {
|
||||
Logger.debug("\(TAG) Timed out \(#function)")
|
||||
|
||||
// React to the action timeout if necessary, such as showing an error UI.
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
|
||||
Logger.debug("\(TAG) Received \(#function)")
|
||||
|
||||
startAudio()
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
|
||||
Logger.debug("\(TAG) Received \(#function)")
|
||||
|
||||
/*
|
||||
Restart any non-call related audio now that the app's audio session has been
|
||||
de-activated after having its priority restored to normal.
|
||||
*/
|
||||
}
|
||||
|
||||
// MARK: - Audio
|
||||
|
||||
func startAudio() {
|
||||
guard let audioManager = self.audioManager else {
|
||||
Logger.error("\(TAG) audioManager was unexpectedly nil while tryign to start audio")
|
||||
return
|
||||
}
|
||||
|
||||
audioManager.startAudio()
|
||||
}
|
||||
|
||||
func stopAudio() {
|
||||
guard let audioManager = self.audioManager else {
|
||||
Logger.error("\(TAG) audioManager was unexpectedly nil while tryign to stop audio")
|
||||
return
|
||||
}
|
||||
|
||||
audioManager.stopAudio()
|
||||
}
|
||||
|
||||
func configureAudioSession() {
|
||||
guard let audioManager = self.audioManager else {
|
||||
Logger.error("\(TAG) audioManager was unexpectedly nil while trying to: \(#function)")
|
||||
return
|
||||
}
|
||||
|
||||
audioManager.configureAudioSession()
|
||||
}
|
||||
}
|
|
@ -48,42 +48,42 @@ class CallUIAdapter {
|
|||
adaptee = NonCallKitCallUIAdaptee(callService: callService, notificationsAdapter: notificationsAdapter)
|
||||
} else if #available(iOS 10.0, *) {
|
||||
Logger.info("\(TAG) choosing callkit adaptee for iOS10+")
|
||||
adaptee = CallKitProviderDelegate(callService: callService, notificationsAdapter: notificationsAdapter)
|
||||
adaptee = CallKitCallUIAdaptee(callService: callService, notificationsAdapter: notificationsAdapter)
|
||||
} else {
|
||||
Logger.info("\(TAG) choosing non-callkit adaptee for older iOS")
|
||||
adaptee = NonCallKitCallUIAdaptee(callService: callService, notificationsAdapter: notificationsAdapter)
|
||||
}
|
||||
}
|
||||
|
||||
public func reportIncomingCall(_ call: SignalCall, thread: TSContactThread, audioManager: SignalCallAudioManager) {
|
||||
internal func reportIncomingCall(_ call: SignalCall, thread: TSContactThread, audioManager: SignalCallAudioManager) {
|
||||
let callerName = self.contactsManager.displayName(forPhoneIdentifier: call.remotePhoneNumber)
|
||||
adaptee.reportIncomingCall(call, callerName: callerName, audioManager: audioManager)
|
||||
}
|
||||
|
||||
public func reportMissedCall(_ call: SignalCall) {
|
||||
internal func reportMissedCall(_ call: SignalCall) {
|
||||
let callerName = self.contactsManager.displayName(forPhoneIdentifier: call.remotePhoneNumber)
|
||||
adaptee.reportMissedCall(call, callerName: callerName)
|
||||
}
|
||||
|
||||
public func startOutgoingCall(handle: String) -> SignalCall {
|
||||
internal func startOutgoingCall(handle: String) -> SignalCall {
|
||||
let call = SignalCall.outgoingCall(localId: UUID(), remotePhoneNumber: handle)
|
||||
adaptee.startOutgoingCall(call)
|
||||
return call
|
||||
}
|
||||
|
||||
public func answerCall(_ call: SignalCall) {
|
||||
internal func answerCall(_ call: SignalCall) {
|
||||
adaptee.answerCall(call)
|
||||
}
|
||||
|
||||
public func declineCall(_ call: SignalCall) {
|
||||
internal func declineCall(_ call: SignalCall) {
|
||||
adaptee.declineCall(call)
|
||||
}
|
||||
|
||||
public func endCall(_ call: SignalCall) {
|
||||
internal func endCall(_ call: SignalCall) {
|
||||
adaptee.endCall(call)
|
||||
}
|
||||
|
||||
public func showCall(_ call: SignalCall) {
|
||||
internal func showCall(_ call: SignalCall) {
|
||||
adaptee.showCall(call)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue