blob: 465ce8c9b804b1db970b4b2491f7ecca6a7448fc [file] [log] [blame]
tkchin@webrtc.org87776a82014-12-09 19:32:35 +00001/*
Donald E Curtisa8736442015-08-05 15:48:13 -07002 * Copyright 2014 The WebRTC Project Authors. All rights reserved.
tkchin@webrtc.org87776a82014-12-09 19:32:35 +00003 *
Donald E Curtisa8736442015-08-05 15:48:13 -07004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
tkchin@webrtc.org87776a82014-12-09 19:32:35 +00009 */
10
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000011#import "ARDAppClient+Internal.h"
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000012
tkchin9eeb6242016-04-27 01:54:20 -070013#import "WebRTC/RTCAudioTrack.h"
sakalc522e752017-04-05 12:17:48 -070014#import "WebRTC/RTCCameraVideoCapturer.h"
tkchin9eeb6242016-04-27 01:54:20 -070015#import "WebRTC/RTCConfiguration.h"
16#import "WebRTC/RTCFileLogger.h"
Daniela012b56b2017-11-15 13:15:24 +010017#import "WebRTC/RTCFileVideoCapturer.h"
tkchin9eeb6242016-04-27 01:54:20 -070018#import "WebRTC/RTCIceServer.h"
19#import "WebRTC/RTCLogging.h"
20#import "WebRTC/RTCMediaConstraints.h"
21#import "WebRTC/RTCMediaStream.h"
22#import "WebRTC/RTCPeerConnectionFactory.h"
skvladf3569c82016-04-29 15:30:16 -070023#import "WebRTC/RTCRtpSender.h"
Steve Antonaf23b752018-03-01 09:22:48 -080024#import "WebRTC/RTCRtpTransceiver.h"
tkchin204177f2016-06-14 15:03:11 -070025#import "WebRTC/RTCTracing.h"
Anders Carlsson1d4c1522017-10-30 13:07:07 +010026#import "WebRTC/RTCVideoCodecFactory.h"
Kári Tristan Helgason0d3c9a32018-02-08 20:17:34 +010027#import "WebRTC/RTCVideoSource.h"
sakalc522e752017-04-05 12:17:48 -070028#import "WebRTC/RTCVideoTrack.h"
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000029
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000030#import "ARDAppEngineClient.h"
Anders Carlsson358f2e02018-06-04 10:24:37 +020031#import "ARDExternalSampleCapturer.h"
tkchin@webrtc.org36401ab2015-01-27 21:34:39 +000032#import "ARDJoinResponse.h"
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000033#import "ARDMessageResponse.h"
sakalc4adacf2017-03-28 01:22:48 -070034#import "ARDSettingsModel.h"
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000035#import "ARDSignalingMessage.h"
sakalc4adacf2017-03-28 01:22:48 -070036#import "ARDTURNClient+Internal.h"
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000037#import "ARDUtilities.h"
38#import "ARDWebSocketChannel.h"
hjon79858f82016-03-13 22:08:26 -070039#import "RTCIceCandidate+JSON.h"
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000040#import "RTCSessionDescription+JSON.h"
Zeke Chin57cc74e2015-05-05 07:52:31 -070041
kthelgasoncc882af2017-01-13 05:59:46 -080042static NSString * const kARDIceServerRequestUrl = @"https://appr.tc/params";
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000043
tkchin@webrtc.org8cc47e92015-03-18 23:38:04 +000044static NSString * const kARDAppClientErrorDomain = @"ARDAppClient";
45static NSInteger const kARDAppClientErrorUnknown = -1;
46static NSInteger const kARDAppClientErrorRoomFull = -2;
47static NSInteger const kARDAppClientErrorCreateSDP = -3;
48static NSInteger const kARDAppClientErrorSetSDP = -4;
49static NSInteger const kARDAppClientErrorInvalidClient = -5;
50static NSInteger const kARDAppClientErrorInvalidRoom = -6;
skvladf3569c82016-04-29 15:30:16 -070051static NSString * const kARDMediaStreamId = @"ARDAMS";
52static NSString * const kARDAudioTrackId = @"ARDAMSa0";
53static NSString * const kARDVideoTrackId = @"ARDAMSv0";
denicija9af2b602016-11-17 00:43:43 -080054static NSString * const kARDVideoTrackKind = @"video";
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000055
tkchin204177f2016-06-14 15:03:11 -070056// TODO(tkchin): Add these as UI options.
Mirko Bonadei3e603ec2018-07-10 14:21:23 +020057#if defined(WEBRTC_IOS)
tkchind1fb26d2016-02-03 01:51:18 -080058static BOOL const kARDAppClientEnableTracing = NO;
tkchin204177f2016-06-14 15:03:11 -070059static BOOL const kARDAppClientEnableRtcEventLog = YES;
tkchinfce0e2c2016-08-30 12:58:11 -070060static int64_t const kARDAppClientAecDumpMaxSizeInBytes = 5e6; // 5 MB.
tkchin204177f2016-06-14 15:03:11 -070061static int64_t const kARDAppClientRtcEventLogMaxSizeInBytes = 5e6; // 5 MB.
Mirko Bonadei3e603ec2018-07-10 14:21:23 +020062#endif
denicija9af2b602016-11-17 00:43:43 -080063static int const kKbpsMultiplier = 1000;
tkchind1fb26d2016-02-03 01:51:18 -080064
Zeke Chind3325802015-08-14 11:00:02 -070065// We need a proxy to NSTimer because it causes a strong retain cycle. When
66// using the proxy, |invalidate| must be called before it properly deallocs.
67@interface ARDTimerProxy : NSObject
68
69- (instancetype)initWithInterval:(NSTimeInterval)interval
70 repeats:(BOOL)repeats
71 timerHandler:(void (^)(void))timerHandler;
72- (void)invalidate;
73
74@end
75
76@implementation ARDTimerProxy {
77 NSTimer *_timer;
78 void (^_timerHandler)(void);
Zeke Chin2d3b7e22015-07-14 12:55:44 -070079}
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000080
Zeke Chind3325802015-08-14 11:00:02 -070081- (instancetype)initWithInterval:(NSTimeInterval)interval
82 repeats:(BOOL)repeats
83 timerHandler:(void (^)(void))timerHandler {
84 NSParameterAssert(timerHandler);
85 if (self = [super init]) {
86 _timerHandler = timerHandler;
87 _timer = [NSTimer scheduledTimerWithTimeInterval:interval
88 target:self
89 selector:@selector(timerDidFire:)
90 userInfo:nil
91 repeats:repeats];
92 }
93 return self;
94}
95
96- (void)invalidate {
97 [_timer invalidate];
98}
99
100- (void)timerDidFire:(NSTimer *)timer {
101 _timerHandler();
102}
103
104@end
105
106@implementation ARDAppClient {
107 RTCFileLogger *_fileLogger;
108 ARDTimerProxy *_statsTimer;
sakalc4adacf2017-03-28 01:22:48 -0700109 ARDSettingsModel *_settings;
sakalc522e752017-04-05 12:17:48 -0700110 RTCVideoTrack *_localVideoTrack;
Zeke Chind3325802015-08-14 11:00:02 -0700111}
112
113@synthesize shouldGetStats = _shouldGetStats;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000114@synthesize state = _state;
Zeke Chind3325802015-08-14 11:00:02 -0700115@synthesize delegate = _delegate;
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000116@synthesize roomServerClient = _roomServerClient;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000117@synthesize channel = _channel;
haysc913e6452015-10-02 11:44:03 -0700118@synthesize loopbackChannel = _loopbackChannel;
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000119@synthesize turnClient = _turnClient;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000120@synthesize peerConnection = _peerConnection;
121@synthesize factory = _factory;
122@synthesize messageQueue = _messageQueue;
123@synthesize isTurnComplete = _isTurnComplete;
124@synthesize hasReceivedSdp = _hasReceivedSdp;
125@synthesize roomId = _roomId;
126@synthesize clientId = _clientId;
127@synthesize isInitiator = _isInitiator;
128@synthesize iceServers = _iceServers;
129@synthesize webSocketURL = _websocketURL;
130@synthesize webSocketRestURL = _websocketRestURL;
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000131@synthesize defaultPeerConnectionConstraints =
132 _defaultPeerConnectionConstraints;
haysc913e6452015-10-02 11:44:03 -0700133@synthesize isLoopback = _isLoopback;
Anders Carlsson358f2e02018-06-04 10:24:37 +0200134@synthesize broadcast = _broadcast;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000135
tkchin@webrtc.org8cc47e92015-03-18 23:38:04 +0000136- (instancetype)init {
sakalc4adacf2017-03-28 01:22:48 -0700137 return [self initWithDelegate:nil];
tkchin@webrtc.org8cc47e92015-03-18 23:38:04 +0000138}
139
sakalc4adacf2017-03-28 01:22:48 -0700140- (instancetype)initWithDelegate:(id<ARDAppClientDelegate>)delegate {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000141 if (self = [super init]) {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000142 _roomServerClient = [[ARDAppEngineClient alloc] init];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000143 _delegate = delegate;
kthelgasoncc882af2017-01-13 05:59:46 -0800144 NSURL *turnRequestURL = [NSURL URLWithString:kARDIceServerRequestUrl];
145 _turnClient = [[ARDTURNClient alloc] initWithURL:turnRequestURL];
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000146 [self configure];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000147 }
148 return self;
149}
150
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000151// TODO(tkchin): Provide signaling channel factory interface so we can recreate
152// channel if we need to on network failure. Also, make this the default public
153// constructor.
154- (instancetype)initWithRoomServerClient:(id<ARDRoomServerClient>)rsClient
155 signalingChannel:(id<ARDSignalingChannel>)channel
156 turnClient:(id<ARDTURNClient>)turnClient
157 delegate:(id<ARDAppClientDelegate>)delegate {
158 NSParameterAssert(rsClient);
159 NSParameterAssert(channel);
160 NSParameterAssert(turnClient);
161 if (self = [super init]) {
162 _roomServerClient = rsClient;
163 _channel = channel;
164 _turnClient = turnClient;
165 _delegate = delegate;
166 [self configure];
167 }
168 return self;
169}
170
171- (void)configure {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000172 _messageQueue = [NSMutableArray array];
kthelgasoncc882af2017-01-13 05:59:46 -0800173 _iceServers = [NSMutableArray array];
Zeke Chin2d3b7e22015-07-14 12:55:44 -0700174 _fileLogger = [[RTCFileLogger alloc] init];
175 [_fileLogger start];
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000176}
177
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000178- (void)dealloc {
Zeke Chind3325802015-08-14 11:00:02 -0700179 self.shouldGetStats = NO;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000180 [self disconnect];
181}
182
Zeke Chind3325802015-08-14 11:00:02 -0700183- (void)setShouldGetStats:(BOOL)shouldGetStats {
184 if (_shouldGetStats == shouldGetStats) {
185 return;
186 }
187 if (shouldGetStats) {
188 __weak ARDAppClient *weakSelf = self;
189 _statsTimer = [[ARDTimerProxy alloc] initWithInterval:1
190 repeats:YES
191 timerHandler:^{
192 ARDAppClient *strongSelf = weakSelf;
hjon79858f82016-03-13 22:08:26 -0700193 [strongSelf.peerConnection statsForTrack:nil
194 statsOutputLevel:RTCStatsOutputLevelDebug
195 completionHandler:^(NSArray *stats) {
196 dispatch_async(dispatch_get_main_queue(), ^{
197 ARDAppClient *strongSelf = weakSelf;
198 [strongSelf.delegate appClient:strongSelf didGetStats:stats];
199 });
200 }];
Zeke Chind3325802015-08-14 11:00:02 -0700201 }];
202 } else {
203 [_statsTimer invalidate];
204 _statsTimer = nil;
205 }
206 _shouldGetStats = shouldGetStats;
207}
208
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000209- (void)setState:(ARDAppClientState)state {
210 if (_state == state) {
211 return;
212 }
213 _state = state;
214 [_delegate appClient:self didChangeState:_state];
215}
216
217- (void)connectToRoomWithId:(NSString *)roomId
sakalc4adacf2017-03-28 01:22:48 -0700218 settings:(ARDSettingsModel *)settings
Anders Carlssone1500582017-06-15 16:05:13 +0200219 isLoopback:(BOOL)isLoopback {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000220 NSParameterAssert(roomId.length);
221 NSParameterAssert(_state == kARDAppClientStateDisconnected);
sakalc4adacf2017-03-28 01:22:48 -0700222 _settings = settings;
haysc913e6452015-10-02 11:44:03 -0700223 _isLoopback = isLoopback;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000224 self.state = kARDAppClientStateConnecting;
225
Anders Carlsson1d4c1522017-10-30 13:07:07 +0100226 RTCDefaultVideoDecoderFactory *decoderFactory = [[RTCDefaultVideoDecoderFactory alloc] init];
227 RTCDefaultVideoEncoderFactory *encoderFactory = [[RTCDefaultVideoEncoderFactory alloc] init];
Anders Carlsson6bf43d22017-10-16 13:51:43 +0200228 encoderFactory.preferredCodec = [settings currentVideoCodecSettingFromStore];
229 _factory = [[RTCPeerConnectionFactory alloc] initWithEncoderFactory:encoderFactory
230 decoderFactory:decoderFactory];
231
tkchind1fb26d2016-02-03 01:51:18 -0800232#if defined(WEBRTC_IOS)
233 if (kARDAppClientEnableTracing) {
tkchin204177f2016-06-14 15:03:11 -0700234 NSString *filePath = [self documentsFilePathForFileName:@"webrtc-trace.txt"];
tkchind1fb26d2016-02-03 01:51:18 -0800235 RTCStartInternalCapture(filePath);
236 }
237#endif
238
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000239 // Request TURN.
240 __weak ARDAppClient *weakSelf = self;
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000241 [_turnClient requestServersWithCompletionHandler:^(NSArray *turnServers,
242 NSError *error) {
243 if (error) {
Anders Carlsson358f2e02018-06-04 10:24:37 +0200244 RTCLogError(@"Error retrieving TURN servers: %@", error.localizedDescription);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000245 }
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000246 ARDAppClient *strongSelf = weakSelf;
247 [strongSelf.iceServers addObjectsFromArray:turnServers];
248 strongSelf.isTurnComplete = YES;
249 [strongSelf startSignalingIfReady];
250 }];
jiayl@webrtc.org27f53172014-12-31 00:26:20 +0000251
tkchin@webrtc.org36401ab2015-01-27 21:34:39 +0000252 // Join room on room server.
253 [_roomServerClient joinRoomWithRoomId:roomId
haysc913e6452015-10-02 11:44:03 -0700254 isLoopback:isLoopback
tkchin@webrtc.org36401ab2015-01-27 21:34:39 +0000255 completionHandler:^(ARDJoinResponse *response, NSError *error) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000256 ARDAppClient *strongSelf = weakSelf;
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000257 if (error) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000258 [strongSelf.delegate appClient:strongSelf didError:error];
259 return;
260 }
tkchin@webrtc.org36401ab2015-01-27 21:34:39 +0000261 NSError *joinError =
262 [[strongSelf class] errorForJoinResultType:response.result];
263 if (joinError) {
tkchinc3f46a92015-07-23 12:50:55 -0700264 RTCLogError(@"Failed to join room:%@ on room server.", roomId);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000265 [strongSelf disconnect];
tkchin@webrtc.org36401ab2015-01-27 21:34:39 +0000266 [strongSelf.delegate appClient:strongSelf didError:joinError];
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000267 return;
268 }
tkchinc3f46a92015-07-23 12:50:55 -0700269 RTCLog(@"Joined room:%@ on room server.", roomId);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000270 strongSelf.roomId = response.roomId;
271 strongSelf.clientId = response.clientId;
272 strongSelf.isInitiator = response.isInitiator;
273 for (ARDSignalingMessage *message in response.messages) {
274 if (message.type == kARDSignalingMessageTypeOffer ||
275 message.type == kARDSignalingMessageTypeAnswer) {
276 strongSelf.hasReceivedSdp = YES;
277 [strongSelf.messageQueue insertObject:message atIndex:0];
278 } else {
279 [strongSelf.messageQueue addObject:message];
280 }
281 }
282 strongSelf.webSocketURL = response.webSocketURL;
283 strongSelf.webSocketRestURL = response.webSocketRestURL;
284 [strongSelf registerWithColliderIfReady];
285 [strongSelf startSignalingIfReady];
286 }];
287}
288
289- (void)disconnect {
290 if (_state == kARDAppClientStateDisconnected) {
291 return;
292 }
tkchin@webrtc.org36401ab2015-01-27 21:34:39 +0000293 if (self.hasJoinedRoomServerRoom) {
294 [_roomServerClient leaveRoomWithRoomId:_roomId
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000295 clientId:_clientId
296 completionHandler:nil];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000297 }
298 if (_channel) {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000299 if (_channel.state == kARDSignalingChannelStateRegistered) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000300 // Tell the other client we're hanging up.
301 ARDByeMessage *byeMessage = [[ARDByeMessage alloc] init];
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000302 [_channel sendMessage:byeMessage];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000303 }
304 // Disconnect from collider.
305 _channel = nil;
306 }
307 _clientId = nil;
308 _roomId = nil;
309 _isInitiator = NO;
310 _hasReceivedSdp = NO;
311 _messageQueue = [NSMutableArray array];
sakalc522e752017-04-05 12:17:48 -0700312 _localVideoTrack = nil;
ivoc14d5dbe2016-07-04 07:06:55 -0700313#if defined(WEBRTC_IOS)
tkchinfce0e2c2016-08-30 12:58:11 -0700314 [_factory stopAecDump];
ivoc14d5dbe2016-07-04 07:06:55 -0700315 [_peerConnection stopRtcEventLog];
316#endif
magjedcc8b9062017-07-24 07:32:33 -0700317 [_peerConnection close];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000318 _peerConnection = nil;
319 self.state = kARDAppClientStateDisconnected;
tkchind1fb26d2016-02-03 01:51:18 -0800320#if defined(WEBRTC_IOS)
adam.fedorbcc5d872016-11-07 14:53:28 -0800321 if (kARDAppClientEnableTracing) {
322 RTCStopInternalCapture();
323 }
tkchind1fb26d2016-02-03 01:51:18 -0800324#endif
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000325}
326
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000327#pragma mark - ARDSignalingChannelDelegate
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000328
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000329- (void)channel:(id<ARDSignalingChannel>)channel
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000330 didReceiveMessage:(ARDSignalingMessage *)message {
331 switch (message.type) {
332 case kARDSignalingMessageTypeOffer:
333 case kARDSignalingMessageTypeAnswer:
tkchin@webrtc.org8cc47e92015-03-18 23:38:04 +0000334 // Offers and answers must be processed before any other message, so we
335 // place them at the front of the queue.
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000336 _hasReceivedSdp = YES;
337 [_messageQueue insertObject:message atIndex:0];
338 break;
339 case kARDSignalingMessageTypeCandidate:
Honghai Zhangda2ba4d2016-05-23 11:53:14 -0700340 case kARDSignalingMessageTypeCandidateRemoval:
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000341 [_messageQueue addObject:message];
342 break;
343 case kARDSignalingMessageTypeBye:
tkchin@webrtc.org8cc47e92015-03-18 23:38:04 +0000344 // Disconnects can be processed immediately.
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000345 [self processSignalingMessage:message];
346 return;
347 }
348 [self drainMessageQueueIfReady];
349}
350
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000351- (void)channel:(id<ARDSignalingChannel>)channel
352 didChangeState:(ARDSignalingChannelState)state {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000353 switch (state) {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000354 case kARDSignalingChannelStateOpen:
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000355 break;
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000356 case kARDSignalingChannelStateRegistered:
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000357 break;
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000358 case kARDSignalingChannelStateClosed:
359 case kARDSignalingChannelStateError:
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000360 // TODO(tkchin): reconnection scenarios. Right now we just disconnect
361 // completely if the websocket connection fails.
362 [self disconnect];
363 break;
364 }
365}
366
367#pragma mark - RTCPeerConnectionDelegate
tkchin@webrtc.org8cc47e92015-03-18 23:38:04 +0000368// Callbacks for this delegate occur on non-main thread and need to be
369// dispatched back to main queue as needed.
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000370
371- (void)peerConnection:(RTCPeerConnection *)peerConnection
hjon79858f82016-03-13 22:08:26 -0700372 didChangeSignalingState:(RTCSignalingState)stateChanged {
373 RTCLog(@"Signaling state changed: %ld", (long)stateChanged);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000374}
375
376- (void)peerConnection:(RTCPeerConnection *)peerConnection
hjon79858f82016-03-13 22:08:26 -0700377 didAddStream:(RTCMediaStream *)stream {
Steve Antonaf23b752018-03-01 09:22:48 -0800378 RTCLog(@"Stream with %lu video tracks and %lu audio tracks was added.",
379 (unsigned long)stream.videoTracks.count,
380 (unsigned long)stream.audioTracks.count);
381}
382
383- (void)peerConnection:(RTCPeerConnection *)peerConnection
384 didStartReceivingOnTransceiver:(RTCRtpTransceiver *)transceiver {
385 RTCMediaStreamTrack *track = transceiver.receiver.track;
386 RTCLog(@"Now receiving %@ on track %@.", track.kind, track.trackId);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000387}
388
389- (void)peerConnection:(RTCPeerConnection *)peerConnection
hjon79858f82016-03-13 22:08:26 -0700390 didRemoveStream:(RTCMediaStream *)stream {
tkchinc3f46a92015-07-23 12:50:55 -0700391 RTCLog(@"Stream was removed.");
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000392}
393
hjon79858f82016-03-13 22:08:26 -0700394- (void)peerConnectionShouldNegotiate:(RTCPeerConnection *)peerConnection {
tkchinc3f46a92015-07-23 12:50:55 -0700395 RTCLog(@"WARNING: Renegotiation needed but unimplemented.");
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000396}
397
398- (void)peerConnection:(RTCPeerConnection *)peerConnection
hjon79858f82016-03-13 22:08:26 -0700399 didChangeIceConnectionState:(RTCIceConnectionState)newState {
400 RTCLog(@"ICE state changed: %ld", (long)newState);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000401 dispatch_async(dispatch_get_main_queue(), ^{
402 [_delegate appClient:self didChangeConnectionState:newState];
403 });
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000404}
405
406- (void)peerConnection:(RTCPeerConnection *)peerConnection
hjon79858f82016-03-13 22:08:26 -0700407 didChangeIceGatheringState:(RTCIceGatheringState)newState {
408 RTCLog(@"ICE gathering state changed: %ld", (long)newState);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000409}
410
411- (void)peerConnection:(RTCPeerConnection *)peerConnection
hjon79858f82016-03-13 22:08:26 -0700412 didGenerateIceCandidate:(RTCIceCandidate *)candidate {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000413 dispatch_async(dispatch_get_main_queue(), ^{
414 ARDICECandidateMessage *message =
415 [[ARDICECandidateMessage alloc] initWithCandidate:candidate];
416 [self sendSignalingMessage:message];
417 });
418}
419
Zeke Chind3325802015-08-14 11:00:02 -0700420- (void)peerConnection:(RTCPeerConnection *)peerConnection
Honghai Zhangda2ba4d2016-05-23 11:53:14 -0700421 didRemoveIceCandidates:(NSArray<RTCIceCandidate *> *)candidates {
422 dispatch_async(dispatch_get_main_queue(), ^{
423 ARDICECandidateRemovalMessage *message =
424 [[ARDICECandidateRemovalMessage alloc]
425 initWithRemovedCandidates:candidates];
426 [self sendSignalingMessage:message];
427 });
428}
429
430- (void)peerConnection:(RTCPeerConnection *)peerConnection
Zeke Chind3325802015-08-14 11:00:02 -0700431 didOpenDataChannel:(RTCDataChannel *)dataChannel {
432}
433
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000434#pragma mark - RTCSessionDescriptionDelegate
tkchin@webrtc.org8cc47e92015-03-18 23:38:04 +0000435// Callbacks for this delegate occur on non-main thread and need to be
436// dispatched back to main queue as needed.
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000437
438- (void)peerConnection:(RTCPeerConnection *)peerConnection
439 didCreateSessionDescription:(RTCSessionDescription *)sdp
440 error:(NSError *)error {
441 dispatch_async(dispatch_get_main_queue(), ^{
442 if (error) {
tkchinc3f46a92015-07-23 12:50:55 -0700443 RTCLogError(@"Failed to create session description. Error: %@", error);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000444 [self disconnect];
445 NSDictionary *userInfo = @{
446 NSLocalizedDescriptionKey: @"Failed to create session description.",
447 };
448 NSError *sdpError =
449 [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
450 code:kARDAppClientErrorCreateSDP
451 userInfo:userInfo];
452 [_delegate appClient:self didError:sdpError];
453 return;
454 }
hjon79858f82016-03-13 22:08:26 -0700455 __weak ARDAppClient *weakSelf = self;
Anders Carlsson6bf43d22017-10-16 13:51:43 +0200456 [_peerConnection setLocalDescription:sdp
hjon79858f82016-03-13 22:08:26 -0700457 completionHandler:^(NSError *error) {
Anders Carlsson6bf43d22017-10-16 13:51:43 +0200458 ARDAppClient *strongSelf = weakSelf;
459 [strongSelf peerConnection:strongSelf.peerConnection
460 didSetSessionDescriptionWithError:error];
461 }];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000462 ARDSessionDescriptionMessage *message =
Anders Carlsson6bf43d22017-10-16 13:51:43 +0200463 [[ARDSessionDescriptionMessage alloc] initWithDescription:sdp];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000464 [self sendSignalingMessage:message];
denicija9af2b602016-11-17 00:43:43 -0800465 [self setMaxBitrateForPeerConnectionVideoSender];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000466 });
467}
468
469- (void)peerConnection:(RTCPeerConnection *)peerConnection
470 didSetSessionDescriptionWithError:(NSError *)error {
471 dispatch_async(dispatch_get_main_queue(), ^{
472 if (error) {
tkchinc3f46a92015-07-23 12:50:55 -0700473 RTCLogError(@"Failed to set session description. Error: %@", error);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000474 [self disconnect];
475 NSDictionary *userInfo = @{
476 NSLocalizedDescriptionKey: @"Failed to set session description.",
477 };
478 NSError *sdpError =
479 [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
480 code:kARDAppClientErrorSetSDP
481 userInfo:userInfo];
482 [_delegate appClient:self didError:sdpError];
483 return;
484 }
485 // If we're answering and we've just set the remote offer we need to create
486 // an answer and set the local description.
487 if (!_isInitiator && !_peerConnection.localDescription) {
488 RTCMediaConstraints *constraints = [self defaultAnswerConstraints];
hjon79858f82016-03-13 22:08:26 -0700489 __weak ARDAppClient *weakSelf = self;
490 [_peerConnection answerForConstraints:constraints
491 completionHandler:^(RTCSessionDescription *sdp,
492 NSError *error) {
493 ARDAppClient *strongSelf = weakSelf;
494 [strongSelf peerConnection:strongSelf.peerConnection
495 didCreateSessionDescription:sdp
496 error:error];
497 }];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000498 }
499 });
500}
501
502#pragma mark - Private
503
tkchin204177f2016-06-14 15:03:11 -0700504#if defined(WEBRTC_IOS)
505
506- (NSString *)documentsFilePathForFileName:(NSString *)fileName {
507 NSParameterAssert(fileName.length);
508 NSArray *paths = NSSearchPathForDirectoriesInDomains(
509 NSDocumentDirectory, NSUserDomainMask, YES);
510 NSString *documentsDirPath = paths.firstObject;
511 NSString *filePath =
512 [documentsDirPath stringByAppendingPathComponent:fileName];
513 return filePath;
514}
515
516#endif
517
tkchin@webrtc.org36401ab2015-01-27 21:34:39 +0000518- (BOOL)hasJoinedRoomServerRoom {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000519 return _clientId.length;
520}
521
tkchin@webrtc.org8cc47e92015-03-18 23:38:04 +0000522// Begins the peer connection connection process if we have both joined a room
523// on the room server and tried to obtain a TURN server. Otherwise does nothing.
524// A peer connection object will be created with a stream that contains local
525// audio and video capture. If this client is the caller, an offer is created as
526// well, otherwise the client will wait for an offer to arrive.
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000527- (void)startSignalingIfReady {
tkchin@webrtc.org36401ab2015-01-27 21:34:39 +0000528 if (!_isTurnComplete || !self.hasJoinedRoomServerRoom) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000529 return;
530 }
531 self.state = kARDAppClientStateConnected;
532
533 // Create peer connection.
534 RTCMediaConstraints *constraints = [self defaultPeerConnectionConstraints];
Zeke Chinbc7dd7e2015-05-29 14:59:14 -0700535 RTCConfiguration *config = [[RTCConfiguration alloc] init];
Michael Iedemaccee56b2018-07-05 15:28:24 +0200536 RTCCertificate *pcert = [RTCCertificate generateCertificateWithParams:@{
537 @"expires" : @100000,
538 @"name" : @"RSASSA-PKCS1-v1_5"
539 }];
Zeke Chinbc7dd7e2015-05-29 14:59:14 -0700540 config.iceServers = _iceServers;
Steve Antonaf23b752018-03-01 09:22:48 -0800541 config.sdpSemantics = RTCSdpSemanticsUnifiedPlan;
Michael Iedemaccee56b2018-07-05 15:28:24 +0200542 config.certificate = pcert;
543
Tze Kwang Chinf3cb49f2016-03-22 10:57:40 -0700544 _peerConnection = [_factory peerConnectionWithConfiguration:config
545 constraints:constraints
546 delegate:self];
skvladf3569c82016-04-29 15:30:16 -0700547 // Create AV senders.
Alex Narestb3944f02017-10-13 14:56:18 +0200548 [self createMediaSenders];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000549 if (_isInitiator) {
tkchin@webrtc.org8cc47e92015-03-18 23:38:04 +0000550 // Send offer.
hjon79858f82016-03-13 22:08:26 -0700551 __weak ARDAppClient *weakSelf = self;
552 [_peerConnection offerForConstraints:[self defaultOfferConstraints]
553 completionHandler:^(RTCSessionDescription *sdp,
554 NSError *error) {
555 ARDAppClient *strongSelf = weakSelf;
556 [strongSelf peerConnection:strongSelf.peerConnection
557 didCreateSessionDescription:sdp
558 error:error];
559 }];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000560 } else {
tkchin@webrtc.org8cc47e92015-03-18 23:38:04 +0000561 // Check if we've received an offer.
562 [self drainMessageQueueIfReady];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000563 }
ivoc14d5dbe2016-07-04 07:06:55 -0700564#if defined(WEBRTC_IOS)
565 // Start event log.
566 if (kARDAppClientEnableRtcEventLog) {
567 NSString *filePath = [self documentsFilePathForFileName:@"webrtc-rtceventlog"];
568 if (![_peerConnection startRtcEventLogWithFilePath:filePath
569 maxSizeInBytes:kARDAppClientRtcEventLogMaxSizeInBytes]) {
570 RTCLogError(@"Failed to start event logging.");
571 }
572 }
peah5085b0c2016-08-25 22:15:14 -0700573
574 // Start aecdump diagnostic recording.
Anders Carlssone1500582017-06-15 16:05:13 +0200575 if ([_settings currentCreateAecDumpSettingFromStore]) {
tkchinfce0e2c2016-08-30 12:58:11 -0700576 NSString *filePath = [self documentsFilePathForFileName:@"webrtc-audio.aecdump"];
577 if (![_factory startAecDumpWithFilePath:filePath
578 maxSizeInBytes:kARDAppClientAecDumpMaxSizeInBytes]) {
579 RTCLogError(@"Failed to start aec dump.");
peah5085b0c2016-08-25 22:15:14 -0700580 }
581 }
ivoc14d5dbe2016-07-04 07:06:55 -0700582#endif
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000583}
584
tkchin@webrtc.org8cc47e92015-03-18 23:38:04 +0000585// Processes the messages that we've received from the room server and the
586// signaling channel. The offer or answer message must be processed before other
587// signaling messages, however they can arrive out of order. Hence, this method
588// only processes pending messages if there is a peer connection object and
589// if we have received either an offer or answer.
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000590- (void)drainMessageQueueIfReady {
591 if (!_peerConnection || !_hasReceivedSdp) {
592 return;
593 }
594 for (ARDSignalingMessage *message in _messageQueue) {
595 [self processSignalingMessage:message];
596 }
597 [_messageQueue removeAllObjects];
598}
599
tkchin@webrtc.org8cc47e92015-03-18 23:38:04 +0000600// Processes the given signaling message based on its type.
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000601- (void)processSignalingMessage:(ARDSignalingMessage *)message {
602 NSParameterAssert(_peerConnection ||
603 message.type == kARDSignalingMessageTypeBye);
604 switch (message.type) {
605 case kARDSignalingMessageTypeOffer:
606 case kARDSignalingMessageTypeAnswer: {
607 ARDSessionDescriptionMessage *sdpMessage =
608 (ARDSessionDescriptionMessage *)message;
609 RTCSessionDescription *description = sdpMessage.sessionDescription;
hjon79858f82016-03-13 22:08:26 -0700610 __weak ARDAppClient *weakSelf = self;
Anders Carlsson6bf43d22017-10-16 13:51:43 +0200611 [_peerConnection setRemoteDescription:description
hjon79858f82016-03-13 22:08:26 -0700612 completionHandler:^(NSError *error) {
Anders Carlsson6bf43d22017-10-16 13:51:43 +0200613 ARDAppClient *strongSelf = weakSelf;
614 [strongSelf peerConnection:strongSelf.peerConnection
615 didSetSessionDescriptionWithError:error];
616 }];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000617 break;
618 }
619 case kARDSignalingMessageTypeCandidate: {
620 ARDICECandidateMessage *candidateMessage =
621 (ARDICECandidateMessage *)message;
hjon79858f82016-03-13 22:08:26 -0700622 [_peerConnection addIceCandidate:candidateMessage.candidate];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000623 break;
624 }
Honghai Zhangda2ba4d2016-05-23 11:53:14 -0700625 case kARDSignalingMessageTypeCandidateRemoval: {
626 ARDICECandidateRemovalMessage *candidateMessage =
627 (ARDICECandidateRemovalMessage *)message;
628 [_peerConnection removeIceCandidates:candidateMessage.candidates];
629 break;
630 }
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000631 case kARDSignalingMessageTypeBye:
632 // Other client disconnected.
633 // TODO(tkchin): support waiting in room for next client. For now just
634 // disconnect.
635 [self disconnect];
636 break;
637 }
638}
639
tkchin@webrtc.org8cc47e92015-03-18 23:38:04 +0000640// Sends a signaling message to the other client. The caller will send messages
641// through the room server, whereas the callee will send messages over the
642// signaling channel.
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000643- (void)sendSignalingMessage:(ARDSignalingMessage *)message {
644 if (_isInitiator) {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000645 __weak ARDAppClient *weakSelf = self;
646 [_roomServerClient sendMessage:message
647 forRoomId:_roomId
648 clientId:_clientId
649 completionHandler:^(ARDMessageResponse *response,
650 NSError *error) {
651 ARDAppClient *strongSelf = weakSelf;
652 if (error) {
653 [strongSelf.delegate appClient:strongSelf didError:error];
654 return;
655 }
656 NSError *messageError =
657 [[strongSelf class] errorForMessageResultType:response.result];
658 if (messageError) {
659 [strongSelf.delegate appClient:strongSelf didError:messageError];
660 return;
661 }
662 }];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000663 } else {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000664 [_channel sendMessage:message];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000665 }
666}
667
denicija9af2b602016-11-17 00:43:43 -0800668- (void)setMaxBitrateForPeerConnectionVideoSender {
669 for (RTCRtpSender *sender in _peerConnection.senders) {
670 if (sender.track != nil) {
671 if ([sender.track.kind isEqualToString:kARDVideoTrackKind]) {
sakalc4adacf2017-03-28 01:22:48 -0700672 [self setMaxBitrate:[_settings currentMaxBitrateSettingFromStore] forVideoSender:sender];
denicija9af2b602016-11-17 00:43:43 -0800673 }
674 }
denicija8c375de2016-11-08 06:28:17 -0800675 }
676}
677
denicija9af2b602016-11-17 00:43:43 -0800678- (void)setMaxBitrate:(NSNumber *)maxBitrate forVideoSender:(RTCRtpSender *)sender {
679 if (maxBitrate.intValue <= 0) {
680 return;
681 }
682
683 RTCRtpParameters *parametersToModify = sender.parameters;
684 for (RTCRtpEncodingParameters *encoding in parametersToModify.encodings) {
685 encoding.maxBitrateBps = @(maxBitrate.intValue * kKbpsMultiplier);
686 }
687 [sender setParameters:parametersToModify];
688}
689
Steve Antonaf23b752018-03-01 09:22:48 -0800690- (RTCRtpTransceiver *)videoTransceiver {
691 for (RTCRtpTransceiver *transceiver in _peerConnection.transceivers) {
692 if (transceiver.mediaType == RTCRtpMediaTypeVideo) {
693 return transceiver;
694 }
695 }
696 return nil;
697}
698
Alex Narestb3944f02017-10-13 14:56:18 +0200699- (void)createMediaSenders {
tkchinab1293a2016-08-30 12:35:05 -0700700 RTCMediaConstraints *constraints = [self defaultMediaAudioConstraints];
701 RTCAudioSource *source = [_factory audioSourceWithConstraints:constraints];
702 RTCAudioTrack *track = [_factory audioTrackWithSource:source
703 trackId:kARDAudioTrackId];
Seth Hampson513449e2018-03-06 09:35:56 -0800704 [_peerConnection addTrack:track streamIds:@[ kARDMediaStreamId ]];
Alex Narestb3944f02017-10-13 14:56:18 +0200705 _localVideoTrack = [self createLocalVideoTrack];
706 if (_localVideoTrack) {
Seth Hampson513449e2018-03-06 09:35:56 -0800707 [_peerConnection addTrack:_localVideoTrack streamIds:@[ kARDMediaStreamId ]];
Piasy Xue7e06022018-05-30 23:31:07 +0800708 [_delegate appClient:self didReceiveLocalVideoTrack:_localVideoTrack];
Steve Antonaf23b752018-03-01 09:22:48 -0800709 // We can set up rendering for the remote track right away since the transceiver already has an
710 // RTCRtpReceiver with a track. The track will automatically get unmuted and produce frames
711 // once RTP is received.
712 RTCVideoTrack *track = (RTCVideoTrack *)([self videoTransceiver].receiver.track);
713 [_delegate appClient:self didReceiveRemoteVideoTrack:track];
Alex Narestb3944f02017-10-13 14:56:18 +0200714 }
Zeke Chin57cc74e2015-05-05 07:52:31 -0700715}
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000716
Zeke Chin57cc74e2015-05-05 07:52:31 -0700717- (RTCVideoTrack *)createLocalVideoTrack {
Daniela012b56b2017-11-15 13:15:24 +0100718 if ([_settings currentAudioOnlySettingFromStore]) {
719 return nil;
720 }
721
722 RTCVideoSource *source = [_factory videoSource];
723
kthelgason314bc5f2016-08-31 10:23:27 -0700724#if !TARGET_IPHONE_SIMULATOR
Anders Carlsson358f2e02018-06-04 10:24:37 +0200725 if (self.isBroadcast) {
726 ARDExternalSampleCapturer *capturer =
727 [[ARDExternalSampleCapturer alloc] initWithDelegate:source];
728 [_delegate appClient:self didCreateLocalExternalSampleCapturer:capturer];
729 } else {
730 RTCCameraVideoCapturer *capturer = [[RTCCameraVideoCapturer alloc] initWithDelegate:source];
731 [_delegate appClient:self didCreateLocalCapturer:capturer];
732 }
Daniela012b56b2017-11-15 13:15:24 +0100733#else
734#if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
735 if (@available(iOS 10, *)) {
736 RTCFileVideoCapturer *fileCapturer = [[RTCFileVideoCapturer alloc] initWithDelegate:source];
737 [_delegate appClient:self didCreateLocalFileCapturer:fileCapturer];
haysc913e6452015-10-02 11:44:03 -0700738 }
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000739#endif
Daniela012b56b2017-11-15 13:15:24 +0100740#endif
741
742 return [_factory videoTrackWithSource:source trackId:kARDVideoTrackId];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000743}
744
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000745#pragma mark - Collider methods
746
747- (void)registerWithColliderIfReady {
tkchin@webrtc.org36401ab2015-01-27 21:34:39 +0000748 if (!self.hasJoinedRoomServerRoom) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000749 return;
750 }
751 // Open WebSocket connection.
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000752 if (!_channel) {
753 _channel =
754 [[ARDWebSocketChannel alloc] initWithURL:_websocketURL
755 restURL:_websocketRestURL
756 delegate:self];
haysc913e6452015-10-02 11:44:03 -0700757 if (_isLoopback) {
758 _loopbackChannel =
759 [[ARDLoopbackWebSocketChannel alloc] initWithURL:_websocketURL
760 restURL:_websocketRestURL];
761 }
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000762 }
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000763 [_channel registerForRoomId:_roomId clientId:_clientId];
haysc913e6452015-10-02 11:44:03 -0700764 if (_isLoopback) {
765 [_loopbackChannel registerForRoomId:_roomId clientId:@"LOOPBACK_CLIENT_ID"];
766 }
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000767}
768
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000769#pragma mark - Defaults
770
tkchinab1293a2016-08-30 12:35:05 -0700771 - (RTCMediaConstraints *)defaultMediaAudioConstraints {
Sam Zackrisson9e981f02018-02-28 16:20:58 +0100772 NSDictionary *mandatoryConstraints = @{};
denicijad17d5362016-11-02 02:56:09 -0700773 RTCMediaConstraints *constraints =
774 [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatoryConstraints
775 optionalConstraints:nil];
tkchinab1293a2016-08-30 12:35:05 -0700776 return constraints;
777}
778
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000779- (RTCMediaConstraints *)defaultAnswerConstraints {
780 return [self defaultOfferConstraints];
781}
782
783- (RTCMediaConstraints *)defaultOfferConstraints {
hjon79858f82016-03-13 22:08:26 -0700784 NSDictionary *mandatoryConstraints = @{
785 @"OfferToReceiveAudio" : @"true",
786 @"OfferToReceiveVideo" : @"true"
787 };
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000788 RTCMediaConstraints* constraints =
789 [[RTCMediaConstraints alloc]
790 initWithMandatoryConstraints:mandatoryConstraints
791 optionalConstraints:nil];
792 return constraints;
793}
794
795- (RTCMediaConstraints *)defaultPeerConnectionConstraints {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000796 if (_defaultPeerConnectionConstraints) {
797 return _defaultPeerConnectionConstraints;
798 }
haysc913e6452015-10-02 11:44:03 -0700799 NSString *value = _isLoopback ? @"false" : @"true";
hjon79858f82016-03-13 22:08:26 -0700800 NSDictionary *optionalConstraints = @{ @"DtlsSrtpKeyAgreement" : value };
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000801 RTCMediaConstraints* constraints =
802 [[RTCMediaConstraints alloc]
803 initWithMandatoryConstraints:nil
804 optionalConstraints:optionalConstraints];
805 return constraints;
806}
807
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000808#pragma mark - Errors
809
tkchin@webrtc.org36401ab2015-01-27 21:34:39 +0000810+ (NSError *)errorForJoinResultType:(ARDJoinResultType)resultType {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000811 NSError *error = nil;
812 switch (resultType) {
tkchin@webrtc.org36401ab2015-01-27 21:34:39 +0000813 case kARDJoinResultTypeSuccess:
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000814 break;
tkchin@webrtc.org36401ab2015-01-27 21:34:39 +0000815 case kARDJoinResultTypeUnknown: {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000816 error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
817 code:kARDAppClientErrorUnknown
818 userInfo:@{
819 NSLocalizedDescriptionKey: @"Unknown error.",
820 }];
821 break;
822 }
tkchin@webrtc.org36401ab2015-01-27 21:34:39 +0000823 case kARDJoinResultTypeFull: {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000824 error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
825 code:kARDAppClientErrorRoomFull
826 userInfo:@{
827 NSLocalizedDescriptionKey: @"Room is full.",
828 }];
829 break;
830 }
831 }
832 return error;
833}
834
835+ (NSError *)errorForMessageResultType:(ARDMessageResultType)resultType {
836 NSError *error = nil;
837 switch (resultType) {
838 case kARDMessageResultTypeSuccess:
839 break;
840 case kARDMessageResultTypeUnknown:
841 error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
842 code:kARDAppClientErrorUnknown
843 userInfo:@{
844 NSLocalizedDescriptionKey: @"Unknown error.",
845 }];
846 break;
847 case kARDMessageResultTypeInvalidClient:
848 error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
849 code:kARDAppClientErrorInvalidClient
850 userInfo:@{
851 NSLocalizedDescriptionKey: @"Invalid client.",
852 }];
853 break;
854 case kARDMessageResultTypeInvalidRoom:
855 error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
856 code:kARDAppClientErrorInvalidRoom
857 userInfo:@{
858 NSLocalizedDescriptionKey: @"Invalid room.",
859 }];
860 break;
861 }
862 return error;
863}
864
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000865@end