AmazonChimeSDK/AmazonChimeSDK/internal/utils/TURNRequestService.swift (90 lines of code) (raw):

// // TURNRequestService.swift // AmazonChimeSDK // // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 // import AmazonChimeSDKMedia import Foundation import UIKit @objcMembers public class TURNRequestService: NSObject { private static let contentTypeHeader = "Content-Type" private static let contentType = "application/json" private static let userAgentTypeHeader = "User-Agent" private static let meetingIdKey = "meetingId" private static let tokenHeader = "X-Chime-Auth-Token" private static let tokenKey = "_aws_wt_session" private static let turnRequestHttpMethod = "POST" static func postTURNRequest(meetingId: String, turnControlUrl: String, joinToken: String, logger: Logger, completion: @escaping (MeetingSessionTURNCredentials?) -> Void) { guard let turnRequest = constructTURNRequest(meetingId: meetingId, turnControlUrl: turnControlUrl, joinToken: joinToken) else { logger.error(msg: "Failed to construct TURN request") completion(nil) return } let session = URLSession(configuration: .default) session.dataTask(with: turnRequest) { data, resp, error in if let error = error { logger.error(msg: "Failed to make TURN request, error: \(error.localizedDescription)") completion(nil) return } if let httpResponse = resp as? HTTPURLResponse { guard httpResponse.statusCode == 200 else { logger.error(msg: "Received status code \(httpResponse.statusCode) when making TURN request") completion(nil) return } } if let turnCredentials = processTurnResponse(data: data) { completion(turnCredentials) } else { logger.error(msg: "Failed to decode TURN response") completion(nil) } }.resume() } private static func constructTURNRequest(meetingId: String, turnControlUrl: String, joinToken: String) -> URLRequest? { guard let serverUrl = URL(string: turnControlUrl) else { return nil } var request = URLRequest(url: serverUrl) request.httpMethod = turnRequestHttpMethod request.addValue("\(tokenKey)=\(joinToken)", forHTTPHeaderField: tokenHeader) request.addValue(contentType, forHTTPHeaderField: contentTypeHeader) request.addValue(getUserAgent(), forHTTPHeaderField: userAgentTypeHeader) // Write meetingId into HTTP request body let meetingIdDict = [meetingIdKey: meetingId] do { request.httpBody = try JSONSerialization.data(withJSONObject: meetingIdDict) } catch { return nil } return request } private static func processTurnResponse(data: Data?) -> MeetingSessionTURNCredentials? { guard let data = data else { return nil } let jsonDecoder = JSONDecoder() do { let turnCredentials: MeetingSessionTURNCredentials = try jsonDecoder.decode( MeetingSessionTURNCredentials.self, from: data ) return turnCredentials } catch { return nil } } private static func getUserAgent() -> String { let model = UIDevice.current.model let systemVersion = UIDevice.current.systemVersion let scaleFactor = UIScreen.main.scale let defaultAgent = "(\(model); iOS \(systemVersion); Scale/\(String(format: "%.2f", scaleFactor)))" if let dict = Bundle.main.infoDictionary { if let identifier = dict[kCFBundleExecutableKey as String] ?? dict[kCFBundleIdentifierKey as String], let version = dict[kCFBundleVersionKey as String] { return "\(identifier)/\(version) \(defaultAgent)" } } return defaultAgent } }