/* * libjingle * Copyright 2013 Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif #import "RTCPeerConnection+Internal.h" #import "RTCDataChannel+Internal.h" #import "RTCEnumConverter.h" #import "RTCICECandidate+Internal.h" #import "RTCICEServer+Internal.h" #import "RTCMediaConstraints+Internal.h" #import "RTCMediaStream+Internal.h" #import "RTCMediaStreamTrack+Internal.h" #import "RTCPeerConnectionObserver.h" #import "RTCSessionDescription+Internal.h" #import "RTCSessionDescription.h" #import "RTCSessionDescriptionDelegate.h" #import "RTCStatsDelegate.h" #import "RTCStatsReport+Internal.h" #include "talk/app/webrtc/jsep.h" NSString* const kRTCSessionDescriptionDelegateErrorDomain = @"RTCSDPError"; int const kRTCSessionDescriptionDelegateErrorCode = -1; namespace webrtc { class RTCCreateSessionDescriptionObserver : public CreateSessionDescriptionObserver { public: RTCCreateSessionDescriptionObserver( id delegate, RTCPeerConnection* peerConnection) { _delegate = delegate; _peerConnection = peerConnection; } void OnSuccess(SessionDescriptionInterface* desc) override { RTCSessionDescription* session = [[RTCSessionDescription alloc] initWithSessionDescription:desc]; [_delegate peerConnection:_peerConnection didCreateSessionDescription:session error:nil]; delete desc; } void OnFailure(const std::string& error) override { NSString* str = @(error.c_str()); NSError* err = [NSError errorWithDomain:kRTCSessionDescriptionDelegateErrorDomain code:kRTCSessionDescriptionDelegateErrorCode userInfo:@{@"error" : str}]; [_delegate peerConnection:_peerConnection didCreateSessionDescription:nil error:err]; } private: id _delegate; RTCPeerConnection* _peerConnection; }; class RTCSetSessionDescriptionObserver : public SetSessionDescriptionObserver { public: RTCSetSessionDescriptionObserver(id delegate, RTCPeerConnection* peerConnection) { _delegate = delegate; _peerConnection = peerConnection; } void OnSuccess() override { [_delegate peerConnection:_peerConnection didSetSessionDescriptionWithError:nil]; } void OnFailure(const std::string& error) override { NSString* str = @(error.c_str()); NSError* err = [NSError errorWithDomain:kRTCSessionDescriptionDelegateErrorDomain code:kRTCSessionDescriptionDelegateErrorCode userInfo:@{@"error" : str}]; [_delegate peerConnection:_peerConnection didSetSessionDescriptionWithError:err]; } private: id _delegate; RTCPeerConnection* _peerConnection; }; class RTCStatsObserver : public StatsObserver { public: RTCStatsObserver(id delegate, RTCPeerConnection* peerConnection) { _delegate = delegate; _peerConnection = peerConnection; } void OnComplete(const StatsReports& reports) override { NSMutableArray* stats = [NSMutableArray arrayWithCapacity:reports.size()]; for (const auto* report : reports) { RTCStatsReport* statsReport = [[RTCStatsReport alloc] initWithStatsReport:*report]; [stats addObject:statsReport]; } [_delegate peerConnection:_peerConnection didGetStats:stats]; } private: id _delegate; RTCPeerConnection* _peerConnection; }; } @implementation RTCPeerConnection { NSMutableArray* _localStreams; rtc::scoped_ptr _observer; rtc::scoped_refptr _peerConnection; } - (BOOL)addICECandidate:(RTCICECandidate*)candidate { rtc::scoped_ptr iceCandidate( candidate.candidate); return self.peerConnection->AddIceCandidate(iceCandidate.get()); } - (BOOL)addStream:(RTCMediaStream*)stream { BOOL ret = self.peerConnection->AddStream(stream.mediaStream); if (!ret) { return NO; } [_localStreams addObject:stream]; return YES; } - (RTCDataChannel*)createDataChannelWithLabel:(NSString*)label config:(RTCDataChannelInit*)config { std::string labelString([label UTF8String]); rtc::scoped_refptr dataChannel = self.peerConnection->CreateDataChannel(labelString, config.dataChannelInit); return [[RTCDataChannel alloc] initWithDataChannel:dataChannel]; } - (void)createAnswerWithDelegate:(id)delegate constraints:(RTCMediaConstraints*)constraints { rtc::scoped_refptr observer(new rtc::RefCountedObject< webrtc::RTCCreateSessionDescriptionObserver>(delegate, self)); self.peerConnection->CreateAnswer(observer, constraints.constraints); } - (void)createOfferWithDelegate:(id)delegate constraints:(RTCMediaConstraints*)constraints { rtc::scoped_refptr observer(new rtc::RefCountedObject< webrtc::RTCCreateSessionDescriptionObserver>(delegate, self)); self.peerConnection->CreateOffer(observer, constraints.constraints); } - (void)removeStream:(RTCMediaStream*)stream { self.peerConnection->RemoveStream(stream.mediaStream); [_localStreams removeObject:stream]; } - (void)setLocalDescriptionWithDelegate: (id)delegate sessionDescription:(RTCSessionDescription*)sdp { rtc::scoped_refptr observer( new rtc::RefCountedObject( delegate, self)); self.peerConnection->SetLocalDescription(observer, sdp.sessionDescription); } - (void)setRemoteDescriptionWithDelegate: (id)delegate sessionDescription:(RTCSessionDescription*)sdp { rtc::scoped_refptr observer( new rtc::RefCountedObject( delegate, self)); self.peerConnection->SetRemoteDescription(observer, sdp.sessionDescription); } - (BOOL)setConfiguration:(RTCConfiguration *)configuration { return self.peerConnection->SetConfiguration( configuration.nativeConfiguration); } - (RTCSessionDescription*)localDescription { const webrtc::SessionDescriptionInterface* sdi = self.peerConnection->local_description(); return sdi ? [[RTCSessionDescription alloc] initWithSessionDescription:sdi] : nil; } - (NSArray*)localStreams { return [_localStreams copy]; } - (RTCSessionDescription*)remoteDescription { const webrtc::SessionDescriptionInterface* sdi = self.peerConnection->remote_description(); return sdi ? [[RTCSessionDescription alloc] initWithSessionDescription:sdi] : nil; } - (RTCICEConnectionState)iceConnectionState { return [RTCEnumConverter convertIceConnectionStateToObjC:self.peerConnection ->ice_connection_state()]; } - (RTCICEGatheringState)iceGatheringState { return [RTCEnumConverter convertIceGatheringStateToObjC:self.peerConnection ->ice_gathering_state()]; } - (RTCSignalingState)signalingState { return [RTCEnumConverter convertSignalingStateToObjC:self.peerConnection->signaling_state()]; } - (void)close { self.peerConnection->Close(); } - (BOOL)getStatsWithDelegate:(id)delegate mediaStreamTrack:(RTCMediaStreamTrack*)mediaStreamTrack statsOutputLevel:(RTCStatsOutputLevel)statsOutputLevel { rtc::scoped_refptr observer( new rtc::RefCountedObject(delegate, self)); webrtc::PeerConnectionInterface::StatsOutputLevel nativeOutputLevel = [RTCEnumConverter convertStatsOutputLevelToNative:statsOutputLevel]; return self.peerConnection->GetStats( observer, mediaStreamTrack.mediaTrack, nativeOutputLevel); } @end @implementation RTCPeerConnection (Internal) - (instancetype)initWithFactory:(webrtc::PeerConnectionFactoryInterface*)factory iceServers:(const webrtc::PeerConnectionInterface::IceServers&)iceServers constraints:(const webrtc::MediaConstraintsInterface*)constraints { NSParameterAssert(factory != NULL); if (self = [super init]) { _observer.reset(new webrtc::RTCPeerConnectionObserver(self)); _peerConnection = factory->CreatePeerConnection( iceServers, constraints, NULL, NULL, _observer.get()); _localStreams = [[NSMutableArray alloc] init]; } return self; } - (instancetype)initWithFactory:(webrtc::PeerConnectionFactoryInterface *)factory config:(const webrtc::PeerConnectionInterface::RTCConfiguration &)config constraints:(const webrtc::MediaConstraintsInterface *)constraints delegate:(id)delegate { NSParameterAssert(factory); if (self = [super init]) { _observer.reset(new webrtc::RTCPeerConnectionObserver(self)); _peerConnection = factory->CreatePeerConnection(config, constraints, nullptr, nullptr, _observer.get()); _localStreams = [[NSMutableArray alloc] init]; _delegate = delegate; } return self; } - (rtc::scoped_refptr)peerConnection { return _peerConnection; } @end