1/* 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#import "RTCConfiguration+Private.h" 12 13#include <memory> 14 15#import "RTCCertificate.h" 16#import "RTCConfiguration+Native.h" 17#import "RTCIceServer+Private.h" 18#import "base/RTCLogging.h" 19 20#include "rtc_base/rtc_certificate_generator.h" 21#include "rtc_base/ssl_identity.h" 22 23@implementation RTC_OBJC_TYPE (RTCConfiguration) 24 25@synthesize enableDscp = _enableDscp; 26@synthesize iceServers = _iceServers; 27@synthesize certificate = _certificate; 28@synthesize iceTransportPolicy = _iceTransportPolicy; 29@synthesize bundlePolicy = _bundlePolicy; 30@synthesize rtcpMuxPolicy = _rtcpMuxPolicy; 31@synthesize tcpCandidatePolicy = _tcpCandidatePolicy; 32@synthesize candidateNetworkPolicy = _candidateNetworkPolicy; 33@synthesize continualGatheringPolicy = _continualGatheringPolicy; 34@synthesize disableIPV6 = _disableIPV6; 35@synthesize disableIPV6OnWiFi = _disableIPV6OnWiFi; 36@synthesize maxIPv6Networks = _maxIPv6Networks; 37@synthesize disableLinkLocalNetworks = _disableLinkLocalNetworks; 38@synthesize audioJitterBufferMaxPackets = _audioJitterBufferMaxPackets; 39@synthesize audioJitterBufferFastAccelerate = _audioJitterBufferFastAccelerate; 40@synthesize iceConnectionReceivingTimeout = _iceConnectionReceivingTimeout; 41@synthesize iceBackupCandidatePairPingInterval = 42 _iceBackupCandidatePairPingInterval; 43@synthesize keyType = _keyType; 44@synthesize iceCandidatePoolSize = _iceCandidatePoolSize; 45@synthesize shouldPruneTurnPorts = _shouldPruneTurnPorts; 46@synthesize shouldPresumeWritableWhenFullyRelayed = 47 _shouldPresumeWritableWhenFullyRelayed; 48@synthesize shouldSurfaceIceCandidatesOnIceTransportTypeChanged = 49 _shouldSurfaceIceCandidatesOnIceTransportTypeChanged; 50@synthesize iceCheckMinInterval = _iceCheckMinInterval; 51@synthesize sdpSemantics = _sdpSemantics; 52@synthesize turnCustomizer = _turnCustomizer; 53@synthesize activeResetSrtpParams = _activeResetSrtpParams; 54@synthesize allowCodecSwitching = _allowCodecSwitching; 55@synthesize cryptoOptions = _cryptoOptions; 56@synthesize rtcpAudioReportIntervalMs = _rtcpAudioReportIntervalMs; 57@synthesize rtcpVideoReportIntervalMs = _rtcpVideoReportIntervalMs; 58 59- (instancetype)init { 60 // Copy defaults. 61 webrtc::PeerConnectionInterface::RTCConfiguration config; 62 return [self initWithNativeConfiguration:config]; 63} 64 65- (instancetype)initWithNativeConfiguration: 66 (const webrtc::PeerConnectionInterface::RTCConfiguration &)config { 67 if (self = [super init]) { 68 _enableDscp = config.dscp(); 69 NSMutableArray *iceServers = [NSMutableArray array]; 70 for (const webrtc::PeerConnectionInterface::IceServer& server : config.servers) { 71 RTC_OBJC_TYPE(RTCIceServer) *iceServer = 72 [[RTC_OBJC_TYPE(RTCIceServer) alloc] initWithNativeServer:server]; 73 [iceServers addObject:iceServer]; 74 } 75 _iceServers = iceServers; 76 if (!config.certificates.empty()) { 77 rtc::scoped_refptr<rtc::RTCCertificate> native_cert; 78 native_cert = config.certificates[0]; 79 rtc::RTCCertificatePEM native_pem = native_cert->ToPEM(); 80 _certificate = [[RTC_OBJC_TYPE(RTCCertificate) alloc] 81 initWithPrivateKey:@(native_pem.private_key().c_str()) 82 certificate:@(native_pem.certificate().c_str())]; 83 } 84 _iceTransportPolicy = 85 [[self class] transportPolicyForTransportsType:config.type]; 86 _bundlePolicy = 87 [[self class] bundlePolicyForNativePolicy:config.bundle_policy]; 88 _rtcpMuxPolicy = 89 [[self class] rtcpMuxPolicyForNativePolicy:config.rtcp_mux_policy]; 90 _tcpCandidatePolicy = [[self class] tcpCandidatePolicyForNativePolicy: 91 config.tcp_candidate_policy]; 92 _candidateNetworkPolicy = [[self class] 93 candidateNetworkPolicyForNativePolicy:config.candidate_network_policy]; 94 webrtc::PeerConnectionInterface::ContinualGatheringPolicy nativePolicy = 95 config.continual_gathering_policy; 96 _continualGatheringPolicy = 97 [[self class] continualGatheringPolicyForNativePolicy:nativePolicy]; 98 _disableIPV6 = config.disable_ipv6; 99 _disableIPV6OnWiFi = config.disable_ipv6_on_wifi; 100 _maxIPv6Networks = config.max_ipv6_networks; 101 _disableLinkLocalNetworks = config.disable_link_local_networks; 102 _audioJitterBufferMaxPackets = config.audio_jitter_buffer_max_packets; 103 _audioJitterBufferFastAccelerate = config.audio_jitter_buffer_fast_accelerate; 104 _iceConnectionReceivingTimeout = config.ice_connection_receiving_timeout; 105 _iceBackupCandidatePairPingInterval = 106 config.ice_backup_candidate_pair_ping_interval; 107 _keyType = RTCEncryptionKeyTypeECDSA; 108 _iceCandidatePoolSize = config.ice_candidate_pool_size; 109 _shouldPruneTurnPorts = config.prune_turn_ports; 110 _shouldPresumeWritableWhenFullyRelayed = 111 config.presume_writable_when_fully_relayed; 112 _shouldSurfaceIceCandidatesOnIceTransportTypeChanged = 113 config.surface_ice_candidates_on_ice_transport_type_changed; 114 if (config.ice_check_min_interval) { 115 _iceCheckMinInterval = 116 [NSNumber numberWithInt:*config.ice_check_min_interval]; 117 } 118 _sdpSemantics = [[self class] sdpSemanticsForNativeSdpSemantics:config.sdp_semantics]; 119 _turnCustomizer = config.turn_customizer; 120 _activeResetSrtpParams = config.active_reset_srtp_params; 121 if (config.crypto_options) { 122 _cryptoOptions = [[RTC_OBJC_TYPE(RTCCryptoOptions) alloc] 123 initWithSrtpEnableGcmCryptoSuites:config.crypto_options->srtp 124 .enable_gcm_crypto_suites 125 srtpEnableAes128Sha1_32CryptoCipher:config.crypto_options->srtp 126 .enable_aes128_sha1_32_crypto_cipher 127 srtpEnableEncryptedRtpHeaderExtensions:config.crypto_options->srtp 128 .enable_encrypted_rtp_header_extensions 129 sframeRequireFrameEncryption:config.crypto_options->sframe 130 .require_frame_encryption]; 131 } 132 _rtcpAudioReportIntervalMs = config.audio_rtcp_report_interval_ms(); 133 _rtcpVideoReportIntervalMs = config.video_rtcp_report_interval_ms(); 134 _allowCodecSwitching = config.allow_codec_switching.value_or(false); 135 } 136 return self; 137} 138 139- (NSString *)description { 140 static NSString *formatString = @"RTC_OBJC_TYPE(RTCConfiguration): " 141 @"{\n%@\n%@\n%@\n%@\n%@\n%@\n%@\n%@\n%d\n%d\n%d\n%d\n%d\n%d\n" 142 @"%d\n%@\n%d\n%d\n%d\n%d\n%d\n%@\n}\n"; 143 144 return [NSString 145 stringWithFormat:formatString, 146 _iceServers, 147 [[self class] stringForTransportPolicy:_iceTransportPolicy], 148 [[self class] stringForBundlePolicy:_bundlePolicy], 149 [[self class] stringForRtcpMuxPolicy:_rtcpMuxPolicy], 150 [[self class] stringForTcpCandidatePolicy:_tcpCandidatePolicy], 151 [[self class] stringForCandidateNetworkPolicy:_candidateNetworkPolicy], 152 [[self class] stringForContinualGatheringPolicy:_continualGatheringPolicy], 153 [[self class] stringForSdpSemantics:_sdpSemantics], 154 _audioJitterBufferMaxPackets, 155 _audioJitterBufferFastAccelerate, 156 _iceConnectionReceivingTimeout, 157 _iceBackupCandidatePairPingInterval, 158 _iceCandidatePoolSize, 159 _shouldPruneTurnPorts, 160 _shouldPresumeWritableWhenFullyRelayed, 161 _shouldSurfaceIceCandidatesOnIceTransportTypeChanged, 162 _iceCheckMinInterval, 163 _disableLinkLocalNetworks, 164 _disableIPV6, 165 _disableIPV6OnWiFi, 166 _maxIPv6Networks, 167 _activeResetSrtpParams, 168 _enableDscp]; 169} 170 171#pragma mark - Private 172 173- (webrtc::PeerConnectionInterface::RTCConfiguration *) 174 createNativeConfiguration { 175 std::unique_ptr<webrtc::PeerConnectionInterface::RTCConfiguration> 176 nativeConfig(new webrtc::PeerConnectionInterface::RTCConfiguration( 177 webrtc::PeerConnectionInterface::RTCConfigurationType::kAggressive)); 178 179 nativeConfig->set_dscp(_enableDscp); 180 for (RTC_OBJC_TYPE(RTCIceServer) * iceServer in _iceServers) { 181 nativeConfig->servers.push_back(iceServer.nativeServer); 182 } 183 nativeConfig->type = 184 [[self class] nativeTransportsTypeForTransportPolicy:_iceTransportPolicy]; 185 nativeConfig->bundle_policy = 186 [[self class] nativeBundlePolicyForPolicy:_bundlePolicy]; 187 nativeConfig->rtcp_mux_policy = 188 [[self class] nativeRtcpMuxPolicyForPolicy:_rtcpMuxPolicy]; 189 nativeConfig->tcp_candidate_policy = 190 [[self class] nativeTcpCandidatePolicyForPolicy:_tcpCandidatePolicy]; 191 nativeConfig->candidate_network_policy = [[self class] 192 nativeCandidateNetworkPolicyForPolicy:_candidateNetworkPolicy]; 193 nativeConfig->continual_gathering_policy = [[self class] 194 nativeContinualGatheringPolicyForPolicy:_continualGatheringPolicy]; 195 nativeConfig->disable_ipv6 = _disableIPV6; 196 nativeConfig->disable_ipv6_on_wifi = _disableIPV6OnWiFi; 197 nativeConfig->max_ipv6_networks = _maxIPv6Networks; 198 nativeConfig->disable_link_local_networks = _disableLinkLocalNetworks; 199 nativeConfig->audio_jitter_buffer_max_packets = _audioJitterBufferMaxPackets; 200 nativeConfig->audio_jitter_buffer_fast_accelerate = 201 _audioJitterBufferFastAccelerate ? true : false; 202 nativeConfig->ice_connection_receiving_timeout = 203 _iceConnectionReceivingTimeout; 204 nativeConfig->ice_backup_candidate_pair_ping_interval = 205 _iceBackupCandidatePairPingInterval; 206 rtc::KeyType keyType = 207 [[self class] nativeEncryptionKeyTypeForKeyType:_keyType]; 208 if (_certificate != nullptr) { 209 // if offered a pemcert use it... 210 RTC_LOG(LS_INFO) << "Have configured cert - using it."; 211 std::string pem_private_key = [[_certificate private_key] UTF8String]; 212 std::string pem_certificate = [[_certificate certificate] UTF8String]; 213 rtc::RTCCertificatePEM pem = rtc::RTCCertificatePEM(pem_private_key, pem_certificate); 214 rtc::scoped_refptr<rtc::RTCCertificate> certificate = rtc::RTCCertificate::FromPEM(pem); 215 RTC_LOG(LS_INFO) << "Created cert from PEM strings."; 216 if (!certificate) { 217 RTC_LOG(LS_ERROR) << "Failed to generate certificate from PEM."; 218 return nullptr; 219 } 220 nativeConfig->certificates.push_back(certificate); 221 } else { 222 RTC_LOG(LS_INFO) << "Don't have configured cert."; 223 // Generate non-default certificate. 224 if (keyType != rtc::KT_DEFAULT) { 225 rtc::scoped_refptr<rtc::RTCCertificate> certificate = 226 rtc::RTCCertificateGenerator::GenerateCertificate(rtc::KeyParams(keyType), 227 absl::optional<uint64_t>()); 228 if (!certificate) { 229 RTCLogError(@"Failed to generate certificate."); 230 return nullptr; 231 } 232 nativeConfig->certificates.push_back(certificate); 233 } 234 } 235 nativeConfig->ice_candidate_pool_size = _iceCandidatePoolSize; 236 nativeConfig->prune_turn_ports = _shouldPruneTurnPorts ? true : false; 237 nativeConfig->presume_writable_when_fully_relayed = 238 _shouldPresumeWritableWhenFullyRelayed ? true : false; 239 nativeConfig->surface_ice_candidates_on_ice_transport_type_changed = 240 _shouldSurfaceIceCandidatesOnIceTransportTypeChanged ? true : false; 241 if (_iceCheckMinInterval != nil) { 242 nativeConfig->ice_check_min_interval = absl::optional<int>(_iceCheckMinInterval.intValue); 243 } 244 nativeConfig->sdp_semantics = [[self class] nativeSdpSemanticsForSdpSemantics:_sdpSemantics]; 245 if (_turnCustomizer) { 246 nativeConfig->turn_customizer = _turnCustomizer; 247 } 248 nativeConfig->active_reset_srtp_params = _activeResetSrtpParams ? true : false; 249 if (_cryptoOptions) { 250 webrtc::CryptoOptions nativeCryptoOptions; 251 nativeCryptoOptions.srtp.enable_gcm_crypto_suites = 252 _cryptoOptions.srtpEnableGcmCryptoSuites ? true : false; 253 nativeCryptoOptions.srtp.enable_aes128_sha1_32_crypto_cipher = 254 _cryptoOptions.srtpEnableAes128Sha1_32CryptoCipher ? true : false; 255 nativeCryptoOptions.srtp.enable_encrypted_rtp_header_extensions = 256 _cryptoOptions.srtpEnableEncryptedRtpHeaderExtensions ? true : false; 257 nativeCryptoOptions.sframe.require_frame_encryption = 258 _cryptoOptions.sframeRequireFrameEncryption ? true : false; 259 nativeConfig->crypto_options = absl::optional<webrtc::CryptoOptions>(nativeCryptoOptions); 260 } 261 nativeConfig->set_audio_rtcp_report_interval_ms(_rtcpAudioReportIntervalMs); 262 nativeConfig->set_video_rtcp_report_interval_ms(_rtcpVideoReportIntervalMs); 263 nativeConfig->allow_codec_switching = _allowCodecSwitching; 264 return nativeConfig.release(); 265} 266 267+ (webrtc::PeerConnectionInterface::IceTransportsType) 268 nativeTransportsTypeForTransportPolicy:(RTCIceTransportPolicy)policy { 269 switch (policy) { 270 case RTCIceTransportPolicyNone: 271 return webrtc::PeerConnectionInterface::kNone; 272 case RTCIceTransportPolicyRelay: 273 return webrtc::PeerConnectionInterface::kRelay; 274 case RTCIceTransportPolicyNoHost: 275 return webrtc::PeerConnectionInterface::kNoHost; 276 case RTCIceTransportPolicyAll: 277 return webrtc::PeerConnectionInterface::kAll; 278 } 279} 280 281+ (RTCIceTransportPolicy)transportPolicyForTransportsType: 282 (webrtc::PeerConnectionInterface::IceTransportsType)nativeType { 283 switch (nativeType) { 284 case webrtc::PeerConnectionInterface::kNone: 285 return RTCIceTransportPolicyNone; 286 case webrtc::PeerConnectionInterface::kRelay: 287 return RTCIceTransportPolicyRelay; 288 case webrtc::PeerConnectionInterface::kNoHost: 289 return RTCIceTransportPolicyNoHost; 290 case webrtc::PeerConnectionInterface::kAll: 291 return RTCIceTransportPolicyAll; 292 } 293} 294 295+ (NSString *)stringForTransportPolicy:(RTCIceTransportPolicy)policy { 296 switch (policy) { 297 case RTCIceTransportPolicyNone: 298 return @"NONE"; 299 case RTCIceTransportPolicyRelay: 300 return @"RELAY"; 301 case RTCIceTransportPolicyNoHost: 302 return @"NO_HOST"; 303 case RTCIceTransportPolicyAll: 304 return @"ALL"; 305 } 306} 307 308+ (webrtc::PeerConnectionInterface::BundlePolicy)nativeBundlePolicyForPolicy: 309 (RTCBundlePolicy)policy { 310 switch (policy) { 311 case RTCBundlePolicyBalanced: 312 return webrtc::PeerConnectionInterface::kBundlePolicyBalanced; 313 case RTCBundlePolicyMaxCompat: 314 return webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat; 315 case RTCBundlePolicyMaxBundle: 316 return webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle; 317 } 318} 319 320+ (RTCBundlePolicy)bundlePolicyForNativePolicy: 321 (webrtc::PeerConnectionInterface::BundlePolicy)nativePolicy { 322 switch (nativePolicy) { 323 case webrtc::PeerConnectionInterface::kBundlePolicyBalanced: 324 return RTCBundlePolicyBalanced; 325 case webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat: 326 return RTCBundlePolicyMaxCompat; 327 case webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle: 328 return RTCBundlePolicyMaxBundle; 329 } 330} 331 332+ (NSString *)stringForBundlePolicy:(RTCBundlePolicy)policy { 333 switch (policy) { 334 case RTCBundlePolicyBalanced: 335 return @"BALANCED"; 336 case RTCBundlePolicyMaxCompat: 337 return @"MAX_COMPAT"; 338 case RTCBundlePolicyMaxBundle: 339 return @"MAX_BUNDLE"; 340 } 341} 342 343+ (webrtc::PeerConnectionInterface::RtcpMuxPolicy)nativeRtcpMuxPolicyForPolicy: 344 (RTCRtcpMuxPolicy)policy { 345 switch (policy) { 346 case RTCRtcpMuxPolicyNegotiate: 347 return webrtc::PeerConnectionInterface::kRtcpMuxPolicyNegotiate; 348 case RTCRtcpMuxPolicyRequire: 349 return webrtc::PeerConnectionInterface::kRtcpMuxPolicyRequire; 350 } 351} 352 353+ (RTCRtcpMuxPolicy)rtcpMuxPolicyForNativePolicy: 354 (webrtc::PeerConnectionInterface::RtcpMuxPolicy)nativePolicy { 355 switch (nativePolicy) { 356 case webrtc::PeerConnectionInterface::kRtcpMuxPolicyNegotiate: 357 return RTCRtcpMuxPolicyNegotiate; 358 case webrtc::PeerConnectionInterface::kRtcpMuxPolicyRequire: 359 return RTCRtcpMuxPolicyRequire; 360 } 361} 362 363+ (NSString *)stringForRtcpMuxPolicy:(RTCRtcpMuxPolicy)policy { 364 switch (policy) { 365 case RTCRtcpMuxPolicyNegotiate: 366 return @"NEGOTIATE"; 367 case RTCRtcpMuxPolicyRequire: 368 return @"REQUIRE"; 369 } 370} 371 372+ (webrtc::PeerConnectionInterface::TcpCandidatePolicy) 373 nativeTcpCandidatePolicyForPolicy:(RTCTcpCandidatePolicy)policy { 374 switch (policy) { 375 case RTCTcpCandidatePolicyEnabled: 376 return webrtc::PeerConnectionInterface::kTcpCandidatePolicyEnabled; 377 case RTCTcpCandidatePolicyDisabled: 378 return webrtc::PeerConnectionInterface::kTcpCandidatePolicyDisabled; 379 } 380} 381 382+ (webrtc::PeerConnectionInterface::CandidateNetworkPolicy) 383 nativeCandidateNetworkPolicyForPolicy:(RTCCandidateNetworkPolicy)policy { 384 switch (policy) { 385 case RTCCandidateNetworkPolicyAll: 386 return webrtc::PeerConnectionInterface::kCandidateNetworkPolicyAll; 387 case RTCCandidateNetworkPolicyLowCost: 388 return webrtc::PeerConnectionInterface::kCandidateNetworkPolicyLowCost; 389 } 390} 391 392+ (RTCTcpCandidatePolicy)tcpCandidatePolicyForNativePolicy: 393 (webrtc::PeerConnectionInterface::TcpCandidatePolicy)nativePolicy { 394 switch (nativePolicy) { 395 case webrtc::PeerConnectionInterface::kTcpCandidatePolicyEnabled: 396 return RTCTcpCandidatePolicyEnabled; 397 case webrtc::PeerConnectionInterface::kTcpCandidatePolicyDisabled: 398 return RTCTcpCandidatePolicyDisabled; 399 } 400} 401 402+ (NSString *)stringForTcpCandidatePolicy:(RTCTcpCandidatePolicy)policy { 403 switch (policy) { 404 case RTCTcpCandidatePolicyEnabled: 405 return @"TCP_ENABLED"; 406 case RTCTcpCandidatePolicyDisabled: 407 return @"TCP_DISABLED"; 408 } 409} 410 411+ (RTCCandidateNetworkPolicy)candidateNetworkPolicyForNativePolicy: 412 (webrtc::PeerConnectionInterface::CandidateNetworkPolicy)nativePolicy { 413 switch (nativePolicy) { 414 case webrtc::PeerConnectionInterface::kCandidateNetworkPolicyAll: 415 return RTCCandidateNetworkPolicyAll; 416 case webrtc::PeerConnectionInterface::kCandidateNetworkPolicyLowCost: 417 return RTCCandidateNetworkPolicyLowCost; 418 } 419} 420 421+ (NSString *)stringForCandidateNetworkPolicy: 422 (RTCCandidateNetworkPolicy)policy { 423 switch (policy) { 424 case RTCCandidateNetworkPolicyAll: 425 return @"CANDIDATE_ALL_NETWORKS"; 426 case RTCCandidateNetworkPolicyLowCost: 427 return @"CANDIDATE_LOW_COST_NETWORKS"; 428 } 429} 430 431+ (webrtc::PeerConnectionInterface::ContinualGatheringPolicy) 432 nativeContinualGatheringPolicyForPolicy: 433 (RTCContinualGatheringPolicy)policy { 434 switch (policy) { 435 case RTCContinualGatheringPolicyGatherOnce: 436 return webrtc::PeerConnectionInterface::GATHER_ONCE; 437 case RTCContinualGatheringPolicyGatherContinually: 438 return webrtc::PeerConnectionInterface::GATHER_CONTINUALLY; 439 } 440} 441 442+ (RTCContinualGatheringPolicy)continualGatheringPolicyForNativePolicy: 443 (webrtc::PeerConnectionInterface::ContinualGatheringPolicy)nativePolicy { 444 switch (nativePolicy) { 445 case webrtc::PeerConnectionInterface::GATHER_ONCE: 446 return RTCContinualGatheringPolicyGatherOnce; 447 case webrtc::PeerConnectionInterface::GATHER_CONTINUALLY: 448 return RTCContinualGatheringPolicyGatherContinually; 449 } 450} 451 452+ (NSString *)stringForContinualGatheringPolicy: 453 (RTCContinualGatheringPolicy)policy { 454 switch (policy) { 455 case RTCContinualGatheringPolicyGatherOnce: 456 return @"GATHER_ONCE"; 457 case RTCContinualGatheringPolicyGatherContinually: 458 return @"GATHER_CONTINUALLY"; 459 } 460} 461 462+ (rtc::KeyType)nativeEncryptionKeyTypeForKeyType: 463 (RTCEncryptionKeyType)keyType { 464 switch (keyType) { 465 case RTCEncryptionKeyTypeRSA: 466 return rtc::KT_RSA; 467 case RTCEncryptionKeyTypeECDSA: 468 return rtc::KT_ECDSA; 469 } 470} 471 472+ (webrtc::SdpSemantics)nativeSdpSemanticsForSdpSemantics:(RTCSdpSemantics)sdpSemantics { 473 switch (sdpSemantics) { 474 case RTCSdpSemanticsPlanB: 475 return webrtc::SdpSemantics::kPlanB; 476 case RTCSdpSemanticsUnifiedPlan: 477 return webrtc::SdpSemantics::kUnifiedPlan; 478 } 479} 480 481+ (RTCSdpSemantics)sdpSemanticsForNativeSdpSemantics:(webrtc::SdpSemantics)sdpSemantics { 482 switch (sdpSemantics) { 483 case webrtc::SdpSemantics::kPlanB: 484 return RTCSdpSemanticsPlanB; 485 case webrtc::SdpSemantics::kUnifiedPlan: 486 return RTCSdpSemanticsUnifiedPlan; 487 } 488} 489 490+ (NSString *)stringForSdpSemantics:(RTCSdpSemantics)sdpSemantics { 491 switch (sdpSemantics) { 492 case RTCSdpSemanticsPlanB: 493 return @"PLAN_B"; 494 case RTCSdpSemanticsUnifiedPlan: 495 return @"UNIFIED_PLAN"; 496 } 497} 498 499@end 500