blob: 75d454a44c3a1372dc4761ade72cbb9f4ca78b7c [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
tkchin9eeb6242016-04-27 01:54:20 -070015#import "WebRTC/RTCDispatcher.h"
16#import "WebRTC/RTCLogging.h"
Tze Kwang Chin307a0922016-03-21 13:57:40 -070017#import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h"
18#import "webrtc/modules/audio_device/ios/objc/RTCAudioSessionConfiguration.h"
19
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000020#import "ARDAppClient.h"
21#import "ARDMainView.h"
denicija2256e042016-11-09 06:26:18 -080022#import "ARDSettingsModel.h"
denicijad17d5362016-11-02 02:56:09 -070023#import "ARDSettingsViewController.h"
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000024#import "ARDVideoCallViewController.h"
25
denicijad17d5362016-11-02 02:56:09 -070026static NSString *const barButtonImageString = @"ic_settings_black_24dp.png";
denicija6d6762c2016-10-28 04:53:16 -070027
denicija5db450d2017-03-28 08:27:41 -070028// Launch argument to be passed to indicate that the app should start loopback immediatly
29static NSString *const loopbackLaunchProcessArgument = @"loopback";
30
Tze Kwang Chin307a0922016-03-21 13:57:40 -070031@interface ARDMainViewController () <
32 ARDMainViewDelegate,
tkchind2511962016-05-06 18:54:15 -070033 ARDVideoCallViewControllerDelegate,
Tze Kwang Chin307a0922016-03-21 13:57:40 -070034 RTCAudioSessionDelegate>
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000035@end
36
Tze Kwang Chin307a0922016-03-21 13:57:40 -070037@implementation ARDMainViewController {
38 ARDMainView *_mainView;
39 AVAudioPlayer *_audioPlayer;
tkchind2511962016-05-06 18:54:15 -070040 BOOL _useManualAudio;
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000041}
42
denicija5db450d2017-03-28 08:27:41 -070043- (void)viewDidLoad {
44 [super viewDidLoad];
45 if ([[[NSProcessInfo processInfo] arguments] containsObject:loopbackLaunchProcessArgument]) {
46 [self mainView:nil
47 didInputRoom:@""
48 isLoopback:YES
49 isAudioOnly:NO
50 shouldMakeAecDump:NO
51 shouldUseLevelControl:NO
52 useManualAudio:NO];
53 }
54}
55
Tze Kwang Chin307a0922016-03-21 13:57:40 -070056- (void)loadView {
denicija6d6762c2016-10-28 04:53:16 -070057 self.title = @"AppRTC Mobile";
Tze Kwang Chin307a0922016-03-21 13:57:40 -070058 _mainView = [[ARDMainView alloc] initWithFrame:CGRectZero];
59 _mainView.delegate = self;
60 self.view = _mainView;
denicija6d6762c2016-10-28 04:53:16 -070061 [self addSettingsBarButton];
Tze Kwang Chin307a0922016-03-21 13:57:40 -070062
tkchind2511962016-05-06 18:54:15 -070063 RTCAudioSessionConfiguration *webRTCConfig =
64 [RTCAudioSessionConfiguration webRTCConfiguration];
65 webRTCConfig.categoryOptions = webRTCConfig.categoryOptions |
66 AVAudioSessionCategoryOptionDefaultToSpeaker;
67 [RTCAudioSessionConfiguration setWebRTCConfiguration:webRTCConfig];
68
69 RTCAudioSession *session = [RTCAudioSession sharedInstance];
70 [session addDelegate:self];
71
72 [self configureAudioSession];
Tze Kwang Chin307a0922016-03-21 13:57:40 -070073 [self setupAudioPlayer];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000074}
75
denicija6d6762c2016-10-28 04:53:16 -070076- (void)addSettingsBarButton {
77 UIBarButtonItem *settingsButton =
78 [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:barButtonImageString]
79 style:UIBarButtonItemStylePlain
80 target:self
81 action:@selector(showSettings:)];
82 self.navigationItem.rightBarButtonItem = settingsButton;
83}
84
denicija5db450d2017-03-28 08:27:41 -070085+ (NSString *)loopbackRoomString {
86 NSString *loopbackRoomString =
87 [[NSUUID UUID].UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""];
88 return loopbackRoomString;
89}
90
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000091#pragma mark - ARDMainViewDelegate
92
haysc913e6452015-10-02 11:44:03 -070093- (void)mainView:(ARDMainView *)mainView
tkchinab1293a2016-08-30 12:35:05 -070094 didInputRoom:(NSString *)room
95 isLoopback:(BOOL)isLoopback
96 isAudioOnly:(BOOL)isAudioOnly
97 shouldMakeAecDump:(BOOL)shouldMakeAecDump
98 shouldUseLevelControl:(BOOL)shouldUseLevelControl
99 useManualAudio:(BOOL)useManualAudio {
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000100 if (!room.length) {
denicija5db450d2017-03-28 08:27:41 -0700101 if (isLoopback) {
102 // If this is a loopback call, allow a generated room name.
103 room = [[self class] loopbackRoomString];
104 } else {
105 [self showAlertWithMessage:@"Missing room name."];
106 return;
107 }
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000108 }
109 // Trim whitespaces.
110 NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceCharacterSet];
111 NSString *trimmedRoom = [room stringByTrimmingCharactersInSet:whitespaceSet];
112
113 // Check that room name is valid.
114 NSError *error = nil;
115 NSRegularExpressionOptions options = NSRegularExpressionCaseInsensitive;
116 NSRegularExpression *regex =
117 [NSRegularExpression regularExpressionWithPattern:@"\\w+"
118 options:options
119 error:&error];
120 if (error) {
121 [self showAlertWithMessage:error.localizedDescription];
122 return;
123 }
124 NSRange matchRange =
125 [regex rangeOfFirstMatchInString:trimmedRoom
126 options:0
127 range:NSMakeRange(0, trimmedRoom.length)];
128 if (matchRange.location == NSNotFound ||
129 matchRange.length != trimmedRoom.length) {
130 [self showAlertWithMessage:@"Invalid room name."];
131 return;
132 }
133
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700134 RTCAudioSession *session = [RTCAudioSession sharedInstance];
tkchind2511962016-05-06 18:54:15 -0700135 session.useManualAudio = useManualAudio;
136 session.isAudioEnabled = NO;
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700137
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000138 // Kick off the video call.
139 ARDVideoCallViewController *videoCallViewController =
haysc913e6452015-10-02 11:44:03 -0700140 [[ARDVideoCallViewController alloc] initForRoom:trimmedRoom
141 isLoopback:isLoopback
tkchind2511962016-05-06 18:54:15 -0700142 isAudioOnly:isAudioOnly
peah5085b0c2016-08-25 22:15:14 -0700143 shouldMakeAecDump:shouldMakeAecDump
tkchinab1293a2016-08-30 12:35:05 -0700144 shouldUseLevelControl:shouldUseLevelControl
tkchind2511962016-05-06 18:54:15 -0700145 delegate:self];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000146 videoCallViewController.modalTransitionStyle =
147 UIModalTransitionStyleCrossDissolve;
148 [self presentViewController:videoCallViewController
149 animated:YES
150 completion:nil];
151}
152
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700153- (void)mainViewDidToggleAudioLoop:(ARDMainView *)mainView {
154 if (mainView.isAudioLoopPlaying) {
155 [_audioPlayer stop];
156 } else {
157 [_audioPlayer play];
158 }
159 mainView.isAudioLoopPlaying = _audioPlayer.playing;
160}
161
tkchind2511962016-05-06 18:54:15 -0700162#pragma mark - ARDVideoCallViewControllerDelegate
163
164- (void)viewControllerDidFinish:(ARDVideoCallViewController *)viewController {
165 if (![viewController isBeingDismissed]) {
166 RTCLog(@"Dismissing VC");
167 [self dismissViewControllerAnimated:YES completion:^{
168 [self restartAudioPlayerIfNeeded];
169 }];
170 }
171 RTCAudioSession *session = [RTCAudioSession sharedInstance];
172 session.isAudioEnabled = NO;
173}
174
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700175#pragma mark - RTCAudioSessionDelegate
176
tkchind2511962016-05-06 18:54:15 -0700177- (void)audioSessionDidStartPlayOrRecord:(RTCAudioSession *)session {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700178 // Stop playback on main queue and then configure WebRTC.
179 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeMain
180 block:^{
181 if (_mainView.isAudioLoopPlaying) {
182 RTCLog(@"Stopping audio loop due to WebRTC start.");
183 [_audioPlayer stop];
184 }
tkchind2511962016-05-06 18:54:15 -0700185 RTCLog(@"Setting isAudioEnabled to YES.");
186 session.isAudioEnabled = YES;
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700187 }];
188}
189
tkchind2511962016-05-06 18:54:15 -0700190- (void)audioSessionDidStopPlayOrRecord:(RTCAudioSession *)session {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700191 // WebRTC is done with the audio session. Restart playback.
192 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeMain
193 block:^{
tkchind2511962016-05-06 18:54:15 -0700194 RTCLog(@"audioSessionDidStopPlayOrRecord");
195 [self restartAudioPlayerIfNeeded];
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700196 }];
197}
198
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000199#pragma mark - Private
denicija6d6762c2016-10-28 04:53:16 -0700200- (void)showSettings:(id)sender {
denicijad17d5362016-11-02 02:56:09 -0700201 ARDSettingsViewController *settingsController =
denicijab04b5c22016-11-09 04:28:46 -0800202 [[ARDSettingsViewController alloc] initWithStyle:UITableViewStyleGrouped
denicija2256e042016-11-09 06:26:18 -0800203 settingsModel:[[ARDSettingsModel alloc] init]];
204
denicijad17d5362016-11-02 02:56:09 -0700205 UINavigationController *navigationController =
206 [[UINavigationController alloc] initWithRootViewController:settingsController];
207 [self presentViewControllerAsModal:navigationController];
208}
209
210- (void)presentViewControllerAsModal:(UIViewController *)viewController {
211 [self presentViewController:viewController animated:YES completion:nil];
denicija6d6762c2016-10-28 04:53:16 -0700212}
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000213
tkchind2511962016-05-06 18:54:15 -0700214- (void)configureAudioSession {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700215 RTCAudioSessionConfiguration *configuration =
216 [[RTCAudioSessionConfiguration alloc] init];
217 configuration.category = AVAudioSessionCategoryAmbient;
218 configuration.categoryOptions = AVAudioSessionCategoryOptionDuckOthers;
219 configuration.mode = AVAudioSessionModeDefault;
220
221 RTCAudioSession *session = [RTCAudioSession sharedInstance];
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700222 [session lockForConfiguration];
tkchind2511962016-05-06 18:54:15 -0700223 BOOL hasSucceeded = NO;
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700224 NSError *error = nil;
tkchind2511962016-05-06 18:54:15 -0700225 if (session.isActive) {
226 hasSucceeded = [session setConfiguration:configuration error:&error];
227 } else {
228 hasSucceeded = [session setConfiguration:configuration
229 active:YES
230 error:&error];
231 }
232 if (!hasSucceeded) {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700233 RTCLogError(@"Error setting configuration: %@", error.localizedDescription);
234 }
235 [session unlockForConfiguration];
236}
237
238- (void)setupAudioPlayer {
239 NSString *audioFilePath =
240 [[NSBundle mainBundle] pathForResource:@"mozart" ofType:@"mp3"];
241 NSURL *audioFileURL = [NSURL URLWithString:audioFilePath];
242 _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL
243 error:nil];
244 _audioPlayer.numberOfLoops = -1;
245 _audioPlayer.volume = 1.0;
246 [_audioPlayer prepareToPlay];
247}
248
tkchind2511962016-05-06 18:54:15 -0700249- (void)restartAudioPlayerIfNeeded {
250 if (_mainView.isAudioLoopPlaying && !self.presentedViewController) {
251 RTCLog(@"Starting audio loop due to WebRTC end.");
252 [self configureAudioSession];
253 [_audioPlayer play];
254 }
255}
256
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000257- (void)showAlertWithMessage:(NSString*)message {
258 UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:nil
259 message:message
260 delegate:nil
261 cancelButtonTitle:@"OK"
262 otherButtonTitles:nil];
263 [alertView show];
264}
265
266@end