xref: /aosp_15_r20/external/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker/*
2*d9f75844SAndroid Build Coastguard Worker *  Copyright 2014 The WebRTC Project Authors. All rights reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker#import "ARDAppClient+Internal.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/api/peerconnection/RTCAudioTrack.h"
14*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/api/peerconnection/RTCConfiguration.h"
15*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/api/peerconnection/RTCFileLogger.h"
16*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/api/peerconnection/RTCIceCandidateErrorEvent.h"
17*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/api/peerconnection/RTCIceServer.h"
18*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/api/peerconnection/RTCMediaConstraints.h"
19*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/api/peerconnection/RTCMediaStream.h"
20*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h"
21*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/api/peerconnection/RTCRtpSender.h"
22*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/api/peerconnection/RTCRtpTransceiver.h"
23*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/api/peerconnection/RTCTracing.h"
24*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/api/peerconnection/RTCVideoSource.h"
25*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/api/peerconnection/RTCVideoTrack.h"
26*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/base/RTCLogging.h"
27*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/components/capturer/RTCCameraVideoCapturer.h"
28*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/components/capturer/RTCFileVideoCapturer.h"
29*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/components/video_codec/RTCDefaultVideoDecoderFactory.h"
30*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/components/video_codec/RTCDefaultVideoEncoderFactory.h"
31*d9f75844SAndroid Build Coastguard Worker
32*d9f75844SAndroid Build Coastguard Worker#import "ARDAppEngineClient.h"
33*d9f75844SAndroid Build Coastguard Worker#import "ARDExternalSampleCapturer.h"
34*d9f75844SAndroid Build Coastguard Worker#import "ARDJoinResponse.h"
35*d9f75844SAndroid Build Coastguard Worker#import "ARDMessageResponse.h"
36*d9f75844SAndroid Build Coastguard Worker#import "ARDSettingsModel.h"
37*d9f75844SAndroid Build Coastguard Worker#import "ARDSignalingMessage.h"
38*d9f75844SAndroid Build Coastguard Worker#import "ARDTURNClient+Internal.h"
39*d9f75844SAndroid Build Coastguard Worker#import "ARDUtilities.h"
40*d9f75844SAndroid Build Coastguard Worker#import "ARDWebSocketChannel.h"
41*d9f75844SAndroid Build Coastguard Worker#import "RTCIceCandidate+JSON.h"
42*d9f75844SAndroid Build Coastguard Worker#import "RTCSessionDescription+JSON.h"
43*d9f75844SAndroid Build Coastguard Worker
44*d9f75844SAndroid Build Coastguard Workerstatic NSString * const kARDIceServerRequestUrl = @"https://appr.tc/params";
45*d9f75844SAndroid Build Coastguard Worker
46*d9f75844SAndroid Build Coastguard Workerstatic NSString * const kARDAppClientErrorDomain = @"ARDAppClient";
47*d9f75844SAndroid Build Coastguard Workerstatic NSInteger const kARDAppClientErrorUnknown = -1;
48*d9f75844SAndroid Build Coastguard Workerstatic NSInteger const kARDAppClientErrorRoomFull = -2;
49*d9f75844SAndroid Build Coastguard Workerstatic NSInteger const kARDAppClientErrorCreateSDP = -3;
50*d9f75844SAndroid Build Coastguard Workerstatic NSInteger const kARDAppClientErrorSetSDP = -4;
51*d9f75844SAndroid Build Coastguard Workerstatic NSInteger const kARDAppClientErrorInvalidClient = -5;
52*d9f75844SAndroid Build Coastguard Workerstatic NSInteger const kARDAppClientErrorInvalidRoom = -6;
53*d9f75844SAndroid Build Coastguard Workerstatic NSString * const kARDMediaStreamId = @"ARDAMS";
54*d9f75844SAndroid Build Coastguard Workerstatic NSString * const kARDAudioTrackId = @"ARDAMSa0";
55*d9f75844SAndroid Build Coastguard Workerstatic NSString * const kARDVideoTrackId = @"ARDAMSv0";
56*d9f75844SAndroid Build Coastguard Workerstatic NSString * const kARDVideoTrackKind = @"video";
57*d9f75844SAndroid Build Coastguard Worker
58*d9f75844SAndroid Build Coastguard Worker// TODO(tkchin): Add these as UI options.
59*d9f75844SAndroid Build Coastguard Worker#if defined(WEBRTC_IOS)
60*d9f75844SAndroid Build Coastguard Workerstatic BOOL const kARDAppClientEnableTracing = NO;
61*d9f75844SAndroid Build Coastguard Workerstatic BOOL const kARDAppClientEnableRtcEventLog = YES;
62*d9f75844SAndroid Build Coastguard Workerstatic int64_t const kARDAppClientAecDumpMaxSizeInBytes = 5e6;  // 5 MB.
63*d9f75844SAndroid Build Coastguard Workerstatic int64_t const kARDAppClientRtcEventLogMaxSizeInBytes = 5e6;  // 5 MB.
64*d9f75844SAndroid Build Coastguard Worker#endif
65*d9f75844SAndroid Build Coastguard Workerstatic int const kKbpsMultiplier = 1000;
66*d9f75844SAndroid Build Coastguard Worker
67*d9f75844SAndroid Build Coastguard Worker// We need a proxy to NSTimer because it causes a strong retain cycle. When
68*d9f75844SAndroid Build Coastguard Worker// using the proxy, `invalidate` must be called before it properly deallocs.
69*d9f75844SAndroid Build Coastguard Worker@interface ARDTimerProxy : NSObject
70*d9f75844SAndroid Build Coastguard Worker
71*d9f75844SAndroid Build Coastguard Worker- (instancetype)initWithInterval:(NSTimeInterval)interval
72*d9f75844SAndroid Build Coastguard Worker                         repeats:(BOOL)repeats
73*d9f75844SAndroid Build Coastguard Worker                    timerHandler:(void (^)(void))timerHandler;
74*d9f75844SAndroid Build Coastguard Worker- (void)invalidate;
75*d9f75844SAndroid Build Coastguard Worker
76*d9f75844SAndroid Build Coastguard Worker@end
77*d9f75844SAndroid Build Coastguard Worker
78*d9f75844SAndroid Build Coastguard Worker@implementation ARDTimerProxy {
79*d9f75844SAndroid Build Coastguard Worker  NSTimer *_timer;
80*d9f75844SAndroid Build Coastguard Worker  void (^_timerHandler)(void);
81*d9f75844SAndroid Build Coastguard Worker}
82*d9f75844SAndroid Build Coastguard Worker
83*d9f75844SAndroid Build Coastguard Worker- (instancetype)initWithInterval:(NSTimeInterval)interval
84*d9f75844SAndroid Build Coastguard Worker                         repeats:(BOOL)repeats
85*d9f75844SAndroid Build Coastguard Worker                    timerHandler:(void (^)(void))timerHandler {
86*d9f75844SAndroid Build Coastguard Worker  NSParameterAssert(timerHandler);
87*d9f75844SAndroid Build Coastguard Worker  if (self = [super init]) {
88*d9f75844SAndroid Build Coastguard Worker    _timerHandler = timerHandler;
89*d9f75844SAndroid Build Coastguard Worker    _timer = [NSTimer scheduledTimerWithTimeInterval:interval
90*d9f75844SAndroid Build Coastguard Worker                                              target:self
91*d9f75844SAndroid Build Coastguard Worker                                            selector:@selector(timerDidFire:)
92*d9f75844SAndroid Build Coastguard Worker                                            userInfo:nil
93*d9f75844SAndroid Build Coastguard Worker                                             repeats:repeats];
94*d9f75844SAndroid Build Coastguard Worker  }
95*d9f75844SAndroid Build Coastguard Worker  return self;
96*d9f75844SAndroid Build Coastguard Worker}
97*d9f75844SAndroid Build Coastguard Worker
98*d9f75844SAndroid Build Coastguard Worker- (void)invalidate {
99*d9f75844SAndroid Build Coastguard Worker  [_timer invalidate];
100*d9f75844SAndroid Build Coastguard Worker}
101*d9f75844SAndroid Build Coastguard Worker
102*d9f75844SAndroid Build Coastguard Worker- (void)timerDidFire:(NSTimer *)timer {
103*d9f75844SAndroid Build Coastguard Worker  _timerHandler();
104*d9f75844SAndroid Build Coastguard Worker}
105*d9f75844SAndroid Build Coastguard Worker
106*d9f75844SAndroid Build Coastguard Worker@end
107*d9f75844SAndroid Build Coastguard Worker
108*d9f75844SAndroid Build Coastguard Worker@implementation ARDAppClient {
109*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCFileLogger) * _fileLogger;
110*d9f75844SAndroid Build Coastguard Worker  ARDTimerProxy *_statsTimer;
111*d9f75844SAndroid Build Coastguard Worker  ARDSettingsModel *_settings;
112*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCVideoTrack) * _localVideoTrack;
113*d9f75844SAndroid Build Coastguard Worker}
114*d9f75844SAndroid Build Coastguard Worker
115*d9f75844SAndroid Build Coastguard Worker@synthesize shouldGetStats = _shouldGetStats;
116*d9f75844SAndroid Build Coastguard Worker@synthesize state = _state;
117*d9f75844SAndroid Build Coastguard Worker@synthesize delegate = _delegate;
118*d9f75844SAndroid Build Coastguard Worker@synthesize roomServerClient = _roomServerClient;
119*d9f75844SAndroid Build Coastguard Worker@synthesize channel = _channel;
120*d9f75844SAndroid Build Coastguard Worker@synthesize loopbackChannel = _loopbackChannel;
121*d9f75844SAndroid Build Coastguard Worker@synthesize turnClient = _turnClient;
122*d9f75844SAndroid Build Coastguard Worker@synthesize peerConnection = _peerConnection;
123*d9f75844SAndroid Build Coastguard Worker@synthesize factory = _factory;
124*d9f75844SAndroid Build Coastguard Worker@synthesize messageQueue = _messageQueue;
125*d9f75844SAndroid Build Coastguard Worker@synthesize isTurnComplete = _isTurnComplete;
126*d9f75844SAndroid Build Coastguard Worker@synthesize hasReceivedSdp  = _hasReceivedSdp;
127*d9f75844SAndroid Build Coastguard Worker@synthesize roomId = _roomId;
128*d9f75844SAndroid Build Coastguard Worker@synthesize clientId = _clientId;
129*d9f75844SAndroid Build Coastguard Worker@synthesize isInitiator = _isInitiator;
130*d9f75844SAndroid Build Coastguard Worker@synthesize iceServers = _iceServers;
131*d9f75844SAndroid Build Coastguard Worker@synthesize webSocketURL = _websocketURL;
132*d9f75844SAndroid Build Coastguard Worker@synthesize webSocketRestURL = _websocketRestURL;
133*d9f75844SAndroid Build Coastguard Worker@synthesize defaultPeerConnectionConstraints =
134*d9f75844SAndroid Build Coastguard Worker    _defaultPeerConnectionConstraints;
135*d9f75844SAndroid Build Coastguard Worker@synthesize isLoopback = _isLoopback;
136*d9f75844SAndroid Build Coastguard Worker@synthesize broadcast = _broadcast;
137*d9f75844SAndroid Build Coastguard Worker
138*d9f75844SAndroid Build Coastguard Worker- (instancetype)init {
139*d9f75844SAndroid Build Coastguard Worker  return [self initWithDelegate:nil];
140*d9f75844SAndroid Build Coastguard Worker}
141*d9f75844SAndroid Build Coastguard Worker
142*d9f75844SAndroid Build Coastguard Worker- (instancetype)initWithDelegate:(id<ARDAppClientDelegate>)delegate {
143*d9f75844SAndroid Build Coastguard Worker  if (self = [super init]) {
144*d9f75844SAndroid Build Coastguard Worker    _roomServerClient = [[ARDAppEngineClient alloc] init];
145*d9f75844SAndroid Build Coastguard Worker    _delegate = delegate;
146*d9f75844SAndroid Build Coastguard Worker    NSURL *turnRequestURL = [NSURL URLWithString:kARDIceServerRequestUrl];
147*d9f75844SAndroid Build Coastguard Worker    _turnClient = [[ARDTURNClient alloc] initWithURL:turnRequestURL];
148*d9f75844SAndroid Build Coastguard Worker    [self configure];
149*d9f75844SAndroid Build Coastguard Worker  }
150*d9f75844SAndroid Build Coastguard Worker  return self;
151*d9f75844SAndroid Build Coastguard Worker}
152*d9f75844SAndroid Build Coastguard Worker
153*d9f75844SAndroid Build Coastguard Worker// TODO(tkchin): Provide signaling channel factory interface so we can recreate
154*d9f75844SAndroid Build Coastguard Worker// channel if we need to on network failure. Also, make this the default public
155*d9f75844SAndroid Build Coastguard Worker// constructor.
156*d9f75844SAndroid Build Coastguard Worker- (instancetype)initWithRoomServerClient:(id<ARDRoomServerClient>)rsClient
157*d9f75844SAndroid Build Coastguard Worker                        signalingChannel:(id<ARDSignalingChannel>)channel
158*d9f75844SAndroid Build Coastguard Worker                              turnClient:(id<ARDTURNClient>)turnClient
159*d9f75844SAndroid Build Coastguard Worker                                delegate:(id<ARDAppClientDelegate>)delegate {
160*d9f75844SAndroid Build Coastguard Worker  NSParameterAssert(rsClient);
161*d9f75844SAndroid Build Coastguard Worker  NSParameterAssert(channel);
162*d9f75844SAndroid Build Coastguard Worker  NSParameterAssert(turnClient);
163*d9f75844SAndroid Build Coastguard Worker  if (self = [super init]) {
164*d9f75844SAndroid Build Coastguard Worker    _roomServerClient = rsClient;
165*d9f75844SAndroid Build Coastguard Worker    _channel = channel;
166*d9f75844SAndroid Build Coastguard Worker    _turnClient = turnClient;
167*d9f75844SAndroid Build Coastguard Worker    _delegate = delegate;
168*d9f75844SAndroid Build Coastguard Worker    [self configure];
169*d9f75844SAndroid Build Coastguard Worker  }
170*d9f75844SAndroid Build Coastguard Worker  return self;
171*d9f75844SAndroid Build Coastguard Worker}
172*d9f75844SAndroid Build Coastguard Worker
173*d9f75844SAndroid Build Coastguard Worker- (void)configure {
174*d9f75844SAndroid Build Coastguard Worker  _messageQueue = [NSMutableArray array];
175*d9f75844SAndroid Build Coastguard Worker  _iceServers = [NSMutableArray array];
176*d9f75844SAndroid Build Coastguard Worker  _fileLogger = [[RTC_OBJC_TYPE(RTCFileLogger) alloc] init];
177*d9f75844SAndroid Build Coastguard Worker  [_fileLogger start];
178*d9f75844SAndroid Build Coastguard Worker}
179*d9f75844SAndroid Build Coastguard Worker
180*d9f75844SAndroid Build Coastguard Worker- (void)dealloc {
181*d9f75844SAndroid Build Coastguard Worker  self.shouldGetStats = NO;
182*d9f75844SAndroid Build Coastguard Worker  [self disconnect];
183*d9f75844SAndroid Build Coastguard Worker}
184*d9f75844SAndroid Build Coastguard Worker
185*d9f75844SAndroid Build Coastguard Worker- (void)setShouldGetStats:(BOOL)shouldGetStats {
186*d9f75844SAndroid Build Coastguard Worker  if (_shouldGetStats == shouldGetStats) {
187*d9f75844SAndroid Build Coastguard Worker    return;
188*d9f75844SAndroid Build Coastguard Worker  }
189*d9f75844SAndroid Build Coastguard Worker  if (shouldGetStats) {
190*d9f75844SAndroid Build Coastguard Worker    __weak ARDAppClient *weakSelf = self;
191*d9f75844SAndroid Build Coastguard Worker    _statsTimer = [[ARDTimerProxy alloc] initWithInterval:1
192*d9f75844SAndroid Build Coastguard Worker                                                  repeats:YES
193*d9f75844SAndroid Build Coastguard Worker                                             timerHandler:^{
194*d9f75844SAndroid Build Coastguard Worker      ARDAppClient *strongSelf = weakSelf;
195*d9f75844SAndroid Build Coastguard Worker      [strongSelf.peerConnection statisticsWithCompletionHandler:^(
196*d9f75844SAndroid Build Coastguard Worker                                     RTC_OBJC_TYPE(RTCStatisticsReport) * stats) {
197*d9f75844SAndroid Build Coastguard Worker        dispatch_async(dispatch_get_main_queue(), ^{
198*d9f75844SAndroid Build Coastguard Worker          ARDAppClient *strongSelf = weakSelf;
199*d9f75844SAndroid Build Coastguard Worker          [strongSelf.delegate appClient:strongSelf didGetStats:stats];
200*d9f75844SAndroid Build Coastguard Worker        });
201*d9f75844SAndroid Build Coastguard Worker      }];
202*d9f75844SAndroid Build Coastguard Worker    }];
203*d9f75844SAndroid Build Coastguard Worker  } else {
204*d9f75844SAndroid Build Coastguard Worker    [_statsTimer invalidate];
205*d9f75844SAndroid Build Coastguard Worker    _statsTimer = nil;
206*d9f75844SAndroid Build Coastguard Worker  }
207*d9f75844SAndroid Build Coastguard Worker  _shouldGetStats = shouldGetStats;
208*d9f75844SAndroid Build Coastguard Worker}
209*d9f75844SAndroid Build Coastguard Worker
210*d9f75844SAndroid Build Coastguard Worker- (void)setState:(ARDAppClientState)state {
211*d9f75844SAndroid Build Coastguard Worker  if (_state == state) {
212*d9f75844SAndroid Build Coastguard Worker    return;
213*d9f75844SAndroid Build Coastguard Worker  }
214*d9f75844SAndroid Build Coastguard Worker  _state = state;
215*d9f75844SAndroid Build Coastguard Worker  [_delegate appClient:self didChangeState:_state];
216*d9f75844SAndroid Build Coastguard Worker}
217*d9f75844SAndroid Build Coastguard Worker
218*d9f75844SAndroid Build Coastguard Worker- (void)connectToRoomWithId:(NSString *)roomId
219*d9f75844SAndroid Build Coastguard Worker                   settings:(ARDSettingsModel *)settings
220*d9f75844SAndroid Build Coastguard Worker                 isLoopback:(BOOL)isLoopback {
221*d9f75844SAndroid Build Coastguard Worker  NSParameterAssert(roomId.length);
222*d9f75844SAndroid Build Coastguard Worker  NSParameterAssert(_state == kARDAppClientStateDisconnected);
223*d9f75844SAndroid Build Coastguard Worker  _settings = settings;
224*d9f75844SAndroid Build Coastguard Worker  _isLoopback = isLoopback;
225*d9f75844SAndroid Build Coastguard Worker  self.state = kARDAppClientStateConnecting;
226*d9f75844SAndroid Build Coastguard Worker
227*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCDefaultVideoDecoderFactory) *decoderFactory =
228*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCDefaultVideoDecoderFactory) alloc] init];
229*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCDefaultVideoEncoderFactory) *encoderFactory =
230*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCDefaultVideoEncoderFactory) alloc] init];
231*d9f75844SAndroid Build Coastguard Worker  encoderFactory.preferredCodec = [settings currentVideoCodecSettingFromStore];
232*d9f75844SAndroid Build Coastguard Worker  _factory =
233*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCPeerConnectionFactory) alloc] initWithEncoderFactory:encoderFactory
234*d9f75844SAndroid Build Coastguard Worker                                                               decoderFactory:decoderFactory];
235*d9f75844SAndroid Build Coastguard Worker
236*d9f75844SAndroid Build Coastguard Worker#if defined(WEBRTC_IOS)
237*d9f75844SAndroid Build Coastguard Worker  if (kARDAppClientEnableTracing) {
238*d9f75844SAndroid Build Coastguard Worker    NSString *filePath = [self documentsFilePathForFileName:@"webrtc-trace.txt"];
239*d9f75844SAndroid Build Coastguard Worker    RTCStartInternalCapture(filePath);
240*d9f75844SAndroid Build Coastguard Worker  }
241*d9f75844SAndroid Build Coastguard Worker#endif
242*d9f75844SAndroid Build Coastguard Worker
243*d9f75844SAndroid Build Coastguard Worker  // Request TURN.
244*d9f75844SAndroid Build Coastguard Worker  __weak ARDAppClient *weakSelf = self;
245*d9f75844SAndroid Build Coastguard Worker  [_turnClient requestServersWithCompletionHandler:^(NSArray *turnServers,
246*d9f75844SAndroid Build Coastguard Worker                                                     NSError *error) {
247*d9f75844SAndroid Build Coastguard Worker    if (error) {
248*d9f75844SAndroid Build Coastguard Worker      RTCLogError(@"Error retrieving TURN servers: %@", error.localizedDescription);
249*d9f75844SAndroid Build Coastguard Worker    }
250*d9f75844SAndroid Build Coastguard Worker    ARDAppClient *strongSelf = weakSelf;
251*d9f75844SAndroid Build Coastguard Worker    [strongSelf.iceServers addObjectsFromArray:turnServers];
252*d9f75844SAndroid Build Coastguard Worker    strongSelf.isTurnComplete = YES;
253*d9f75844SAndroid Build Coastguard Worker    [strongSelf startSignalingIfReady];
254*d9f75844SAndroid Build Coastguard Worker  }];
255*d9f75844SAndroid Build Coastguard Worker
256*d9f75844SAndroid Build Coastguard Worker  // Join room on room server.
257*d9f75844SAndroid Build Coastguard Worker  [_roomServerClient joinRoomWithRoomId:roomId
258*d9f75844SAndroid Build Coastguard Worker                             isLoopback:isLoopback
259*d9f75844SAndroid Build Coastguard Worker      completionHandler:^(ARDJoinResponse *response, NSError *error) {
260*d9f75844SAndroid Build Coastguard Worker    ARDAppClient *strongSelf = weakSelf;
261*d9f75844SAndroid Build Coastguard Worker    if (error) {
262*d9f75844SAndroid Build Coastguard Worker      [strongSelf.delegate appClient:strongSelf didError:error];
263*d9f75844SAndroid Build Coastguard Worker      return;
264*d9f75844SAndroid Build Coastguard Worker    }
265*d9f75844SAndroid Build Coastguard Worker    NSError *joinError =
266*d9f75844SAndroid Build Coastguard Worker        [[strongSelf class] errorForJoinResultType:response.result];
267*d9f75844SAndroid Build Coastguard Worker    if (joinError) {
268*d9f75844SAndroid Build Coastguard Worker      RTCLogError(@"Failed to join room:%@ on room server.", roomId);
269*d9f75844SAndroid Build Coastguard Worker      [strongSelf disconnect];
270*d9f75844SAndroid Build Coastguard Worker      [strongSelf.delegate appClient:strongSelf didError:joinError];
271*d9f75844SAndroid Build Coastguard Worker      return;
272*d9f75844SAndroid Build Coastguard Worker    }
273*d9f75844SAndroid Build Coastguard Worker    RTCLog(@"Joined room:%@ on room server.", roomId);
274*d9f75844SAndroid Build Coastguard Worker    strongSelf.roomId = response.roomId;
275*d9f75844SAndroid Build Coastguard Worker    strongSelf.clientId = response.clientId;
276*d9f75844SAndroid Build Coastguard Worker    strongSelf.isInitiator = response.isInitiator;
277*d9f75844SAndroid Build Coastguard Worker    for (ARDSignalingMessage *message in response.messages) {
278*d9f75844SAndroid Build Coastguard Worker      if (message.type == kARDSignalingMessageTypeOffer ||
279*d9f75844SAndroid Build Coastguard Worker          message.type == kARDSignalingMessageTypeAnswer) {
280*d9f75844SAndroid Build Coastguard Worker        strongSelf.hasReceivedSdp = YES;
281*d9f75844SAndroid Build Coastguard Worker        [strongSelf.messageQueue insertObject:message atIndex:0];
282*d9f75844SAndroid Build Coastguard Worker      } else {
283*d9f75844SAndroid Build Coastguard Worker        [strongSelf.messageQueue addObject:message];
284*d9f75844SAndroid Build Coastguard Worker      }
285*d9f75844SAndroid Build Coastguard Worker    }
286*d9f75844SAndroid Build Coastguard Worker    strongSelf.webSocketURL = response.webSocketURL;
287*d9f75844SAndroid Build Coastguard Worker    strongSelf.webSocketRestURL = response.webSocketRestURL;
288*d9f75844SAndroid Build Coastguard Worker    [strongSelf registerWithColliderIfReady];
289*d9f75844SAndroid Build Coastguard Worker    [strongSelf startSignalingIfReady];
290*d9f75844SAndroid Build Coastguard Worker  }];
291*d9f75844SAndroid Build Coastguard Worker}
292*d9f75844SAndroid Build Coastguard Worker
293*d9f75844SAndroid Build Coastguard Worker- (void)disconnect {
294*d9f75844SAndroid Build Coastguard Worker  if (_state == kARDAppClientStateDisconnected) {
295*d9f75844SAndroid Build Coastguard Worker    return;
296*d9f75844SAndroid Build Coastguard Worker  }
297*d9f75844SAndroid Build Coastguard Worker  if (self.hasJoinedRoomServerRoom) {
298*d9f75844SAndroid Build Coastguard Worker    [_roomServerClient leaveRoomWithRoomId:_roomId
299*d9f75844SAndroid Build Coastguard Worker                                  clientId:_clientId
300*d9f75844SAndroid Build Coastguard Worker                         completionHandler:nil];
301*d9f75844SAndroid Build Coastguard Worker  }
302*d9f75844SAndroid Build Coastguard Worker  if (_channel) {
303*d9f75844SAndroid Build Coastguard Worker    if (_channel.state == kARDSignalingChannelStateRegistered) {
304*d9f75844SAndroid Build Coastguard Worker      // Tell the other client we're hanging up.
305*d9f75844SAndroid Build Coastguard Worker      ARDByeMessage *byeMessage = [[ARDByeMessage alloc] init];
306*d9f75844SAndroid Build Coastguard Worker      [_channel sendMessage:byeMessage];
307*d9f75844SAndroid Build Coastguard Worker    }
308*d9f75844SAndroid Build Coastguard Worker    // Disconnect from collider.
309*d9f75844SAndroid Build Coastguard Worker    _channel = nil;
310*d9f75844SAndroid Build Coastguard Worker  }
311*d9f75844SAndroid Build Coastguard Worker  _clientId = nil;
312*d9f75844SAndroid Build Coastguard Worker  _roomId = nil;
313*d9f75844SAndroid Build Coastguard Worker  _isInitiator = NO;
314*d9f75844SAndroid Build Coastguard Worker  _hasReceivedSdp = NO;
315*d9f75844SAndroid Build Coastguard Worker  _messageQueue = [NSMutableArray array];
316*d9f75844SAndroid Build Coastguard Worker  _localVideoTrack = nil;
317*d9f75844SAndroid Build Coastguard Worker#if defined(WEBRTC_IOS)
318*d9f75844SAndroid Build Coastguard Worker  [_factory stopAecDump];
319*d9f75844SAndroid Build Coastguard Worker  [_peerConnection stopRtcEventLog];
320*d9f75844SAndroid Build Coastguard Worker#endif
321*d9f75844SAndroid Build Coastguard Worker  [_peerConnection close];
322*d9f75844SAndroid Build Coastguard Worker  _peerConnection = nil;
323*d9f75844SAndroid Build Coastguard Worker  self.state = kARDAppClientStateDisconnected;
324*d9f75844SAndroid Build Coastguard Worker#if defined(WEBRTC_IOS)
325*d9f75844SAndroid Build Coastguard Worker  if (kARDAppClientEnableTracing) {
326*d9f75844SAndroid Build Coastguard Worker    RTCStopInternalCapture();
327*d9f75844SAndroid Build Coastguard Worker  }
328*d9f75844SAndroid Build Coastguard Worker#endif
329*d9f75844SAndroid Build Coastguard Worker}
330*d9f75844SAndroid Build Coastguard Worker
331*d9f75844SAndroid Build Coastguard Worker#pragma mark - ARDSignalingChannelDelegate
332*d9f75844SAndroid Build Coastguard Worker
333*d9f75844SAndroid Build Coastguard Worker- (void)channel:(id<ARDSignalingChannel>)channel
334*d9f75844SAndroid Build Coastguard Worker    didReceiveMessage:(ARDSignalingMessage *)message {
335*d9f75844SAndroid Build Coastguard Worker  switch (message.type) {
336*d9f75844SAndroid Build Coastguard Worker    case kARDSignalingMessageTypeOffer:
337*d9f75844SAndroid Build Coastguard Worker    case kARDSignalingMessageTypeAnswer:
338*d9f75844SAndroid Build Coastguard Worker      // Offers and answers must be processed before any other message, so we
339*d9f75844SAndroid Build Coastguard Worker      // place them at the front of the queue.
340*d9f75844SAndroid Build Coastguard Worker      _hasReceivedSdp = YES;
341*d9f75844SAndroid Build Coastguard Worker      [_messageQueue insertObject:message atIndex:0];
342*d9f75844SAndroid Build Coastguard Worker      break;
343*d9f75844SAndroid Build Coastguard Worker    case kARDSignalingMessageTypeCandidate:
344*d9f75844SAndroid Build Coastguard Worker    case kARDSignalingMessageTypeCandidateRemoval:
345*d9f75844SAndroid Build Coastguard Worker      [_messageQueue addObject:message];
346*d9f75844SAndroid Build Coastguard Worker      break;
347*d9f75844SAndroid Build Coastguard Worker    case kARDSignalingMessageTypeBye:
348*d9f75844SAndroid Build Coastguard Worker      // Disconnects can be processed immediately.
349*d9f75844SAndroid Build Coastguard Worker      [self processSignalingMessage:message];
350*d9f75844SAndroid Build Coastguard Worker      return;
351*d9f75844SAndroid Build Coastguard Worker  }
352*d9f75844SAndroid Build Coastguard Worker  [self drainMessageQueueIfReady];
353*d9f75844SAndroid Build Coastguard Worker}
354*d9f75844SAndroid Build Coastguard Worker
355*d9f75844SAndroid Build Coastguard Worker- (void)channel:(id<ARDSignalingChannel>)channel
356*d9f75844SAndroid Build Coastguard Worker    didChangeState:(ARDSignalingChannelState)state {
357*d9f75844SAndroid Build Coastguard Worker  switch (state) {
358*d9f75844SAndroid Build Coastguard Worker    case kARDSignalingChannelStateOpen:
359*d9f75844SAndroid Build Coastguard Worker      break;
360*d9f75844SAndroid Build Coastguard Worker    case kARDSignalingChannelStateRegistered:
361*d9f75844SAndroid Build Coastguard Worker      break;
362*d9f75844SAndroid Build Coastguard Worker    case kARDSignalingChannelStateClosed:
363*d9f75844SAndroid Build Coastguard Worker    case kARDSignalingChannelStateError:
364*d9f75844SAndroid Build Coastguard Worker      // TODO(tkchin): reconnection scenarios. Right now we just disconnect
365*d9f75844SAndroid Build Coastguard Worker      // completely if the websocket connection fails.
366*d9f75844SAndroid Build Coastguard Worker      [self disconnect];
367*d9f75844SAndroid Build Coastguard Worker      break;
368*d9f75844SAndroid Build Coastguard Worker  }
369*d9f75844SAndroid Build Coastguard Worker}
370*d9f75844SAndroid Build Coastguard Worker
371*d9f75844SAndroid Build Coastguard Worker#pragma mark - RTC_OBJC_TYPE(RTCPeerConnectionDelegate)
372*d9f75844SAndroid Build Coastguard Worker// Callbacks for this delegate occur on non-main thread and need to be
373*d9f75844SAndroid Build Coastguard Worker// dispatched back to main queue as needed.
374*d9f75844SAndroid Build Coastguard Worker
375*d9f75844SAndroid Build Coastguard Worker- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection
376*d9f75844SAndroid Build Coastguard Worker    didChangeSignalingState:(RTCSignalingState)stateChanged {
377*d9f75844SAndroid Build Coastguard Worker  RTCLog(@"Signaling state changed: %ld", (long)stateChanged);
378*d9f75844SAndroid Build Coastguard Worker}
379*d9f75844SAndroid Build Coastguard Worker
380*d9f75844SAndroid Build Coastguard Worker- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection
381*d9f75844SAndroid Build Coastguard Worker          didAddStream:(RTC_OBJC_TYPE(RTCMediaStream) *)stream {
382*d9f75844SAndroid Build Coastguard Worker  RTCLog(@"Stream with %lu video tracks and %lu audio tracks was added.",
383*d9f75844SAndroid Build Coastguard Worker         (unsigned long)stream.videoTracks.count,
384*d9f75844SAndroid Build Coastguard Worker         (unsigned long)stream.audioTracks.count);
385*d9f75844SAndroid Build Coastguard Worker}
386*d9f75844SAndroid Build Coastguard Worker
387*d9f75844SAndroid Build Coastguard Worker- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection
388*d9f75844SAndroid Build Coastguard Worker    didStartReceivingOnTransceiver:(RTC_OBJC_TYPE(RTCRtpTransceiver) *)transceiver {
389*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCMediaStreamTrack) *track = transceiver.receiver.track;
390*d9f75844SAndroid Build Coastguard Worker  RTCLog(@"Now receiving %@ on track %@.", track.kind, track.trackId);
391*d9f75844SAndroid Build Coastguard Worker}
392*d9f75844SAndroid Build Coastguard Worker
393*d9f75844SAndroid Build Coastguard Worker- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection
394*d9f75844SAndroid Build Coastguard Worker       didRemoveStream:(RTC_OBJC_TYPE(RTCMediaStream) *)stream {
395*d9f75844SAndroid Build Coastguard Worker  RTCLog(@"Stream was removed.");
396*d9f75844SAndroid Build Coastguard Worker}
397*d9f75844SAndroid Build Coastguard Worker
398*d9f75844SAndroid Build Coastguard Worker- (void)peerConnectionShouldNegotiate:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection {
399*d9f75844SAndroid Build Coastguard Worker  RTCLog(@"WARNING: Renegotiation needed but unimplemented.");
400*d9f75844SAndroid Build Coastguard Worker}
401*d9f75844SAndroid Build Coastguard Worker
402*d9f75844SAndroid Build Coastguard Worker- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection
403*d9f75844SAndroid Build Coastguard Worker    didChangeIceConnectionState:(RTCIceConnectionState)newState {
404*d9f75844SAndroid Build Coastguard Worker  RTCLog(@"ICE state changed: %ld", (long)newState);
405*d9f75844SAndroid Build Coastguard Worker  dispatch_async(dispatch_get_main_queue(), ^{
406*d9f75844SAndroid Build Coastguard Worker    [self.delegate appClient:self didChangeConnectionState:newState];
407*d9f75844SAndroid Build Coastguard Worker  });
408*d9f75844SAndroid Build Coastguard Worker}
409*d9f75844SAndroid Build Coastguard Worker
410*d9f75844SAndroid Build Coastguard Worker- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection
411*d9f75844SAndroid Build Coastguard Worker    didChangeConnectionState:(RTCPeerConnectionState)newState {
412*d9f75844SAndroid Build Coastguard Worker  RTCLog(@"ICE+DTLS state changed: %ld", (long)newState);
413*d9f75844SAndroid Build Coastguard Worker}
414*d9f75844SAndroid Build Coastguard Worker
415*d9f75844SAndroid Build Coastguard Worker- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection
416*d9f75844SAndroid Build Coastguard Worker    didChangeIceGatheringState:(RTCIceGatheringState)newState {
417*d9f75844SAndroid Build Coastguard Worker  RTCLog(@"ICE gathering state changed: %ld", (long)newState);
418*d9f75844SAndroid Build Coastguard Worker}
419*d9f75844SAndroid Build Coastguard Worker
420*d9f75844SAndroid Build Coastguard Worker- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection
421*d9f75844SAndroid Build Coastguard Worker    didGenerateIceCandidate:(RTC_OBJC_TYPE(RTCIceCandidate) *)candidate {
422*d9f75844SAndroid Build Coastguard Worker  dispatch_async(dispatch_get_main_queue(), ^{
423*d9f75844SAndroid Build Coastguard Worker    ARDICECandidateMessage *message =
424*d9f75844SAndroid Build Coastguard Worker        [[ARDICECandidateMessage alloc] initWithCandidate:candidate];
425*d9f75844SAndroid Build Coastguard Worker    [self sendSignalingMessage:message];
426*d9f75844SAndroid Build Coastguard Worker  });
427*d9f75844SAndroid Build Coastguard Worker}
428*d9f75844SAndroid Build Coastguard Worker
429*d9f75844SAndroid Build Coastguard Worker- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection
430*d9f75844SAndroid Build Coastguard Worker    didFailToGatherIceCandidate:(RTC_OBJC_TYPE(RTCIceCandidateErrorEvent) *)event {
431*d9f75844SAndroid Build Coastguard Worker  RTCLog(@"Failed to gather ICE candidate. address: %@, port: %d, url: %@, errorCode: %d, "
432*d9f75844SAndroid Build Coastguard Worker         @"errorText: %@",
433*d9f75844SAndroid Build Coastguard Worker         event.address,
434*d9f75844SAndroid Build Coastguard Worker         event.port,
435*d9f75844SAndroid Build Coastguard Worker         event.url,
436*d9f75844SAndroid Build Coastguard Worker         event.errorCode,
437*d9f75844SAndroid Build Coastguard Worker         event.errorText);
438*d9f75844SAndroid Build Coastguard Worker}
439*d9f75844SAndroid Build Coastguard Worker
440*d9f75844SAndroid Build Coastguard Worker- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection
441*d9f75844SAndroid Build Coastguard Worker    didRemoveIceCandidates:(NSArray<RTC_OBJC_TYPE(RTCIceCandidate) *> *)candidates {
442*d9f75844SAndroid Build Coastguard Worker  dispatch_async(dispatch_get_main_queue(), ^{
443*d9f75844SAndroid Build Coastguard Worker    ARDICECandidateRemovalMessage *message =
444*d9f75844SAndroid Build Coastguard Worker        [[ARDICECandidateRemovalMessage alloc]
445*d9f75844SAndroid Build Coastguard Worker            initWithRemovedCandidates:candidates];
446*d9f75844SAndroid Build Coastguard Worker    [self sendSignalingMessage:message];
447*d9f75844SAndroid Build Coastguard Worker  });
448*d9f75844SAndroid Build Coastguard Worker}
449*d9f75844SAndroid Build Coastguard Worker
450*d9f75844SAndroid Build Coastguard Worker- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection
451*d9f75844SAndroid Build Coastguard Worker     didChangeLocalCandidate:(RTC_OBJC_TYPE(RTCIceCandidate) *)local
452*d9f75844SAndroid Build Coastguard Worker    didChangeRemoteCandidate:(RTC_OBJC_TYPE(RTCIceCandidate) *)remote
453*d9f75844SAndroid Build Coastguard Worker              lastReceivedMs:(int)lastDataReceivedMs
454*d9f75844SAndroid Build Coastguard Worker               didHaveReason:(NSString *)reason {
455*d9f75844SAndroid Build Coastguard Worker  RTCLog(@"ICE candidate pair changed because: %@", reason);
456*d9f75844SAndroid Build Coastguard Worker}
457*d9f75844SAndroid Build Coastguard Worker
458*d9f75844SAndroid Build Coastguard Worker- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection
459*d9f75844SAndroid Build Coastguard Worker    didOpenDataChannel:(RTC_OBJC_TYPE(RTCDataChannel) *)dataChannel {
460*d9f75844SAndroid Build Coastguard Worker}
461*d9f75844SAndroid Build Coastguard Worker
462*d9f75844SAndroid Build Coastguard Worker#pragma mark - RTCSessionDescriptionDelegate
463*d9f75844SAndroid Build Coastguard Worker// Callbacks for this delegate occur on non-main thread and need to be
464*d9f75844SAndroid Build Coastguard Worker// dispatched back to main queue as needed.
465*d9f75844SAndroid Build Coastguard Worker
466*d9f75844SAndroid Build Coastguard Worker- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection
467*d9f75844SAndroid Build Coastguard Worker    didCreateSessionDescription:(RTC_OBJC_TYPE(RTCSessionDescription) *)sdp
468*d9f75844SAndroid Build Coastguard Worker                          error:(NSError *)error {
469*d9f75844SAndroid Build Coastguard Worker  dispatch_async(dispatch_get_main_queue(), ^{
470*d9f75844SAndroid Build Coastguard Worker    if (error) {
471*d9f75844SAndroid Build Coastguard Worker      RTCLogError(@"Failed to create session description. Error: %@", error);
472*d9f75844SAndroid Build Coastguard Worker      [self disconnect];
473*d9f75844SAndroid Build Coastguard Worker      NSDictionary *userInfo = @{
474*d9f75844SAndroid Build Coastguard Worker        NSLocalizedDescriptionKey: @"Failed to create session description.",
475*d9f75844SAndroid Build Coastguard Worker      };
476*d9f75844SAndroid Build Coastguard Worker      NSError *sdpError =
477*d9f75844SAndroid Build Coastguard Worker          [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
478*d9f75844SAndroid Build Coastguard Worker                                     code:kARDAppClientErrorCreateSDP
479*d9f75844SAndroid Build Coastguard Worker                                 userInfo:userInfo];
480*d9f75844SAndroid Build Coastguard Worker      [self.delegate appClient:self didError:sdpError];
481*d9f75844SAndroid Build Coastguard Worker      return;
482*d9f75844SAndroid Build Coastguard Worker    }
483*d9f75844SAndroid Build Coastguard Worker    __weak ARDAppClient *weakSelf = self;
484*d9f75844SAndroid Build Coastguard Worker    [self.peerConnection setLocalDescription:sdp
485*d9f75844SAndroid Build Coastguard Worker                           completionHandler:^(NSError *error) {
486*d9f75844SAndroid Build Coastguard Worker                             ARDAppClient *strongSelf = weakSelf;
487*d9f75844SAndroid Build Coastguard Worker                             [strongSelf peerConnection:strongSelf.peerConnection
488*d9f75844SAndroid Build Coastguard Worker                                 didSetSessionDescriptionWithError:error];
489*d9f75844SAndroid Build Coastguard Worker                           }];
490*d9f75844SAndroid Build Coastguard Worker    ARDSessionDescriptionMessage *message =
491*d9f75844SAndroid Build Coastguard Worker        [[ARDSessionDescriptionMessage alloc] initWithDescription:sdp];
492*d9f75844SAndroid Build Coastguard Worker    [self sendSignalingMessage:message];
493*d9f75844SAndroid Build Coastguard Worker    [self setMaxBitrateForPeerConnectionVideoSender];
494*d9f75844SAndroid Build Coastguard Worker  });
495*d9f75844SAndroid Build Coastguard Worker}
496*d9f75844SAndroid Build Coastguard Worker
497*d9f75844SAndroid Build Coastguard Worker- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection
498*d9f75844SAndroid Build Coastguard Worker    didSetSessionDescriptionWithError:(NSError *)error {
499*d9f75844SAndroid Build Coastguard Worker  dispatch_async(dispatch_get_main_queue(), ^{
500*d9f75844SAndroid Build Coastguard Worker    if (error) {
501*d9f75844SAndroid Build Coastguard Worker      RTCLogError(@"Failed to set session description. Error: %@", error);
502*d9f75844SAndroid Build Coastguard Worker      [self disconnect];
503*d9f75844SAndroid Build Coastguard Worker      NSDictionary *userInfo = @{
504*d9f75844SAndroid Build Coastguard Worker        NSLocalizedDescriptionKey: @"Failed to set session description.",
505*d9f75844SAndroid Build Coastguard Worker      };
506*d9f75844SAndroid Build Coastguard Worker      NSError *sdpError =
507*d9f75844SAndroid Build Coastguard Worker          [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
508*d9f75844SAndroid Build Coastguard Worker                                     code:kARDAppClientErrorSetSDP
509*d9f75844SAndroid Build Coastguard Worker                                 userInfo:userInfo];
510*d9f75844SAndroid Build Coastguard Worker      [self.delegate appClient:self didError:sdpError];
511*d9f75844SAndroid Build Coastguard Worker      return;
512*d9f75844SAndroid Build Coastguard Worker    }
513*d9f75844SAndroid Build Coastguard Worker    // If we're answering and we've just set the remote offer we need to create
514*d9f75844SAndroid Build Coastguard Worker    // an answer and set the local description.
515*d9f75844SAndroid Build Coastguard Worker    if (!self.isInitiator && !self.peerConnection.localDescription) {
516*d9f75844SAndroid Build Coastguard Worker      RTC_OBJC_TYPE(RTCMediaConstraints) *constraints = [self defaultAnswerConstraints];
517*d9f75844SAndroid Build Coastguard Worker      __weak ARDAppClient *weakSelf = self;
518*d9f75844SAndroid Build Coastguard Worker      [self.peerConnection
519*d9f75844SAndroid Build Coastguard Worker          answerForConstraints:constraints
520*d9f75844SAndroid Build Coastguard Worker             completionHandler:^(RTC_OBJC_TYPE(RTCSessionDescription) * sdp, NSError * error) {
521*d9f75844SAndroid Build Coastguard Worker               ARDAppClient *strongSelf = weakSelf;
522*d9f75844SAndroid Build Coastguard Worker               [strongSelf peerConnection:strongSelf.peerConnection
523*d9f75844SAndroid Build Coastguard Worker                   didCreateSessionDescription:sdp
524*d9f75844SAndroid Build Coastguard Worker                                         error:error];
525*d9f75844SAndroid Build Coastguard Worker             }];
526*d9f75844SAndroid Build Coastguard Worker    }
527*d9f75844SAndroid Build Coastguard Worker  });
528*d9f75844SAndroid Build Coastguard Worker}
529*d9f75844SAndroid Build Coastguard Worker
530*d9f75844SAndroid Build Coastguard Worker#pragma mark - Private
531*d9f75844SAndroid Build Coastguard Worker
532*d9f75844SAndroid Build Coastguard Worker#if defined(WEBRTC_IOS)
533*d9f75844SAndroid Build Coastguard Worker
534*d9f75844SAndroid Build Coastguard Worker- (NSString *)documentsFilePathForFileName:(NSString *)fileName {
535*d9f75844SAndroid Build Coastguard Worker  NSParameterAssert(fileName.length);
536*d9f75844SAndroid Build Coastguard Worker  NSArray *paths = NSSearchPathForDirectoriesInDomains(
537*d9f75844SAndroid Build Coastguard Worker      NSDocumentDirectory, NSUserDomainMask, YES);
538*d9f75844SAndroid Build Coastguard Worker  NSString *documentsDirPath = paths.firstObject;
539*d9f75844SAndroid Build Coastguard Worker  NSString *filePath =
540*d9f75844SAndroid Build Coastguard Worker      [documentsDirPath stringByAppendingPathComponent:fileName];
541*d9f75844SAndroid Build Coastguard Worker  return filePath;
542*d9f75844SAndroid Build Coastguard Worker}
543*d9f75844SAndroid Build Coastguard Worker
544*d9f75844SAndroid Build Coastguard Worker#endif
545*d9f75844SAndroid Build Coastguard Worker
546*d9f75844SAndroid Build Coastguard Worker- (BOOL)hasJoinedRoomServerRoom {
547*d9f75844SAndroid Build Coastguard Worker  return _clientId.length;
548*d9f75844SAndroid Build Coastguard Worker}
549*d9f75844SAndroid Build Coastguard Worker
550*d9f75844SAndroid Build Coastguard Worker// Begins the peer connection connection process if we have both joined a room
551*d9f75844SAndroid Build Coastguard Worker// on the room server and tried to obtain a TURN server. Otherwise does nothing.
552*d9f75844SAndroid Build Coastguard Worker// A peer connection object will be created with a stream that contains local
553*d9f75844SAndroid Build Coastguard Worker// audio and video capture. If this client is the caller, an offer is created as
554*d9f75844SAndroid Build Coastguard Worker// well, otherwise the client will wait for an offer to arrive.
555*d9f75844SAndroid Build Coastguard Worker- (void)startSignalingIfReady {
556*d9f75844SAndroid Build Coastguard Worker  if (!_isTurnComplete || !self.hasJoinedRoomServerRoom) {
557*d9f75844SAndroid Build Coastguard Worker    return;
558*d9f75844SAndroid Build Coastguard Worker  }
559*d9f75844SAndroid Build Coastguard Worker  self.state = kARDAppClientStateConnected;
560*d9f75844SAndroid Build Coastguard Worker
561*d9f75844SAndroid Build Coastguard Worker  // Create peer connection.
562*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCMediaConstraints) *constraints = [self defaultPeerConnectionConstraints];
563*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCConfiguration) *config = [[RTC_OBJC_TYPE(RTCConfiguration) alloc] init];
564*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCertificate) *pcert = [RTC_OBJC_TYPE(RTCCertificate)
565*d9f75844SAndroid Build Coastguard Worker      generateCertificateWithParams:@{@"expires" : @100000, @"name" : @"RSASSA-PKCS1-v1_5"}];
566*d9f75844SAndroid Build Coastguard Worker  config.iceServers = _iceServers;
567*d9f75844SAndroid Build Coastguard Worker  config.sdpSemantics = RTCSdpSemanticsUnifiedPlan;
568*d9f75844SAndroid Build Coastguard Worker  config.certificate = pcert;
569*d9f75844SAndroid Build Coastguard Worker
570*d9f75844SAndroid Build Coastguard Worker  _peerConnection = [_factory peerConnectionWithConfiguration:config
571*d9f75844SAndroid Build Coastguard Worker                                                  constraints:constraints
572*d9f75844SAndroid Build Coastguard Worker                                                     delegate:self];
573*d9f75844SAndroid Build Coastguard Worker  // Create AV senders.
574*d9f75844SAndroid Build Coastguard Worker  [self createMediaSenders];
575*d9f75844SAndroid Build Coastguard Worker  if (_isInitiator) {
576*d9f75844SAndroid Build Coastguard Worker    // Send offer.
577*d9f75844SAndroid Build Coastguard Worker    __weak ARDAppClient *weakSelf = self;
578*d9f75844SAndroid Build Coastguard Worker    [_peerConnection
579*d9f75844SAndroid Build Coastguard Worker        offerForConstraints:[self defaultOfferConstraints]
580*d9f75844SAndroid Build Coastguard Worker          completionHandler:^(RTC_OBJC_TYPE(RTCSessionDescription) * sdp, NSError * error) {
581*d9f75844SAndroid Build Coastguard Worker            ARDAppClient *strongSelf = weakSelf;
582*d9f75844SAndroid Build Coastguard Worker            [strongSelf peerConnection:strongSelf.peerConnection
583*d9f75844SAndroid Build Coastguard Worker                didCreateSessionDescription:sdp
584*d9f75844SAndroid Build Coastguard Worker                                      error:error];
585*d9f75844SAndroid Build Coastguard Worker          }];
586*d9f75844SAndroid Build Coastguard Worker  } else {
587*d9f75844SAndroid Build Coastguard Worker    // Check if we've received an offer.
588*d9f75844SAndroid Build Coastguard Worker    [self drainMessageQueueIfReady];
589*d9f75844SAndroid Build Coastguard Worker  }
590*d9f75844SAndroid Build Coastguard Worker#if defined(WEBRTC_IOS)
591*d9f75844SAndroid Build Coastguard Worker  // Start event log.
592*d9f75844SAndroid Build Coastguard Worker  if (kARDAppClientEnableRtcEventLog) {
593*d9f75844SAndroid Build Coastguard Worker    NSString *filePath = [self documentsFilePathForFileName:@"webrtc-rtceventlog"];
594*d9f75844SAndroid Build Coastguard Worker    if (![_peerConnection startRtcEventLogWithFilePath:filePath
595*d9f75844SAndroid Build Coastguard Worker                                 maxSizeInBytes:kARDAppClientRtcEventLogMaxSizeInBytes]) {
596*d9f75844SAndroid Build Coastguard Worker      RTCLogError(@"Failed to start event logging.");
597*d9f75844SAndroid Build Coastguard Worker    }
598*d9f75844SAndroid Build Coastguard Worker  }
599*d9f75844SAndroid Build Coastguard Worker
600*d9f75844SAndroid Build Coastguard Worker  // Start aecdump diagnostic recording.
601*d9f75844SAndroid Build Coastguard Worker  if ([_settings currentCreateAecDumpSettingFromStore]) {
602*d9f75844SAndroid Build Coastguard Worker    NSString *filePath = [self documentsFilePathForFileName:@"webrtc-audio.aecdump"];
603*d9f75844SAndroid Build Coastguard Worker    if (![_factory startAecDumpWithFilePath:filePath
604*d9f75844SAndroid Build Coastguard Worker                             maxSizeInBytes:kARDAppClientAecDumpMaxSizeInBytes]) {
605*d9f75844SAndroid Build Coastguard Worker      RTCLogError(@"Failed to start aec dump.");
606*d9f75844SAndroid Build Coastguard Worker    }
607*d9f75844SAndroid Build Coastguard Worker  }
608*d9f75844SAndroid Build Coastguard Worker#endif
609*d9f75844SAndroid Build Coastguard Worker}
610*d9f75844SAndroid Build Coastguard Worker
611*d9f75844SAndroid Build Coastguard Worker// Processes the messages that we've received from the room server and the
612*d9f75844SAndroid Build Coastguard Worker// signaling channel. The offer or answer message must be processed before other
613*d9f75844SAndroid Build Coastguard Worker// signaling messages, however they can arrive out of order. Hence, this method
614*d9f75844SAndroid Build Coastguard Worker// only processes pending messages if there is a peer connection object and
615*d9f75844SAndroid Build Coastguard Worker// if we have received either an offer or answer.
616*d9f75844SAndroid Build Coastguard Worker- (void)drainMessageQueueIfReady {
617*d9f75844SAndroid Build Coastguard Worker  if (!_peerConnection || !_hasReceivedSdp) {
618*d9f75844SAndroid Build Coastguard Worker    return;
619*d9f75844SAndroid Build Coastguard Worker  }
620*d9f75844SAndroid Build Coastguard Worker  for (ARDSignalingMessage *message in _messageQueue) {
621*d9f75844SAndroid Build Coastguard Worker    [self processSignalingMessage:message];
622*d9f75844SAndroid Build Coastguard Worker  }
623*d9f75844SAndroid Build Coastguard Worker  [_messageQueue removeAllObjects];
624*d9f75844SAndroid Build Coastguard Worker}
625*d9f75844SAndroid Build Coastguard Worker
626*d9f75844SAndroid Build Coastguard Worker// Processes the given signaling message based on its type.
627*d9f75844SAndroid Build Coastguard Worker- (void)processSignalingMessage:(ARDSignalingMessage *)message {
628*d9f75844SAndroid Build Coastguard Worker  NSParameterAssert(_peerConnection ||
629*d9f75844SAndroid Build Coastguard Worker      message.type == kARDSignalingMessageTypeBye);
630*d9f75844SAndroid Build Coastguard Worker  switch (message.type) {
631*d9f75844SAndroid Build Coastguard Worker    case kARDSignalingMessageTypeOffer:
632*d9f75844SAndroid Build Coastguard Worker    case kARDSignalingMessageTypeAnswer: {
633*d9f75844SAndroid Build Coastguard Worker      ARDSessionDescriptionMessage *sdpMessage =
634*d9f75844SAndroid Build Coastguard Worker          (ARDSessionDescriptionMessage *)message;
635*d9f75844SAndroid Build Coastguard Worker      RTC_OBJC_TYPE(RTCSessionDescription) *description = sdpMessage.sessionDescription;
636*d9f75844SAndroid Build Coastguard Worker      __weak ARDAppClient *weakSelf = self;
637*d9f75844SAndroid Build Coastguard Worker      [_peerConnection setRemoteDescription:description
638*d9f75844SAndroid Build Coastguard Worker                          completionHandler:^(NSError *error) {
639*d9f75844SAndroid Build Coastguard Worker                            ARDAppClient *strongSelf = weakSelf;
640*d9f75844SAndroid Build Coastguard Worker                            [strongSelf peerConnection:strongSelf.peerConnection
641*d9f75844SAndroid Build Coastguard Worker                                didSetSessionDescriptionWithError:error];
642*d9f75844SAndroid Build Coastguard Worker                          }];
643*d9f75844SAndroid Build Coastguard Worker      break;
644*d9f75844SAndroid Build Coastguard Worker    }
645*d9f75844SAndroid Build Coastguard Worker    case kARDSignalingMessageTypeCandidate: {
646*d9f75844SAndroid Build Coastguard Worker      ARDICECandidateMessage *candidateMessage =
647*d9f75844SAndroid Build Coastguard Worker          (ARDICECandidateMessage *)message;
648*d9f75844SAndroid Build Coastguard Worker      __weak ARDAppClient *weakSelf = self;
649*d9f75844SAndroid Build Coastguard Worker      [_peerConnection addIceCandidate:candidateMessage.candidate
650*d9f75844SAndroid Build Coastguard Worker                     completionHandler:^(NSError *error) {
651*d9f75844SAndroid Build Coastguard Worker                       ARDAppClient *strongSelf = weakSelf;
652*d9f75844SAndroid Build Coastguard Worker                       if (error) {
653*d9f75844SAndroid Build Coastguard Worker                         [strongSelf.delegate appClient:strongSelf didError:error];
654*d9f75844SAndroid Build Coastguard Worker                       }
655*d9f75844SAndroid Build Coastguard Worker                     }];
656*d9f75844SAndroid Build Coastguard Worker      break;
657*d9f75844SAndroid Build Coastguard Worker    }
658*d9f75844SAndroid Build Coastguard Worker    case kARDSignalingMessageTypeCandidateRemoval: {
659*d9f75844SAndroid Build Coastguard Worker      ARDICECandidateRemovalMessage *candidateMessage =
660*d9f75844SAndroid Build Coastguard Worker          (ARDICECandidateRemovalMessage *)message;
661*d9f75844SAndroid Build Coastguard Worker      [_peerConnection removeIceCandidates:candidateMessage.candidates];
662*d9f75844SAndroid Build Coastguard Worker      break;
663*d9f75844SAndroid Build Coastguard Worker    }
664*d9f75844SAndroid Build Coastguard Worker    case kARDSignalingMessageTypeBye:
665*d9f75844SAndroid Build Coastguard Worker      // Other client disconnected.
666*d9f75844SAndroid Build Coastguard Worker      // TODO(tkchin): support waiting in room for next client. For now just
667*d9f75844SAndroid Build Coastguard Worker      // disconnect.
668*d9f75844SAndroid Build Coastguard Worker      [self disconnect];
669*d9f75844SAndroid Build Coastguard Worker      break;
670*d9f75844SAndroid Build Coastguard Worker  }
671*d9f75844SAndroid Build Coastguard Worker}
672*d9f75844SAndroid Build Coastguard Worker
673*d9f75844SAndroid Build Coastguard Worker// Sends a signaling message to the other client. The caller will send messages
674*d9f75844SAndroid Build Coastguard Worker// through the room server, whereas the callee will send messages over the
675*d9f75844SAndroid Build Coastguard Worker// signaling channel.
676*d9f75844SAndroid Build Coastguard Worker- (void)sendSignalingMessage:(ARDSignalingMessage *)message {
677*d9f75844SAndroid Build Coastguard Worker  if (_isInitiator) {
678*d9f75844SAndroid Build Coastguard Worker    __weak ARDAppClient *weakSelf = self;
679*d9f75844SAndroid Build Coastguard Worker    [_roomServerClient sendMessage:message
680*d9f75844SAndroid Build Coastguard Worker                         forRoomId:_roomId
681*d9f75844SAndroid Build Coastguard Worker                          clientId:_clientId
682*d9f75844SAndroid Build Coastguard Worker                 completionHandler:^(ARDMessageResponse *response,
683*d9f75844SAndroid Build Coastguard Worker                                     NSError *error) {
684*d9f75844SAndroid Build Coastguard Worker      ARDAppClient *strongSelf = weakSelf;
685*d9f75844SAndroid Build Coastguard Worker      if (error) {
686*d9f75844SAndroid Build Coastguard Worker        [strongSelf.delegate appClient:strongSelf didError:error];
687*d9f75844SAndroid Build Coastguard Worker        return;
688*d9f75844SAndroid Build Coastguard Worker      }
689*d9f75844SAndroid Build Coastguard Worker      NSError *messageError =
690*d9f75844SAndroid Build Coastguard Worker          [[strongSelf class] errorForMessageResultType:response.result];
691*d9f75844SAndroid Build Coastguard Worker      if (messageError) {
692*d9f75844SAndroid Build Coastguard Worker        [strongSelf.delegate appClient:strongSelf didError:messageError];
693*d9f75844SAndroid Build Coastguard Worker        return;
694*d9f75844SAndroid Build Coastguard Worker      }
695*d9f75844SAndroid Build Coastguard Worker    }];
696*d9f75844SAndroid Build Coastguard Worker  } else {
697*d9f75844SAndroid Build Coastguard Worker    [_channel sendMessage:message];
698*d9f75844SAndroid Build Coastguard Worker  }
699*d9f75844SAndroid Build Coastguard Worker}
700*d9f75844SAndroid Build Coastguard Worker
701*d9f75844SAndroid Build Coastguard Worker- (void)setMaxBitrateForPeerConnectionVideoSender {
702*d9f75844SAndroid Build Coastguard Worker  for (RTC_OBJC_TYPE(RTCRtpSender) * sender in _peerConnection.senders) {
703*d9f75844SAndroid Build Coastguard Worker    if (sender.track != nil) {
704*d9f75844SAndroid Build Coastguard Worker      if ([sender.track.kind isEqualToString:kARDVideoTrackKind]) {
705*d9f75844SAndroid Build Coastguard Worker        [self setMaxBitrate:[_settings currentMaxBitrateSettingFromStore] forVideoSender:sender];
706*d9f75844SAndroid Build Coastguard Worker      }
707*d9f75844SAndroid Build Coastguard Worker    }
708*d9f75844SAndroid Build Coastguard Worker  }
709*d9f75844SAndroid Build Coastguard Worker}
710*d9f75844SAndroid Build Coastguard Worker
711*d9f75844SAndroid Build Coastguard Worker- (void)setMaxBitrate:(NSNumber *)maxBitrate forVideoSender:(RTC_OBJC_TYPE(RTCRtpSender) *)sender {
712*d9f75844SAndroid Build Coastguard Worker  if (maxBitrate.intValue <= 0) {
713*d9f75844SAndroid Build Coastguard Worker    return;
714*d9f75844SAndroid Build Coastguard Worker  }
715*d9f75844SAndroid Build Coastguard Worker
716*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCRtpParameters) *parametersToModify = sender.parameters;
717*d9f75844SAndroid Build Coastguard Worker  for (RTC_OBJC_TYPE(RTCRtpEncodingParameters) * encoding in parametersToModify.encodings) {
718*d9f75844SAndroid Build Coastguard Worker    encoding.maxBitrateBps = @(maxBitrate.intValue * kKbpsMultiplier);
719*d9f75844SAndroid Build Coastguard Worker  }
720*d9f75844SAndroid Build Coastguard Worker  [sender setParameters:parametersToModify];
721*d9f75844SAndroid Build Coastguard Worker}
722*d9f75844SAndroid Build Coastguard Worker
723*d9f75844SAndroid Build Coastguard Worker- (RTC_OBJC_TYPE(RTCRtpTransceiver) *)videoTransceiver {
724*d9f75844SAndroid Build Coastguard Worker  for (RTC_OBJC_TYPE(RTCRtpTransceiver) * transceiver in _peerConnection.transceivers) {
725*d9f75844SAndroid Build Coastguard Worker    if (transceiver.mediaType == RTCRtpMediaTypeVideo) {
726*d9f75844SAndroid Build Coastguard Worker      return transceiver;
727*d9f75844SAndroid Build Coastguard Worker    }
728*d9f75844SAndroid Build Coastguard Worker  }
729*d9f75844SAndroid Build Coastguard Worker  return nil;
730*d9f75844SAndroid Build Coastguard Worker}
731*d9f75844SAndroid Build Coastguard Worker
732*d9f75844SAndroid Build Coastguard Worker- (void)createMediaSenders {
733*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCMediaConstraints) *constraints = [self defaultMediaAudioConstraints];
734*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCAudioSource) *source = [_factory audioSourceWithConstraints:constraints];
735*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCAudioTrack) *track = [_factory audioTrackWithSource:source
736*d9f75844SAndroid Build Coastguard Worker                                                               trackId:kARDAudioTrackId];
737*d9f75844SAndroid Build Coastguard Worker  [_peerConnection addTrack:track streamIds:@[ kARDMediaStreamId ]];
738*d9f75844SAndroid Build Coastguard Worker  _localVideoTrack = [self createLocalVideoTrack];
739*d9f75844SAndroid Build Coastguard Worker  if (_localVideoTrack) {
740*d9f75844SAndroid Build Coastguard Worker    [_peerConnection addTrack:_localVideoTrack streamIds:@[ kARDMediaStreamId ]];
741*d9f75844SAndroid Build Coastguard Worker    [_delegate appClient:self didReceiveLocalVideoTrack:_localVideoTrack];
742*d9f75844SAndroid Build Coastguard Worker    // We can set up rendering for the remote track right away since the transceiver already has an
743*d9f75844SAndroid Build Coastguard Worker    // RTC_OBJC_TYPE(RTCRtpReceiver) with a track. The track will automatically get unmuted and
744*d9f75844SAndroid Build Coastguard Worker    // produce frames once RTP is received.
745*d9f75844SAndroid Build Coastguard Worker    RTC_OBJC_TYPE(RTCVideoTrack) *track =
746*d9f75844SAndroid Build Coastguard Worker        (RTC_OBJC_TYPE(RTCVideoTrack) *)([self videoTransceiver].receiver.track);
747*d9f75844SAndroid Build Coastguard Worker    [_delegate appClient:self didReceiveRemoteVideoTrack:track];
748*d9f75844SAndroid Build Coastguard Worker  }
749*d9f75844SAndroid Build Coastguard Worker}
750*d9f75844SAndroid Build Coastguard Worker
751*d9f75844SAndroid Build Coastguard Worker- (RTC_OBJC_TYPE(RTCVideoTrack) *)createLocalVideoTrack {
752*d9f75844SAndroid Build Coastguard Worker  if ([_settings currentAudioOnlySettingFromStore]) {
753*d9f75844SAndroid Build Coastguard Worker    return nil;
754*d9f75844SAndroid Build Coastguard Worker  }
755*d9f75844SAndroid Build Coastguard Worker
756*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCVideoSource) *source = [_factory videoSource];
757*d9f75844SAndroid Build Coastguard Worker
758*d9f75844SAndroid Build Coastguard Worker#if !TARGET_IPHONE_SIMULATOR
759*d9f75844SAndroid Build Coastguard Worker  if (self.isBroadcast) {
760*d9f75844SAndroid Build Coastguard Worker    ARDExternalSampleCapturer *capturer =
761*d9f75844SAndroid Build Coastguard Worker        [[ARDExternalSampleCapturer alloc] initWithDelegate:source];
762*d9f75844SAndroid Build Coastguard Worker    [_delegate appClient:self didCreateLocalExternalSampleCapturer:capturer];
763*d9f75844SAndroid Build Coastguard Worker  } else {
764*d9f75844SAndroid Build Coastguard Worker    RTC_OBJC_TYPE(RTCCameraVideoCapturer) *capturer =
765*d9f75844SAndroid Build Coastguard Worker        [[RTC_OBJC_TYPE(RTCCameraVideoCapturer) alloc] initWithDelegate:source];
766*d9f75844SAndroid Build Coastguard Worker    [_delegate appClient:self didCreateLocalCapturer:capturer];
767*d9f75844SAndroid Build Coastguard Worker  }
768*d9f75844SAndroid Build Coastguard Worker#else
769*d9f75844SAndroid Build Coastguard Worker#if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
770*d9f75844SAndroid Build Coastguard Worker  if (@available(iOS 10, *)) {
771*d9f75844SAndroid Build Coastguard Worker    RTC_OBJC_TYPE(RTCFileVideoCapturer) *fileCapturer =
772*d9f75844SAndroid Build Coastguard Worker        [[RTC_OBJC_TYPE(RTCFileVideoCapturer) alloc] initWithDelegate:source];
773*d9f75844SAndroid Build Coastguard Worker    [_delegate appClient:self didCreateLocalFileCapturer:fileCapturer];
774*d9f75844SAndroid Build Coastguard Worker  }
775*d9f75844SAndroid Build Coastguard Worker#endif
776*d9f75844SAndroid Build Coastguard Worker#endif
777*d9f75844SAndroid Build Coastguard Worker
778*d9f75844SAndroid Build Coastguard Worker  return [_factory videoTrackWithSource:source trackId:kARDVideoTrackId];
779*d9f75844SAndroid Build Coastguard Worker}
780*d9f75844SAndroid Build Coastguard Worker
781*d9f75844SAndroid Build Coastguard Worker#pragma mark - Collider methods
782*d9f75844SAndroid Build Coastguard Worker
783*d9f75844SAndroid Build Coastguard Worker- (void)registerWithColliderIfReady {
784*d9f75844SAndroid Build Coastguard Worker  if (!self.hasJoinedRoomServerRoom) {
785*d9f75844SAndroid Build Coastguard Worker    return;
786*d9f75844SAndroid Build Coastguard Worker  }
787*d9f75844SAndroid Build Coastguard Worker  // Open WebSocket connection.
788*d9f75844SAndroid Build Coastguard Worker  if (!_channel) {
789*d9f75844SAndroid Build Coastguard Worker    _channel =
790*d9f75844SAndroid Build Coastguard Worker        [[ARDWebSocketChannel alloc] initWithURL:_websocketURL
791*d9f75844SAndroid Build Coastguard Worker                                         restURL:_websocketRestURL
792*d9f75844SAndroid Build Coastguard Worker                                        delegate:self];
793*d9f75844SAndroid Build Coastguard Worker    if (_isLoopback) {
794*d9f75844SAndroid Build Coastguard Worker      _loopbackChannel =
795*d9f75844SAndroid Build Coastguard Worker          [[ARDLoopbackWebSocketChannel alloc] initWithURL:_websocketURL
796*d9f75844SAndroid Build Coastguard Worker                                                   restURL:_websocketRestURL];
797*d9f75844SAndroid Build Coastguard Worker    }
798*d9f75844SAndroid Build Coastguard Worker  }
799*d9f75844SAndroid Build Coastguard Worker  [_channel registerForRoomId:_roomId clientId:_clientId];
800*d9f75844SAndroid Build Coastguard Worker  if (_isLoopback) {
801*d9f75844SAndroid Build Coastguard Worker    [_loopbackChannel registerForRoomId:_roomId clientId:@"LOOPBACK_CLIENT_ID"];
802*d9f75844SAndroid Build Coastguard Worker  }
803*d9f75844SAndroid Build Coastguard Worker}
804*d9f75844SAndroid Build Coastguard Worker
805*d9f75844SAndroid Build Coastguard Worker#pragma mark - Defaults
806*d9f75844SAndroid Build Coastguard Worker
807*d9f75844SAndroid Build Coastguard Worker- (RTC_OBJC_TYPE(RTCMediaConstraints) *)defaultMediaAudioConstraints {
808*d9f75844SAndroid Build Coastguard Worker  NSDictionary *mandatoryConstraints = @{};
809*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCMediaConstraints) *constraints =
810*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCMediaConstraints) alloc] initWithMandatoryConstraints:mandatoryConstraints
811*d9f75844SAndroid Build Coastguard Worker                                                           optionalConstraints:nil];
812*d9f75844SAndroid Build Coastguard Worker  return constraints;
813*d9f75844SAndroid Build Coastguard Worker}
814*d9f75844SAndroid Build Coastguard Worker
815*d9f75844SAndroid Build Coastguard Worker- (RTC_OBJC_TYPE(RTCMediaConstraints) *)defaultAnswerConstraints {
816*d9f75844SAndroid Build Coastguard Worker  return [self defaultOfferConstraints];
817*d9f75844SAndroid Build Coastguard Worker}
818*d9f75844SAndroid Build Coastguard Worker
819*d9f75844SAndroid Build Coastguard Worker- (RTC_OBJC_TYPE(RTCMediaConstraints) *)defaultOfferConstraints {
820*d9f75844SAndroid Build Coastguard Worker  NSDictionary *mandatoryConstraints = @{
821*d9f75844SAndroid Build Coastguard Worker    @"OfferToReceiveAudio" : @"true",
822*d9f75844SAndroid Build Coastguard Worker    @"OfferToReceiveVideo" : @"true"
823*d9f75844SAndroid Build Coastguard Worker  };
824*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCMediaConstraints) *constraints =
825*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCMediaConstraints) alloc] initWithMandatoryConstraints:mandatoryConstraints
826*d9f75844SAndroid Build Coastguard Worker                                                           optionalConstraints:nil];
827*d9f75844SAndroid Build Coastguard Worker  return constraints;
828*d9f75844SAndroid Build Coastguard Worker}
829*d9f75844SAndroid Build Coastguard Worker
830*d9f75844SAndroid Build Coastguard Worker- (RTC_OBJC_TYPE(RTCMediaConstraints) *)defaultPeerConnectionConstraints {
831*d9f75844SAndroid Build Coastguard Worker  if (_defaultPeerConnectionConstraints) {
832*d9f75844SAndroid Build Coastguard Worker    return _defaultPeerConnectionConstraints;
833*d9f75844SAndroid Build Coastguard Worker  }
834*d9f75844SAndroid Build Coastguard Worker  NSString *value = _isLoopback ? @"false" : @"true";
835*d9f75844SAndroid Build Coastguard Worker  NSDictionary *optionalConstraints = @{ @"DtlsSrtpKeyAgreement" : value };
836*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCMediaConstraints) *constraints =
837*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCMediaConstraints) alloc] initWithMandatoryConstraints:nil
838*d9f75844SAndroid Build Coastguard Worker                                                           optionalConstraints:optionalConstraints];
839*d9f75844SAndroid Build Coastguard Worker  return constraints;
840*d9f75844SAndroid Build Coastguard Worker}
841*d9f75844SAndroid Build Coastguard Worker
842*d9f75844SAndroid Build Coastguard Worker#pragma mark - Errors
843*d9f75844SAndroid Build Coastguard Worker
844*d9f75844SAndroid Build Coastguard Worker+ (NSError *)errorForJoinResultType:(ARDJoinResultType)resultType {
845*d9f75844SAndroid Build Coastguard Worker  NSError *error = nil;
846*d9f75844SAndroid Build Coastguard Worker  switch (resultType) {
847*d9f75844SAndroid Build Coastguard Worker    case kARDJoinResultTypeSuccess:
848*d9f75844SAndroid Build Coastguard Worker      break;
849*d9f75844SAndroid Build Coastguard Worker    case kARDJoinResultTypeUnknown: {
850*d9f75844SAndroid Build Coastguard Worker      error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
851*d9f75844SAndroid Build Coastguard Worker                                         code:kARDAppClientErrorUnknown
852*d9f75844SAndroid Build Coastguard Worker                                     userInfo:@{
853*d9f75844SAndroid Build Coastguard Worker        NSLocalizedDescriptionKey: @"Unknown error.",
854*d9f75844SAndroid Build Coastguard Worker      }];
855*d9f75844SAndroid Build Coastguard Worker      break;
856*d9f75844SAndroid Build Coastguard Worker    }
857*d9f75844SAndroid Build Coastguard Worker    case kARDJoinResultTypeFull: {
858*d9f75844SAndroid Build Coastguard Worker      error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
859*d9f75844SAndroid Build Coastguard Worker                                         code:kARDAppClientErrorRoomFull
860*d9f75844SAndroid Build Coastguard Worker                                     userInfo:@{
861*d9f75844SAndroid Build Coastguard Worker        NSLocalizedDescriptionKey: @"Room is full.",
862*d9f75844SAndroid Build Coastguard Worker      }];
863*d9f75844SAndroid Build Coastguard Worker      break;
864*d9f75844SAndroid Build Coastguard Worker    }
865*d9f75844SAndroid Build Coastguard Worker  }
866*d9f75844SAndroid Build Coastguard Worker  return error;
867*d9f75844SAndroid Build Coastguard Worker}
868*d9f75844SAndroid Build Coastguard Worker
869*d9f75844SAndroid Build Coastguard Worker+ (NSError *)errorForMessageResultType:(ARDMessageResultType)resultType {
870*d9f75844SAndroid Build Coastguard Worker  NSError *error = nil;
871*d9f75844SAndroid Build Coastguard Worker  switch (resultType) {
872*d9f75844SAndroid Build Coastguard Worker    case kARDMessageResultTypeSuccess:
873*d9f75844SAndroid Build Coastguard Worker      break;
874*d9f75844SAndroid Build Coastguard Worker    case kARDMessageResultTypeUnknown:
875*d9f75844SAndroid Build Coastguard Worker      error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
876*d9f75844SAndroid Build Coastguard Worker                                         code:kARDAppClientErrorUnknown
877*d9f75844SAndroid Build Coastguard Worker                                     userInfo:@{
878*d9f75844SAndroid Build Coastguard Worker        NSLocalizedDescriptionKey: @"Unknown error.",
879*d9f75844SAndroid Build Coastguard Worker      }];
880*d9f75844SAndroid Build Coastguard Worker      break;
881*d9f75844SAndroid Build Coastguard Worker    case kARDMessageResultTypeInvalidClient:
882*d9f75844SAndroid Build Coastguard Worker      error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
883*d9f75844SAndroid Build Coastguard Worker                                         code:kARDAppClientErrorInvalidClient
884*d9f75844SAndroid Build Coastguard Worker                                     userInfo:@{
885*d9f75844SAndroid Build Coastguard Worker        NSLocalizedDescriptionKey: @"Invalid client.",
886*d9f75844SAndroid Build Coastguard Worker      }];
887*d9f75844SAndroid Build Coastguard Worker      break;
888*d9f75844SAndroid Build Coastguard Worker    case kARDMessageResultTypeInvalidRoom:
889*d9f75844SAndroid Build Coastguard Worker      error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
890*d9f75844SAndroid Build Coastguard Worker                                         code:kARDAppClientErrorInvalidRoom
891*d9f75844SAndroid Build Coastguard Worker                                     userInfo:@{
892*d9f75844SAndroid Build Coastguard Worker        NSLocalizedDescriptionKey: @"Invalid room.",
893*d9f75844SAndroid Build Coastguard Worker      }];
894*d9f75844SAndroid Build Coastguard Worker      break;
895*d9f75844SAndroid Build Coastguard Worker  }
896*d9f75844SAndroid Build Coastguard Worker  return error;
897*d9f75844SAndroid Build Coastguard Worker}
898*d9f75844SAndroid Build Coastguard Worker
899*d9f75844SAndroid Build Coastguard Worker@end
900