/* * Copyright 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #import "RTCPeerConnection+Private.h" #import "RTCConfiguration+Private.h" #import "RTCDataChannel+Private.h" #import "RTCIceCandidate+Private.h" #import "RTCLegacyStatsReport+Private.h" #import "RTCMediaConstraints+Private.h" #import "RTCMediaStream+Private.h" #import "RTCMediaStreamTrack+Private.h" #import "RTCPeerConnectionFactory+Private.h" #import "RTCRtpReceiver+Private.h" #import "RTCRtpSender+Private.h" #import "RTCRtpTransceiver+Private.h" #import "RTCSessionDescription+Private.h" #import "base/RTCLogging.h" #import "helpers/NSString+StdString.h" #include #include "api/jsep_ice_candidate.h" #include "api/rtc_event_log_output_file.h" #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_conversions.h" NSString *const kRTCPeerConnectionErrorDomain = @"org.webrtc.RTC_OBJC_TYPE(RTCPeerConnection)"; int const kRTCPeerConnnectionSessionDescriptionError = -1; namespace webrtc { class CreateSessionDescriptionObserverAdapter : public CreateSessionDescriptionObserver { public: CreateSessionDescriptionObserverAdapter(void (^completionHandler)( RTC_OBJC_TYPE(RTCSessionDescription) * sessionDescription, NSError *error)) { completion_handler_ = completionHandler; } ~CreateSessionDescriptionObserverAdapter() override { completion_handler_ = nil; } void OnSuccess(SessionDescriptionInterface *desc) override { RTC_DCHECK(completion_handler_); std::unique_ptr description = std::unique_ptr(desc); RTC_OBJC_TYPE(RTCSessionDescription) *session = [[RTC_OBJC_TYPE(RTCSessionDescription) alloc] initWithNativeDescription:description.get()]; completion_handler_(session, nil); completion_handler_ = nil; } void OnFailure(RTCError error) override { RTC_DCHECK(completion_handler_); // TODO(hta): Add handling of error.type() NSString *str = [NSString stringForStdString:error.message()]; NSError* err = [NSError errorWithDomain:kRTCPeerConnectionErrorDomain code:kRTCPeerConnnectionSessionDescriptionError userInfo:@{ NSLocalizedDescriptionKey : str }]; completion_handler_(nil, err); completion_handler_ = nil; } private: void (^completion_handler_)(RTC_OBJC_TYPE(RTCSessionDescription) * sessionDescription, NSError *error); }; class SetSessionDescriptionObserverAdapter : public SetSessionDescriptionObserver { public: SetSessionDescriptionObserverAdapter(void (^completionHandler) (NSError *error)) { completion_handler_ = completionHandler; } ~SetSessionDescriptionObserverAdapter() override { completion_handler_ = nil; } void OnSuccess() override { RTC_DCHECK(completion_handler_); completion_handler_(nil); completion_handler_ = nil; } void OnFailure(RTCError error) override { RTC_DCHECK(completion_handler_); // TODO(hta): Add handling of error.type() NSString *str = [NSString stringForStdString:error.message()]; NSError* err = [NSError errorWithDomain:kRTCPeerConnectionErrorDomain code:kRTCPeerConnnectionSessionDescriptionError userInfo:@{ NSLocalizedDescriptionKey : str }]; completion_handler_(err); completion_handler_ = nil; } private: void (^completion_handler_)(NSError *error); }; PeerConnectionDelegateAdapter::PeerConnectionDelegateAdapter(RTC_OBJC_TYPE(RTCPeerConnection) * peerConnection) { peer_connection_ = peerConnection; } PeerConnectionDelegateAdapter::~PeerConnectionDelegateAdapter() { peer_connection_ = nil; } void PeerConnectionDelegateAdapter::OnSignalingChange( PeerConnectionInterface::SignalingState new_state) { RTCSignalingState state = [[RTC_OBJC_TYPE(RTCPeerConnection) class] signalingStateForNativeState:new_state]; RTC_OBJC_TYPE(RTCPeerConnection) *peer_connection = peer_connection_; [peer_connection.delegate peerConnection:peer_connection didChangeSignalingState:state]; } void PeerConnectionDelegateAdapter::OnAddStream( rtc::scoped_refptr stream) { RTC_OBJC_TYPE(RTCPeerConnection) *peer_connection = peer_connection_; RTC_OBJC_TYPE(RTCMediaStream) *mediaStream = [[RTC_OBJC_TYPE(RTCMediaStream) alloc] initWithFactory:peer_connection.factory nativeMediaStream:stream]; [peer_connection.delegate peerConnection:peer_connection didAddStream:mediaStream]; } void PeerConnectionDelegateAdapter::OnRemoveStream( rtc::scoped_refptr stream) { RTC_OBJC_TYPE(RTCPeerConnection) *peer_connection = peer_connection_; RTC_OBJC_TYPE(RTCMediaStream) *mediaStream = [[RTC_OBJC_TYPE(RTCMediaStream) alloc] initWithFactory:peer_connection.factory nativeMediaStream:stream]; [peer_connection.delegate peerConnection:peer_connection didRemoveStream:mediaStream]; } void PeerConnectionDelegateAdapter::OnTrack( rtc::scoped_refptr nativeTransceiver) { RTC_OBJC_TYPE(RTCPeerConnection) *peer_connection = peer_connection_; RTC_OBJC_TYPE(RTCRtpTransceiver) *transceiver = [[RTC_OBJC_TYPE(RTCRtpTransceiver) alloc] initWithFactory:peer_connection.factory nativeRtpTransceiver:nativeTransceiver]; if ([peer_connection.delegate respondsToSelector:@selector(peerConnection:didStartReceivingOnTransceiver:)]) { [peer_connection.delegate peerConnection:peer_connection didStartReceivingOnTransceiver:transceiver]; } } void PeerConnectionDelegateAdapter::OnDataChannel( rtc::scoped_refptr data_channel) { RTC_OBJC_TYPE(RTCPeerConnection) *peer_connection = peer_connection_; RTC_OBJC_TYPE(RTCDataChannel) *dataChannel = [[RTC_OBJC_TYPE(RTCDataChannel) alloc] initWithFactory:peer_connection.factory nativeDataChannel:data_channel]; [peer_connection.delegate peerConnection:peer_connection didOpenDataChannel:dataChannel]; } void PeerConnectionDelegateAdapter::OnRenegotiationNeeded() { RTC_OBJC_TYPE(RTCPeerConnection) *peer_connection = peer_connection_; [peer_connection.delegate peerConnectionShouldNegotiate:peer_connection]; } void PeerConnectionDelegateAdapter::OnIceConnectionChange( PeerConnectionInterface::IceConnectionState new_state) { RTCIceConnectionState state = [RTC_OBJC_TYPE(RTCPeerConnection) iceConnectionStateForNativeState:new_state]; [peer_connection_.delegate peerConnection:peer_connection_ didChangeIceConnectionState:state]; } void PeerConnectionDelegateAdapter::OnStandardizedIceConnectionChange( PeerConnectionInterface::IceConnectionState new_state) { if ([peer_connection_.delegate respondsToSelector:@selector(peerConnection:didChangeStandardizedIceConnectionState:)]) { RTCIceConnectionState state = [RTC_OBJC_TYPE(RTCPeerConnection) iceConnectionStateForNativeState:new_state]; [peer_connection_.delegate peerConnection:peer_connection_ didChangeStandardizedIceConnectionState:state]; } } void PeerConnectionDelegateAdapter::OnConnectionChange( PeerConnectionInterface::PeerConnectionState new_state) { if ([peer_connection_.delegate respondsToSelector:@selector(peerConnection:didChangeConnectionState:)]) { RTCPeerConnectionState state = [RTC_OBJC_TYPE(RTCPeerConnection) connectionStateForNativeState:new_state]; [peer_connection_.delegate peerConnection:peer_connection_ didChangeConnectionState:state]; } } void PeerConnectionDelegateAdapter::OnIceGatheringChange( PeerConnectionInterface::IceGatheringState new_state) { RTCIceGatheringState state = [[RTC_OBJC_TYPE(RTCPeerConnection) class] iceGatheringStateForNativeState:new_state]; RTC_OBJC_TYPE(RTCPeerConnection) *peer_connection = peer_connection_; [peer_connection.delegate peerConnection:peer_connection didChangeIceGatheringState:state]; } void PeerConnectionDelegateAdapter::OnIceCandidate( const IceCandidateInterface *candidate) { RTC_OBJC_TYPE(RTCIceCandidate) *iceCandidate = [[RTC_OBJC_TYPE(RTCIceCandidate) alloc] initWithNativeCandidate:candidate]; RTC_OBJC_TYPE(RTCPeerConnection) *peer_connection = peer_connection_; [peer_connection.delegate peerConnection:peer_connection didGenerateIceCandidate:iceCandidate]; } void PeerConnectionDelegateAdapter::OnIceCandidatesRemoved( const std::vector& candidates) { NSMutableArray* ice_candidates = [NSMutableArray arrayWithCapacity:candidates.size()]; for (const auto& candidate : candidates) { std::unique_ptr candidate_wrapper( new JsepIceCandidate(candidate.transport_name(), -1, candidate)); RTC_OBJC_TYPE(RTCIceCandidate) *ice_candidate = [[RTC_OBJC_TYPE(RTCIceCandidate) alloc] initWithNativeCandidate:candidate_wrapper.get()]; [ice_candidates addObject:ice_candidate]; } RTC_OBJC_TYPE(RTCPeerConnection) *peer_connection = peer_connection_; [peer_connection.delegate peerConnection:peer_connection didRemoveIceCandidates:ice_candidates]; } void PeerConnectionDelegateAdapter::OnIceSelectedCandidatePairChanged( const cricket::CandidatePairChangeEvent &event) { const auto &selected_pair = event.selected_candidate_pair; auto local_candidate_wrapper = std::make_unique( selected_pair.local_candidate().transport_name(), -1, selected_pair.local_candidate()); RTC_OBJC_TYPE(RTCIceCandidate) *local_candidate = [[RTC_OBJC_TYPE(RTCIceCandidate) alloc] initWithNativeCandidate:local_candidate_wrapper.release()]; auto remote_candidate_wrapper = std::make_unique( selected_pair.remote_candidate().transport_name(), -1, selected_pair.remote_candidate()); RTC_OBJC_TYPE(RTCIceCandidate) *remote_candidate = [[RTC_OBJC_TYPE(RTCIceCandidate) alloc] initWithNativeCandidate:remote_candidate_wrapper.release()]; RTC_OBJC_TYPE(RTCPeerConnection) *peer_connection = peer_connection_; NSString *nsstr_reason = [NSString stringForStdString:event.reason]; if ([peer_connection.delegate respondsToSelector:@selector (peerConnection:didChangeLocalCandidate:remoteCandidate:lastReceivedMs:changeReason:)]) { [peer_connection.delegate peerConnection:peer_connection didChangeLocalCandidate:local_candidate remoteCandidate:remote_candidate lastReceivedMs:event.last_data_received_ms changeReason:nsstr_reason]; } } void PeerConnectionDelegateAdapter::OnAddTrack( rtc::scoped_refptr receiver, const std::vector> &streams) { RTC_OBJC_TYPE(RTCPeerConnection) *peer_connection = peer_connection_; if ([peer_connection.delegate respondsToSelector:@selector(peerConnection: didAddReceiver:streams:)]) { NSMutableArray *mediaStreams = [NSMutableArray arrayWithCapacity:streams.size()]; for (const auto &nativeStream : streams) { RTC_OBJC_TYPE(RTCMediaStream) *mediaStream = [[RTC_OBJC_TYPE(RTCMediaStream) alloc] initWithFactory:peer_connection.factory nativeMediaStream:nativeStream]; [mediaStreams addObject:mediaStream]; } RTC_OBJC_TYPE(RTCRtpReceiver) *rtpReceiver = [[RTC_OBJC_TYPE(RTCRtpReceiver) alloc] initWithFactory:peer_connection.factory nativeRtpReceiver:receiver]; [peer_connection.delegate peerConnection:peer_connection didAddReceiver:rtpReceiver streams:mediaStreams]; } } void PeerConnectionDelegateAdapter::OnRemoveTrack( rtc::scoped_refptr receiver) { RTC_OBJC_TYPE(RTCPeerConnection) *peer_connection = peer_connection_; if ([peer_connection.delegate respondsToSelector:@selector(peerConnection:didRemoveReceiver:)]) { RTC_OBJC_TYPE(RTCRtpReceiver) *rtpReceiver = [[RTC_OBJC_TYPE(RTCRtpReceiver) alloc] initWithFactory:peer_connection.factory nativeRtpReceiver:receiver]; [peer_connection.delegate peerConnection:peer_connection didRemoveReceiver:rtpReceiver]; } } } // namespace webrtc @implementation RTC_OBJC_TYPE (RTCPeerConnection) { RTC_OBJC_TYPE(RTCPeerConnectionFactory) * _factory; NSMutableArray *_localStreams; std::unique_ptr _observer; rtc::scoped_refptr _peerConnection; std::unique_ptr _nativeConstraints; BOOL _hasStartedRtcEventLog; } @synthesize delegate = _delegate; @synthesize factory = _factory; - (instancetype)initWithFactory:(RTC_OBJC_TYPE(RTCPeerConnectionFactory) *)factory configuration:(RTC_OBJC_TYPE(RTCConfiguration) *)configuration constraints:(RTC_OBJC_TYPE(RTCMediaConstraints) *)constraints delegate:(id)delegate { NSParameterAssert(factory); std::unique_ptr dependencies = std::make_unique(nullptr); return [self initWithDependencies:factory configuration:configuration constraints:constraints dependencies:std::move(dependencies) delegate:delegate]; } - (instancetype)initWithDependencies:(RTC_OBJC_TYPE(RTCPeerConnectionFactory) *)factory configuration:(RTC_OBJC_TYPE(RTCConfiguration) *)configuration constraints:(RTC_OBJC_TYPE(RTCMediaConstraints) *)constraints dependencies: (std::unique_ptr)dependencies delegate:(id)delegate { NSParameterAssert(factory); NSParameterAssert(dependencies.get()); std::unique_ptr config( [configuration createNativeConfiguration]); if (!config) { return nil; } if (self = [super init]) { _observer.reset(new webrtc::PeerConnectionDelegateAdapter(self)); _nativeConstraints = constraints.nativeConstraints; CopyConstraintsIntoRtcConfiguration(_nativeConstraints.get(), config.get()); webrtc::PeerConnectionDependencies deps = std::move(*dependencies.release()); deps.observer = _observer.get(); _peerConnection = factory.nativeFactory->CreatePeerConnection(*config, std::move(deps)); if (!_peerConnection) { return nil; } _factory = factory; _localStreams = [[NSMutableArray alloc] init]; _delegate = delegate; } return self; } - (NSArray *)localStreams { return [_localStreams copy]; } - (RTC_OBJC_TYPE(RTCSessionDescription) *)localDescription { const webrtc::SessionDescriptionInterface *description = _peerConnection->local_description(); return description ? [[RTC_OBJC_TYPE(RTCSessionDescription) alloc] initWithNativeDescription:description] : nil; } - (RTC_OBJC_TYPE(RTCSessionDescription) *)remoteDescription { const webrtc::SessionDescriptionInterface *description = _peerConnection->remote_description(); return description ? [[RTC_OBJC_TYPE(RTCSessionDescription) alloc] initWithNativeDescription:description] : nil; } - (RTCSignalingState)signalingState { return [[self class] signalingStateForNativeState:_peerConnection->signaling_state()]; } - (RTCIceConnectionState)iceConnectionState { return [[self class] iceConnectionStateForNativeState: _peerConnection->ice_connection_state()]; } - (RTCPeerConnectionState)connectionState { return [[self class] connectionStateForNativeState:_peerConnection->peer_connection_state()]; } - (RTCIceGatheringState)iceGatheringState { return [[self class] iceGatheringStateForNativeState: _peerConnection->ice_gathering_state()]; } - (BOOL)setConfiguration:(RTC_OBJC_TYPE(RTCConfiguration) *)configuration { std::unique_ptr config( [configuration createNativeConfiguration]); if (!config) { return NO; } CopyConstraintsIntoRtcConfiguration(_nativeConstraints.get(), config.get()); return _peerConnection->SetConfiguration(*config).ok(); } - (RTC_OBJC_TYPE(RTCConfiguration) *)configuration { webrtc::PeerConnectionInterface::RTCConfiguration config = _peerConnection->GetConfiguration(); return [[RTC_OBJC_TYPE(RTCConfiguration) alloc] initWithNativeConfiguration:config]; } - (void)close { _peerConnection->Close(); } - (void)addIceCandidate:(RTC_OBJC_TYPE(RTCIceCandidate) *)candidate { std::unique_ptr iceCandidate( candidate.nativeCandidate); _peerConnection->AddIceCandidate(iceCandidate.get()); } - (void)removeIceCandidates:(NSArray *)iceCandidates { std::vector candidates; for (RTC_OBJC_TYPE(RTCIceCandidate) * iceCandidate in iceCandidates) { std::unique_ptr candidate( iceCandidate.nativeCandidate); if (candidate) { candidates.push_back(candidate->candidate()); // Need to fill the transport name from the sdp_mid. candidates.back().set_transport_name(candidate->sdp_mid()); } } if (!candidates.empty()) { _peerConnection->RemoveIceCandidates(candidates); } } - (void)addStream:(RTC_OBJC_TYPE(RTCMediaStream) *)stream { if (!_peerConnection->AddStream(stream.nativeMediaStream)) { RTCLogError(@"Failed to add stream: %@", stream); return; } [_localStreams addObject:stream]; } - (void)removeStream:(RTC_OBJC_TYPE(RTCMediaStream) *)stream { _peerConnection->RemoveStream(stream.nativeMediaStream); [_localStreams removeObject:stream]; } - (RTC_OBJC_TYPE(RTCRtpSender) *)addTrack:(RTC_OBJC_TYPE(RTCMediaStreamTrack) *)track streamIds:(NSArray *)streamIds { std::vector nativeStreamIds; for (NSString *streamId in streamIds) { nativeStreamIds.push_back([streamId UTF8String]); } webrtc::RTCErrorOr> nativeSenderOrError = _peerConnection->AddTrack(track.nativeTrack, nativeStreamIds); if (!nativeSenderOrError.ok()) { RTCLogError(@"Failed to add track %@: %s", track, nativeSenderOrError.error().message()); return nil; } return [[RTC_OBJC_TYPE(RTCRtpSender) alloc] initWithFactory:self.factory nativeRtpSender:nativeSenderOrError.MoveValue()]; } - (BOOL)removeTrack:(RTC_OBJC_TYPE(RTCRtpSender) *)sender { bool result = _peerConnection->RemoveTrack(sender.nativeRtpSender); if (!result) { RTCLogError(@"Failed to remote track %@", sender); } return result; } - (RTC_OBJC_TYPE(RTCRtpTransceiver) *)addTransceiverWithTrack: (RTC_OBJC_TYPE(RTCMediaStreamTrack) *)track { return [self addTransceiverWithTrack:track init:[[RTC_OBJC_TYPE(RTCRtpTransceiverInit) alloc] init]]; } - (RTC_OBJC_TYPE(RTCRtpTransceiver) *) addTransceiverWithTrack:(RTC_OBJC_TYPE(RTCMediaStreamTrack) *)track init:(RTC_OBJC_TYPE(RTCRtpTransceiverInit) *)init { webrtc::RTCErrorOr> nativeTransceiverOrError = _peerConnection->AddTransceiver(track.nativeTrack, init.nativeInit); if (!nativeTransceiverOrError.ok()) { RTCLogError( @"Failed to add transceiver %@: %s", track, nativeTransceiverOrError.error().message()); return nil; } return [[RTC_OBJC_TYPE(RTCRtpTransceiver) alloc] initWithFactory:self.factory nativeRtpTransceiver:nativeTransceiverOrError.MoveValue()]; } - (RTC_OBJC_TYPE(RTCRtpTransceiver) *)addTransceiverOfType:(RTCRtpMediaType)mediaType { return [self addTransceiverOfType:mediaType init:[[RTC_OBJC_TYPE(RTCRtpTransceiverInit) alloc] init]]; } - (RTC_OBJC_TYPE(RTCRtpTransceiver) *)addTransceiverOfType:(RTCRtpMediaType)mediaType init:(RTC_OBJC_TYPE(RTCRtpTransceiverInit) *) init { webrtc::RTCErrorOr> nativeTransceiverOrError = _peerConnection->AddTransceiver( [RTC_OBJC_TYPE(RTCRtpReceiver) nativeMediaTypeForMediaType:mediaType], init.nativeInit); if (!nativeTransceiverOrError.ok()) { RTCLogError(@"Failed to add transceiver %@: %s", [RTC_OBJC_TYPE(RTCRtpReceiver) stringForMediaType:mediaType], nativeTransceiverOrError.error().message()); return nil; } return [[RTC_OBJC_TYPE(RTCRtpTransceiver) alloc] initWithFactory:self.factory nativeRtpTransceiver:nativeTransceiverOrError.MoveValue()]; } - (void)offerForConstraints:(RTC_OBJC_TYPE(RTCMediaConstraints) *)constraints completionHandler:(void (^)(RTC_OBJC_TYPE(RTCSessionDescription) * sessionDescription, NSError *error))completionHandler { rtc::scoped_refptr observer(new rtc::RefCountedObject (completionHandler)); webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options; CopyConstraintsIntoOfferAnswerOptions(constraints.nativeConstraints.get(), &options); _peerConnection->CreateOffer(observer, options); } - (void)answerForConstraints:(RTC_OBJC_TYPE(RTCMediaConstraints) *)constraints completionHandler:(void (^)(RTC_OBJC_TYPE(RTCSessionDescription) * sessionDescription, NSError *error))completionHandler { rtc::scoped_refptr observer(new rtc::RefCountedObject (completionHandler)); webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options; CopyConstraintsIntoOfferAnswerOptions(constraints.nativeConstraints.get(), &options); _peerConnection->CreateAnswer(observer, options); } - (void)setLocalDescription:(RTC_OBJC_TYPE(RTCSessionDescription) *)sdp completionHandler:(void (^)(NSError *error))completionHandler { rtc::scoped_refptr observer( new rtc::RefCountedObject( completionHandler)); _peerConnection->SetLocalDescription(observer, sdp.nativeDescription); } - (void)setRemoteDescription:(RTC_OBJC_TYPE(RTCSessionDescription) *)sdp completionHandler:(void (^)(NSError *error))completionHandler { rtc::scoped_refptr observer( new rtc::RefCountedObject( completionHandler)); _peerConnection->SetRemoteDescription(observer, sdp.nativeDescription); } - (BOOL)setBweMinBitrateBps:(nullable NSNumber *)minBitrateBps currentBitrateBps:(nullable NSNumber *)currentBitrateBps maxBitrateBps:(nullable NSNumber *)maxBitrateBps { webrtc::BitrateSettings params; if (minBitrateBps != nil) { params.min_bitrate_bps = absl::optional(minBitrateBps.intValue); } if (currentBitrateBps != nil) { params.start_bitrate_bps = absl::optional(currentBitrateBps.intValue); } if (maxBitrateBps != nil) { params.max_bitrate_bps = absl::optional(maxBitrateBps.intValue); } return _peerConnection->SetBitrate(params).ok(); } - (BOOL)startRtcEventLogWithFilePath:(NSString *)filePath maxSizeInBytes:(int64_t)maxSizeInBytes { RTC_DCHECK(filePath.length); RTC_DCHECK_GT(maxSizeInBytes, 0); RTC_DCHECK(!_hasStartedRtcEventLog); if (_hasStartedRtcEventLog) { RTCLogError(@"Event logging already started."); return NO; } FILE *f = fopen(filePath.UTF8String, "wb"); if (!f) { RTCLogError(@"Error opening file: %@. Error: %d", filePath, errno); return NO; } // TODO(eladalon): It would be better to not allow negative values into PC. const size_t max_size = (maxSizeInBytes < 0) ? webrtc::RtcEventLog::kUnlimitedOutput : rtc::saturated_cast(maxSizeInBytes); _hasStartedRtcEventLog = _peerConnection->StartRtcEventLog( std::make_unique(f, max_size)); return _hasStartedRtcEventLog; } - (void)stopRtcEventLog { _peerConnection->StopRtcEventLog(); _hasStartedRtcEventLog = NO; } - (RTC_OBJC_TYPE(RTCRtpSender) *)senderWithKind:(NSString *)kind streamId:(NSString *)streamId { std::string nativeKind = [NSString stdStringForString:kind]; std::string nativeStreamId = [NSString stdStringForString:streamId]; rtc::scoped_refptr nativeSender( _peerConnection->CreateSender(nativeKind, nativeStreamId)); return nativeSender ? [[RTC_OBJC_TYPE(RTCRtpSender) alloc] initWithFactory:self.factory nativeRtpSender:nativeSender] : nil; } - (NSArray *)senders { std::vector> nativeSenders( _peerConnection->GetSenders()); NSMutableArray *senders = [[NSMutableArray alloc] init]; for (const auto &nativeSender : nativeSenders) { RTC_OBJC_TYPE(RTCRtpSender) *sender = [[RTC_OBJC_TYPE(RTCRtpSender) alloc] initWithFactory:self.factory nativeRtpSender:nativeSender]; [senders addObject:sender]; } return senders; } - (NSArray *)receivers { std::vector> nativeReceivers( _peerConnection->GetReceivers()); NSMutableArray *receivers = [[NSMutableArray alloc] init]; for (const auto &nativeReceiver : nativeReceivers) { RTC_OBJC_TYPE(RTCRtpReceiver) *receiver = [[RTC_OBJC_TYPE(RTCRtpReceiver) alloc] initWithFactory:self.factory nativeRtpReceiver:nativeReceiver]; [receivers addObject:receiver]; } return receivers; } - (NSArray *)transceivers { std::vector> nativeTransceivers( _peerConnection->GetTransceivers()); NSMutableArray *transceivers = [[NSMutableArray alloc] init]; for (const auto &nativeTransceiver : nativeTransceivers) { RTC_OBJC_TYPE(RTCRtpTransceiver) *transceiver = [[RTC_OBJC_TYPE(RTCRtpTransceiver) alloc] initWithFactory:self.factory nativeRtpTransceiver:nativeTransceiver]; [transceivers addObject:transceiver]; } return transceivers; } #pragma mark - Private + (webrtc::PeerConnectionInterface::SignalingState)nativeSignalingStateForState: (RTCSignalingState)state { switch (state) { case RTCSignalingStateStable: return webrtc::PeerConnectionInterface::kStable; case RTCSignalingStateHaveLocalOffer: return webrtc::PeerConnectionInterface::kHaveLocalOffer; case RTCSignalingStateHaveLocalPrAnswer: return webrtc::PeerConnectionInterface::kHaveLocalPrAnswer; case RTCSignalingStateHaveRemoteOffer: return webrtc::PeerConnectionInterface::kHaveRemoteOffer; case RTCSignalingStateHaveRemotePrAnswer: return webrtc::PeerConnectionInterface::kHaveRemotePrAnswer; case RTCSignalingStateClosed: return webrtc::PeerConnectionInterface::kClosed; } } + (RTCSignalingState)signalingStateForNativeState: (webrtc::PeerConnectionInterface::SignalingState)nativeState { switch (nativeState) { case webrtc::PeerConnectionInterface::kStable: return RTCSignalingStateStable; case webrtc::PeerConnectionInterface::kHaveLocalOffer: return RTCSignalingStateHaveLocalOffer; case webrtc::PeerConnectionInterface::kHaveLocalPrAnswer: return RTCSignalingStateHaveLocalPrAnswer; case webrtc::PeerConnectionInterface::kHaveRemoteOffer: return RTCSignalingStateHaveRemoteOffer; case webrtc::PeerConnectionInterface::kHaveRemotePrAnswer: return RTCSignalingStateHaveRemotePrAnswer; case webrtc::PeerConnectionInterface::kClosed: return RTCSignalingStateClosed; } } + (NSString *)stringForSignalingState:(RTCSignalingState)state { switch (state) { case RTCSignalingStateStable: return @"STABLE"; case RTCSignalingStateHaveLocalOffer: return @"HAVE_LOCAL_OFFER"; case RTCSignalingStateHaveLocalPrAnswer: return @"HAVE_LOCAL_PRANSWER"; case RTCSignalingStateHaveRemoteOffer: return @"HAVE_REMOTE_OFFER"; case RTCSignalingStateHaveRemotePrAnswer: return @"HAVE_REMOTE_PRANSWER"; case RTCSignalingStateClosed: return @"CLOSED"; } } + (webrtc::PeerConnectionInterface::PeerConnectionState)nativeConnectionStateForState: (RTCPeerConnectionState)state { switch (state) { case RTCPeerConnectionStateNew: return webrtc::PeerConnectionInterface::PeerConnectionState::kNew; case RTCPeerConnectionStateConnecting: return webrtc::PeerConnectionInterface::PeerConnectionState::kConnecting; case RTCPeerConnectionStateConnected: return webrtc::PeerConnectionInterface::PeerConnectionState::kConnected; case RTCPeerConnectionStateFailed: return webrtc::PeerConnectionInterface::PeerConnectionState::kFailed; case RTCPeerConnectionStateDisconnected: return webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected; case RTCPeerConnectionStateClosed: return webrtc::PeerConnectionInterface::PeerConnectionState::kClosed; } } + (RTCPeerConnectionState)connectionStateForNativeState: (webrtc::PeerConnectionInterface::PeerConnectionState)nativeState { switch (nativeState) { case webrtc::PeerConnectionInterface::PeerConnectionState::kNew: return RTCPeerConnectionStateNew; case webrtc::PeerConnectionInterface::PeerConnectionState::kConnecting: return RTCPeerConnectionStateConnecting; case webrtc::PeerConnectionInterface::PeerConnectionState::kConnected: return RTCPeerConnectionStateConnected; case webrtc::PeerConnectionInterface::PeerConnectionState::kFailed: return RTCPeerConnectionStateFailed; case webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected: return RTCPeerConnectionStateDisconnected; case webrtc::PeerConnectionInterface::PeerConnectionState::kClosed: return RTCPeerConnectionStateClosed; } } + (NSString *)stringForConnectionState:(RTCPeerConnectionState)state { switch (state) { case RTCPeerConnectionStateNew: return @"NEW"; case RTCPeerConnectionStateConnecting: return @"CONNECTING"; case RTCPeerConnectionStateConnected: return @"CONNECTED"; case RTCPeerConnectionStateFailed: return @"FAILED"; case RTCPeerConnectionStateDisconnected: return @"DISCONNECTED"; case RTCPeerConnectionStateClosed: return @"CLOSED"; } } + (webrtc::PeerConnectionInterface::IceConnectionState) nativeIceConnectionStateForState:(RTCIceConnectionState)state { switch (state) { case RTCIceConnectionStateNew: return webrtc::PeerConnectionInterface::kIceConnectionNew; case RTCIceConnectionStateChecking: return webrtc::PeerConnectionInterface::kIceConnectionChecking; case RTCIceConnectionStateConnected: return webrtc::PeerConnectionInterface::kIceConnectionConnected; case RTCIceConnectionStateCompleted: return webrtc::PeerConnectionInterface::kIceConnectionCompleted; case RTCIceConnectionStateFailed: return webrtc::PeerConnectionInterface::kIceConnectionFailed; case RTCIceConnectionStateDisconnected: return webrtc::PeerConnectionInterface::kIceConnectionDisconnected; case RTCIceConnectionStateClosed: return webrtc::PeerConnectionInterface::kIceConnectionClosed; case RTCIceConnectionStateCount: return webrtc::PeerConnectionInterface::kIceConnectionMax; } } + (RTCIceConnectionState)iceConnectionStateForNativeState: (webrtc::PeerConnectionInterface::IceConnectionState)nativeState { switch (nativeState) { case webrtc::PeerConnectionInterface::kIceConnectionNew: return RTCIceConnectionStateNew; case webrtc::PeerConnectionInterface::kIceConnectionChecking: return RTCIceConnectionStateChecking; case webrtc::PeerConnectionInterface::kIceConnectionConnected: return RTCIceConnectionStateConnected; case webrtc::PeerConnectionInterface::kIceConnectionCompleted: return RTCIceConnectionStateCompleted; case webrtc::PeerConnectionInterface::kIceConnectionFailed: return RTCIceConnectionStateFailed; case webrtc::PeerConnectionInterface::kIceConnectionDisconnected: return RTCIceConnectionStateDisconnected; case webrtc::PeerConnectionInterface::kIceConnectionClosed: return RTCIceConnectionStateClosed; case webrtc::PeerConnectionInterface::kIceConnectionMax: return RTCIceConnectionStateCount; } } + (NSString *)stringForIceConnectionState:(RTCIceConnectionState)state { switch (state) { case RTCIceConnectionStateNew: return @"NEW"; case RTCIceConnectionStateChecking: return @"CHECKING"; case RTCIceConnectionStateConnected: return @"CONNECTED"; case RTCIceConnectionStateCompleted: return @"COMPLETED"; case RTCIceConnectionStateFailed: return @"FAILED"; case RTCIceConnectionStateDisconnected: return @"DISCONNECTED"; case RTCIceConnectionStateClosed: return @"CLOSED"; case RTCIceConnectionStateCount: return @"COUNT"; } } + (webrtc::PeerConnectionInterface::IceGatheringState) nativeIceGatheringStateForState:(RTCIceGatheringState)state { switch (state) { case RTCIceGatheringStateNew: return webrtc::PeerConnectionInterface::kIceGatheringNew; case RTCIceGatheringStateGathering: return webrtc::PeerConnectionInterface::kIceGatheringGathering; case RTCIceGatheringStateComplete: return webrtc::PeerConnectionInterface::kIceGatheringComplete; } } + (RTCIceGatheringState)iceGatheringStateForNativeState: (webrtc::PeerConnectionInterface::IceGatheringState)nativeState { switch (nativeState) { case webrtc::PeerConnectionInterface::kIceGatheringNew: return RTCIceGatheringStateNew; case webrtc::PeerConnectionInterface::kIceGatheringGathering: return RTCIceGatheringStateGathering; case webrtc::PeerConnectionInterface::kIceGatheringComplete: return RTCIceGatheringStateComplete; } } + (NSString *)stringForIceGatheringState:(RTCIceGatheringState)state { switch (state) { case RTCIceGatheringStateNew: return @"NEW"; case RTCIceGatheringStateGathering: return @"GATHERING"; case RTCIceGatheringStateComplete: return @"COMPLETE"; } } + (webrtc::PeerConnectionInterface::StatsOutputLevel) nativeStatsOutputLevelForLevel:(RTCStatsOutputLevel)level { switch (level) { case RTCStatsOutputLevelStandard: return webrtc::PeerConnectionInterface::kStatsOutputLevelStandard; case RTCStatsOutputLevelDebug: return webrtc::PeerConnectionInterface::kStatsOutputLevelDebug; } } - (rtc::scoped_refptr)nativePeerConnection { return _peerConnection; } @end