Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is/feature/custom headers #111

Merged
merged 13 commits into from
Oct 25, 2023
2 changes: 1 addition & 1 deletion TelnyxRTC.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Pod::Spec.new do |spec|

spec.name = "TelnyxRTC"
spec.version = "0.1.13"
spec.version = "0.1.14"
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"
Expand Down
33 changes: 32 additions & 1 deletion TelnyxRTC.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
1B0B82F8E58A096FBA0FB9CC /* Pods_TelnyxWebRTCDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 820AA51E2426DDF94E656DBF /* Pods_TelnyxWebRTCDemo.framework */; };
3B1BE6F72AA9A467000B7962 /* TxPushIPConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B1BE6F62AA9A467000B7962 /* TxPushIPConfig.swift */; };
3B1F43EF2AE0B01E00A610BA /* Params.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B1F43EE2AE0B01E00A610BA /* Params.swift */; };
3B49B7152AA9B0A20026D36D /* AttachCallMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B49B7142AA9B0A20026D36D /* AttachCallMessage.swift */; };
3B72695D2A9396BF00D2A602 /* DisablePushMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B72695C2A9396BF00D2A602 /* DisablePushMessage.swift */; };
568DF7EAE9BC54FA55C6C689 /* Pods_TelnyxRTC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E0D4B133B1289001948EE69E /* Pods_TelnyxRTC.framework */; };
Expand Down Expand Up @@ -70,6 +71,7 @@
B3E1029A25F2C16500227DCE /* ModifyMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E1029925F2C16500227DCE /* ModifyMessage.swift */; };
B3E1033225F7F94900227DCE /* incoming_call.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = B3E1033025F7F94900227DCE /* incoming_call.mp3 */; };
B3E1033325F7F94900227DCE /* ringback_tone.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = B3E1033125F7F94900227DCE /* ringback_tone.mp3 */; };
EFE662D4D4205BA0737A8CDF /* Pods_TelnyxWebRTCDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 195824CF298256C4E12F9349 /* Pods_TelnyxWebRTCDemo.framework */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -102,9 +104,14 @@
2863A4F1B4A0DEA270929B3A /* Pods-TelnyxWebRTCDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TelnyxWebRTCDemo.release.xcconfig"; path = "Target Support Files/Pods-TelnyxWebRTCDemo/Pods-TelnyxWebRTCDemo.release.xcconfig"; sourceTree = "<group>"; };
32B652E983D4C9ED833E9501 /* Pods-TelnyxRTC.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TelnyxRTC.debug.xcconfig"; path = "Target Support Files/Pods-TelnyxRTC/Pods-TelnyxRTC.debug.xcconfig"; sourceTree = "<group>"; };
3B1BE6F62AA9A467000B7962 /* TxPushIPConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TxPushIPConfig.swift; sourceTree = "<group>"; };
3B1F43EE2AE0B01E00A610BA /* Params.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Params.swift; sourceTree = "<group>"; };
3B49B7142AA9B0A20026D36D /* AttachCallMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachCallMessage.swift; sourceTree = "<group>"; };
3B72695C2A9396BF00D2A602 /* DisablePushMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisablePushMessage.swift; sourceTree = "<group>"; };
820AA51E2426DDF94E656DBF /* Pods_TelnyxWebRTCDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TelnyxWebRTCDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4247DF5BDC3E90EC89E44712 /* Pods_TelnyxRTC.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TelnyxRTC.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7441B69A8427DCD0108C3C80 /* Pods-TelnyxRTC.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TelnyxRTC.release.xcconfig"; path = "Target Support Files/Pods-TelnyxRTC/Pods-TelnyxRTC.release.xcconfig"; sourceTree = "<group>"; };
9001F8CFF56796278425B095 /* Pods-TelnyxRTC.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TelnyxRTC.debug.xcconfig"; path = "Target Support Files/Pods-TelnyxRTC/Pods-TelnyxRTC.debug.xcconfig"; sourceTree = "<group>"; };
9A835C8C2EB192DA45FE6FDA /* Pods-TelnyxRTC-TelnyxRTCTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TelnyxRTC-TelnyxRTCTests.release.xcconfig"; path = "Target Support Files/Pods-TelnyxRTC-TelnyxRTCTests/Pods-TelnyxRTC-TelnyxRTCTests.release.xcconfig"; sourceTree = "<group>"; };
B2B42AFBD4625B8F66519231 /* Pods_TelnyxRTC_TelnyxRTCTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TelnyxRTC_TelnyxRTCTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B309D11125EF107F00A2AADF /* Starscream.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Starscream.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B309D1D525F020B300A2AADF /* Message.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = "<group>"; };
B309D1DA25F020D400A2AADF /* Method.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Method.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -244,6 +251,7 @@
B39121AE25FFCE680051E076 /* TxError.swift */,
B3B1D9A026542860008D28C9 /* TxPushConfig.swift */,
B32AE8B226CD4F9200C7C6F4 /* TxServerConfiguration.swift */,
3B1F43EE2AE0B01E00A610BA /* Params.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -682,6 +690,28 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TelnyxWebRTCDemo/Pods-TelnyxWebRTCDemo-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
E4F7024869E64C30684DD710 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-TelnyxRTC-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
Expand All @@ -707,6 +737,7 @@
B3B1D9A126542860008D28C9 /* TxPushConfig.swift in Sources */,
B309D23625F06D2100A2AADF /* TxCallInfo.swift in Sources */,
B309D23B25F06DC000A2AADF /* TxCallOptions.swift in Sources */,
3B1F43EF2AE0B01E00A610BA /* Params.swift in Sources */,
B3AF249825EE7DC70062EDA9 /* SocketDelegate.swift in Sources */,
B3E0B0662656ED73005E7431 /* InfoMessage.swift in Sources */,
B3E1029A25F2C16500227DCE /* ModifyMessage.swift in Sources */,
Expand Down
28 changes: 28 additions & 0 deletions TelnyxRTC/Telnyx/Models/Params.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Params.swift
// TelnyxRTC
//
// Created by Isaac Akakpo on 19/10/2023.
//

import Foundation


struct CustomHeaderData:Codable{
let jsonrpc:String
let method:String
let params:Params
}

struct Params: Codable {
let dialogParams: DialogParams
}

struct DialogParams: Codable {
let custom_headers: [XHeader]
}

struct XHeader: Codable {
let name: String
let value: String
}
64 changes: 52 additions & 12 deletions TelnyxRTC/Telnyx/TxClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ public class TxClient {
private var gatewayState: GatewayStates = .NOREG
private var isCallFromPush: Bool = false
private var currentCallId:UUID = UUID()
private var pendingAnswerHeaders = [String:String]()
private var speakerOn:Bool = false

func isSpeakerEnabled() -> Bool {
Expand All @@ -165,6 +166,20 @@ public class TxClient {
RTCAudioSession.sharedInstance().isAudioEnabled = newValue
}
}

let currentRoute = AVAudioSession.sharedInstance().currentRoute

func isSppeakerEnabled() -> Bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

misspelling: double p in speaker

for output in currentRoute.outputs {
switch output.portType {
case AVAudioSession.Port.builtInSpeaker:
return true
default:
break
}
}
return false
}

/// Client must be registered in order to receive or place calls.
public var isRegistered: Bool {
Expand Down Expand Up @@ -228,14 +243,21 @@ public class TxClient {
}

/// To answer and control callKit active flow
public func answerFromCallkit(answerAction:CXAnswerCallAction) {
/// - Parameters:
/// - answerAction : `CXAnswerCallAction` from callKit
/// - customHeaders: (Optional)
public func answerFromCallkit(answerAction:CXAnswerCallAction,customHeaders:[String:String] = [:]) {
isaacakakpo1 marked this conversation as resolved.
Show resolved Hide resolved
self.answerCallAction = answerAction
///answer call if currentPushCall is not nil
///This means the client has connected and we can safelyanswer
if(self.calls[currentCallId] != nil){
self.calls[currentCallId]?.answer()
self.calls[currentCallId]?.answer(customHeaders: customHeaders)
answerCallAction?.fulfill()
resetPushVariables()
Logger.log.i(message: "answered from callkit")
}else{
/// Let's Keep track od the `customHeaders` passed
pendingAnswerHeaders = customHeaders
}
}

Expand Down Expand Up @@ -378,16 +400,19 @@ extension TxClient {
/// - destinationNumber: The destination `SIP user address` (sip:[email protected]) or `phone number`.
/// - callId: The current call UUID.
/// - clientState: (optional) Custom state in string format encoded in base64
/// - customHeaders: (optional) Custom Headers to be passed over webRTC Messages, should be in the
/// format `X-key:Value` `X` is required for headers to be passed.
/// - Throws:
/// - sessionId is required if user is not logged in
/// - socket connection error if socket is not connected
/// - destination number is required to start a call.
/// - Returns: The call that has been created
public func newCall(callerName: String,
callerNumber: String,
destinationNumber: String,
callId: UUID,
clientState: String? = nil) throws -> Call {
callerNumber: String,
destinationNumber: String,
callId: UUID,
clientState: String? = nil,
customHeaders:[String:String] = [:]) throws -> Call {
//User needs to be logged in to get a sessionId
guard let sessionId = self.sessionId else {
throw TxError.callFailed(reason: .sessionIdIsRequired)
Expand All @@ -410,7 +435,7 @@ extension TxClient {
ringtone: self.txConfig?.ringtone,
ringbackTone: self.txConfig?.ringBackTone,
iceServers: self.serverConfiguration.webRTCIceServers)
call.newCall(callerName: callerName, callerNumber: callerNumber, destinationNumber: destinationNumber, clientState: clientState)
call.newCall(callerName: callerName, callerNumber: callerNumber, destinationNumber: destinationNumber, clientState: clientState,customHeaders: customHeaders)
isaacakakpo1 marked this conversation as resolved.
Show resolved Hide resolved

currentCallId = callId
self.calls[callId] = call
Expand All @@ -430,7 +455,8 @@ extension TxClient {
callId: UUID,
remoteSdp: String,
telnyxSessionId: String,
telnyxLegId: String) {
telnyxLegId: String,
customHeaders:[String:String] = [:]) {

guard let sessionId = self.sessionId,
let socket = self.socket else {
Expand All @@ -450,7 +476,7 @@ extension TxClient {
call.callInfo?.callerName = callerName
call.callInfo?.callerNumber = callerNumber
call.callOptions = TxCallOptions(audio: true)

call.inviteCustomHeaders = customHeaders
self.calls[callId] = call
// propagate the incoming call to the App
Logger.log.i(message: "TxClient:: push flow createIncomingCall \(call)")
Expand All @@ -461,7 +487,7 @@ extension TxClient {
self.delegate?.onPushCall(call: call)
//Answer is pending from push - Answer Call
if(answerCallAction != nil){
call.answer()
call.answer(customHeaders: pendingAnswerHeaders)
answerCallAction?.fulfill()
resetPushVariables()
}
Expand Down Expand Up @@ -663,7 +689,7 @@ extension TxClient : SocketDelegate {
let callUUIDString = params["callID"] as? String,
let callUUID = UUID(uuidString: callUUIDString),
let call = calls[callUUID] {
call.handleVertoMessage(message: vertoMessage,txclient: self)
call.handleVertoMessage(message: vertoMessage,dataMessage: message,txClient: self)
isaacakakpo1 marked this conversation as resolved.
Show resolved Hide resolved
}


Expand Down Expand Up @@ -709,12 +735,26 @@ extension TxClient : SocketDelegate {
if telnyxLegId.isEmpty {
Logger.log.w(message: "TxClient:: Telnyx Leg ID unavailable on INVITE message")
}

var customHeaders = [String:String]()
if params["dialogParams"] is [String:Any] {
do {
let dataDecoded = try JSONDecoder().decode(CustomHeaderData.self, from: message.data(using: .utf8)!)
dataDecoded.params.dialogParams.custom_headers.forEach { xHeader in
customHeaders[xHeader.name] = xHeader.value
}
print("Data Decode : \(dataDecoded)")
} catch {
print("decoding error: \(error)")
}
}
self.createIncomingCall(callerName: callerName,
callerNumber: callerNumber,
callId: uuid,
remoteSdp: sdp,
telnyxSessionId: telnyxSessionId,
telnyxLegId: telnyxLegId)
telnyxLegId: telnyxLegId,
customHeaders: customHeaders)
}
break;
//Mark: to send meassage to pong
Expand Down
13 changes: 12 additions & 1 deletion TelnyxRTC/Telnyx/Verto/AnswerMessage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ class AnswerMessage : Message {
init(sessionId: String,
sdp: String,
callInfo: TxCallInfo,
callOptions: TxCallOptions) {
callOptions: TxCallOptions,
customHeaders:[String:String] = [:]) {

var params = [String: Any]()
var dialogParams = [String: Any]()
var xHeaders = [Any]()
// Merge callInfo into dialogParams
callInfo.encode().forEach { (key, value) in dialogParams[key] = value }
// Merge callOptions into dialogParams
Expand All @@ -26,6 +28,15 @@ class AnswerMessage : Message {

params["sessionId"] = sessionId
params["sdp"] = sdp
if(!customHeaders.isEmpty){
isaacakakpo1 marked this conversation as resolved.
Show resolved Hide resolved
customHeaders.keys.forEach { key in
var header = [String:String]()
header["name"] = key
header["value"] = customHeaders[key]
xHeaders.append(header)
}
dialogParams["custom_headers"] = xHeaders
}
params["dialogParams"] = dialogParams
super.init(params, method: .ANSWER)
}
Expand Down
16 changes: 14 additions & 2 deletions TelnyxRTC/Telnyx/Verto/InviteMessage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@

import Foundation


class InviteMessage : Message {

init(sessionId: String,
sdp: String,
callInfo: TxCallInfo,
callOptions: TxCallOptions) {
callOptions: TxCallOptions,
customHeaders:[String:String] = [:]
) {
var params = [String: Any]()
var dialogParams = [String: Any]()

var xHeaders = [Any]()
dialogParams["callID"] = callInfo.callId.uuidString.lowercased()
dialogParams["destination_number"] = callOptions.destinationNumber
dialogParams["remote_caller_id_name"] = callOptions.remoteCallerName
Expand All @@ -28,6 +31,15 @@ class InviteMessage : Message {
dialogParams["attach"] = callOptions.attach
dialogParams["screenShare"] = callOptions.screenShare
dialogParams["userVariables"] = callOptions.userVariables
if(!customHeaders.isEmpty){
customHeaders.keys.forEach { key in
var header = [String:String]()
header["name"] = key
header["value"] = customHeaders[key]
xHeaders.append(header)
}
dialogParams["custom_headers"] = xHeaders
}
if let clientState = callOptions.clientState {
dialogParams["clientState"] = clientState
}
Expand Down
Loading
Loading