diff --git a/README.md b/README.md index 1cbaba7f..8079364a 100644 --- a/README.md +++ b/README.md @@ -510,6 +510,37 @@ extension AppDelegate : CXProviderDelegate { ```
+__*Reporting calls with CallKit*__ + +To properly report calls to callKit with right statuses, you need to invoke the following callKit methods at the right instances : + +Use `provider.reportNewIncomingCall(with: uuid, update: callUpdate)` to report an incoming call. + +```Swift + guard let provider = callKitProvider else { + print("AppDelegate:: CallKit provider not available") + return + } + + let callHandle = CXHandle(type: .generic, value: from) + let callUpdate = CXCallUpdate() + callUpdate.remoteHandle = callHandle + + provider.reportNewIncomingCall(with: uuid, update: callUpdate) { error in + // handle error + } +``` + +Use `provider.reportOutgoingCall(with: callKitUUID, connectedAt:nil)` to report a connected outgoing call. +```Swift + if let provider = self.callKitProvider, + let callKitUUID = self.callKitUUID { + let date = Date() + provider.reportOutgoingCall(with: callKitUUID, connectedAt:date) + } +``` + + ### Best Practices when Using PushNotifications with Callkit. 1. When receiving calls from push notifications, it is always required to wait for the connection to the WebSocket before fulfilling the call answer action. This can be achieved by implementing the CXProviderDelegate in the following way (SDK version >=0.1.11): @@ -576,6 +607,7 @@ func provider(_ provider: CXProvider, perform action: CXEndCallAction) { Calling this method solves the race condition, where call is ended before the client connects to the webserver. This way the call is ended on the callee side once a connection is established. + 2. Logs on the receiver's end are necessary to thoroughly debug issues related to push notifications. However, the debugger is not attached when the app is completely killed. To address this, the app can simply be placed in the background. VOIP push notifications should then come through, and the debugger should record all logs. You can filter logs using the keyword 'TxClient' to isolate all SDK-related messages ![image](https://github.com/team-telnyx/telnyx-webrtc-ios/assets/134492608/e04b9ade-9390-452c-a078-3386ace8d0c2) diff --git a/TelnyxRTC.podspec b/TelnyxRTC.podspec index c5297d38..5b7241bc 100644 --- a/TelnyxRTC.podspec +++ b/TelnyxRTC.podspec @@ -2,7 +2,7 @@ Pod::Spec.new do |spec| spec.name = "TelnyxRTC" - spec.version = "0.1.12" + spec.version = "0.1.13" spec.summary = "Enable Telnyx real-time communication services on iOS." spec.description = "The Telnyx iOS WebRTC Client SDK provides all the functionality you need to start making voice calls from an iPhone." spec.homepage = "https://github.com/team-telnyx/telnyx-webrtc-ios" diff --git a/TelnyxRTC.xcodeproj/project.pbxproj b/TelnyxRTC.xcodeproj/project.pbxproj index a0d976cd..f223f19c 100644 --- a/TelnyxRTC.xcodeproj/project.pbxproj +++ b/TelnyxRTC.xcodeproj/project.pbxproj @@ -928,7 +928,7 @@ "@loader_path/Frameworks", "$(BUILT_PRODUCTS_DIR)/Starscream", ); - MARKETING_VERSION = 0.1.10; + MARKETING_VERSION = 0.1.13; PRODUCT_BUNDLE_IDENTIFIER = com.telnyx.WebRTCSDK; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -961,7 +961,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 0.1.10; + MARKETING_VERSION = 0.1.13; PRODUCT_BUNDLE_IDENTIFIER = com.telnyx.WebRTCSDK; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; diff --git a/TelnyxRTC/Telnyx/WebRTC/Call.swift b/TelnyxRTC/Telnyx/WebRTC/Call.swift index 9a342a97..60e696c0 100644 --- a/TelnyxRTC/Telnyx/WebRTC/Call.swift +++ b/TelnyxRTC/Telnyx/WebRTC/Call.swift @@ -226,7 +226,22 @@ public class Call { }) } - + /** + This function should be called when the remote SDP is inside the telnyx_rtc.media message. + It sets the incoming sdp as the remoteDecription. + sdp: Is the remote SDP to configure in the current RTCPeerConnection + */ + private func streamMedia(sdp: String) { + let remoteDescription = RTCSessionDescription(type: .prAnswer, sdp: sdp) + self.peer?.connection?.setRemoteDescription(remoteDescription, completionHandler: { (error) in + if let error = error { + Logger.log.e(message: "Call:: Error setting remote description: \(error)") + return + } + + Logger.log.i(message: "Call:: Media Streaming") + }) + } //TODO: We can move this inside the answer() function of the Peer class private func incomingOffer(sdp: String) { @@ -478,6 +493,7 @@ extension Call { return } self.remoteSdp = remoteSdp + self.streamMedia(sdp: remoteSdp) } //TODO: handle error when there's no SDP break diff --git a/TelnyxWebRTCDemo/AppDelegate.swift b/TelnyxWebRTCDemo/AppDelegate.swift index 3561d403..3df1cbf3 100644 --- a/TelnyxWebRTCDemo/AppDelegate.swift +++ b/TelnyxWebRTCDemo/AppDelegate.swift @@ -32,7 +32,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var callKitUUID: UUID? var userDefaults: UserDefaults = UserDefaults.init() - + var isCallOutGoing:Bool = false private var pushRegistry = PKPushRegistry.init(queue: DispatchQueue.main) weak var voipDelegate: VoIPDelegate? diff --git a/TelnyxWebRTCDemo/Extensions/AppDelegateCallKitExtension.swift b/TelnyxWebRTCDemo/Extensions/AppDelegateCallKitExtension.swift index dba7ac11..0d62883e 100644 --- a/TelnyxWebRTCDemo/Extensions/AppDelegateCallKitExtension.swift +++ b/TelnyxWebRTCDemo/Extensions/AppDelegateCallKitExtension.swift @@ -46,6 +46,16 @@ extension AppDelegate : CXProviderDelegate { provider.reportCall(with: uuid, updated: callUpdate) } } + + func executeOutGoingCall() { + if let provider = self.callKitProvider, + let callKitUUID = self.callKitUUID { + let date = Date() + provider.reportOutgoingCall(with: callKitUUID, connectedAt:nil) + print("Outgoing Call Reported at \(date)") + self.isCallOutGoing = false + } + } /// Report a new incoming call. This will generate the Native Incoming call notification /// - Parameters: @@ -135,7 +145,7 @@ extension AppDelegate : CXProviderDelegate { self.currentCall = call if call != nil { print("AppDelegate:: performVoiceCall() successful") - provider.reportOutgoingCall(with: action.callUUID, connectedAt: Date()) + self.isCallOutGoing = true } else { print("AppDelegate:: performVoiceCall() failed") } diff --git a/TelnyxWebRTCDemo/Extensions/ViewControllerVoIPExtension.swift b/TelnyxWebRTCDemo/Extensions/ViewControllerVoIPExtension.swift index 9098ad2f..a31cfb6e 100644 --- a/TelnyxWebRTCDemo/Extensions/ViewControllerVoIPExtension.swift +++ b/TelnyxWebRTCDemo/Extensions/ViewControllerVoIPExtension.swift @@ -103,6 +103,9 @@ extension ViewController : VoIPDelegate { case .ACTIVE: self.incomingCallView.isHidden = true self.callView.isHidden = false + if(self.isCallOutGoing()){ + self.appDelegate.executeOutGoingCall() + } break case .DONE: self.resetCallStates() diff --git a/TelnyxWebRTCDemo/ViewController.swift b/TelnyxWebRTCDemo/ViewController.swift index 91a58c06..596ea144 100644 --- a/TelnyxWebRTCDemo/ViewController.swift +++ b/TelnyxWebRTCDemo/ViewController.swift @@ -184,6 +184,10 @@ class ViewController: UIViewController { self.callView.resetHoldUnholdState() self.callView.resetSpeakerState() } + + func isCallOutGoing() -> Bool { + return appDelegate.isCallOutGoing + } } // MARK: - UIIncomingCallViewDelegate