diff --git a/swift/CallTutorial/CallTutorial.xcodeproj/project.pbxproj b/swift/CallTutorial/CallTutorial.xcodeproj/project.pbxproj index 52cd544..66029b8 100644 --- a/swift/CallTutorial/CallTutorial.xcodeproj/project.pbxproj +++ b/swift/CallTutorial/CallTutorial.xcodeproj/project.pbxproj @@ -29,6 +29,7 @@ 6604166224D451F40064FC6C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 6604166424D451F40064FC6C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6604166A24D453240064FC6C /* CallExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallExample.swift; sourceTree = ""; }; + 66A3B37A24E138ED00E94540 /* CallTutorial.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CallTutorial.entitlements; sourceTree = ""; }; 66B14FBA24DAF68E0041952F /* CallKitProviderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallKitProviderDelegate.swift; sourceTree = ""; }; 79CE65CD0070AF94E21BFCE7 /* Pods-CallTutorial.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CallTutorial.debug.xcconfig"; path = "Target Support Files/Pods-CallTutorial/Pods-CallTutorial.debug.xcconfig"; sourceTree = ""; }; C26219FCE26251F1C3C2E96E /* Pods-CallTutorial.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CallTutorial.release.xcconfig"; path = "Target Support Files/Pods-CallTutorial/Pods-CallTutorial.release.xcconfig"; sourceTree = ""; }; @@ -84,6 +85,7 @@ 6604165524D451F10064FC6C /* CallTutorial */ = { isa = PBXGroup; children = ( + 66A3B37A24E138ED00E94540 /* CallTutorial.entitlements */, 6604165624D451F10064FC6C /* AppDelegate.swift */, 6604165824D451F10064FC6C /* SceneDelegate.swift */, 66B14FBA24DAF68E0041952F /* CallKitProviderDelegate.swift */, @@ -361,6 +363,7 @@ baseConfigurationReference = 79CE65CD0070AF94E21BFCE7 /* Pods-CallTutorial.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = CallTutorial/CallTutorial.entitlements; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"CallTutorial/Preview Content\""; DEVELOPMENT_TEAM = Z2V957B3D6; @@ -370,7 +373,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = BC.CallTutorial; + PRODUCT_BUNDLE_IDENTIFIER = com.belledonne.Wtest; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -382,6 +385,7 @@ baseConfigurationReference = C26219FCE26251F1C3C2E96E /* Pods-CallTutorial.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = CallTutorial/CallTutorial.entitlements; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"CallTutorial/Preview Content\""; DEVELOPMENT_TEAM = Z2V957B3D6; @@ -391,7 +395,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = BC.CallTutorial; + PRODUCT_BUNDLE_IDENTIFIER = com.belledonne.Wtest; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/swift/CallTutorial/CallTutorial/CallExample.swift b/swift/CallTutorial/CallTutorial/CallExample.swift index 22987d9..a87438b 100644 --- a/swift/CallTutorial/CallTutorial/CallExample.swift +++ b/swift/CallTutorial/CallTutorial/CallExample.swift @@ -22,8 +22,10 @@ class CallExampleContext : ObservableObject /*------------ Call tutorial related variables ---------------*/ let mCallStateTracer = CallStateDelegate() var mCall: Call! + var proxy_cfg : ProxyConfig! var mVideoDevices : [String] = [] var mUsedVideoDeviceId : Int = 0 + var callAlreadyStopped = false; @Published var audioEnabled : Bool = true @Published var videoEnabled : Bool = false @@ -41,10 +43,9 @@ class CallExampleContext : ObservableObject let outgoingCallName = "Outgoing call example" let incomingCallName = "Incoming call example" - @Published var enableCallKit = false; - init() { + mProviderDelegate = CallKitProviderDelegate(context : self) mCallStateTracer.tutorialContext = self mRegistrationDelegate.tutorialContext = self @@ -63,6 +64,7 @@ class CallExampleContext : ObservableObject // main loop for receiving notifications and doing background linphonecore work: mCore.autoIterateEnabled = true mCore.callkitEnabled = true + mCore.pushNotificationEnabled = true try? mCore.start() mVideoDevices = mCore.videoDevicesList @@ -70,14 +72,13 @@ class CallExampleContext : ObservableObject mCore.addDelegate(delegate: mCallStateTracer) mCore.addDelegate(delegate: mRegistrationDelegate) - mProviderDelegate = CallKitProviderDelegate(context : self) } func registrationExample() { let factory = Factory.Instance do { - let proxy_cfg = try mCore.createProxyConfig() + 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) @@ -122,6 +123,7 @@ class CallExampleContext : ObservableObject print("Could not place call to \(dest)\n") } else { print("Call to \(dest) is in progress...") + mProviderDelegate.outgoingCallUUID = UUID() } } else @@ -139,20 +141,10 @@ class CallExampleContext : ObservableObject { if ((callRunning || isCallIncoming) && mCall.state != Call.State.End) { + callAlreadyStopped = true; // terminate the call print("Terminating the call...\n") - do { - if (enableCallKit) - { - mProviderDelegate.stopCall() - } - else - { - try mCall.terminate() - } - } catch { - print(error) - } + mProviderDelegate.stopCall() } } @@ -200,6 +192,10 @@ class LinphoneRegistrationDelegate: CoreDelegate { print("New registration state \(cstate) for user id \( String(describing: cfg.identityAddress?.asString()))\n") if (cstate == .Ok) { + if (!tutorialContext.loggedIn) + { + tutorialContext.mProviderDelegate.registerForVoIPPushes() + } tutorialContext.loggedIn = true } } @@ -230,29 +226,27 @@ class CallStateDelegate: CoreDelegate { // We're being called by someone tutorialContext.mCall = call tutorialContext.isCallIncoming = true - if (tutorialContext.enableCallKit) - { - // Report the incoming call for CallKit - tutorialContext.mProviderDelegate.incomingCall() - } } else if (cstate == .OutgoingRinging) { // We're calling someone tutorialContext.callRunning = true } else if (cstate == .End) { // Call has been terminated by any side - tutorialContext.callRunning = false - tutorialContext.isCallIncoming = false; - if (tutorialContext.enableCallKit) + if (!tutorialContext.callAlreadyStopped) { // Report to CallKit that the call is over tutorialContext.mProviderDelegate.stopCall() + tutorialContext.callAlreadyStopped = false } + tutorialContext.callRunning = false + tutorialContext.isCallIncoming = false } else if (cstate == .StreamsRunning) { // Call has successfully began tutorialContext.callRunning = true - tutorialContext.isCallIncoming = false + } else if (cstate == .PushIncomingReceived) + { + print("PushTrace -- push incoming") } } } diff --git a/swift/CallTutorial/CallTutorial/CallKitProviderDelegate.swift b/swift/CallTutorial/CallTutorial/CallKitProviderDelegate.swift index b32ef98..a654c46 100644 --- a/swift/CallTutorial/CallTutorial/CallKitProviderDelegate.swift +++ b/swift/CallTutorial/CallTutorial/CallKitProviderDelegate.swift @@ -8,12 +8,14 @@ import Foundation import CallKit +import PushKit import linphonesw import AVFoundation class CallKitProviderDelegate : NSObject { + private var voipRegistry: PKPushRegistry! private let provider: CXProvider let mCallController = CXCallController() var tutorialContext : CallExampleContext! @@ -53,16 +55,30 @@ class CallKitProviderDelegate : NSObject let startCallAction = CXStartCallAction(call: outgoingCallUUID, handle: handle) let transaction = CXTransaction(action: startCallAction) + provider.reportOutgoingCall(with: outgoingCallUUID, connectedAt: nil) mCallController.request(transaction, completion: { error in }) } func stopCall() { - let endCallAction = CXEndCallAction(call: incomingCallUUID) + var callId = UUID(); + if (tutorialContext.isCallIncoming) { + callId = incomingCallUUID + } else if (tutorialContext.callRunning) { + callId = outgoingCallUUID + } + let endCallAction = CXEndCallAction(call: callId) let transaction = CXTransaction(action: endCallAction) mCallController.request(transaction, completion: { error in }) } + + func registerForVoIPPushes() { + voipRegistry = PKPushRegistry(queue: nil) + voipRegistry.delegate = self + voipRegistry.desiredPushTypes = [PKPushType.voIP] + } + } @@ -116,3 +132,40 @@ extension CallKitProviderDelegate: CXProviderDelegate { tutorialContext.mCore.activateAudioSession(actived: false) } } + + +extension CallKitProviderDelegate: PKPushRegistryDelegate { + + func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) { + print("PushTrace -- pushRegistry 1") + + /* + let deviceTokenString = pushCredentials.token.map { String(format: "%02x", $0) }.joined() /*convert push tocken into hex string to be compliant with flexisip format*/ + let aStr = String(format: "pn-provider=apns.dev;pn-prid=%@:voip;pn-param=Z2V957B3D6.org.linphone.tutorials.callkit.voip" + ,deviceTokenString) + */ + let deviceTokenString = pushCredentials.token.map { String(format: "%02x", $0) }.joined() /*convert push tocken into hex string to be compliant with flexisip format*/ + let aStr = String(format: "pn-provider=apns.dev;pn-prid=%@:voip;pn-param=Z2V957B3D6.com.belledonne.Wtest.voip" + ,deviceTokenString) + + tutorialContext.proxy_cfg.edit() + tutorialContext.proxy_cfg.pushNotificationAllowed = true + tutorialContext.proxy_cfg.contactUriParameters = aStr + + do { + try tutorialContext.proxy_cfg.done() + } catch { + print(error) + } + } + + func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { + print("PushTrace -- pushRegistry 2") + incomingCall(); + } + + func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor: PKPushType) + { + print("PushTrace -- pushRegistry 3") + } +} diff --git a/swift/CallTutorial/CallTutorial/CallTutorial.entitlements b/swift/CallTutorial/CallTutorial/CallTutorial.entitlements new file mode 100644 index 0000000..903def2 --- /dev/null +++ b/swift/CallTutorial/CallTutorial/CallTutorial.entitlements @@ -0,0 +1,8 @@ + + + + + aps-environment + development + + diff --git a/swift/CallTutorial/CallTutorial/ContentView.swift b/swift/CallTutorial/CallTutorial/ContentView.swift index 0badbdb..a7fd99f 100644 --- a/swift/CallTutorial/CallTutorial/ContentView.swift +++ b/swift/CallTutorial/CallTutorial/ContentView.swift @@ -14,12 +14,12 @@ struct ContentView: View { func getCallButtonText() -> String { - if (tutorialContext.isCallIncoming) { - return "Answer" - } - else if (tutorialContext.callRunning) { + if (tutorialContext.callRunning) { return "Update Call" } + else if (tutorialContext.isCallIncoming) { + return "Answer" + } else { return "Call" } @@ -27,12 +27,12 @@ struct ContentView: View { func callStateString() -> String { - if (tutorialContext.isCallIncoming) { - return "Incoming call" - } - else if (tutorialContext.callRunning) { + if (tutorialContext.callRunning) { return "Call running" } + else if (tutorialContext.isCallIncoming) { + return "Incoming call" + } else { return "No Call" } @@ -64,7 +64,7 @@ struct ContentView: View { } Text("Login State : ") .font(.footnote) - Text(tutorialContext.loggedIn ? "Looged in" : "Unregistered") + Text(tutorialContext.loggedIn ? "Logged in" : "Unregistered") .font(.footnote) .foregroundColor(tutorialContext.loggedIn ? Color.green : Color.black) } @@ -116,7 +116,7 @@ struct ContentView: View { self.tutorialContext.acceptCall() } else { - self.tutorialContext.outgoingCallExample() + self.tutorialContext.mProviderDelegate.outgoingCall() } }) { @@ -141,19 +141,6 @@ struct ContentView: View { } .padding(.top) } - - VStack(alignment: .leading) { - Button(action: tutorialContext.mProviderDelegate.outgoingCall) { - Text("CallKit Call") - .font(.largeTitle) - .foregroundColor(Color.white) - .frame(width: 180.0, height: 42.0) - .background(Color.green) - } - Toggle(isOn: $tutorialContext.enableCallKit) { - Text("CallKit incoming Call detection") - }.frame(width : 290.0) - }.padding(.top, 10.0) Spacer() Group { Toggle(isOn: $tutorialContext.logsEnabled) { diff --git a/swift/CallTutorial/CallTutorial/Info.plist b/swift/CallTutorial/CallTutorial/Info.plist index f1eba1b..84b1af3 100644 --- a/swift/CallTutorial/CallTutorial/Info.plist +++ b/swift/CallTutorial/CallTutorial/Info.plist @@ -2,16 +2,6 @@ - UIBackgroundModes - - voip - - NSCameraUsageDescription - Camera access - NSMicrophoneUsageDescription - Microphone access - LSApplicationCategoryType - CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable @@ -28,8 +18,14 @@ 1.0 CFBundleVersion 1 + LSApplicationCategoryType + LSRequiresIPhoneOS + NSCameraUsageDescription + Camera access + NSMicrophoneUsageDescription + Microphone access UIApplicationSceneManifest UIApplicationSupportsMultipleScenes @@ -47,6 +43,10 @@ + UIBackgroundModes + + voip + UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities