1/*
2 * libjingle
3 * Copyright 2013 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *  1. Redistributions of source code must retain the above copyright notice,
9 *     this list of conditions and the following disclaimer.
10 *  2. Redistributions in binary form must reproduce the above copyright notice,
11 *     this list of conditions and the following disclaimer in the documentation
12 *     and/or other materials provided with the distribution.
13 *  3. The name of the author may not be used to endorse or promote products
14 *     derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#if !defined(__has_feature) || !__has_feature(objc_arc)
29#error "This file requires ARC support."
30#endif
31
32#import "RTCPeerConnection+Internal.h"
33
34#import "RTCDataChannel+Internal.h"
35#import "RTCEnumConverter.h"
36#import "RTCICECandidate+Internal.h"
37#import "RTCICEServer+Internal.h"
38#import "RTCMediaConstraints+Internal.h"
39#import "RTCMediaStream+Internal.h"
40#import "RTCMediaStreamTrack+Internal.h"
41#import "RTCPeerConnectionObserver.h"
42#import "RTCSessionDescription+Internal.h"
43#import "RTCSessionDescription.h"
44#import "RTCSessionDescriptionDelegate.h"
45#import "RTCStatsDelegate.h"
46#import "RTCStatsReport+Internal.h"
47
48#include "talk/app/webrtc/jsep.h"
49
50NSString* const kRTCSessionDescriptionDelegateErrorDomain = @"RTCSDPError";
51int const kRTCSessionDescriptionDelegateErrorCode = -1;
52
53namespace webrtc {
54
55class RTCCreateSessionDescriptionObserver
56    : public CreateSessionDescriptionObserver {
57 public:
58  RTCCreateSessionDescriptionObserver(
59      id<RTCSessionDescriptionDelegate> delegate,
60      RTCPeerConnection* peerConnection) {
61    _delegate = delegate;
62    _peerConnection = peerConnection;
63  }
64
65  void OnSuccess(SessionDescriptionInterface* desc) override {
66    RTCSessionDescription* session =
67        [[RTCSessionDescription alloc] initWithSessionDescription:desc];
68    [_delegate peerConnection:_peerConnection
69        didCreateSessionDescription:session
70                              error:nil];
71    delete desc;
72  }
73
74  void OnFailure(const std::string& error) override {
75    NSString* str = @(error.c_str());
76    NSError* err =
77        [NSError errorWithDomain:kRTCSessionDescriptionDelegateErrorDomain
78                            code:kRTCSessionDescriptionDelegateErrorCode
79                        userInfo:@{@"error" : str}];
80    [_delegate peerConnection:_peerConnection
81        didCreateSessionDescription:nil
82                              error:err];
83  }
84
85 private:
86  id<RTCSessionDescriptionDelegate> _delegate;
87  RTCPeerConnection* _peerConnection;
88};
89
90class RTCSetSessionDescriptionObserver : public SetSessionDescriptionObserver {
91 public:
92  RTCSetSessionDescriptionObserver(id<RTCSessionDescriptionDelegate> delegate,
93                                   RTCPeerConnection* peerConnection) {
94    _delegate = delegate;
95    _peerConnection = peerConnection;
96  }
97
98  void OnSuccess() override {
99    [_delegate peerConnection:_peerConnection
100        didSetSessionDescriptionWithError:nil];
101  }
102
103  void OnFailure(const std::string& error) override {
104    NSString* str = @(error.c_str());
105    NSError* err =
106        [NSError errorWithDomain:kRTCSessionDescriptionDelegateErrorDomain
107                            code:kRTCSessionDescriptionDelegateErrorCode
108                        userInfo:@{@"error" : str}];
109    [_delegate peerConnection:_peerConnection
110        didSetSessionDescriptionWithError:err];
111  }
112
113 private:
114  id<RTCSessionDescriptionDelegate> _delegate;
115  RTCPeerConnection* _peerConnection;
116};
117
118class RTCStatsObserver : public StatsObserver {
119 public:
120  RTCStatsObserver(id<RTCStatsDelegate> delegate,
121                   RTCPeerConnection* peerConnection) {
122    _delegate = delegate;
123    _peerConnection = peerConnection;
124  }
125
126  void OnComplete(const StatsReports& reports) override {
127    NSMutableArray* stats = [NSMutableArray arrayWithCapacity:reports.size()];
128    for (const auto* report : reports) {
129      RTCStatsReport* statsReport =
130          [[RTCStatsReport alloc] initWithStatsReport:*report];
131      [stats addObject:statsReport];
132    }
133    [_delegate peerConnection:_peerConnection didGetStats:stats];
134  }
135
136 private:
137  id<RTCStatsDelegate> _delegate;
138  RTCPeerConnection* _peerConnection;
139};
140}
141
142@implementation RTCPeerConnection {
143  NSMutableArray* _localStreams;
144  rtc::scoped_ptr<webrtc::RTCPeerConnectionObserver> _observer;
145  rtc::scoped_refptr<webrtc::PeerConnectionInterface> _peerConnection;
146}
147
148- (BOOL)addICECandidate:(RTCICECandidate*)candidate {
149  rtc::scoped_ptr<const webrtc::IceCandidateInterface> iceCandidate(
150      candidate.candidate);
151  return self.peerConnection->AddIceCandidate(iceCandidate.get());
152}
153
154- (BOOL)addStream:(RTCMediaStream*)stream {
155  BOOL ret = self.peerConnection->AddStream(stream.mediaStream);
156  if (!ret) {
157    return NO;
158  }
159  [_localStreams addObject:stream];
160  return YES;
161}
162
163- (RTCDataChannel*)createDataChannelWithLabel:(NSString*)label
164                                       config:(RTCDataChannelInit*)config {
165  std::string labelString([label UTF8String]);
166  rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel =
167      self.peerConnection->CreateDataChannel(labelString,
168                                             config.dataChannelInit);
169  return [[RTCDataChannel alloc] initWithDataChannel:dataChannel];
170}
171
172- (void)createAnswerWithDelegate:(id<RTCSessionDescriptionDelegate>)delegate
173                     constraints:(RTCMediaConstraints*)constraints {
174  rtc::scoped_refptr<webrtc::RTCCreateSessionDescriptionObserver>
175      observer(new rtc::RefCountedObject<
176          webrtc::RTCCreateSessionDescriptionObserver>(delegate, self));
177  self.peerConnection->CreateAnswer(observer, constraints.constraints);
178}
179
180- (void)createOfferWithDelegate:(id<RTCSessionDescriptionDelegate>)delegate
181                    constraints:(RTCMediaConstraints*)constraints {
182  rtc::scoped_refptr<webrtc::RTCCreateSessionDescriptionObserver>
183      observer(new rtc::RefCountedObject<
184          webrtc::RTCCreateSessionDescriptionObserver>(delegate, self));
185  self.peerConnection->CreateOffer(observer, constraints.constraints);
186}
187
188- (void)removeStream:(RTCMediaStream*)stream {
189  self.peerConnection->RemoveStream(stream.mediaStream);
190  [_localStreams removeObject:stream];
191}
192
193- (void)setLocalDescriptionWithDelegate:
194            (id<RTCSessionDescriptionDelegate>)delegate
195                     sessionDescription:(RTCSessionDescription*)sdp {
196  rtc::scoped_refptr<webrtc::RTCSetSessionDescriptionObserver> observer(
197      new rtc::RefCountedObject<webrtc::RTCSetSessionDescriptionObserver>(
198          delegate, self));
199  self.peerConnection->SetLocalDescription(observer, sdp.sessionDescription);
200}
201
202- (void)setRemoteDescriptionWithDelegate:
203            (id<RTCSessionDescriptionDelegate>)delegate
204                      sessionDescription:(RTCSessionDescription*)sdp {
205  rtc::scoped_refptr<webrtc::RTCSetSessionDescriptionObserver> observer(
206      new rtc::RefCountedObject<webrtc::RTCSetSessionDescriptionObserver>(
207          delegate, self));
208  self.peerConnection->SetRemoteDescription(observer, sdp.sessionDescription);
209}
210
211- (BOOL)setConfiguration:(RTCConfiguration *)configuration {
212  return self.peerConnection->SetConfiguration(
213      configuration.nativeConfiguration);
214}
215
216- (RTCSessionDescription*)localDescription {
217  const webrtc::SessionDescriptionInterface* sdi =
218      self.peerConnection->local_description();
219  return sdi ? [[RTCSessionDescription alloc] initWithSessionDescription:sdi]
220             : nil;
221}
222
223- (NSArray*)localStreams {
224  return [_localStreams copy];
225}
226
227- (RTCSessionDescription*)remoteDescription {
228  const webrtc::SessionDescriptionInterface* sdi =
229      self.peerConnection->remote_description();
230  return sdi ? [[RTCSessionDescription alloc] initWithSessionDescription:sdi]
231             : nil;
232}
233
234- (RTCICEConnectionState)iceConnectionState {
235  return [RTCEnumConverter
236      convertIceConnectionStateToObjC:self.peerConnection
237                                          ->ice_connection_state()];
238}
239
240- (RTCICEGatheringState)iceGatheringState {
241  return [RTCEnumConverter
242      convertIceGatheringStateToObjC:self.peerConnection
243                                         ->ice_gathering_state()];
244}
245
246- (RTCSignalingState)signalingState {
247  return [RTCEnumConverter
248      convertSignalingStateToObjC:self.peerConnection->signaling_state()];
249}
250
251- (void)close {
252  self.peerConnection->Close();
253}
254
255- (BOOL)getStatsWithDelegate:(id<RTCStatsDelegate>)delegate
256            mediaStreamTrack:(RTCMediaStreamTrack*)mediaStreamTrack
257            statsOutputLevel:(RTCStatsOutputLevel)statsOutputLevel {
258  rtc::scoped_refptr<webrtc::RTCStatsObserver> observer(
259      new rtc::RefCountedObject<webrtc::RTCStatsObserver>(delegate,
260                                                                self));
261  webrtc::PeerConnectionInterface::StatsOutputLevel nativeOutputLevel =
262      [RTCEnumConverter convertStatsOutputLevelToNative:statsOutputLevel];
263  return self.peerConnection->GetStats(
264      observer, mediaStreamTrack.mediaTrack, nativeOutputLevel);
265}
266
267@end
268
269@implementation RTCPeerConnection (Internal)
270
271- (instancetype)initWithFactory:(webrtc::PeerConnectionFactoryInterface*)factory
272     iceServers:(const webrtc::PeerConnectionInterface::IceServers&)iceServers
273    constraints:(const webrtc::MediaConstraintsInterface*)constraints {
274  NSParameterAssert(factory != nullptr);
275  if (self = [super init]) {
276    webrtc::PeerConnectionInterface::RTCConfiguration config;
277    config.servers = iceServers;
278    _observer.reset(new webrtc::RTCPeerConnectionObserver(self));
279    _peerConnection = factory->CreatePeerConnection(
280        config, constraints, nullptr, nullptr, _observer.get());
281    _localStreams = [[NSMutableArray alloc] init];
282  }
283  return self;
284}
285
286- (instancetype)initWithFactory:(webrtc::PeerConnectionFactoryInterface *)factory
287                         config:(const webrtc::PeerConnectionInterface::RTCConfiguration &)config
288                    constraints:(const webrtc::MediaConstraintsInterface *)constraints
289                       delegate:(id<RTCPeerConnectionDelegate>)delegate {
290  NSParameterAssert(factory);
291  if (self = [super init]) {
292    _observer.reset(new webrtc::RTCPeerConnectionObserver(self));
293    _peerConnection =
294        factory->CreatePeerConnection(config, constraints, nullptr, nullptr, _observer.get());
295    _localStreams = [[NSMutableArray alloc] init];
296    _delegate = delegate;
297  }
298  return self;
299}
300
301- (rtc::scoped_refptr<webrtc::PeerConnectionInterface>)peerConnection {
302  return _peerConnection;
303}
304
305@end
306