// // ProviderDelegate.swift // CallTutorial // // Created by QuentinArguillere on 05/08/2020. // Copyright © 2020 BelledonneCommunications. All rights reserved. // import Foundation import CallKit import linphonesw import AVFoundation class CallKitProviderDelegate : NSObject { private let provider: CXProvider let mCallController = CXCallController() var tutorialContext : CallKitExampleContext! var incomingCallUUID : UUID! init(context: CallKitExampleContext) { tutorialContext = context let providerConfiguration = CXProviderConfiguration() providerConfiguration.supportsVideo = true providerConfiguration.supportedHandleTypes = [.generic] providerConfiguration.maximumCallsPerCallGroup = 1 providerConfiguration.maximumCallGroups = 1 provider = CXProvider(configuration: providerConfiguration) super.init() provider.setDelegate(self, queue: nil) // The CXProvider delegate will trigger CallKit related callbacks } func incomingCall() { NSLog("Callkit incomingCall -- Is main thread ? \(Thread.isMainThread ? "yes" : "no") ") incomingCallUUID = UUID() let update = CXCallUpdate() update.remoteHandle = CXHandle(type:.generic, value: tutorialContext.incomingCallName) provider.reportNewIncomingCall(with: incomingCallUUID, update: update, completion: { error in }) // Report to CallKit a call is incoming } func stopCall() { NSLog("Callkit stopCall -- Is main thread ? \(Thread.isMainThread ? "yes" : "no") ") let endCallAction = CXEndCallAction(call: incomingCallUUID) let transaction = CXTransaction(action: endCallAction) mCallController.request(transaction, completion: { error in }) // Report to CallKit a call must end } } // In this extension, we implement the action we want to be done when CallKit is notified of something. // This can happen through the CallKit GUI in the app, or directly in the code (see, incomingCall(), stopCall() functions above) extension CallKitProviderDelegate: CXProviderDelegate { func provider(_ provider: CXProvider, perform action: CXEndCallAction) { NSLog("Callkit CXEndCallAction -- Is main thread ? \(Thread.isMainThread ? "yes" : "no") ") tutorialContext.$mCore.receive(on: coreQueue).sink { core in do { if (self.tutorialContext.mCall?.state != .End && self.tutorialContext.mCall?.state != .Released) { try self.tutorialContext.mCall?.terminate() } LinphoneAsyncHelper.postOnMainQueue { self.tutorialContext.isCallRunning = false self.tutorialContext.isCallIncoming = false } } catch { NSLog(error.localizedDescription) } }.store(in: &cancellables) action.fulfill() } func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) { NSLog("Callkit CXAnswerCallAction -- Is main thread ? \(Thread.isMainThread ? "yes" : "no") ") tutorialContext.$mCore.receive(on: coreQueue).sink { core in do { // The audio stream is going to start shortly: the AVAudioSession must be configured now. // It is worth to note that an application does not have permission to configure the // AVAudioSession outside of this delegate action while it is running in background, // which is usually the case in an incoming call scenario. core?.configureAudioSession(); try self.tutorialContext.mCall?.accept() LinphoneAsyncHelper.postOnMainQueue { self.tutorialContext.isCallRunning = true } } catch { print(error) } }.store(in: &cancellables) action.fulfill() } func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {} func provider(_ provider: CXProvider, perform action: CXStartCallAction) { // This tutorial is not doing outgoing calls. If it had to do so, // configureAudioSession() shall be called from here, just before launching the // call. // tutorialContext.mCore.configureAudioSession(); // tutorialContext.mCore.invite("sip:bob@example.net"); // action.fulfill(); } func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {} func provider(_ provider: CXProvider, perform action: CXPlayDTMFCallAction) {} func provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {} func providerDidReset(_ provider: CXProvider) {} func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) { NSLog("Callkit didActivateaudiosession -- Is main thread ? \(Thread.isMainThread ? "yes" : "no") ") // The linphone Core must be notified that CallKit has activated the AVAudioSession // in order to start streaming audio. tutorialContext.$mCore.receive(on: coreQueue).sink { core in core?.activateAudioSession(actived: true) }.store(in: &cancellables) } func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) { // The linphone Core must be notified that CallKit has deactivated the AVAudioSession. tutorialContext.$mCore.receive(on: coreQueue).sink { core in core?.activateAudioSession(actived: false) }.store(in: &cancellables) } }