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  virtual void OnSuccess(SessionDescriptionInterface* desc) OVERRIDE {
66    RTCSessionDescription* session =
67        [[RTCSessionDescription alloc] initWithSessionDescription:desc];
68    [_delegate peerConnection:_peerConnection
69        didCreateSessionDescription:session
70                              error:nil];
71  }
72
73  virtual void OnFailure(const std::string& error) OVERRIDE {
74    NSString* str = @(error.c_str());
75    NSError* err =
76        [NSError errorWithDomain:kRTCSessionDescriptionDelegateErrorDomain
77                            code:kRTCSessionDescriptionDelegateErrorCode
78                        userInfo:@{@"error" : str}];
79    [_delegate peerConnection:_peerConnection
80        didCreateSessionDescription:nil
81                              error:err];
82  }
83
84 private:
85  id<RTCSessionDescriptionDelegate> _delegate;
86  RTCPeerConnection* _peerConnection;
87};
88
89class RTCSetSessionDescriptionObserver : public SetSessionDescriptionObserver {
90 public:
91  RTCSetSessionDescriptionObserver(id<RTCSessionDescriptionDelegate> delegate,
92                                   RTCPeerConnection* peerConnection) {
93    _delegate = delegate;
94    _peerConnection = peerConnection;
95  }
96
97  virtual void OnSuccess() OVERRIDE {
98    [_delegate peerConnection:_peerConnection
99        didSetSessionDescriptionWithError:nil];
100  }
101
102  virtual void OnFailure(const std::string& error) OVERRIDE {
103    NSString* str = @(error.c_str());
104    NSError* err =
105        [NSError errorWithDomain:kRTCSessionDescriptionDelegateErrorDomain
106                            code:kRTCSessionDescriptionDelegateErrorCode
107                        userInfo:@{@"error" : str}];
108    [_delegate peerConnection:_peerConnection
109        didSetSessionDescriptionWithError:err];
110  }
111
112 private:
113  id<RTCSessionDescriptionDelegate> _delegate;
114  RTCPeerConnection* _peerConnection;
115};
116
117class RTCStatsObserver : public StatsObserver {
118 public:
119  RTCStatsObserver(id<RTCStatsDelegate> delegate,
120                   RTCPeerConnection* peerConnection) {
121    _delegate = delegate;
122    _peerConnection = peerConnection;
123  }
124
125  virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
126    NSMutableArray* stats = [NSMutableArray arrayWithCapacity:reports.size()];
127    std::vector<StatsReport>::const_iterator it = reports.begin();
128    for (; it != reports.end(); ++it) {
129      RTCStatsReport* statsReport =
130          [[RTCStatsReport alloc] initWithStatsReport:*it];
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      constraints:(RTCMediaConstraints*)constraints {
156  BOOL ret = self.peerConnection->AddStream(stream.mediaStream,
157                                            constraints.constraints);
158  if (!ret) {
159    return NO;
160  }
161  [_localStreams addObject:stream];
162  return YES;
163}
164
165- (RTCDataChannel*)createDataChannelWithLabel:(NSString*)label
166                                       config:(RTCDataChannelInit*)config {
167  std::string labelString([label UTF8String]);
168  rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel =
169      self.peerConnection->CreateDataChannel(labelString,
170                                             config.dataChannelInit);
171  return [[RTCDataChannel alloc] initWithDataChannel:dataChannel];
172}
173
174- (void)createAnswerWithDelegate:(id<RTCSessionDescriptionDelegate>)delegate
175                     constraints:(RTCMediaConstraints*)constraints {
176  rtc::scoped_refptr<webrtc::RTCCreateSessionDescriptionObserver>
177      observer(new rtc::RefCountedObject<
178          webrtc::RTCCreateSessionDescriptionObserver>(delegate, self));
179  self.peerConnection->CreateAnswer(observer, constraints.constraints);
180}
181
182- (void)createOfferWithDelegate:(id<RTCSessionDescriptionDelegate>)delegate
183                    constraints:(RTCMediaConstraints*)constraints {
184  rtc::scoped_refptr<webrtc::RTCCreateSessionDescriptionObserver>
185      observer(new rtc::RefCountedObject<
186          webrtc::RTCCreateSessionDescriptionObserver>(delegate, self));
187  self.peerConnection->CreateOffer(observer, constraints.constraints);
188}
189
190- (void)removeStream:(RTCMediaStream*)stream {
191  self.peerConnection->RemoveStream(stream.mediaStream);
192  [_localStreams removeObject:stream];
193}
194
195- (void)setLocalDescriptionWithDelegate:
196            (id<RTCSessionDescriptionDelegate>)delegate
197                     sessionDescription:(RTCSessionDescription*)sdp {
198  rtc::scoped_refptr<webrtc::RTCSetSessionDescriptionObserver> observer(
199      new rtc::RefCountedObject<webrtc::RTCSetSessionDescriptionObserver>(
200          delegate, self));
201  self.peerConnection->SetLocalDescription(observer, sdp.sessionDescription);
202}
203
204- (void)setRemoteDescriptionWithDelegate:
205            (id<RTCSessionDescriptionDelegate>)delegate
206                      sessionDescription:(RTCSessionDescription*)sdp {
207  rtc::scoped_refptr<webrtc::RTCSetSessionDescriptionObserver> observer(
208      new rtc::RefCountedObject<webrtc::RTCSetSessionDescriptionObserver>(
209          delegate, self));
210  self.peerConnection->SetRemoteDescription(observer, sdp.sessionDescription);
211}
212
213- (BOOL)updateICEServers:(NSArray*)servers
214             constraints:(RTCMediaConstraints*)constraints {
215  webrtc::PeerConnectionInterface::IceServers iceServers;
216  for (RTCICEServer* server in servers) {
217    iceServers.push_back(server.iceServer);
218  }
219  return self.peerConnection->UpdateIce(iceServers, constraints.constraints);
220}
221
222- (RTCSessionDescription*)localDescription {
223  const webrtc::SessionDescriptionInterface* sdi =
224      self.peerConnection->local_description();
225  return sdi ? [[RTCSessionDescription alloc] initWithSessionDescription:sdi]
226             : nil;
227}
228
229- (NSArray*)localStreams {
230  return [_localStreams copy];
231}
232
233- (RTCSessionDescription*)remoteDescription {
234  const webrtc::SessionDescriptionInterface* sdi =
235      self.peerConnection->remote_description();
236  return sdi ? [[RTCSessionDescription alloc] initWithSessionDescription:sdi]
237             : nil;
238}
239
240- (RTCICEConnectionState)iceConnectionState {
241  return [RTCEnumConverter
242      convertIceConnectionStateToObjC:self.peerConnection
243                                          ->ice_connection_state()];
244}
245
246- (RTCICEGatheringState)iceGatheringState {
247  return [RTCEnumConverter
248      convertIceGatheringStateToObjC:self.peerConnection
249                                         ->ice_gathering_state()];
250}
251
252- (RTCSignalingState)signalingState {
253  return [RTCEnumConverter
254      convertSignalingStateToObjC:self.peerConnection->signaling_state()];
255}
256
257- (void)close {
258  self.peerConnection->Close();
259}
260
261- (BOOL)getStatsWithDelegate:(id<RTCStatsDelegate>)delegate
262            mediaStreamTrack:(RTCMediaStreamTrack*)mediaStreamTrack
263            statsOutputLevel:(RTCStatsOutputLevel)statsOutputLevel {
264  rtc::scoped_refptr<webrtc::RTCStatsObserver> observer(
265      new rtc::RefCountedObject<webrtc::RTCStatsObserver>(delegate,
266                                                                self));
267  webrtc::PeerConnectionInterface::StatsOutputLevel nativeOutputLevel =
268      [RTCEnumConverter convertStatsOutputLevelToNative:statsOutputLevel];
269  return self.peerConnection->GetStats(
270      observer, mediaStreamTrack.mediaTrack, nativeOutputLevel);
271}
272
273@end
274
275@implementation RTCPeerConnection (Internal)
276
277- (instancetype)initWithFactory:(webrtc::PeerConnectionFactoryInterface*)factory
278     iceServers:(const webrtc::PeerConnectionInterface::IceServers&)iceServers
279    constraints:(const webrtc::MediaConstraintsInterface*)constraints {
280  NSParameterAssert(factory != NULL);
281  if (self = [super init]) {
282    _observer.reset(new webrtc::RTCPeerConnectionObserver(self));
283    _peerConnection = factory->CreatePeerConnection(
284        iceServers, constraints, NULL, NULL, _observer.get());
285    _localStreams = [[NSMutableArray alloc] init];
286  }
287  return self;
288}
289
290- (rtc::scoped_refptr<webrtc::PeerConnectionInterface>)peerConnection {
291  return _peerConnection;
292}
293
294@end
295