ARDVideoCallViewController.m (8987B)
1 /* 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 * 4 * 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. 9 */ 10 11 #import "ARDVideoCallViewController.h" 12 13 #import "sdk/objc/api/peerconnection/RTCMediaConstraints.h" 14 #import "sdk/objc/base/RTCLogging.h" 15 #import "sdk/objc/components/audio/RTCAudioSession.h" 16 #import "sdk/objc/components/capturer/RTCCameraVideoCapturer.h" 17 #import "sdk/objc/helpers/RTCDispatcher.h" 18 19 #import "ARDAppClient.h" 20 #import "ARDCaptureController.h" 21 #import "ARDFileCaptureController.h" 22 #import "ARDSettingsModel.h" 23 #import "ARDVideoCallView.h" 24 25 @interface ARDVideoCallViewController () < 26 ARDAppClientDelegate, 27 ARDVideoCallViewDelegate, 28 RTC_OBJC_TYPE (RTCAudioSessionDelegate)> 29 @property(nonatomic, strong) RTC_OBJC_TYPE(RTCVideoTrack) * remoteVideoTrack; 30 @property(nonatomic, readonly) ARDVideoCallView *videoCallView; 31 @property(nonatomic, assign) AVAudioSessionPortOverride portOverride; 32 @end 33 34 @implementation ARDVideoCallViewController { 35 ARDAppClient *_client; 36 RTC_OBJC_TYPE(RTCVideoTrack) * _remoteVideoTrack; 37 ARDCaptureController *_captureController; 38 ARDFileCaptureController *_fileCaptureController NS_AVAILABLE_IOS(10); 39 } 40 41 @synthesize videoCallView = _videoCallView; 42 @synthesize remoteVideoTrack = _remoteVideoTrack; 43 @synthesize delegate = _delegate; 44 @synthesize portOverride = _portOverride; 45 46 - (instancetype)initForRoom:(NSString *)room 47 isLoopback:(BOOL)isLoopback 48 delegate:(id<ARDVideoCallViewControllerDelegate>)delegate { 49 self = [super init]; 50 if (self) { 51 ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init]; 52 _delegate = delegate; 53 54 _client = [[ARDAppClient alloc] initWithDelegate:self]; 55 [_client connectToRoomWithId:room 56 settings:settingsModel 57 isLoopback:isLoopback]; 58 } 59 return self; 60 } 61 62 - (void)loadView { 63 _videoCallView = [[ARDVideoCallView alloc] initWithFrame:CGRectZero]; 64 _videoCallView.delegate = self; 65 _videoCallView.statusLabel.text = 66 [self statusTextForState:RTCIceConnectionStateNew]; 67 self.view = _videoCallView; 68 69 RTC_OBJC_TYPE(RTCAudioSession) *session = 70 [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; 71 [session addDelegate:self]; 72 } 73 74 - (UIInterfaceOrientationMask)supportedInterfaceOrientations { 75 return UIInterfaceOrientationMaskAll; 76 } 77 78 #pragma mark - ARDAppClientDelegate 79 80 - (void)appClient:(ARDAppClient *)client 81 didChangeState:(ARDAppClientState)state { 82 switch (state) { 83 case kARDAppClientStateConnected: 84 RTCLog(@"Client connected."); 85 break; 86 case kARDAppClientStateConnecting: 87 RTCLog(@"Client connecting."); 88 break; 89 case kARDAppClientStateDisconnected: 90 RTCLog(@"Client disconnected."); 91 [self hangup]; 92 break; 93 } 94 } 95 96 - (void)appClient:(ARDAppClient *)client 97 didChangeConnectionState:(RTCIceConnectionState)state { 98 RTCLog(@"ICE state changed: %ld", (long)state); 99 __weak ARDVideoCallViewController *weakSelf = self; 100 dispatch_async(dispatch_get_main_queue(), ^{ 101 ARDVideoCallViewController *strongSelf = weakSelf; 102 strongSelf.videoCallView.statusLabel.text = 103 [strongSelf statusTextForState:state]; 104 }); 105 } 106 107 - (void)appClient:(ARDAppClient *)client 108 didCreateLocalCapturer: 109 (RTC_OBJC_TYPE(RTCCameraVideoCapturer) *)localCapturer { 110 _videoCallView.localVideoView.captureSession = localCapturer.captureSession; 111 ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init]; 112 _captureController = 113 [[ARDCaptureController alloc] initWithCapturer:localCapturer 114 settings:settingsModel]; 115 [_captureController startCapture]; 116 } 117 118 - (void)appClient:(ARDAppClient *)client 119 didCreateLocalFileCapturer: 120 (RTC_OBJC_TYPE(RTCFileVideoCapturer) *)fileCapturer { 121 #if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0) 122 if (@available(iOS 10, *)) { 123 _fileCaptureController = 124 [[ARDFileCaptureController alloc] initWithCapturer:fileCapturer]; 125 [_fileCaptureController startCapture]; 126 } 127 #endif 128 } 129 130 - (void)appClient:(ARDAppClient *)client 131 didReceiveLocalVideoTrack:(RTC_OBJC_TYPE(RTCVideoTrack) *)localVideoTrack { 132 } 133 134 - (void)appClient:(ARDAppClient *)client 135 didReceiveRemoteVideoTrack: 136 (RTC_OBJC_TYPE(RTCVideoTrack) *)remoteVideoTrack { 137 self.remoteVideoTrack = remoteVideoTrack; 138 __weak ARDVideoCallViewController *weakSelf = self; 139 dispatch_async(dispatch_get_main_queue(), ^{ 140 ARDVideoCallViewController *strongSelf = weakSelf; 141 strongSelf.videoCallView.statusLabel.hidden = YES; 142 }); 143 } 144 145 - (void)appClient:(ARDAppClient *)client 146 didGetStats:(RTC_OBJC_TYPE(RTCStatisticsReport) *)stats { 147 _videoCallView.statsView.stats = stats; 148 [_videoCallView setNeedsLayout]; 149 } 150 151 - (void)appClient:(ARDAppClient *)client didError:(NSError *)error { 152 NSString *message = 153 [NSString stringWithFormat:@"%@", error.localizedDescription]; 154 [self hangup]; 155 [self showAlertWithMessage:message]; 156 } 157 158 #pragma mark - ARDVideoCallViewDelegate 159 160 - (void)videoCallViewDidHangup:(ARDVideoCallView *)view { 161 [self hangup]; 162 } 163 164 - (void)videoCallView:(ARDVideoCallView *)view 165 shouldSwitchCameraWithCompletion:(void (^)(NSError *))completion { 166 [_captureController switchCamera:completion]; 167 } 168 169 - (void)videoCallView:(ARDVideoCallView *)view 170 shouldChangeRouteWithCompletion:(void (^)(void))completion { 171 NSParameterAssert(completion); 172 AVAudioSessionPortOverride override = AVAudioSessionPortOverrideNone; 173 if (_portOverride == AVAudioSessionPortOverrideNone) { 174 override = AVAudioSessionPortOverrideSpeaker; 175 } 176 [RTC_OBJC_TYPE(RTCDispatcher) 177 dispatchAsyncOnType:RTCDispatcherTypeAudioSession 178 block:^{ 179 RTC_OBJC_TYPE(RTCAudioSession) *session = 180 [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; 181 [session lockForConfiguration]; 182 NSError *error = nil; 183 if ([session overrideOutputAudioPort:override 184 error:&error]) { 185 self.portOverride = override; 186 } else { 187 RTCLogError(@"Error overriding output port: %@", 188 error.localizedDescription); 189 } 190 [session unlockForConfiguration]; 191 completion(); 192 }]; 193 } 194 195 - (void)videoCallViewDidEnableStats:(ARDVideoCallView *)view { 196 _client.shouldGetStats = YES; 197 _videoCallView.statsView.hidden = NO; 198 } 199 200 #pragma mark - RTC_OBJC_TYPE(RTCAudioSessionDelegate) 201 202 - (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession 203 didDetectPlayoutGlitch:(int64_t)totalNumberOfGlitches { 204 RTCLog(@"Audio session detected glitch, total: %lld", totalNumberOfGlitches); 205 } 206 207 #pragma mark - Private 208 209 - (void)setRemoteVideoTrack:(RTC_OBJC_TYPE(RTCVideoTrack) *)remoteVideoTrack { 210 if (_remoteVideoTrack == remoteVideoTrack) { 211 return; 212 } 213 [_remoteVideoTrack removeRenderer:_videoCallView.remoteVideoView]; 214 _remoteVideoTrack = nil; 215 [_videoCallView.remoteVideoView renderFrame:nil]; 216 _remoteVideoTrack = remoteVideoTrack; 217 [_remoteVideoTrack addRenderer:_videoCallView.remoteVideoView]; 218 } 219 220 - (void)hangup { 221 self.remoteVideoTrack = nil; 222 _videoCallView.localVideoView.captureSession = nil; 223 [_captureController stopCapture]; 224 _captureController = nil; 225 [_fileCaptureController stopCapture]; 226 _fileCaptureController = nil; 227 [_client disconnect]; 228 [_delegate viewControllerDidFinish:self]; 229 } 230 231 - (NSString *)statusTextForState:(RTCIceConnectionState)state { 232 switch (state) { 233 case RTCIceConnectionStateNew: 234 case RTCIceConnectionStateChecking: 235 return @"Connecting..."; 236 case RTCIceConnectionStateConnected: 237 case RTCIceConnectionStateCompleted: 238 case RTCIceConnectionStateFailed: 239 case RTCIceConnectionStateDisconnected: 240 case RTCIceConnectionStateClosed: 241 case RTCIceConnectionStateCount: 242 return nil; 243 } 244 } 245 246 - (void)showAlertWithMessage:(NSString *)message { 247 UIAlertController *alert = 248 [UIAlertController alertControllerWithTitle:nil 249 message:message 250 preferredStyle:UIAlertControllerStyleAlert]; 251 252 UIAlertAction *defaultAction = 253 [UIAlertAction actionWithTitle:@"OK" 254 style:UIAlertActionStyleDefault 255 handler:^(UIAlertAction *action){ 256 }]; 257 258 [alert addAction:defaultAction]; 259 [self presentViewController:alert animated:YES completion:nil]; 260 } 261 262 @end