You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
874 lines
36 KiB
874 lines
36 KiB
/*
|
|
* 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 <memory>
|
|
|
|
#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<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);
|
|
};
|
|
|
|
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<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::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;
|
|
|
|
- (instancetype)initWithFactory:(RTC_OBJC_TYPE(RTCPeerConnectionFactory) *)factory
|
|
configuration:(RTC_OBJC_TYPE(RTCConfiguration) *)configuration
|
|
constraints:(RTC_OBJC_TYPE(RTCMediaConstraints) *)constraints
|
|
delegate:(id<RTC_OBJC_TYPE(RTCPeerConnectionDelegate)>)delegate {
|
|
NSParameterAssert(factory);
|
|
std::unique_ptr<webrtc::PeerConnectionDependencies> dependencies =
|
|
std::make_unique<webrtc::PeerConnectionDependencies>(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<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();
|
|
_peerConnection = factory.nativeFactory->CreatePeerConnection(*config, std::move(deps));
|
|
|
|
if (!_peerConnection) {
|
|
return nil;
|
|
}
|
|
_factory = factory;
|
|
_localStreams = [[NSMutableArray alloc] init];
|
|
_delegate = delegate;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (NSArray<RTC_OBJC_TYPE(RTCMediaStream) *> *)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<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)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)) {
|
|
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<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->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<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()];
|
|
}
|
|
|
|
- (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<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)offerForConstraints:(RTC_OBJC_TYPE(RTCMediaConstraints) *)constraints
|
|
completionHandler:(void (^)(RTC_OBJC_TYPE(RTCSessionDescription) * sessionDescription,
|
|
NSError *error))completionHandler {
|
|
rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserverAdapter>
|
|
observer(new rtc::RefCountedObject
|
|
<webrtc::CreateSessionDescriptionObserverAdapter>(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<webrtc::CreateSessionDescriptionObserverAdapter>
|
|
observer(new rtc::RefCountedObject
|
|
<webrtc::CreateSessionDescriptionObserverAdapter>(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<webrtc::SetSessionDescriptionObserverAdapter> observer(
|
|
new rtc::RefCountedObject<webrtc::SetSessionDescriptionObserverAdapter>(
|
|
completionHandler));
|
|
_peerConnection->SetLocalDescription(observer, sdp.nativeDescription);
|
|
}
|
|
|
|
- (void)setRemoteDescription:(RTC_OBJC_TYPE(RTCSessionDescription) *)sdp
|
|
completionHandler:(void (^)(NSError *error))completionHandler {
|
|
rtc::scoped_refptr<webrtc::SetSessionDescriptionObserverAdapter> observer(
|
|
new rtc::RefCountedObject<webrtc::SetSessionDescriptionObserverAdapter>(
|
|
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<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
|