blob: 2827bf94423cb023e45ea984f5e77687ae764a0a [file] [log] [blame]
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +00001/*
Donald E Curtisa8736442015-08-05 15:48:13 -07002 * Copyright 2015 The WebRTC Project Authors. All rights reserved.
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +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.orgef2a5dd2015-01-15 22:38:21 +00009 */
10
11#import "ARDVideoCallViewController.h"
12
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020013#import <WebRTC/RTCAudioSession.h>
14#import <WebRTC/RTCCameraVideoCapturer.h>
15#import <WebRTC/RTCDispatcher.h>
16#import <WebRTC/RTCLogging.h>
17#import <WebRTC/RTCMediaConstraints.h>
tkchin0ce3bf92016-03-12 16:52:04 -080018
denicijad17d5362016-11-02 02:56:09 -070019#import "ARDAppClient.h"
sakalc522e752017-04-05 12:17:48 -070020#import "ARDCaptureController.h"
Daniela012b56b2017-11-15 13:15:24 +010021#import "ARDFileCaptureController.h"
denicija2256e042016-11-09 06:26:18 -080022#import "ARDSettingsModel.h"
denicijad17d5362016-11-02 02:56:09 -070023#import "ARDVideoCallView.h"
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000024
25@interface ARDVideoCallViewController () <ARDAppClientDelegate,
Anders Carlsson121ea322017-06-26 15:34:47 +020026 ARDVideoCallViewDelegate,
27 RTCAudioSessionDelegate>
Zeke Chin57cc74e2015-05-05 07:52:31 -070028@property(nonatomic, strong) RTCVideoTrack *remoteVideoTrack;
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000029@property(nonatomic, readonly) ARDVideoCallView *videoCallView;
30@end
31
32@implementation ARDVideoCallViewController {
33 ARDAppClient *_client;
34 RTCVideoTrack *_remoteVideoTrack;
sakalc522e752017-04-05 12:17:48 -070035 ARDCaptureController *_captureController;
Daniela012b56b2017-11-15 13:15:24 +010036 ARDFileCaptureController *_fileCaptureController NS_AVAILABLE_IOS(10);
tkchin0ce3bf92016-03-12 16:52:04 -080037 AVAudioSessionPortOverride _portOverride;
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000038}
39
40@synthesize videoCallView = _videoCallView;
kthelgasonb13237b2017-03-30 04:56:05 -070041@synthesize remoteVideoTrack = _remoteVideoTrack;
tkchind2511962016-05-06 18:54:15 -070042@synthesize delegate = _delegate;
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000043
haysc913e6452015-10-02 11:44:03 -070044- (instancetype)initForRoom:(NSString *)room
45 isLoopback:(BOOL)isLoopback
tkchind2511962016-05-06 18:54:15 -070046 delegate:(id<ARDVideoCallViewControllerDelegate>)delegate {
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000047 if (self = [super init]) {
denicija2256e042016-11-09 06:26:18 -080048 ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init];
sakal68b5df92017-03-17 09:01:59 -070049 _delegate = delegate;
sakalc522e752017-04-05 12:17:48 -070050
sakalc4adacf2017-03-28 01:22:48 -070051 _client = [[ARDAppClient alloc] initWithDelegate:self];
Anders Carlssone1500582017-06-15 16:05:13 +020052 [_client connectToRoomWithId:room settings:settingsModel isLoopback:isLoopback];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000053 }
54 return self;
55}
56
57- (void)loadView {
58 _videoCallView = [[ARDVideoCallView alloc] initWithFrame:CGRectZero];
59 _videoCallView.delegate = self;
60 _videoCallView.statusLabel.text =
hjon79858f82016-03-13 22:08:26 -070061 [self statusTextForState:RTCIceConnectionStateNew];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000062 self.view = _videoCallView;
Anders Carlsson121ea322017-06-26 15:34:47 +020063
64 RTCAudioSession *session = [RTCAudioSession sharedInstance];
65 [session addDelegate:self];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000066}
67
Gustavo Garcia gustavo@lifeonair.com19d77c12017-11-15 16:03:18 +020068- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
69 return UIInterfaceOrientationMaskAll;
70}
71
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000072#pragma mark - ARDAppClientDelegate
73
74- (void)appClient:(ARDAppClient *)client
75 didChangeState:(ARDAppClientState)state {
76 switch (state) {
77 case kARDAppClientStateConnected:
tkchinc3f46a92015-07-23 12:50:55 -070078 RTCLog(@"Client connected.");
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000079 break;
80 case kARDAppClientStateConnecting:
tkchinc3f46a92015-07-23 12:50:55 -070081 RTCLog(@"Client connecting.");
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000082 break;
83 case kARDAppClientStateDisconnected:
tkchinc3f46a92015-07-23 12:50:55 -070084 RTCLog(@"Client disconnected.");
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000085 [self hangup];
86 break;
87 }
88}
89
90- (void)appClient:(ARDAppClient *)client
hjon79858f82016-03-13 22:08:26 -070091 didChangeConnectionState:(RTCIceConnectionState)state {
92 RTCLog(@"ICE state changed: %ld", (long)state);
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000093 __weak ARDVideoCallViewController *weakSelf = self;
94 dispatch_async(dispatch_get_main_queue(), ^{
95 ARDVideoCallViewController *strongSelf = weakSelf;
96 strongSelf.videoCallView.statusLabel.text =
97 [strongSelf statusTextForState:state];
98 });
99}
100
101- (void)appClient:(ARDAppClient *)client
sakalc522e752017-04-05 12:17:48 -0700102 didCreateLocalCapturer:(RTCCameraVideoCapturer *)localCapturer {
103 _videoCallView.localVideoView.captureSession = localCapturer.captureSession;
104 ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init];
105 _captureController =
106 [[ARDCaptureController alloc] initWithCapturer:localCapturer settings:settingsModel];
107 [_captureController startCapture];
108}
109
110- (void)appClient:(ARDAppClient *)client
Daniela012b56b2017-11-15 13:15:24 +0100111 didCreateLocalFileCapturer:(RTCFileVideoCapturer *)fileCapturer {
112#if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
113 if (@available(iOS 10, *)) {
114 _fileCaptureController = [[ARDFileCaptureController alloc] initWithCapturer:fileCapturer];
115 [_fileCaptureController startCapture];
116 }
117#endif
118}
119
120- (void)appClient:(ARDAppClient *)client
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000121 didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack {
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000122}
123
124- (void)appClient:(ARDAppClient *)client
125 didReceiveRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack {
Zeke Chin57cc74e2015-05-05 07:52:31 -0700126 self.remoteVideoTrack = remoteVideoTrack;
Peter Hanspersa1f566b2018-05-02 13:07:53 +0200127 __weak ARDVideoCallViewController *weakSelf = self;
128 dispatch_async(dispatch_get_main_queue(), ^{
129 ARDVideoCallViewController *strongSelf = weakSelf;
130 strongSelf.videoCallView.statusLabel.hidden = YES;
131 });
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000132}
133
134- (void)appClient:(ARDAppClient *)client
Zeke Chind3325802015-08-14 11:00:02 -0700135 didGetStats:(NSArray *)stats {
136 _videoCallView.statsView.stats = stats;
137 [_videoCallView setNeedsLayout];
138}
139
140- (void)appClient:(ARDAppClient *)client
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000141 didError:(NSError *)error {
142 NSString *message =
143 [NSString stringWithFormat:@"%@", error.localizedDescription];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000144 [self hangup];
hewwatt7cc881d2017-05-18 01:33:34 -0700145 [self showAlertWithMessage:message];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000146}
147
148#pragma mark - ARDVideoCallViewDelegate
149
150- (void)videoCallViewDidHangup:(ARDVideoCallView *)view {
151 [self hangup];
152}
153
Zeke Chin57cc74e2015-05-05 07:52:31 -0700154- (void)videoCallViewDidSwitchCamera:(ARDVideoCallView *)view {
155 // TODO(tkchin): Rate limit this so you can't tap continously on it.
156 // Probably through an animation.
sakalc522e752017-04-05 12:17:48 -0700157 [_captureController switchCamera];
Zeke Chin57cc74e2015-05-05 07:52:31 -0700158}
159
tkchin0ce3bf92016-03-12 16:52:04 -0800160- (void)videoCallViewDidChangeRoute:(ARDVideoCallView *)view {
161 AVAudioSessionPortOverride override = AVAudioSessionPortOverrideNone;
162 if (_portOverride == AVAudioSessionPortOverrideNone) {
163 override = AVAudioSessionPortOverrideSpeaker;
164 }
165 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeAudioSession
166 block:^{
167 RTCAudioSession *session = [RTCAudioSession sharedInstance];
168 [session lockForConfiguration];
169 NSError *error = nil;
170 if ([session overrideOutputAudioPort:override error:&error]) {
171 _portOverride = override;
172 } else {
173 RTCLogError(@"Error overriding output port: %@",
174 error.localizedDescription);
175 }
176 [session unlockForConfiguration];
177 }];
178}
179
Zeke Chind3325802015-08-14 11:00:02 -0700180- (void)videoCallViewDidEnableStats:(ARDVideoCallView *)view {
181 _client.shouldGetStats = YES;
182 _videoCallView.statsView.hidden = NO;
183}
184
Anders Carlsson121ea322017-06-26 15:34:47 +0200185#pragma mark - RTCAudioSessionDelegate
186
187- (void)audioSession:(RTCAudioSession *)audioSession
188 didDetectPlayoutGlitch:(int64_t)totalNumberOfGlitches {
189 RTCLog(@"Audio session detected glitch, total: %lld", totalNumberOfGlitches);
190}
191
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000192#pragma mark - Private
193
Zeke Chin57cc74e2015-05-05 07:52:31 -0700194- (void)setRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack {
195 if (_remoteVideoTrack == remoteVideoTrack) {
196 return;
197 }
hayscedd8fef2015-12-08 11:08:39 -0800198 [_remoteVideoTrack removeRenderer:_videoCallView.remoteVideoView];
Zeke Chin57cc74e2015-05-05 07:52:31 -0700199 _remoteVideoTrack = nil;
200 [_videoCallView.remoteVideoView renderFrame:nil];
201 _remoteVideoTrack = remoteVideoTrack;
202 [_remoteVideoTrack addRenderer:_videoCallView.remoteVideoView];
203}
204
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000205- (void)hangup {
Zeke Chin57cc74e2015-05-05 07:52:31 -0700206 self.remoteVideoTrack = nil;
sakalc522e752017-04-05 12:17:48 -0700207 _videoCallView.localVideoView.captureSession = nil;
208 [_captureController stopCapture];
209 _captureController = nil;
Daniela012b56b2017-11-15 13:15:24 +0100210 [_fileCaptureController stopCapture];
211 _fileCaptureController = nil;
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000212 [_client disconnect];
tkchind2511962016-05-06 18:54:15 -0700213 [_delegate viewControllerDidFinish:self];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000214}
215
hjon79858f82016-03-13 22:08:26 -0700216- (NSString *)statusTextForState:(RTCIceConnectionState)state {
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000217 switch (state) {
hjon79858f82016-03-13 22:08:26 -0700218 case RTCIceConnectionStateNew:
219 case RTCIceConnectionStateChecking:
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000220 return @"Connecting...";
hjon79858f82016-03-13 22:08:26 -0700221 case RTCIceConnectionStateConnected:
222 case RTCIceConnectionStateCompleted:
223 case RTCIceConnectionStateFailed:
224 case RTCIceConnectionStateDisconnected:
225 case RTCIceConnectionStateClosed:
hjon8bbbf2c2016-03-14 13:15:44 -0700226 case RTCIceConnectionStateCount:
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000227 return nil;
228 }
229}
230
231- (void)showAlertWithMessage:(NSString*)message {
kthelgasonb13237b2017-03-30 04:56:05 -0700232 UIAlertController *alert =
233 [UIAlertController alertControllerWithTitle:nil
234 message:message
235 preferredStyle:UIAlertControllerStyleAlert];
236
237 UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK"
238 style:UIAlertActionStyleDefault
239 handler:^(UIAlertAction *action){
240 }];
241
242 [alert addAction:defaultAction];
243 [self presentViewController:alert animated:YES completion:nil];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000244}
245
246@end