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 "RTCEnumConverter.h"
35#import "RTCICECandidate+internal.h"
36#import "RTCICEServer+internal.h"
37#import "RTCMediaConstraints+internal.h"
38#import "RTCMediaStream+internal.h"
39#import "RTCSessionDescription+internal.h"
40#import "RTCSessionDescriptonDelegate.h"
41#import "RTCSessionDescription.h"
42
43#include "talk/app/webrtc/jsep.h"
44
45NSString* const kRTCSessionDescriptionDelegateErrorDomain = @"RTCSDPError";
46int const kRTCSessionDescriptionDelegateErrorCode = -1;
47
48namespace webrtc {
49
50class RTCCreateSessionDescriptionObserver
51    : public CreateSessionDescriptionObserver {
52 public:
53  RTCCreateSessionDescriptionObserver(id<RTCSessionDescriptonDelegate> delegate,
54                                      RTCPeerConnection *peerConnection) {
55    _delegate = delegate;
56    _peerConnection = peerConnection;
57  }
58
59  virtual void OnSuccess(SessionDescriptionInterface *desc) OVERRIDE {
60    RTCSessionDescription *session =
61        [[RTCSessionDescription alloc] initWithSessionDescription:desc];
62    [_delegate peerConnection:_peerConnection
63        didCreateSessionDescription:session
64        error:nil];
65  }
66
67  virtual void OnFailure(const std::string &error) OVERRIDE {
68    NSString *str = @(error.c_str());
69    NSError *err =
70        [NSError errorWithDomain:kRTCSessionDescriptionDelegateErrorDomain
71                            code:kRTCSessionDescriptionDelegateErrorCode
72                        userInfo:@{ @"error" : str }];
73    [_delegate peerConnection:_peerConnection
74        didCreateSessionDescription:nil
75        error:err];
76  }
77
78 private:
79  id<RTCSessionDescriptonDelegate> _delegate;
80  RTCPeerConnection *_peerConnection;
81};
82
83class RTCSetSessionDescriptionObserver : public SetSessionDescriptionObserver {
84 public:
85  RTCSetSessionDescriptionObserver(id<RTCSessionDescriptonDelegate> delegate,
86                                   RTCPeerConnection *peerConnection) {
87    _delegate = delegate;
88    _peerConnection = peerConnection;
89  }
90
91  virtual void OnSuccess() OVERRIDE {
92    [_delegate peerConnection:_peerConnection
93        didSetSessionDescriptionWithError:nil];
94  }
95
96  virtual void OnFailure(const std::string &error) OVERRIDE {
97    NSString *str = @(error.c_str());
98    NSError *err =
99        [NSError errorWithDomain:kRTCSessionDescriptionDelegateErrorDomain
100                            code:kRTCSessionDescriptionDelegateErrorCode
101                        userInfo:@{ @"error" : str }];
102    [_delegate peerConnection:_peerConnection
103        didSetSessionDescriptionWithError:err];
104  }
105
106 private:
107  id<RTCSessionDescriptonDelegate> _delegate;
108  RTCPeerConnection *_peerConnection;
109};
110
111}
112
113@implementation RTCPeerConnection {
114  NSMutableArray *_localStreams;
115  talk_base::scoped_ptr<webrtc::RTCPeerConnectionObserver>_observer;
116  talk_base::scoped_refptr<webrtc::PeerConnectionInterface> _peerConnection;
117}
118
119- (BOOL)addICECandidate:(RTCICECandidate *)candidate {
120  const webrtc::IceCandidateInterface *iceCandidate = candidate.candidate;
121  return self.peerConnection->AddIceCandidate(iceCandidate);
122  delete iceCandidate;
123}
124
125- (BOOL)addStream:(RTCMediaStream *)stream
126      constraints:(RTCMediaConstraints *)constraints {
127  BOOL ret = self.peerConnection->AddStream(stream.mediaStream,
128                                            constraints.constraints);
129  if (!ret) {
130    return NO;
131  }
132  [_localStreams addObject:stream];
133  return YES;
134}
135
136- (void)createAnswerWithDelegate:(id<RTCSessionDescriptonDelegate>)delegate
137                     constraints:(RTCMediaConstraints *)constraints {
138  talk_base::scoped_refptr<webrtc::RTCCreateSessionDescriptionObserver>
139      observer(new talk_base::RefCountedObject<
140          webrtc::RTCCreateSessionDescriptionObserver>(delegate, self));
141  self.peerConnection->CreateAnswer(observer, constraints.constraints);
142}
143
144- (void)createOfferWithDelegate:(id<RTCSessionDescriptonDelegate>)delegate
145                    constraints:(RTCMediaConstraints *)constraints {
146  talk_base::scoped_refptr<webrtc::RTCCreateSessionDescriptionObserver>
147      observer(new talk_base::RefCountedObject<
148          webrtc::RTCCreateSessionDescriptionObserver>(delegate, self));
149  self.peerConnection->CreateOffer(observer, constraints.constraints);
150}
151
152- (void)removeStream:(RTCMediaStream *)stream {
153  self.peerConnection->RemoveStream(stream.mediaStream);
154  [_localStreams removeObject:stream];
155}
156
157- (void)
158    setLocalDescriptionWithDelegate:(id<RTCSessionDescriptonDelegate>)delegate
159                 sessionDescription:(RTCSessionDescription *)sdp {
160  talk_base::scoped_refptr<webrtc::RTCSetSessionDescriptionObserver> observer(
161      new talk_base::RefCountedObject<webrtc::RTCSetSessionDescriptionObserver>(
162          delegate, self));
163  self.peerConnection->SetLocalDescription(observer, sdp.sessionDescription);
164}
165
166- (void)
167    setRemoteDescriptionWithDelegate:(id<RTCSessionDescriptonDelegate>)delegate
168                  sessionDescription:(RTCSessionDescription *)sdp {
169  talk_base::scoped_refptr<webrtc::RTCSetSessionDescriptionObserver> observer(
170      new talk_base::RefCountedObject<webrtc::RTCSetSessionDescriptionObserver>(
171          delegate, self));
172  self.peerConnection->SetRemoteDescription(observer, sdp.sessionDescription);
173}
174
175- (BOOL)updateICEServers:(NSArray *)servers
176             constraints:(RTCMediaConstraints *)constraints {
177  webrtc::PeerConnectionInterface::IceServers iceServers;
178  for (RTCICEServer *server in servers) {
179    iceServers.push_back(server.iceServer);
180  }
181  return self.peerConnection->UpdateIce(iceServers, constraints.constraints);
182}
183
184- (RTCSessionDescription *)localDescription {
185  const webrtc::SessionDescriptionInterface *sdi =
186      self.peerConnection->local_description();
187  return sdi ?
188      [[RTCSessionDescription alloc] initWithSessionDescription:sdi] :
189      nil;
190}
191
192- (NSArray *)localStreams {
193  return [_localStreams copy];
194}
195
196- (RTCSessionDescription *)remoteDescription {
197  const webrtc::SessionDescriptionInterface *sdi =
198      self.peerConnection->remote_description();
199  return sdi ?
200      [[RTCSessionDescription alloc] initWithSessionDescription:sdi] :
201      nil;
202}
203
204- (RTCICEConnectionState)iceConnectionState {
205  return [RTCEnumConverter convertIceConnectionStateToObjC:
206      self.peerConnection->ice_connection_state()];
207}
208
209- (RTCICEGatheringState)iceGatheringState {
210  return [RTCEnumConverter convertIceGatheringStateToObjC:
211      self.peerConnection->ice_gathering_state()];
212}
213
214- (RTCSignalingState)signalingState {
215  return [RTCEnumConverter
216      convertSignalingStateToObjC:self.peerConnection->signaling_state()];
217}
218
219- (void)close {
220  self.peerConnection->Close();
221}
222
223@end
224
225@implementation RTCPeerConnection (Internal)
226
227- (id)initWithPeerConnection:(
228    talk_base::scoped_refptr<webrtc::PeerConnectionInterface>)peerConnection
229                    observer:(webrtc::RTCPeerConnectionObserver *)observer {
230  if (!peerConnection || !observer) {
231    NSAssert(NO, @"nil arguments not allowed");
232    self = nil;
233    return nil;
234  }
235  if ((self = [super init])) {
236    _peerConnection = peerConnection;
237    _localStreams = [[NSMutableArray alloc] init];
238    _observer.reset(observer);
239  }
240  return self;
241}
242
243- (talk_base::scoped_refptr<webrtc::PeerConnectionInterface>)peerConnection {
244  return _peerConnection;
245}
246
247@end
248