From cc895c57b0ffef12b951cfc708182da3ad91a799 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Thu, 13 Aug 2020 11:22:56 +0200 Subject: [PATCH] Add configuration file to the push tutorial, in order to have have the incoming calls work even if the app was terminated and is launch by the push notification --- .../CallKitTutorial/AppDelegate.swift | 2 +- .../CallKitTutorial/CallExample.swift | 75 ++++++++++--------- .../CallKitProviderDelegate.swift | 15 ++-- .../CallKitTutorial/ContentView.swift | 4 +- 4 files changed, 50 insertions(+), 46 deletions(-) diff --git a/swift/CallKitTutorial/CallKitTutorial/AppDelegate.swift b/swift/CallKitTutorial/CallKitTutorial/AppDelegate.swift index a6e7898..de98621 100644 --- a/swift/CallKitTutorial/CallKitTutorial/AppDelegate.swift +++ b/swift/CallKitTutorial/CallKitTutorial/AppDelegate.swift @@ -12,7 +12,7 @@ import SwiftUI @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { - @ObservedObject var tutorialContext = CallExampleContext() + @ObservedObject var tutorialContext = CallKitExampleContext() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. diff --git a/swift/CallKitTutorial/CallKitTutorial/CallExample.swift b/swift/CallKitTutorial/CallKitTutorial/CallExample.swift index 16cb7b3..4daf00b 100644 --- a/swift/CallKitTutorial/CallKitTutorial/CallExample.swift +++ b/swift/CallKitTutorial/CallKitTutorial/CallExample.swift @@ -9,7 +9,7 @@ import linphonesw import AVFoundation -class CallExampleContext : ObservableObject +class CallKitExampleContext : ObservableObject { var mCore: Core! // We need a Core for... anything, basically @Published var coreVersion: String = Core.getVersion @@ -59,50 +59,59 @@ class CallExampleContext : ObservableObject log!.logLevel = LogLevel.Debug factory.enableLogCollection(state: LogCollectionState.Enabled) - // Initialize Linphone Core - - try? mCore = factory.createCore(configPath: "", factoryConfigPath: "", systemContext: nil) + // Initialize Linphone Core. + // IMPORTANT : In this tutorial, we require the use of a core configuration file. + // This way, once the registration is done, and until it is cleared, it will return to the LoggedIn state on launch. + // This allows us to have a functional call when the app was closed and is started by a VOIP push notification (incoming call) + let configDir = factory.getConfigDir(context: nil) + try? mCore = factory.createCore(configPath: "\(configDir)/MyConfig", factoryConfigPath: "", systemContext: nil) // main loop for receiving notifications and doing background linphonecore work: mCore.autoIterateEnabled = true mCore.callkitEnabled = true mCore.pushNotificationEnabled = true + // This is necessary to register to the server and handle push Notifications. Make sure you have a certificate to match your app's bundle ID. let pushConfig = mCore.pushNotificationConfig! pushConfig.provider = "apns.dev" try? mCore.start() - mVideoDevices = mCore.videoDevicesList - + // Callbacks on registration and call events mCore.addDelegate(delegate: mCallStateTracer) mCore.addDelegate(delegate: mRegistrationDelegate) + + // Available video devices that can be selected to be used in video calls + mVideoDevices = mCore.videoDevicesList } func registrationExample() { - let factory = Factory.Instance - do { - proxy_cfg = try mCore.createProxyConfig() - let address = try factory.createAddress(addr: id) - let info = try factory.createAuthInfo(username: address.username, userid: "", passwd: passwd, ha1: "", realm: "", domain: address.domain) - mCore.addAuthInfo(info: info) - - try proxy_cfg.setIdentityaddress(newValue: address) - let server_addr = "sip:" + address.domain + ";transport=tls" - try proxy_cfg.setServeraddr(newValue: server_addr) - proxy_cfg.registerEnabled = true - proxy_cfg.pushNotificationAllowed = true - - try mCore.addProxyConfig(config: proxy_cfg) - if ( mCore.defaultProxyConfig == nil) - { - // IMPORTANT : default proxy config setting MUST be done AFTER adding the config to the core ! - mCore.defaultProxyConfig = proxy_cfg - } + if (!loggedIn) // Do not allow multiple registrations for this tutorial + { + let factory = Factory.Instance + do { + proxy_cfg = try mCore.createProxyConfig() + let address = try factory.createAddress(addr: id) + let info = try factory.createAuthInfo(username: address.username, userid: "", passwd: passwd, ha1: "", realm: "", domain: address.domain) + mCore.addAuthInfo(info: info) + + try proxy_cfg.setIdentityaddress(newValue: address) + let server_addr = "sip:" + address.domain + ";transport=tls" + try proxy_cfg.setServeraddr(newValue: server_addr) + proxy_cfg.registerEnabled = true + proxy_cfg.pushNotificationAllowed = true + + try mCore.addProxyConfig(config: proxy_cfg) + if ( mCore.defaultProxyConfig == nil) + { + // IMPORTANT : default proxy config setting MUST be done AFTER adding the config to the core ! + mCore.defaultProxyConfig = proxy_cfg + } - } catch { - print(error) + } catch { + print(error) + } } } @@ -112,7 +121,6 @@ class CallExampleContext : ObservableObject loggedIn = false } - func createCallParams() throws -> CallParams { let callParams = try mCore.createCallParams(call: nil) @@ -178,7 +186,7 @@ class CallExampleContext : ObservableObject // Callback for actions when a change in the Registration State happens class LinphoneRegistrationDelegate: CoreDelegate { - var tutorialContext : CallExampleContext! + var tutorialContext : CallKitExampleContext! override func onRegistrationStateChanged(core lc: Core, proxyConfig cfg: ProxyConfig, state cstate: RegistrationState, message: String?) { print("New registration state \(cstate) for user id \( String(describing: cfg.identityAddress?.asString()))\n") @@ -192,7 +200,7 @@ class LinphoneRegistrationDelegate: CoreDelegate { class LinphoneLoggingServiceManager: LoggingServiceDelegate { - var tutorialContext : CallExampleContext! + var tutorialContext : CallKitExampleContext! override func onLogMessageWritten(logService: LoggingService, domain: String, level lev: LogLevel, message: String) { if (tutorialContext.logsEnabled) @@ -206,7 +214,7 @@ class LinphoneLoggingServiceManager: LoggingServiceDelegate { // Callback for actions when a change in the Call State happens class CallStateDelegate: CoreDelegate { - var tutorialContext : CallExampleContext! + var tutorialContext : CallKitExampleContext! override func onCallStateChanged(core lc: Core, call: Call, state cstate: Call.State, message: String) { print("CallTrace - \(cstate)") @@ -219,11 +227,6 @@ class CallStateDelegate: CoreDelegate { if (cstate == .PushIncomingReceived) { - if (!tutorialContext.loggedIn) - { - // Cannot properly answer call if not registered. If the app was launched from a push notification, register. - tutorialContext.registrationExample() - } // We're being called by someone (and app is in background) initIncomingCall() } diff --git a/swift/CallKitTutorial/CallKitTutorial/CallKitProviderDelegate.swift b/swift/CallKitTutorial/CallKitTutorial/CallKitProviderDelegate.swift index 9b2caec..a3731b8 100644 --- a/swift/CallKitTutorial/CallKitTutorial/CallKitProviderDelegate.swift +++ b/swift/CallKitTutorial/CallKitTutorial/CallKitProviderDelegate.swift @@ -16,12 +16,12 @@ class CallKitProviderDelegate : NSObject { private let provider: CXProvider let mCallController = CXCallController() - var tutorialContext : CallExampleContext! + var tutorialContext : CallKitExampleContext! var incomingCallUUID : UUID! var outgoingCallUUID : UUID! - init(context : CallExampleContext) + init(context: CallKitExampleContext) { tutorialContext = context let providerConfiguration = CXProviderConfiguration(localizedName: Bundle.main.infoDictionary!["CFBundleName"] as! String) @@ -33,7 +33,7 @@ class CallKitProviderDelegate : NSObject provider = CXProvider(configuration: providerConfiguration) super.init() - provider.setDelegate(self, queue: nil) + provider.setDelegate(self, queue: nil) // The CXProvider delegate will trigger CallKit related callbacks } @@ -44,7 +44,7 @@ class CallKitProviderDelegate : NSObject let startCallAction = CXStartCallAction(call: outgoingCallUUID, handle: handle) let transaction = CXTransaction(action: startCallAction) - provider.reportOutgoingCall(with: outgoingCallUUID, startedConnectingAt: nil) + provider.reportOutgoingCall(with: outgoingCallUUID, startedConnectingAt: nil) // Report to CallKit a call is starting mCallController.request(transaction, completion: { error in }) } @@ -55,7 +55,7 @@ class CallKitProviderDelegate : NSObject update.remoteHandle = CXHandle(type:.generic, value: tutorialContext.incomingCallName) update.hasVideo = tutorialContext.videoEnabled - provider.reportNewIncomingCall(with: incomingCallUUID, update: update, completion: { error in }) + provider.reportNewIncomingCall(with: incomingCallUUID, update: update, completion: { error in }) // Report to CallKit a call is incoming } func stopCall() @@ -69,13 +69,14 @@ class CallKitProviderDelegate : NSObject let endCallAction = CXEndCallAction(call: callId) let transaction = CXTransaction(action: endCallAction) - mCallController.request(transaction, completion: { error in }) + mCallController.request(transaction, completion: { error in }) // Report to CallKit a call is incoming } } - +// 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 outgoingCall(), incomingCall(), stopCall() functions above) extension CallKitProviderDelegate: CXProviderDelegate { func provider(_ provider: CXProvider, perform action: CXEndCallAction) { diff --git a/swift/CallKitTutorial/CallKitTutorial/ContentView.swift b/swift/CallKitTutorial/CallKitTutorial/ContentView.swift index 4ea0eba..abeba77 100644 --- a/swift/CallKitTutorial/CallKitTutorial/ContentView.swift +++ b/swift/CallKitTutorial/CallKitTutorial/ContentView.swift @@ -10,7 +10,7 @@ import SwiftUI struct ContentView: View { - @ObservedObject var tutorialContext : CallExampleContext + @ObservedObject var tutorialContext : CallKitExampleContext func getCallButtonText() -> String { @@ -160,6 +160,6 @@ struct ContentView: View { struct ContentView_Previews: PreviewProvider { static var previews: some View { - ContentView(tutorialContext: CallExampleContext()) + ContentView(tutorialContext: CallKitExampleContext()) } }