From 8cb344acfdb19263460d64c9db81c2bada33b1ce Mon Sep 17 00:00:00 2001 From: Steve Anton Date: Tue, 27 Feb 2018 15:34:53 -0800 Subject: [PATCH] Add new PeerConnection APIs to the ObjC SDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL adds wrappers for the following PeerConnection native APIs to the Objective C API: - SdpSemantics enum added to the RTCConfiguration - RTCRtpTransceiver - RTCPeerConnection.addTrack - RTCPeerConnection.removeTrack - RTCPeerConnection.addTransceiver - RTCPeerConnection.transceivers Bug: webrtc:8870 Change-Id: I9449df9742a59e90894712dc7749ca30b569d94b Reviewed-on: https://webrtc-review.googlesource.com/54780 Commit-Queue: Steve Anton Reviewed-by: Kári Helgason Cr-Commit-Position: refs/heads/master@{#22214} --- sdk/BUILD.gn | 4 + .../PeerConnection/RTCConfiguration+Private.h | 6 + .../PeerConnection/RTCConfiguration.mm | 82 ++++++--- .../RTCPeerConnection+Private.h | 2 + .../PeerConnection/RTCPeerConnection.mm | 85 +++++++++ .../PeerConnection/RTCRtpReceiver+Private.h | 4 + .../Classes/PeerConnection/RTCRtpReceiver.mm | 22 +++ .../RTCRtpTransceiver+Private.h | 41 +++++ .../PeerConnection/RTCRtpTransceiver.mm | 163 ++++++++++++++++++ .../Headers/WebRTC/RTCConfiguration.h | 34 ++++ .../Headers/WebRTC/RTCPeerConnection.h | 91 +++++++++- .../Headers/WebRTC/RTCRtpTransceiver.h | 128 ++++++++++++++ 12 files changed, 637 insertions(+), 25 deletions(-) create mode 100644 sdk/objc/Framework/Classes/PeerConnection/RTCRtpTransceiver+Private.h create mode 100644 sdk/objc/Framework/Classes/PeerConnection/RTCRtpTransceiver.mm create mode 100644 sdk/objc/Framework/Headers/WebRTC/RTCRtpTransceiver.h diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn index 1ae826e38f..d55119c8de 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -529,6 +529,8 @@ if (is_ios || is_mac) { "objc/Framework/Classes/PeerConnection/RTCRtpReceiver.mm", "objc/Framework/Classes/PeerConnection/RTCRtpSender+Private.h", "objc/Framework/Classes/PeerConnection/RTCRtpSender.mm", + "objc/Framework/Classes/PeerConnection/RTCRtpTransceiver+Private.h", + "objc/Framework/Classes/PeerConnection/RTCRtpTransceiver.mm", "objc/Framework/Classes/PeerConnection/RTCSSLAdapter.mm", "objc/Framework/Classes/PeerConnection/RTCSessionDescription+Private.h", "objc/Framework/Classes/PeerConnection/RTCSessionDescription.mm", @@ -563,6 +565,7 @@ if (is_ios || is_mac) { "objc/Framework/Headers/WebRTC/RTCRtpParameters.h", "objc/Framework/Headers/WebRTC/RTCRtpReceiver.h", "objc/Framework/Headers/WebRTC/RTCRtpSender.h", + "objc/Framework/Headers/WebRTC/RTCRtpTransceiver.h", "objc/Framework/Headers/WebRTC/RTCSSLAdapter.h", "objc/Framework/Headers/WebRTC/RTCSessionDescription.h", "objc/Framework/Headers/WebRTC/RTCTracing.h", @@ -775,6 +778,7 @@ if (is_ios || is_mac) { "objc/Framework/Headers/WebRTC/RTCRtpParameters.h", "objc/Framework/Headers/WebRTC/RTCRtpReceiver.h", "objc/Framework/Headers/WebRTC/RTCRtpSender.h", + "objc/Framework/Headers/WebRTC/RTCRtpTransceiver.h", "objc/Framework/Headers/WebRTC/RTCDtmfSender.h", "objc/Framework/Headers/WebRTC/RTCSSLAdapter.h", "objc/Framework/Headers/WebRTC/RTCSessionDescription.h", diff --git a/sdk/objc/Framework/Classes/PeerConnection/RTCConfiguration+Private.h b/sdk/objc/Framework/Classes/PeerConnection/RTCConfiguration+Private.h index d9a991650b..c572d6348f 100644 --- a/sdk/objc/Framework/Classes/PeerConnection/RTCConfiguration+Private.h +++ b/sdk/objc/Framework/Classes/PeerConnection/RTCConfiguration+Private.h @@ -58,6 +58,12 @@ NS_ASSUME_NONNULL_BEGIN + (rtc::KeyType)nativeEncryptionKeyTypeForKeyType:(RTCEncryptionKeyType)keyType; ++ (webrtc::SdpSemantics)nativeSdpSemanticsForSdpSemantics:(RTCSdpSemantics)sdpSemantics; + ++ (RTCSdpSemantics)sdpSemanticsForNativeSdpSemantics:(webrtc::SdpSemantics)sdpSemantics; + ++ (NSString *)stringForSdpSemantics:(RTCSdpSemantics)sdpSemantics; + /** * RTCConfiguration struct representation of this RTCConfiguration. This is * needed to pass to the underlying C++ APIs. diff --git a/sdk/objc/Framework/Classes/PeerConnection/RTCConfiguration.mm b/sdk/objc/Framework/Classes/PeerConnection/RTCConfiguration.mm index 92b334bad7..ceaac86ace 100644 --- a/sdk/objc/Framework/Classes/PeerConnection/RTCConfiguration.mm +++ b/sdk/objc/Framework/Classes/PeerConnection/RTCConfiguration.mm @@ -43,6 +43,7 @@ _shouldPresumeWritableWhenFullyRelayed; @synthesize iceCheckMinInterval = _iceCheckMinInterval; @synthesize iceRegatherIntervalRange = _iceRegatherIntervalRange; +@synthesize sdpSemantics = _sdpSemantics; @synthesize turnCustomizer = _turnCustomizer; - (instancetype)init { @@ -96,35 +97,38 @@ _iceRegatherIntervalRange = [[RTCIntervalRange alloc] initWithNativeIntervalRange:nativeIntervalRange]; } + _sdpSemantics = [[self class] sdpSemanticsForNativeSdpSemantics:config.sdp_semantics]; _turnCustomizer = config.turn_customizer; } return self; } - (NSString *)description { - static NSString *formatString = @"RTCConfiguration: " - @"{\n%@\n%@\n%@\n%@\n%@\n%@\n%@\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n%@\n%@\n%d\n%d\n}\n"; + static NSString *formatString = + @"RTCConfiguration: " + @"{\n%@\n%@\n%@\n%@\n%@\n%@\n%@\n%@\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n%@\n%@\n%d\n%d\n}\n"; - return - [NSString stringWithFormat:formatString, - _iceServers, - [[self class] stringForTransportPolicy:_iceTransportPolicy], - [[self class] stringForBundlePolicy:_bundlePolicy], - [[self class] stringForRtcpMuxPolicy:_rtcpMuxPolicy], - [[self class] stringForTcpCandidatePolicy:_tcpCandidatePolicy], - [[self class] stringForCandidateNetworkPolicy:_candidateNetworkPolicy], - [[self class] stringForContinualGatheringPolicy:_continualGatheringPolicy], - _audioJitterBufferMaxPackets, - _audioJitterBufferFastAccelerate, - _iceConnectionReceivingTimeout, - _iceBackupCandidatePairPingInterval, - _iceCandidatePoolSize, - _shouldPruneTurnPorts, - _shouldPresumeWritableWhenFullyRelayed, - _iceCheckMinInterval, - _iceRegatherIntervalRange, - _disableLinkLocalNetworks, - _maxIPv6Networks]; + return [NSString + stringWithFormat:formatString, + _iceServers, + [[self class] stringForTransportPolicy:_iceTransportPolicy], + [[self class] stringForBundlePolicy:_bundlePolicy], + [[self class] stringForRtcpMuxPolicy:_rtcpMuxPolicy], + [[self class] stringForTcpCandidatePolicy:_tcpCandidatePolicy], + [[self class] stringForCandidateNetworkPolicy:_candidateNetworkPolicy], + [[self class] stringForContinualGatheringPolicy:_continualGatheringPolicy], + [[self class] stringForSdpSemantics:_sdpSemantics], + _audioJitterBufferMaxPackets, + _audioJitterBufferFastAccelerate, + _iceConnectionReceivingTimeout, + _iceBackupCandidatePairPingInterval, + _iceCandidatePoolSize, + _shouldPruneTurnPorts, + _shouldPresumeWritableWhenFullyRelayed, + _iceCheckMinInterval, + _iceRegatherIntervalRange, + _disableLinkLocalNetworks, + _maxIPv6Networks]; } #pragma mark - Private @@ -186,6 +190,7 @@ nativeConfig->ice_regather_interval_range = rtc::Optional(*nativeIntervalRange); } + nativeConfig->sdp_semantics = [[self class] nativeSdpSemanticsForSdpSemantics:_sdpSemantics]; if (_turnCustomizer) { nativeConfig->turn_customizer = _turnCustomizer; } @@ -397,4 +402,37 @@ } } ++ (webrtc::SdpSemantics)nativeSdpSemanticsForSdpSemantics:(RTCSdpSemantics)sdpSemantics { + switch (sdpSemantics) { + case RTCSdpSemanticsDefault: + return webrtc::SdpSemantics::kDefault; + case RTCSdpSemanticsPlanB: + return webrtc::SdpSemantics::kPlanB; + case RTCSdpSemanticsUnifiedPlan: + return webrtc::SdpSemantics::kUnifiedPlan; + } +} + ++ (RTCSdpSemantics)sdpSemanticsForNativeSdpSemantics:(webrtc::SdpSemantics)sdpSemantics { + switch (sdpSemantics) { + case webrtc::SdpSemantics::kDefault: + return RTCSdpSemanticsDefault; + case webrtc::SdpSemantics::kPlanB: + return RTCSdpSemanticsPlanB; + case webrtc::SdpSemantics::kUnifiedPlan: + return RTCSdpSemanticsUnifiedPlan; + } +} + ++ (NSString *)stringForSdpSemantics:(RTCSdpSemantics)sdpSemantics { + switch (sdpSemantics) { + case RTCSdpSemanticsDefault: + return @"DEFAULT"; + case RTCSdpSemanticsPlanB: + return @"PLAN_B"; + case RTCSdpSemanticsUnifiedPlan: + return @"UNIFIED_PLAN"; + } +} + @end diff --git a/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection+Private.h b/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection+Private.h index e1017f5e8f..4b46dea435 100644 --- a/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection+Private.h +++ b/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection+Private.h @@ -33,6 +33,8 @@ class PeerConnectionDelegateAdapter : public PeerConnectionObserver { void OnRemoveStream(rtc::scoped_refptr stream) override; + void OnTrack(rtc::scoped_refptr transceiver) override; + void OnDataChannel( rtc::scoped_refptr data_channel) override; diff --git a/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection.mm b/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection.mm index 6376ea0429..08b90479e4 100644 --- a/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection.mm +++ b/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection.mm @@ -17,10 +17,12 @@ #import "RTCLegacyStatsReport+Private.h" #import "RTCMediaConstraints+Private.h" #import "RTCMediaStream+Private.h" +#import "RTCMediaStreamTrack+Private.h" #import "RTCPeerConnection+Native.h" #import "RTCPeerConnectionFactory+Private.h" #import "RTCRtpReceiver+Private.h" #import "RTCRtpSender+Private.h" +#import "RTCRtpTransceiver+Private.h" #import "RTCSessionDescription+Private.h" #import "WebRTC/RTCLogging.h" @@ -144,6 +146,18 @@ void PeerConnectionDelegateAdapter::OnRemoveStream( didRemoveStream:mediaStream]; } +void PeerConnectionDelegateAdapter::OnTrack( + rtc::scoped_refptr nativeTransceiver) { + RTCRtpTransceiver *transceiver = + [[RTCRtpTransceiver alloc] initWithNativeRtpTransceiver:nativeTransceiver]; + RTCPeerConnection *peer_connection = peer_connection_; + if ([peer_connection.delegate + respondsToSelector:@selector(peerConnection:didStartReceivingOnTransceiver:)]) { + [peer_connection.delegate peerConnection:peer_connection + didStartReceivingOnTransceiver:transceiver]; + } +} + void PeerConnectionDelegateAdapter::OnDataChannel( rtc::scoped_refptr data_channel) { RTCDataChannel *dataChannel = @@ -334,6 +348,65 @@ void PeerConnectionDelegateAdapter::OnIceCandidatesRemoved( [_localStreams removeObject:stream]; } +- (RTCRtpSender *)addTrack:(RTCMediaStreamTrack *)track + streamLabels:(NSArray *)streamLabels { + std::vector nativeStreamLabels; + for (NSString *label in streamLabels) { + nativeStreamLabels.push_back([label UTF8String]); + } + webrtc::RTCErrorOr> nativeSenderOrError = + _peerConnection->AddTrack(track.nativeTrack, nativeStreamLabels); + if (!nativeSenderOrError.ok()) { + RTCLogError(@"Failed to add track %@: %s", track, nativeSenderOrError.error().message()); + return nil; + } + return [[RTCRtpSender alloc] initWithNativeRtpSender:nativeSenderOrError.MoveValue()]; +} + +- (BOOL)removeTrack:(RTCRtpSender *)sender { + bool result = _peerConnection->RemoveTrack(sender.nativeRtpSender); + if (!result) { + RTCLogError(@"Failed to remote track %@", sender); + } + return result; +} + +- (RTCRtpTransceiver *)addTransceiverWithTrack:(RTCMediaStreamTrack *)track { + return [self addTransceiverWithTrack:track init:[[RTCRtpTransceiverInit alloc] init]]; +} + +- (RTCRtpTransceiver *)addTransceiverWithTrack:(RTCMediaStreamTrack *)track + init:(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 + [[RTCRtpTransceiver alloc] initWithNativeRtpTransceiver:nativeTransceiverOrError.MoveValue()]; +} + +- (RTCRtpTransceiver *)addTransceiverOfType:(RTCRtpMediaType)mediaType { + return [self addTransceiverOfType:mediaType init:[[RTCRtpTransceiverInit alloc] init]]; +} + +- (RTCRtpTransceiver *)addTransceiverOfType:(RTCRtpMediaType)mediaType + init:(RTCRtpTransceiverInit *)init { + webrtc::RTCErrorOr> nativeTransceiverOrError = + _peerConnection->AddTransceiver([RTCRtpReceiver nativeMediaTypeForMediaType:mediaType], + init.nativeInit); + if (!nativeTransceiverOrError.ok()) { + RTCLogError(@"Failed to add transceiver %@: %s", + [RTCRtpReceiver stringForMediaType:mediaType], + nativeTransceiverOrError.error().message()); + return nil; + } + return + [[RTCRtpTransceiver alloc] initWithNativeRtpTransceiver:nativeTransceiverOrError.MoveValue()]; +} + - (void)offerForConstraints:(RTCMediaConstraints *)constraints completionHandler: (void (^)(RTCSessionDescription *sessionDescription, @@ -451,6 +524,18 @@ void PeerConnectionDelegateAdapter::OnIceCandidatesRemoved( return receivers; } +- (NSArray *)transceivers { + std::vector> nativeTransceivers( + _peerConnection->GetTransceivers()); + NSMutableArray *transceivers = [[NSMutableArray alloc] init]; + for (auto nativeTransceiver : nativeTransceivers) { + RTCRtpTransceiver *transceiver = + [[RTCRtpTransceiver alloc] initWithNativeRtpTransceiver:nativeTransceiver]; + [transceivers addObject:transceiver]; + } + return transceivers; +} + #pragma mark - Private + (webrtc::PeerConnectionInterface::SignalingState)nativeSignalingStateForState: diff --git a/sdk/objc/Framework/Classes/PeerConnection/RTCRtpReceiver+Private.h b/sdk/objc/Framework/Classes/PeerConnection/RTCRtpReceiver+Private.h index 98738114f3..63bdfa3ab6 100644 --- a/sdk/objc/Framework/Classes/PeerConnection/RTCRtpReceiver+Private.h +++ b/sdk/objc/Framework/Classes/PeerConnection/RTCRtpReceiver+Private.h @@ -40,6 +40,10 @@ class RtpReceiverDelegateAdapter : public RtpReceiverObserverInterface { + (RTCRtpMediaType)mediaTypeForNativeMediaType:(cricket::MediaType)nativeMediaType; ++ (cricket::MediaType)nativeMediaTypeForMediaType:(RTCRtpMediaType)mediaType; + ++ (NSString*)stringForMediaType:(RTCRtpMediaType)mediaType; + @end NS_ASSUME_NONNULL_END diff --git a/sdk/objc/Framework/Classes/PeerConnection/RTCRtpReceiver.mm b/sdk/objc/Framework/Classes/PeerConnection/RTCRtpReceiver.mm index 12f3ab6f32..b1f5be9c8a 100644 --- a/sdk/objc/Framework/Classes/PeerConnection/RTCRtpReceiver.mm +++ b/sdk/objc/Framework/Classes/PeerConnection/RTCRtpReceiver.mm @@ -126,4 +126,26 @@ void RtpReceiverDelegateAdapter::OnFirstPacketReceived( } } ++ (cricket::MediaType)nativeMediaTypeForMediaType:(RTCRtpMediaType)mediaType { + switch (mediaType) { + case RTCRtpMediaTypeAudio: + return cricket::MEDIA_TYPE_AUDIO; + case RTCRtpMediaTypeVideo: + return cricket::MEDIA_TYPE_VIDEO; + case RTCRtpMediaTypeData: + return cricket::MEDIA_TYPE_DATA; + } +} + ++ (NSString *)stringForMediaType:(RTCRtpMediaType)mediaType { + switch (mediaType) { + case RTCRtpMediaTypeAudio: + return @"AUDIO"; + case RTCRtpMediaTypeVideo: + return @"VIDEO"; + case RTCRtpMediaTypeData: + return @"DATA"; + } +} + @end diff --git a/sdk/objc/Framework/Classes/PeerConnection/RTCRtpTransceiver+Private.h b/sdk/objc/Framework/Classes/PeerConnection/RTCRtpTransceiver+Private.h new file mode 100644 index 0000000000..cc1f4fe42e --- /dev/null +++ b/sdk/objc/Framework/Classes/PeerConnection/RTCRtpTransceiver+Private.h @@ -0,0 +1,41 @@ +/* + * Copyright 2018 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 "WebRTC/RTCRtpTransceiver.h" + +#include "api/rtptransceiverinterface.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface RTCRtpTransceiverInit () + +@property(nonatomic, readonly) webrtc::RtpTransceiverInit nativeInit; + +@end + +@interface RTCRtpTransceiver () + +@property(nonatomic, readonly) rtc::scoped_refptr + nativeRtpTransceiver; + +/** Initialize an RTCRtpTransceiver with a native RtpTransceiverInterface. */ +- (instancetype)initWithNativeRtpTransceiver: + (rtc::scoped_refptr)nativeRtpTransceiver + NS_DESIGNATED_INITIALIZER; + ++ (webrtc::RtpTransceiverDirection)nativeRtpTransceiverDirectionFromDirection: + (RTCRtpTransceiverDirection)direction; + ++ (RTCRtpTransceiverDirection)rtpTransceiverDirectionFromNativeDirection: + (webrtc::RtpTransceiverDirection)nativeDirection; + +@end + +NS_ASSUME_NONNULL_END diff --git a/sdk/objc/Framework/Classes/PeerConnection/RTCRtpTransceiver.mm b/sdk/objc/Framework/Classes/PeerConnection/RTCRtpTransceiver.mm new file mode 100644 index 0000000000..ce182bc899 --- /dev/null +++ b/sdk/objc/Framework/Classes/PeerConnection/RTCRtpTransceiver.mm @@ -0,0 +1,163 @@ +/* + * Copyright 2018 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 "RTCRtpTransceiver+Private.h" + +#import "NSString+StdString.h" +#import "RTCRtpEncodingParameters+Private.h" +#import "RTCRtpParameters+Private.h" +#import "RTCRtpReceiver+Private.h" +#import "RTCRtpSender+Private.h" +#import "WebRTC/RTCLogging.h" + +@implementation RTCRtpTransceiverInit + +@synthesize direction = _direction; +@synthesize streamLabels = _streamLabels; +@synthesize sendEncodings = _sendEncodings; + +- (instancetype)init { + if (self = [super init]) { + _direction = RTCRtpTransceiverDirectionSendRecv; + } + return self; +} + +- (webrtc::RtpTransceiverInit)nativeInit { + webrtc::RtpTransceiverInit init; + init.direction = [RTCRtpTransceiver nativeRtpTransceiverDirectionFromDirection:_direction]; + for (NSString *streamLabel in _streamLabels) { + init.stream_labels.push_back([streamLabel UTF8String]); + } + for (RTCRtpEncodingParameters *sendEncoding in _sendEncodings) { + init.send_encodings.push_back(sendEncoding.nativeParameters); + } + return init; +} + +@end + +@implementation RTCRtpTransceiver { + rtc::scoped_refptr _nativeRtpTransceiver; +} + +- (RTCRtpMediaType)mediaType { + return [RTCRtpReceiver mediaTypeForNativeMediaType:_nativeRtpTransceiver->media_type()]; +} + +- (NSString *)mid { + if (_nativeRtpTransceiver->mid()) { + return [NSString stringForStdString:*_nativeRtpTransceiver->mid()]; + } else { + return nil; + } +} + +@synthesize sender = _sender; +@synthesize receiver = _receiver; + +- (BOOL)isStopped { + return _nativeRtpTransceiver->stopped(); +} + +- (RTCRtpTransceiverDirection)direction { + return [RTCRtpTransceiver + rtpTransceiverDirectionFromNativeDirection:_nativeRtpTransceiver->direction()]; +} + +- (void)setDirection:(RTCRtpTransceiverDirection)direction { + _nativeRtpTransceiver->SetDirection( + [RTCRtpTransceiver nativeRtpTransceiverDirectionFromDirection:direction]); +} + +- (BOOL)currentDirection:(RTCRtpTransceiverDirection *)currentDirectionOut { + if (_nativeRtpTransceiver->current_direction()) { + *currentDirectionOut = [RTCRtpTransceiver + rtpTransceiverDirectionFromNativeDirection:*_nativeRtpTransceiver->current_direction()]; + return YES; + } else { + return NO; + } +} + +- (void)stop { + _nativeRtpTransceiver->Stop(); +} + +- (NSString *)description { + return [NSString + stringWithFormat:@"RTCRtpTransceiver {\n sender: %@\n receiver: %@\n}", _sender, _receiver]; +} + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (object == nil) { + return NO; + } + if (![object isMemberOfClass:[self class]]) { + return NO; + } + RTCRtpTransceiver *transceiver = (RTCRtpTransceiver *)object; + return _nativeRtpTransceiver == transceiver.nativeRtpTransceiver; +} + +- (NSUInteger)hash { + return (NSUInteger)_nativeRtpTransceiver.get(); +} + +#pragma mark - Private + +- (rtc::scoped_refptr)nativeRtpTransceiver { + return _nativeRtpTransceiver; +} + +- (instancetype)initWithNativeRtpTransceiver: + (rtc::scoped_refptr)nativeRtpTransceiver { + NSParameterAssert(nativeRtpTransceiver); + if (self = [super init]) { + _nativeRtpTransceiver = nativeRtpTransceiver; + _sender = [[RTCRtpSender alloc] initWithNativeRtpSender:nativeRtpTransceiver->sender()]; + _receiver = [[RTCRtpReceiver alloc] initWithNativeRtpReceiver:nativeRtpTransceiver->receiver()]; + RTCLogInfo(@"RTCRtpTransceiver(%p): created transceiver: %@", self, self.description); + } + return self; +} + ++ (webrtc::RtpTransceiverDirection)nativeRtpTransceiverDirectionFromDirection: + (RTCRtpTransceiverDirection)direction { + switch (direction) { + case RTCRtpTransceiverDirectionSendRecv: + return webrtc::RtpTransceiverDirection::kSendRecv; + case RTCRtpTransceiverDirectionSendOnly: + return webrtc::RtpTransceiverDirection::kSendOnly; + case RTCRtpTransceiverDirectionRecvOnly: + return webrtc::RtpTransceiverDirection::kRecvOnly; + case RTCRtpTransceiverDirectionInactive: + return webrtc::RtpTransceiverDirection::kInactive; + } +} + ++ (RTCRtpTransceiverDirection)rtpTransceiverDirectionFromNativeDirection: + (webrtc::RtpTransceiverDirection)nativeDirection { + switch (nativeDirection) { + case webrtc::RtpTransceiverDirection::kSendRecv: + return RTCRtpTransceiverDirectionSendRecv; + case webrtc::RtpTransceiverDirection::kSendOnly: + return RTCRtpTransceiverDirectionSendOnly; + case webrtc::RtpTransceiverDirection::kRecvOnly: + return RTCRtpTransceiverDirectionRecvOnly; + case webrtc::RtpTransceiverDirection::kInactive: + return RTCRtpTransceiverDirectionInactive; + } +} + +@end diff --git a/sdk/objc/Framework/Headers/WebRTC/RTCConfiguration.h b/sdk/objc/Framework/Headers/WebRTC/RTCConfiguration.h index f3a8d3fc99..97cc5a4946 100644 --- a/sdk/objc/Framework/Headers/WebRTC/RTCConfiguration.h +++ b/sdk/objc/Framework/Headers/WebRTC/RTCConfiguration.h @@ -63,6 +63,13 @@ typedef NS_ENUM(NSInteger, RTCEncryptionKeyType) { RTCEncryptionKeyTypeECDSA, }; +/** Represents the chosen SDP semantics for the RTCPeerConnection. */ +typedef NS_ENUM(NSInteger, RTCSdpSemantics) { + RTCSdpSemanticsDefault, + RTCSdpSemanticsPlanB, + RTCSdpSemanticsUnifiedPlan, +}; + NS_ASSUME_NONNULL_BEGIN RTC_EXPORT @@ -132,6 +139,33 @@ RTC_EXPORT */ @property(nonatomic, strong, nullable) RTCIntervalRange *iceRegatherIntervalRange; +/** Configure the SDP semantics used by this PeerConnection. Note that the + * WebRTC 1.0 specification requires UnifiedPlan semantics. The + * RTCRtpTransceiver API is only available with UnifiedPlan semantics. + * + * PlanB will cause RTCPeerConnection to create offers and answers with at + * most one audio and one video m= section with multiple RTCRtpSenders and + * RTCRtpReceivers specified as multiple a=ssrc lines within the section. This + * will also cause RTCPeerConnection to ignore all but the first m= section of + * the same media type. + * + * UnifiedPlan will cause RTCPeerConnection to create offers and answers with + * multiple m= sections where each m= section maps to one RTCRtpSender and one + * RTCRtpReceiver (an RTCRtpTransceiver), either both audio or both video. This + * will also cause RTCPeerConnection to ignore all but the first a=ssrc lines + * that form a Plan B stream. + * + * For users who only send at most one audio and one video track, this + * choice does not matter and should be left as Default. + * + * For users who wish to send multiple audio/video streams and need to stay + * interoperable with legacy WebRTC implementations, specify PlanB. + * + * For users who wish to send multiple audio/video streams and/or wish to + * use the new RTCRtpTransceiver API, specify UnifiedPlan. + */ +@property(nonatomic, assign) RTCSdpSemantics sdpSemantics; + - (instancetype)init; @end diff --git a/sdk/objc/Framework/Headers/WebRTC/RTCPeerConnection.h b/sdk/objc/Framework/Headers/WebRTC/RTCPeerConnection.h index a4c113b1d6..8b69804a16 100644 --- a/sdk/objc/Framework/Headers/WebRTC/RTCPeerConnection.h +++ b/sdk/objc/Framework/Headers/WebRTC/RTCPeerConnection.h @@ -22,9 +22,13 @@ @class RTCPeerConnectionFactory; @class RTCRtpReceiver; @class RTCRtpSender; +@class RTCRtpTransceiver; +@class RTCRtpTransceiverInit; @class RTCSessionDescription; @class RTCLegacyStatsReport; +typedef NS_ENUM(NSInteger, RTCRtpMediaType); + NS_ASSUME_NONNULL_BEGIN extern NSString * const kRTCPeerConnectionErrorDomain; @@ -79,7 +83,9 @@ RTC_EXPORT - (void)peerConnection:(RTCPeerConnection *)peerConnection didAddStream:(RTCMediaStream *)stream; -/** Called when a remote peer closes a stream. */ +/** Called when a remote peer closes a stream. + * This is not called when RTCSdpSemanticsUnifiedPlan is specified. + */ - (void)peerConnection:(RTCPeerConnection *)peerConnection didRemoveStream:(RTCMediaStream *)stream; @@ -106,6 +112,14 @@ RTC_EXPORT - (void)peerConnection:(RTCPeerConnection *)peerConnection didOpenDataChannel:(RTCDataChannel *)dataChannel; +/** Called when signaling indicates a transceiver will be receiving media from + * the remote endpoint. + * This is only called with RTCSdpSemanticsUnifiedPlan specified. + */ +@optional +- (void)peerConnection:(RTCPeerConnection *)peerConnection + didStartReceivingOnTransceiver:(RTCRtpTransceiver *)transceiver; + @end RTC_EXPORT @@ -115,6 +129,9 @@ RTC_EXPORT * streams being added or removed. */ @property(nonatomic, weak, nullable) id delegate; +/** This property is not available with RTCSdpSemanticsUnifiedPlan. Please use + * |senders| instead. + */ @property(nonatomic, readonly) NSArray *localStreams; @property(nonatomic, readonly, nullable) RTCSessionDescription *localDescription; @@ -137,6 +154,14 @@ RTC_EXPORT */ @property(nonatomic, readonly) NSArray *receivers; +/** Gets all RTCRtpTransceivers associated with this peer connection. + * Note: reading this property returns different instances of + * RTCRtpTransceiver. Use isEqual: instead of == to compare RTCRtpTransceiver + * instances. + * This is only available with RTCSdpSemanticsUnifiedPlan specified. + */ +@property(nonatomic, readonly) NSArray *transceivers; + - (instancetype)init NS_UNAVAILABLE; /** Sets the PeerConnection's global configuration to |configuration|. @@ -156,12 +181,70 @@ RTC_EXPORT /** Remove a group of remote candidates from the ICE Agent. */ - (void)removeIceCandidates:(NSArray *)candidates; -/** Add a new media stream to be sent on this peer connection. */ +/** Add a new media stream to be sent on this peer connection. + * This method is not supported with RTCSdpSemanticsUnifiedPlan. Please use + * addTrack instead. + */ - (void)addStream:(RTCMediaStream *)stream; -/** Remove the given media stream from this peer connection. */ +/** Remove the given media stream from this peer connection. + * This method is not supported with RTCSdpSemanticsUnifiedPlan. Please use + * removeTrack instead. + */ - (void)removeStream:(RTCMediaStream *)stream; +/** Add a new media stream track to be sent on this peer connection, and return + * the newly created RTCRtpSender. The RTCRtpSender will be associated with + * the streams specified in the |streamLabels| list. + * + * Errors: If an error occurs, returns nil. An error can occur if: + * - A sender already exists for the track. + * - The peer connection is closed. + */ +- (RTCRtpSender *)addTrack:(RTCMediaStreamTrack *)track + streamLabels:(NSArray *)streamLabels; + +/** With PlanB semantics, removes an RTCRtpSender from this peer connection. + * + * With UnifiedPlan semantics, sets sender's track to null and removes the + * send component from the associated RTCRtpTransceiver's direction. + * + * Returns YES on success. + */ +- (BOOL)removeTrack:(RTCRtpSender *)sender; + +/** addTransceiver creates a new RTCRtpTransceiver and adds it to the set of + * transceivers. Adding a transceiver will cause future calls to CreateOffer + * to add a media description for the corresponding transceiver. + * + * The initial value of |mid| in the returned transceiver is nil. Setting a + * new session description may change it to a non-nil value. + * + * https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtransceiver + * + * Optionally, an RtpTransceiverInit structure can be specified to configure + * the transceiver from construction. If not specified, the transceiver will + * default to having a direction of kSendRecv and not be part of any streams. + * + * These methods are only available when Unified Plan is enabled (see + * RTCConfiguration). + */ + +/** Adds a transceiver with a sender set to transmit the given track. The kind + * of the transceiver (and sender/receiver) will be derived from the kind of + * the track. + */ +- (RTCRtpTransceiver *)addTransceiverWithTrack:(RTCMediaStreamTrack *)track; +- (RTCRtpTransceiver *)addTransceiverWithTrack:(RTCMediaStreamTrack *)track + init:(RTCRtpTransceiverInit *)init; + +/** Adds a transceiver with the given kind. Can either be RTCRtpMediaTypeAudio + * or RTCRtpMediaTypeVideo. + */ +- (RTCRtpTransceiver *)addTransceiverOfType:(RTCRtpMediaType)mediaType; +- (RTCRtpTransceiver *)addTransceiverOfType:(RTCRtpMediaType)mediaType + init:(RTCRtpTransceiverInit *)init; + /** Generate an SDP offer. */ - (void)offerForConstraints:(RTCMediaConstraints *)constraints completionHandler:(nullable void (^) @@ -204,6 +287,8 @@ RTC_EXPORT /** Create an RTCRtpSender with the specified kind and media stream ID. * See RTCMediaStreamTrack.h for available kinds. + * This method is not supported with RTCSdpSemanticsUnifiedPlan. Please use + * addTransceiver instead. */ - (RTCRtpSender *)senderWithKind:(NSString *)kind streamId:(NSString *)streamId; diff --git a/sdk/objc/Framework/Headers/WebRTC/RTCRtpTransceiver.h b/sdk/objc/Framework/Headers/WebRTC/RTCRtpTransceiver.h new file mode 100644 index 0000000000..a670e2b930 --- /dev/null +++ b/sdk/objc/Framework/Headers/WebRTC/RTCRtpTransceiver.h @@ -0,0 +1,128 @@ +/* + * Copyright 2018 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 + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverdirection */ +typedef NS_ENUM(NSInteger, RTCRtpTransceiverDirection) { + RTCRtpTransceiverDirectionSendRecv, + RTCRtpTransceiverDirectionSendOnly, + RTCRtpTransceiverDirectionRecvOnly, + RTCRtpTransceiverDirectionInactive, +}; + +/** Structure for initializing an RTCRtpTransceiver in a call to + * RTCPeerConnection.addTransceiver. + * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverinit + */ +@interface RTCRtpTransceiverInit : NSObject + +/** Direction of the RTCRtpTransceiver. See RTCRtpTransceiver.direction. */ +@property(nonatomic) RTCRtpTransceiverDirection direction; + +/** The added RTCRtpTransceiver will be added to these streams. */ +@property(nonatomic) NSArray *streamLabels; + +/** TODO(bugs.webrtc.org/7600): Not implemented. */ +@property(nonatomic) NSArray *sendEncodings; + +@end + +@class RTCRtpTransceiver; + +/** The RTCRtpTransceiver maps to the RTCRtpTransceiver defined by the WebRTC + * specification. A transceiver represents a combination of an RTCRtpSender + * and an RTCRtpReceiver that share a common mid. As defined in JSEP, an + * RTCRtpTransceiver is said to be associated with a media description if its + * mid property is non-nil; otherwise, it is said to be disassociated. + * JSEP: https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-24 + * + * Note that RTCRtpTransceivers are only supported when using + * RTCPeerConnection with Unified Plan SDP. + * + * WebRTC specification for RTCRtpTransceiver, the JavaScript analog: + * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver + */ +RTC_EXPORT +@protocol RTCRtpTransceiver + +/** Media type of the transceiver. The sender and receiver will also have this + * type. + */ +@property(nonatomic, readonly) RTCRtpMediaType mediaType; + +/** The mid attribute is the mid negotiated and present in the local and + * remote descriptions. Before negotiation is complete, the mid value may be + * nil. After rollbacks, the value may change from a non-nil value to nil. + * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-mid + */ +@property(nonatomic, readonly) NSString *mid; + +/** The sender attribute exposes the RTCRtpSender corresponding to the RTP + * media that may be sent with the transceiver's mid. The sender is always + * present, regardless of the direction of media. + * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-sender + */ +@property(nonatomic, readonly) RTCRtpSender *sender; + +/** The receiver attribute exposes the RTCRtpReceiver corresponding to the RTP + * media that may be received with the transceiver's mid. The receiver is + * always present, regardless of the direction of media. + * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-receiver + */ +@property(nonatomic, readonly) RTCRtpReceiver *receiver; + +/** The isStopped attribute indicates that the sender of this transceiver will + * no longer send, and that the receiver will no longer receive. It is true if + * either stop has been called or if setting the local or remote description + * has caused the RTCRtpTransceiver to be stopped. + * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stopped + */ +@property(nonatomic, readonly) BOOL isStopped; + +/** The direction attribute indicates the preferred direction of this + * transceiver, which will be used in calls to createOffer and createAnswer. + * An update of directionality does not take effect immediately. Instead, + * future calls to createOffer and createAnswer mark the corresponding media + * descriptions as sendrecv, sendonly, recvonly, or inactive. + * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction + */ +@property(nonatomic) RTCRtpTransceiverDirection direction; + +/** The currentDirection attribute indicates the current direction negotiated + * for this transceiver. If this transceiver has never been represented in an + * offer/answer exchange, or if the transceiver is stopped, the value is not + * present and this method returns NO. + * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-currentdirection + */ +- (BOOL)currentDirection:(RTCRtpTransceiverDirection *)currentDirectionOut; + +/** The stop method irreversibly stops the RTCRtpTransceiver. The sender of + * this transceiver will no longer send, the receiver will no longer receive. + * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stop + */ +- (void)stop; + +@end + +RTC_EXPORT +@interface RTCRtpTransceiver : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END