blob: 0e93aae9ad173f04721b59433abe7361c2576f6b [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 "ARDMainViewController.h"
12
Tze Kwang Chin307a0922016-03-21 13:57:40 -070013#import <AVFoundation/AVFoundation.h>
14
denicija59ee91b2017-06-05 05:48:47 -070015#import "WebRTC/RTCAudioSession.h"
16#import "WebRTC/RTCAudioSessionConfiguration.h"
tkchin9eeb6242016-04-27 01:54:20 -070017#import "WebRTC/RTCDispatcher.h"
18#import "WebRTC/RTCLogging.h"
denicija59ee91b2017-06-05 05:48:47 -070019
Tze Kwang Chin307a0922016-03-21 13:57:40 -070020
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000021#import "ARDAppClient.h"
22#import "ARDMainView.h"
denicija2256e042016-11-09 06:26:18 -080023#import "ARDSettingsModel.h"
denicijad17d5362016-11-02 02:56:09 -070024#import "ARDSettingsViewController.h"
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000025#import "ARDVideoCallViewController.h"
26
denicijad17d5362016-11-02 02:56:09 -070027static NSString *const barButtonImageString = @"ic_settings_black_24dp.png";
denicija6d6762c2016-10-28 04:53:16 -070028
denicija5db450d2017-03-28 08:27:41 -070029// Launch argument to be passed to indicate that the app should start loopback immediatly
30static NSString *const loopbackLaunchProcessArgument = @"loopback";
31
Tze Kwang Chin307a0922016-03-21 13:57:40 -070032@interface ARDMainViewController () <
33 ARDMainViewDelegate,
tkchind2511962016-05-06 18:54:15 -070034 ARDVideoCallViewControllerDelegate,
Tze Kwang Chin307a0922016-03-21 13:57:40 -070035 RTCAudioSessionDelegate>
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000036@end
37
Tze Kwang Chin307a0922016-03-21 13:57:40 -070038@implementation ARDMainViewController {
39 ARDMainView *_mainView;
40 AVAudioPlayer *_audioPlayer;
tkchind2511962016-05-06 18:54:15 -070041 BOOL _useManualAudio;
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000042}
43
denicija5db450d2017-03-28 08:27:41 -070044- (void)viewDidLoad {
45 [super viewDidLoad];
46 if ([[[NSProcessInfo processInfo] arguments] containsObject:loopbackLaunchProcessArgument]) {
47 [self mainView:nil
48 didInputRoom:@""
49 isLoopback:YES
50 isAudioOnly:NO
51 shouldMakeAecDump:NO
52 shouldUseLevelControl:NO
53 useManualAudio:NO];
54 }
55}
56
Tze Kwang Chin307a0922016-03-21 13:57:40 -070057- (void)loadView {
denicija6d6762c2016-10-28 04:53:16 -070058 self.title = @"AppRTC Mobile";
Tze Kwang Chin307a0922016-03-21 13:57:40 -070059 _mainView = [[ARDMainView alloc] initWithFrame:CGRectZero];
60 _mainView.delegate = self;
61 self.view = _mainView;
denicija6d6762c2016-10-28 04:53:16 -070062 [self addSettingsBarButton];
Tze Kwang Chin307a0922016-03-21 13:57:40 -070063
tkchind2511962016-05-06 18:54:15 -070064 RTCAudioSessionConfiguration *webRTCConfig =
65 [RTCAudioSessionConfiguration webRTCConfiguration];
66 webRTCConfig.categoryOptions = webRTCConfig.categoryOptions |
67 AVAudioSessionCategoryOptionDefaultToSpeaker;
68 [RTCAudioSessionConfiguration setWebRTCConfiguration:webRTCConfig];
69
70 RTCAudioSession *session = [RTCAudioSession sharedInstance];
71 [session addDelegate:self];
72
73 [self configureAudioSession];
Tze Kwang Chin307a0922016-03-21 13:57:40 -070074 [self setupAudioPlayer];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000075}
76
denicija6d6762c2016-10-28 04:53:16 -070077- (void)addSettingsBarButton {
78 UIBarButtonItem *settingsButton =
79 [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:barButtonImageString]
80 style:UIBarButtonItemStylePlain
81 target:self
82 action:@selector(showSettings:)];
83 self.navigationItem.rightBarButtonItem = settingsButton;
84}
85
denicija5db450d2017-03-28 08:27:41 -070086+ (NSString *)loopbackRoomString {
87 NSString *loopbackRoomString =
88 [[NSUUID UUID].UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""];
89 return loopbackRoomString;
90}
91
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000092#pragma mark - ARDMainViewDelegate
93
haysc913e6452015-10-02 11:44:03 -070094- (void)mainView:(ARDMainView *)mainView
tkchinab1293a2016-08-30 12:35:05 -070095 didInputRoom:(NSString *)room
96 isLoopback:(BOOL)isLoopback
97 isAudioOnly:(BOOL)isAudioOnly
98 shouldMakeAecDump:(BOOL)shouldMakeAecDump
99 shouldUseLevelControl:(BOOL)shouldUseLevelControl
100 useManualAudio:(BOOL)useManualAudio {
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000101 if (!room.length) {
denicija5db450d2017-03-28 08:27:41 -0700102 if (isLoopback) {
103 // If this is a loopback call, allow a generated room name.
104 room = [[self class] loopbackRoomString];
105 } else {
106 [self showAlertWithMessage:@"Missing room name."];
107 return;
108 }
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000109 }
110 // Trim whitespaces.
111 NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceCharacterSet];
112 NSString *trimmedRoom = [room stringByTrimmingCharactersInSet:whitespaceSet];
113
114 // Check that room name is valid.
115 NSError *error = nil;
116 NSRegularExpressionOptions options = NSRegularExpressionCaseInsensitive;
117 NSRegularExpression *regex =
118 [NSRegularExpression regularExpressionWithPattern:@"\\w+"
119 options:options
120 error:&error];
121 if (error) {
122 [self showAlertWithMessage:error.localizedDescription];
123 return;
124 }
125 NSRange matchRange =
126 [regex rangeOfFirstMatchInString:trimmedRoom
127 options:0
128 range:NSMakeRange(0, trimmedRoom.length)];
129 if (matchRange.location == NSNotFound ||
130 matchRange.length != trimmedRoom.length) {
131 [self showAlertWithMessage:@"Invalid room name."];
132 return;
133 }
134
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700135 RTCAudioSession *session = [RTCAudioSession sharedInstance];
tkchind2511962016-05-06 18:54:15 -0700136 session.useManualAudio = useManualAudio;
137 session.isAudioEnabled = NO;
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700138
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000139 // Kick off the video call.
140 ARDVideoCallViewController *videoCallViewController =
haysc913e6452015-10-02 11:44:03 -0700141 [[ARDVideoCallViewController alloc] initForRoom:trimmedRoom
142 isLoopback:isLoopback
tkchind2511962016-05-06 18:54:15 -0700143 isAudioOnly:isAudioOnly
peah5085b0c2016-08-25 22:15:14 -0700144 shouldMakeAecDump:shouldMakeAecDump
tkchinab1293a2016-08-30 12:35:05 -0700145 shouldUseLevelControl:shouldUseLevelControl
tkchind2511962016-05-06 18:54:15 -0700146 delegate:self];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000147 videoCallViewController.modalTransitionStyle =
148 UIModalTransitionStyleCrossDissolve;
149 [self presentViewController:videoCallViewController
150 animated:YES
151 completion:nil];
152}
153
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700154- (void)mainViewDidToggleAudioLoop:(ARDMainView *)mainView {
155 if (mainView.isAudioLoopPlaying) {
156 [_audioPlayer stop];
157 } else {
158 [_audioPlayer play];
159 }
160 mainView.isAudioLoopPlaying = _audioPlayer.playing;
161}
162
tkchind2511962016-05-06 18:54:15 -0700163#pragma mark - ARDVideoCallViewControllerDelegate
164
165- (void)viewControllerDidFinish:(ARDVideoCallViewController *)viewController {
166 if (![viewController isBeingDismissed]) {
167 RTCLog(@"Dismissing VC");
168 [self dismissViewControllerAnimated:YES completion:^{
169 [self restartAudioPlayerIfNeeded];
170 }];
171 }
172 RTCAudioSession *session = [RTCAudioSession sharedInstance];
173 session.isAudioEnabled = NO;
174}
175
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700176#pragma mark - RTCAudioSessionDelegate
177
tkchind2511962016-05-06 18:54:15 -0700178- (void)audioSessionDidStartPlayOrRecord:(RTCAudioSession *)session {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700179 // Stop playback on main queue and then configure WebRTC.
180 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeMain
181 block:^{
182 if (_mainView.isAudioLoopPlaying) {
183 RTCLog(@"Stopping audio loop due to WebRTC start.");
184 [_audioPlayer stop];
185 }
tkchind2511962016-05-06 18:54:15 -0700186 RTCLog(@"Setting isAudioEnabled to YES.");
187 session.isAudioEnabled = YES;
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700188 }];
189}
190
tkchind2511962016-05-06 18:54:15 -0700191- (void)audioSessionDidStopPlayOrRecord:(RTCAudioSession *)session {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700192 // WebRTC is done with the audio session. Restart playback.
193 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeMain
194 block:^{
tkchind2511962016-05-06 18:54:15 -0700195 RTCLog(@"audioSessionDidStopPlayOrRecord");
196 [self restartAudioPlayerIfNeeded];
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700197 }];
198}
199
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000200#pragma mark - Private
denicija6d6762c2016-10-28 04:53:16 -0700201- (void)showSettings:(id)sender {
denicijad17d5362016-11-02 02:56:09 -0700202 ARDSettingsViewController *settingsController =
denicijab04b5c22016-11-09 04:28:46 -0800203 [[ARDSettingsViewController alloc] initWithStyle:UITableViewStyleGrouped
denicija2256e042016-11-09 06:26:18 -0800204 settingsModel:[[ARDSettingsModel alloc] init]];
205
denicijad17d5362016-11-02 02:56:09 -0700206 UINavigationController *navigationController =
207 [[UINavigationController alloc] initWithRootViewController:settingsController];
208 [self presentViewControllerAsModal:navigationController];
209}
210
211- (void)presentViewControllerAsModal:(UIViewController *)viewController {
212 [self presentViewController:viewController animated:YES completion:nil];
denicija6d6762c2016-10-28 04:53:16 -0700213}
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000214
tkchind2511962016-05-06 18:54:15 -0700215- (void)configureAudioSession {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700216 RTCAudioSessionConfiguration *configuration =
217 [[RTCAudioSessionConfiguration alloc] init];
218 configuration.category = AVAudioSessionCategoryAmbient;
219 configuration.categoryOptions = AVAudioSessionCategoryOptionDuckOthers;
220 configuration.mode = AVAudioSessionModeDefault;
221
222 RTCAudioSession *session = [RTCAudioSession sharedInstance];
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700223 [session lockForConfiguration];
tkchind2511962016-05-06 18:54:15 -0700224 BOOL hasSucceeded = NO;
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700225 NSError *error = nil;
tkchind2511962016-05-06 18:54:15 -0700226 if (session.isActive) {
227 hasSucceeded = [session setConfiguration:configuration error:&error];
228 } else {
229 hasSucceeded = [session setConfiguration:configuration
230 active:YES
231 error:&error];
232 }
233 if (!hasSucceeded) {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700234 RTCLogError(@"Error setting configuration: %@", error.localizedDescription);
235 }
236 [session unlockForConfiguration];
237}
238
239- (void)setupAudioPlayer {
240 NSString *audioFilePath =
241 [[NSBundle mainBundle] pathForResource:@"mozart" ofType:@"mp3"];
242 NSURL *audioFileURL = [NSURL URLWithString:audioFilePath];
243 _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL
244 error:nil];
245 _audioPlayer.numberOfLoops = -1;
246 _audioPlayer.volume = 1.0;
247 [_audioPlayer prepareToPlay];
248}
249
tkchind2511962016-05-06 18:54:15 -0700250- (void)restartAudioPlayerIfNeeded {
251 if (_mainView.isAudioLoopPlaying && !self.presentedViewController) {
252 RTCLog(@"Starting audio loop due to WebRTC end.");
253 [self configureAudioSession];
254 [_audioPlayer play];
255 }
256}
257
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000258- (void)showAlertWithMessage:(NSString*)message {
kthelgasonb13237b2017-03-30 04:56:05 -0700259 UIAlertController *alert =
260 [UIAlertController alertControllerWithTitle:nil
261 message:message
262 preferredStyle:UIAlertControllerStyleAlert];
263
264 UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK"
265 style:UIAlertActionStyleDefault
266 handler:^(UIAlertAction *action){
267 }];
268
269 [alert addAction:defaultAction];
270 [self presentViewController:alert animated:YES completion:nil];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000271}
272
273@end