blob: 63b3dd76cad025d9bc985110adc523314428ae07 [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
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020015#import <WebRTC/RTCAudioSession.h>
16#import <WebRTC/RTCAudioSessionConfiguration.h>
17#import <WebRTC/RTCDispatcher.h>
18#import <WebRTC/RTCLogging.h>
Tze Kwang Chin307a0922016-03-21 13:57:40 -070019
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>
Jiawei Ou4aeb35b2018-11-09 13:55:45 -080035@property(nonatomic, strong) ARDMainView *mainView;
36@property(nonatomic, strong) AVAudioPlayer *audioPlayer;
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000037@end
38
Tze Kwang Chin307a0922016-03-21 13:57:40 -070039@implementation ARDMainViewController {
tkchind2511962016-05-06 18:54:15 -070040 BOOL _useManualAudio;
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000041}
42
Jiawei Ou4aeb35b2018-11-09 13:55:45 -080043@synthesize mainView = _mainView;
44@synthesize audioPlayer = _audioPlayer;
45
denicija5db450d2017-03-28 08:27:41 -070046- (void)viewDidLoad {
47 [super viewDidLoad];
48 if ([[[NSProcessInfo processInfo] arguments] containsObject:loopbackLaunchProcessArgument]) {
Anders Carlssone1500582017-06-15 16:05:13 +020049 [self mainView:nil didInputRoom:@"" isLoopback:YES];
denicija5db450d2017-03-28 08:27:41 -070050 }
51}
52
Tze Kwang Chin307a0922016-03-21 13:57:40 -070053- (void)loadView {
denicija6d6762c2016-10-28 04:53:16 -070054 self.title = @"AppRTC Mobile";
Tze Kwang Chin307a0922016-03-21 13:57:40 -070055 _mainView = [[ARDMainView alloc] initWithFrame:CGRectZero];
56 _mainView.delegate = self;
57 self.view = _mainView;
denicija6d6762c2016-10-28 04:53:16 -070058 [self addSettingsBarButton];
Tze Kwang Chin307a0922016-03-21 13:57:40 -070059
tkchind2511962016-05-06 18:54:15 -070060 RTCAudioSessionConfiguration *webRTCConfig =
61 [RTCAudioSessionConfiguration webRTCConfiguration];
62 webRTCConfig.categoryOptions = webRTCConfig.categoryOptions |
63 AVAudioSessionCategoryOptionDefaultToSpeaker;
64 [RTCAudioSessionConfiguration setWebRTCConfiguration:webRTCConfig];
65
66 RTCAudioSession *session = [RTCAudioSession sharedInstance];
67 [session addDelegate:self];
68
69 [self configureAudioSession];
Tze Kwang Chin307a0922016-03-21 13:57:40 -070070 [self setupAudioPlayer];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000071}
72
denicija6d6762c2016-10-28 04:53:16 -070073- (void)addSettingsBarButton {
74 UIBarButtonItem *settingsButton =
75 [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:barButtonImageString]
76 style:UIBarButtonItemStylePlain
77 target:self
78 action:@selector(showSettings:)];
79 self.navigationItem.rightBarButtonItem = settingsButton;
80}
81
denicija5db450d2017-03-28 08:27:41 -070082+ (NSString *)loopbackRoomString {
83 NSString *loopbackRoomString =
84 [[NSUUID UUID].UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""];
85 return loopbackRoomString;
86}
87
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000088#pragma mark - ARDMainViewDelegate
89
Anders Carlssone1500582017-06-15 16:05:13 +020090- (void)mainView:(ARDMainView *)mainView didInputRoom:(NSString *)room isLoopback:(BOOL)isLoopback {
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000091 if (!room.length) {
denicija5db450d2017-03-28 08:27:41 -070092 if (isLoopback) {
93 // If this is a loopback call, allow a generated room name.
94 room = [[self class] loopbackRoomString];
95 } else {
96 [self showAlertWithMessage:@"Missing room name."];
97 return;
98 }
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000099 }
100 // Trim whitespaces.
101 NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceCharacterSet];
102 NSString *trimmedRoom = [room stringByTrimmingCharactersInSet:whitespaceSet];
103
104 // Check that room name is valid.
105 NSError *error = nil;
106 NSRegularExpressionOptions options = NSRegularExpressionCaseInsensitive;
107 NSRegularExpression *regex =
108 [NSRegularExpression regularExpressionWithPattern:@"\\w+"
109 options:options
110 error:&error];
111 if (error) {
112 [self showAlertWithMessage:error.localizedDescription];
113 return;
114 }
115 NSRange matchRange =
116 [regex rangeOfFirstMatchInString:trimmedRoom
117 options:0
118 range:NSMakeRange(0, trimmedRoom.length)];
119 if (matchRange.location == NSNotFound ||
120 matchRange.length != trimmedRoom.length) {
121 [self showAlertWithMessage:@"Invalid room name."];
122 return;
123 }
124
Anders Carlssone1500582017-06-15 16:05:13 +0200125 ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init];
126
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700127 RTCAudioSession *session = [RTCAudioSession sharedInstance];
Anders Carlssone1500582017-06-15 16:05:13 +0200128 session.useManualAudio = [settingsModel currentUseManualAudioConfigSettingFromStore];
tkchind2511962016-05-06 18:54:15 -0700129 session.isAudioEnabled = NO;
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700130
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000131 // Kick off the video call.
132 ARDVideoCallViewController *videoCallViewController =
haysc913e6452015-10-02 11:44:03 -0700133 [[ARDVideoCallViewController alloc] initForRoom:trimmedRoom
134 isLoopback:isLoopback
tkchind2511962016-05-06 18:54:15 -0700135 delegate:self];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000136 videoCallViewController.modalTransitionStyle =
137 UIModalTransitionStyleCrossDissolve;
138 [self presentViewController:videoCallViewController
139 animated:YES
140 completion:nil];
141}
142
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700143- (void)mainViewDidToggleAudioLoop:(ARDMainView *)mainView {
144 if (mainView.isAudioLoopPlaying) {
145 [_audioPlayer stop];
146 } else {
147 [_audioPlayer play];
148 }
149 mainView.isAudioLoopPlaying = _audioPlayer.playing;
150}
151
tkchind2511962016-05-06 18:54:15 -0700152#pragma mark - ARDVideoCallViewControllerDelegate
153
154- (void)viewControllerDidFinish:(ARDVideoCallViewController *)viewController {
155 if (![viewController isBeingDismissed]) {
156 RTCLog(@"Dismissing VC");
157 [self dismissViewControllerAnimated:YES completion:^{
158 [self restartAudioPlayerIfNeeded];
159 }];
160 }
161 RTCAudioSession *session = [RTCAudioSession sharedInstance];
162 session.isAudioEnabled = NO;
163}
164
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700165#pragma mark - RTCAudioSessionDelegate
166
tkchind2511962016-05-06 18:54:15 -0700167- (void)audioSessionDidStartPlayOrRecord:(RTCAudioSession *)session {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700168 // Stop playback on main queue and then configure WebRTC.
169 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeMain
170 block:^{
Jiawei Ou4aeb35b2018-11-09 13:55:45 -0800171 if (self.mainView.isAudioLoopPlaying) {
172 RTCLog(@"Stopping audio loop due to WebRTC start.");
173 [self.audioPlayer stop];
174 }
175 RTCLog(@"Setting isAudioEnabled to YES.");
176 session.isAudioEnabled = YES;
177 }];
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700178}
179
tkchind2511962016-05-06 18:54:15 -0700180- (void)audioSessionDidStopPlayOrRecord:(RTCAudioSession *)session {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700181 // WebRTC is done with the audio session. Restart playback.
182 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeMain
183 block:^{
tkchind2511962016-05-06 18:54:15 -0700184 RTCLog(@"audioSessionDidStopPlayOrRecord");
185 [self restartAudioPlayerIfNeeded];
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700186 }];
187}
188
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000189#pragma mark - Private
denicija6d6762c2016-10-28 04:53:16 -0700190- (void)showSettings:(id)sender {
denicijad17d5362016-11-02 02:56:09 -0700191 ARDSettingsViewController *settingsController =
denicijab04b5c22016-11-09 04:28:46 -0800192 [[ARDSettingsViewController alloc] initWithStyle:UITableViewStyleGrouped
denicija2256e042016-11-09 06:26:18 -0800193 settingsModel:[[ARDSettingsModel alloc] init]];
194
denicijad17d5362016-11-02 02:56:09 -0700195 UINavigationController *navigationController =
196 [[UINavigationController alloc] initWithRootViewController:settingsController];
197 [self presentViewControllerAsModal:navigationController];
198}
199
200- (void)presentViewControllerAsModal:(UIViewController *)viewController {
201 [self presentViewController:viewController animated:YES completion:nil];
denicija6d6762c2016-10-28 04:53:16 -0700202}
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000203
tkchind2511962016-05-06 18:54:15 -0700204- (void)configureAudioSession {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700205 RTCAudioSessionConfiguration *configuration =
206 [[RTCAudioSessionConfiguration alloc] init];
207 configuration.category = AVAudioSessionCategoryAmbient;
208 configuration.categoryOptions = AVAudioSessionCategoryOptionDuckOthers;
209 configuration.mode = AVAudioSessionModeDefault;
210
211 RTCAudioSession *session = [RTCAudioSession sharedInstance];
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700212 [session lockForConfiguration];
tkchind2511962016-05-06 18:54:15 -0700213 BOOL hasSucceeded = NO;
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700214 NSError *error = nil;
tkchind2511962016-05-06 18:54:15 -0700215 if (session.isActive) {
216 hasSucceeded = [session setConfiguration:configuration error:&error];
217 } else {
218 hasSucceeded = [session setConfiguration:configuration
219 active:YES
220 error:&error];
221 }
222 if (!hasSucceeded) {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700223 RTCLogError(@"Error setting configuration: %@", error.localizedDescription);
224 }
225 [session unlockForConfiguration];
226}
227
228- (void)setupAudioPlayer {
229 NSString *audioFilePath =
230 [[NSBundle mainBundle] pathForResource:@"mozart" ofType:@"mp3"];
231 NSURL *audioFileURL = [NSURL URLWithString:audioFilePath];
232 _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL
233 error:nil];
234 _audioPlayer.numberOfLoops = -1;
235 _audioPlayer.volume = 1.0;
236 [_audioPlayer prepareToPlay];
237}
238
tkchind2511962016-05-06 18:54:15 -0700239- (void)restartAudioPlayerIfNeeded {
Anders Carlsson30593782017-06-22 14:27:27 +0200240 [self configureAudioSession];
tkchind2511962016-05-06 18:54:15 -0700241 if (_mainView.isAudioLoopPlaying && !self.presentedViewController) {
242 RTCLog(@"Starting audio loop due to WebRTC end.");
tkchind2511962016-05-06 18:54:15 -0700243 [_audioPlayer play];
244 }
245}
246
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000247- (void)showAlertWithMessage:(NSString*)message {
kthelgasonb13237b2017-03-30 04:56:05 -0700248 UIAlertController *alert =
249 [UIAlertController alertControllerWithTitle:nil
250 message:message
251 preferredStyle:UIAlertControllerStyleAlert];
252
253 UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK"
254 style:UIAlertActionStyleDefault
255 handler:^(UIAlertAction *action){
256 }];
257
258 [alert addAction:defaultAction];
259 [self presentViewController:alert animated:YES completion:nil];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000260}
261
262@end