summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/sdk/objc/api/peerconnection/RTCPeerConnection.mm
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/sdk/objc/api/peerconnection/RTCPeerConnection.mm')
-rw-r--r--third_party/libwebrtc/sdk/objc/api/peerconnection/RTCPeerConnection.mm939
1 files changed, 939 insertions, 0 deletions
diff --git a/third_party/libwebrtc/sdk/objc/api/peerconnection/RTCPeerConnection.mm b/third_party/libwebrtc/sdk/objc/api/peerconnection/RTCPeerConnection.mm
new file mode 100644
index 0000000000..f4db472380
--- /dev/null
+++ b/third_party/libwebrtc/sdk/objc/api/peerconnection/RTCPeerConnection.mm
@@ -0,0 +1,939 @@
+/*
+ * 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 "RTCIceCandidateErrorEvent+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 <memory>
+
+#include "api/jsep_ice_candidate.h"
+#include "api/rtc_event_log_output_file.h"
+#include "api/set_local_description_observer_interface.h"
+#include "api/set_remote_description_observer_interface.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "sdk/objc/native/api/ssl_certificate_verifier.h"
+
+NSString *const kRTCPeerConnectionErrorDomain = @"org.webrtc.RTC_OBJC_TYPE(RTCPeerConnection)";
+int const kRTCPeerConnnectionSessionDescriptionError = -1;
+
+namespace {
+
+class SetSessionDescriptionObserver : public webrtc::SetLocalDescriptionObserverInterface,
+ public webrtc::SetRemoteDescriptionObserverInterface {
+ public:
+ SetSessionDescriptionObserver(RTCSetSessionDescriptionCompletionHandler completionHandler) {
+ completion_handler_ = completionHandler;
+ }
+
+ virtual void OnSetLocalDescriptionComplete(webrtc::RTCError error) override {
+ OnCompelete(error);
+ }
+
+ virtual void OnSetRemoteDescriptionComplete(webrtc::RTCError error) override {
+ OnCompelete(error);
+ }
+
+ private:
+ void OnCompelete(webrtc::RTCError error) {
+ RTC_DCHECK(completion_handler_ != nil);
+ if (error.ok()) {
+ completion_handler_(nil);
+ } else {
+ // 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;
+ }
+ RTCSetSessionDescriptionCompletionHandler completion_handler_;
+};
+
+} // anonymous namespace
+
+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<webrtc::SessionDescriptionInterface> description =
+ std::unique_ptr<webrtc::SessionDescriptionInterface>(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);
+};
+
+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<MediaStreamInterface> 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<MediaStreamInterface> 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<RtpTransceiverInterface> 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<DataChannelInterface> 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::OnIceCandidateError(const std::string &address,
+ int port,
+ const std::string &url,
+ int error_code,
+ const std::string &error_text) {
+ RTC_OBJC_TYPE(RTCPeerConnection) *peer_connection = peer_connection_;
+ RTC_OBJC_TYPE(RTCIceCandidateErrorEvent) *event =
+ [[RTC_OBJC_TYPE(RTCIceCandidateErrorEvent) alloc] initWithAddress:address
+ port:port
+ url:url
+ errorCode:error_code
+ errorText:error_text];
+ if ([peer_connection.delegate respondsToSelector:@selector(peerConnection:
+ didFailToGatherIceCandidate:)]) {
+ [peer_connection.delegate peerConnection:peer_connection didFailToGatherIceCandidate:event];
+ }
+}
+
+void PeerConnectionDelegateAdapter::OnIceCandidatesRemoved(
+ const std::vector<cricket::Candidate>& candidates) {
+ NSMutableArray* ice_candidates =
+ [NSMutableArray arrayWithCapacity:candidates.size()];
+ for (const auto& candidate : candidates) {
+ std::unique_ptr<JsepIceCandidate> 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<JsepIceCandidate>(
+ 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<JsepIceCandidate>(
+ 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<RtpReceiverInterface> receiver,
+ const std::vector<rtc::scoped_refptr<MediaStreamInterface>> &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<RtpReceiverInterface> 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<RTC_OBJC_TYPE(RTCMediaStream) *> *_localStreams;
+ std::unique_ptr<webrtc::PeerConnectionDelegateAdapter> _observer;
+ rtc::scoped_refptr<webrtc::PeerConnectionInterface> _peerConnection;
+ std::unique_ptr<webrtc::MediaConstraints> _nativeConstraints;
+ BOOL _hasStartedRtcEventLog;
+}
+
+@synthesize delegate = _delegate;
+@synthesize factory = _factory;
+
+- (nullable instancetype)initWithFactory:(RTC_OBJC_TYPE(RTCPeerConnectionFactory) *)factory
+ configuration:(RTC_OBJC_TYPE(RTCConfiguration) *)configuration
+ constraints:(RTC_OBJC_TYPE(RTCMediaConstraints) *)constraints
+ certificateVerifier:
+ (nullable id<RTC_OBJC_TYPE(RTCSSLCertificateVerifier)>)certificateVerifier
+ delegate:(id<RTC_OBJC_TYPE(RTCPeerConnectionDelegate)>)delegate {
+ NSParameterAssert(factory);
+ std::unique_ptr<webrtc::PeerConnectionDependencies> dependencies =
+ std::make_unique<webrtc::PeerConnectionDependencies>(nullptr);
+ if (certificateVerifier != nil) {
+ dependencies->tls_cert_verifier = webrtc::ObjCToNativeCertificateVerifier(certificateVerifier);
+ }
+ return [self initWithDependencies:factory
+ configuration:configuration
+ constraints:constraints
+ dependencies:std::move(dependencies)
+ delegate:delegate];
+}
+
+- (nullable instancetype)
+ initWithDependencies:(RTC_OBJC_TYPE(RTCPeerConnectionFactory) *)factory
+ configuration:(RTC_OBJC_TYPE(RTCConfiguration) *)configuration
+ constraints:(RTC_OBJC_TYPE(RTCMediaConstraints) *)constraints
+ dependencies:(std::unique_ptr<webrtc::PeerConnectionDependencies>)dependencies
+ delegate:(id<RTC_OBJC_TYPE(RTCPeerConnectionDelegate)>)delegate {
+ NSParameterAssert(factory);
+ NSParameterAssert(dependencies.get());
+ std::unique_ptr<webrtc::PeerConnectionInterface::RTCConfiguration> 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();
+ auto result = factory.nativeFactory->CreatePeerConnectionOrError(*config, std::move(deps));
+
+ if (!result.ok()) {
+ return nil;
+ }
+ _peerConnection = result.MoveValue();
+ _factory = factory;
+ _localStreams = [[NSMutableArray alloc] init];
+ _delegate = delegate;
+ }
+ return self;
+}
+
+- (NSArray<RTC_OBJC_TYPE(RTCMediaStream) *> *)localStreams {
+ return [_localStreams copy];
+}
+
+- (RTC_OBJC_TYPE(RTCSessionDescription) *)localDescription {
+ // It's only safe to operate on SessionDescriptionInterface on the signaling thread.
+ return _peerConnection->signaling_thread()->Invoke<RTC_OBJC_TYPE(RTCSessionDescription) *>(
+ RTC_FROM_HERE, [self] {
+ const webrtc::SessionDescriptionInterface *description =
+ _peerConnection->local_description();
+ return description ?
+ [[RTC_OBJC_TYPE(RTCSessionDescription) alloc] initWithNativeDescription:description] :
+ nil;
+ });
+}
+
+- (RTC_OBJC_TYPE(RTCSessionDescription) *)remoteDescription {
+ // It's only safe to operate on SessionDescriptionInterface on the signaling thread.
+ return _peerConnection->signaling_thread()->Invoke<RTC_OBJC_TYPE(RTCSessionDescription) *>(
+ RTC_FROM_HERE, [self] {
+ 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<webrtc::PeerConnectionInterface::RTCConfiguration> 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<const webrtc::IceCandidateInterface> iceCandidate(
+ candidate.nativeCandidate);
+ _peerConnection->AddIceCandidate(iceCandidate.get());
+}
+- (void)addIceCandidate:(RTC_OBJC_TYPE(RTCIceCandidate) *)candidate
+ completionHandler:(void (^)(NSError *_Nullable error))completionHandler {
+ RTC_DCHECK(completionHandler != nil);
+ _peerConnection->AddIceCandidate(
+ candidate.nativeCandidate, [completionHandler](const auto &error) {
+ if (error.ok()) {
+ completionHandler(nil);
+ } else {
+ NSString *str = [NSString stringForStdString:error.message()];
+ NSError *err = [NSError errorWithDomain:kRTCPeerConnectionErrorDomain
+ code:static_cast<NSInteger>(error.type())
+ userInfo:@{NSLocalizedDescriptionKey : str}];
+ completionHandler(err);
+ }
+ });
+}
+- (void)removeIceCandidates:(NSArray<RTC_OBJC_TYPE(RTCIceCandidate) *> *)iceCandidates {
+ std::vector<cricket::Candidate> candidates;
+ for (RTC_OBJC_TYPE(RTCIceCandidate) * iceCandidate in iceCandidates) {
+ std::unique_ptr<const webrtc::IceCandidateInterface> 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.get())) {
+ RTCLogError(@"Failed to add stream: %@", stream);
+ return;
+ }
+ [_localStreams addObject:stream];
+}
+
+- (void)removeStream:(RTC_OBJC_TYPE(RTCMediaStream) *)stream {
+ _peerConnection->RemoveStream(stream.nativeMediaStream.get());
+ [_localStreams removeObject:stream];
+}
+
+- (nullable RTC_OBJC_TYPE(RTCRtpSender) *)addTrack:(RTC_OBJC_TYPE(RTCMediaStreamTrack) *)track
+ streamIds:(NSArray<NSString *> *)streamIds {
+ std::vector<std::string> nativeStreamIds;
+ for (NSString *streamId in streamIds) {
+ nativeStreamIds.push_back([streamId UTF8String]);
+ }
+ webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpSenderInterface>> 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->RemoveTrackOrError(sender.nativeRtpSender).ok();
+ if (!result) {
+ RTCLogError(@"Failed to remote track %@", sender);
+ }
+ return result;
+}
+
+- (nullable RTC_OBJC_TYPE(RTCRtpTransceiver) *)addTransceiverWithTrack:
+ (RTC_OBJC_TYPE(RTCMediaStreamTrack) *)track {
+ return [self addTransceiverWithTrack:track
+ init:[[RTC_OBJC_TYPE(RTCRtpTransceiverInit) alloc] init]];
+}
+
+- (nullable RTC_OBJC_TYPE(RTCRtpTransceiver) *)
+ addTransceiverWithTrack:(RTC_OBJC_TYPE(RTCMediaStreamTrack) *)track
+ init:(RTC_OBJC_TYPE(RTCRtpTransceiverInit) *)init {
+ webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>> 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()];
+}
+
+- (nullable RTC_OBJC_TYPE(RTCRtpTransceiver) *)addTransceiverOfType:(RTCRtpMediaType)mediaType {
+ return [self addTransceiverOfType:mediaType
+ init:[[RTC_OBJC_TYPE(RTCRtpTransceiverInit) alloc] init]];
+}
+
+- (nullable RTC_OBJC_TYPE(RTCRtpTransceiver) *)
+ addTransceiverOfType:(RTCRtpMediaType)mediaType
+ init:(RTC_OBJC_TYPE(RTCRtpTransceiverInit) *)init {
+ webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>> 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)restartIce {
+ _peerConnection->RestartIce();
+}
+
+- (void)offerForConstraints:(RTC_OBJC_TYPE(RTCMediaConstraints) *)constraints
+ completionHandler:(RTCCreateSessionDescriptionCompletionHandler)completionHandler {
+ RTC_DCHECK(completionHandler != nil);
+ rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserverAdapter> observer =
+ rtc::make_ref_counted<webrtc::CreateSessionDescriptionObserverAdapter>(completionHandler);
+ webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options;
+ CopyConstraintsIntoOfferAnswerOptions(constraints.nativeConstraints.get(), &options);
+
+ _peerConnection->CreateOffer(observer.get(), options);
+}
+
+- (void)answerForConstraints:(RTC_OBJC_TYPE(RTCMediaConstraints) *)constraints
+ completionHandler:(RTCCreateSessionDescriptionCompletionHandler)completionHandler {
+ RTC_DCHECK(completionHandler != nil);
+ rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserverAdapter> observer =
+ rtc::make_ref_counted<webrtc::CreateSessionDescriptionObserverAdapter>(completionHandler);
+ webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options;
+ CopyConstraintsIntoOfferAnswerOptions(constraints.nativeConstraints.get(), &options);
+
+ _peerConnection->CreateAnswer(observer.get(), options);
+}
+
+- (void)setLocalDescription:(RTC_OBJC_TYPE(RTCSessionDescription) *)sdp
+ completionHandler:(RTCSetSessionDescriptionCompletionHandler)completionHandler {
+ RTC_DCHECK(completionHandler != nil);
+ rtc::scoped_refptr<webrtc::SetLocalDescriptionObserverInterface> observer =
+ rtc::make_ref_counted<::SetSessionDescriptionObserver>(completionHandler);
+ _peerConnection->SetLocalDescription(sdp.nativeDescription, observer);
+}
+
+- (void)setLocalDescriptionWithCompletionHandler:
+ (RTCSetSessionDescriptionCompletionHandler)completionHandler {
+ RTC_DCHECK(completionHandler != nil);
+ rtc::scoped_refptr<webrtc::SetLocalDescriptionObserverInterface> observer =
+ rtc::make_ref_counted<::SetSessionDescriptionObserver>(completionHandler);
+ _peerConnection->SetLocalDescription(observer);
+}
+
+- (void)setRemoteDescription:(RTC_OBJC_TYPE(RTCSessionDescription) *)sdp
+ completionHandler:(RTCSetSessionDescriptionCompletionHandler)completionHandler {
+ RTC_DCHECK(completionHandler != nil);
+ rtc::scoped_refptr<webrtc::SetRemoteDescriptionObserverInterface> observer =
+ rtc::make_ref_counted<::SetSessionDescriptionObserver>(completionHandler);
+ _peerConnection->SetRemoteDescription(sdp.nativeDescription, observer);
+}
+
+- (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<int>(minBitrateBps.intValue);
+ }
+ if (currentBitrateBps != nil) {
+ params.start_bitrate_bps = absl::optional<int>(currentBitrateBps.intValue);
+ }
+ if (maxBitrateBps != nil) {
+ params.max_bitrate_bps = absl::optional<int>(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<size_t>(maxSizeInBytes);
+
+ _hasStartedRtcEventLog = _peerConnection->StartRtcEventLog(
+ std::make_unique<webrtc::RtcEventLogOutputFile>(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<webrtc::RtpSenderInterface> nativeSender(
+ _peerConnection->CreateSender(nativeKind, nativeStreamId));
+ return nativeSender ? [[RTC_OBJC_TYPE(RTCRtpSender) alloc] initWithFactory:self.factory
+ nativeRtpSender:nativeSender] :
+ nil;
+}
+
+- (NSArray<RTC_OBJC_TYPE(RTCRtpSender) *> *)senders {
+ std::vector<rtc::scoped_refptr<webrtc::RtpSenderInterface>> 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<RTC_OBJC_TYPE(RTCRtpReceiver) *> *)receivers {
+ std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>> 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<RTC_OBJC_TYPE(RTCRtpTransceiver) *> *)transceivers {
+ std::vector<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>> 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<webrtc::PeerConnectionInterface>)nativePeerConnection {
+ return _peerConnection;
+}
+
+@end