Skip to content

Commit

Permalink
Merge pull request #111 from team-telnyx/IS/Feature/CustomHeaders
Browse files Browse the repository at this point in the history
Is/feature/custom headers
  • Loading branch information
isaacakakpo1 authored Oct 25, 2023
2 parents a086b2a + 6050e79 commit fdf4420
Show file tree
Hide file tree
Showing 11 changed files with 191 additions and 37 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*.xcworkspace/
project.xcworkspace/
xcuserdata/
DerivedData/

# Podfiles
Pods/
Expand Down
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.15"
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
39 changes: 39 additions & 0 deletions TelnyxRTC/Telnyx/Models/Params.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// 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
}

func appendCustomHeaders(customHeaders:[String:String]) -> [Any] {
var xHeaders = [Any]()
customHeaders.keys.forEach { key in
var header = [String:String]()
header["name"] = key
header["value"] = customHeaders[key]
xHeaders.append(header)
}
return xHeaders
}
54 changes: 41 additions & 13 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,7 +166,9 @@ public class TxClient {
RTCAudioSession.sharedInstance().isAudioEnabled = newValue
}
}


let currentRoute = AVAudioSession.sharedInstance().currentRoute

/// Client must be registered in order to receive or place calls.
public var isRegistered: Bool {
get {
Expand Down Expand Up @@ -228,14 +231,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] = [:]) {
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 +388,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 +423,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)

currentCallId = callId
self.calls[callId] = call
Expand All @@ -430,7 +443,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 +464,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 +475,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 +677,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)
}


Expand Down Expand Up @@ -709,12 +723,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
6 changes: 5 additions & 1 deletion TelnyxRTC/Telnyx/Verto/AnswerMessage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ 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]()
Expand All @@ -26,6 +27,9 @@ class AnswerMessage : Message {

params["sessionId"] = sessionId
params["sdp"] = sdp
if(!customHeaders.isEmpty){
dialogParams["custom_headers"] = appendCustomHeaders(customHeaders: customHeaders)
}
params["dialogParams"] = dialogParams
super.init(params, method: .ANSWER)
}
Expand Down
9 changes: 7 additions & 2 deletions TelnyxRTC/Telnyx/Verto/InviteMessage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@

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]()

dialogParams["callID"] = callInfo.callId.uuidString.lowercased()
dialogParams["destination_number"] = callOptions.destinationNumber
dialogParams["remote_caller_id_name"] = callOptions.remoteCallerName
Expand All @@ -28,6 +30,9 @@ class InviteMessage : Message {
dialogParams["attach"] = callOptions.attach
dialogParams["screenShare"] = callOptions.screenShare
dialogParams["userVariables"] = callOptions.userVariables
if(!customHeaders.isEmpty){
dialogParams["custom_headers"] = appendCustomHeaders(customHeaders: customHeaders)
}
if let clientState = callOptions.clientState {
dialogParams["clientState"] = clientState
}
Expand Down
Loading

0 comments on commit fdf4420

Please sign in to comment.