blob: dea7742a1baf2f9a688ccf65ed079510c4f8fd2c [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
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020031@interface ARDMainViewController () <ARDMainViewDelegate,
32 ARDVideoCallViewControllerDelegate,
33 RTC_OBJC_TYPE (RTCAudioSessionDelegate)>
Jiawei Ou4aeb35b2018-11-09 13:55:45 -080034@property(nonatomic, strong) ARDMainView *mainView;
35@property(nonatomic, strong) AVAudioPlayer *audioPlayer;
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000036@end
37
Tze Kwang Chin307a0922016-03-21 13:57:40 -070038@implementation ARDMainViewController {
tkchind2511962016-05-06 18:54:15 -070039 BOOL _useManualAudio;
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000040}
41
Jiawei Ou4aeb35b2018-11-09 13:55:45 -080042@synthesize mainView = _mainView;
43@synthesize audioPlayer = _audioPlayer;
44
denicija5db450d2017-03-28 08:27:41 -070045- (void)viewDidLoad {
46 [super viewDidLoad];
47 if ([[[NSProcessInfo processInfo] arguments] containsObject:loopbackLaunchProcessArgument]) {
Anders Carlssone1500582017-06-15 16:05:13 +020048 [self mainView:nil didInputRoom:@"" isLoopback:YES];
denicija5db450d2017-03-28 08:27:41 -070049 }
50}
51
Tze Kwang Chin307a0922016-03-21 13:57:40 -070052- (void)loadView {
denicija6d6762c2016-10-28 04:53:16 -070053 self.title = @"AppRTC Mobile";
Tze Kwang Chin307a0922016-03-21 13:57:40 -070054 _mainView = [[ARDMainView alloc] initWithFrame:CGRectZero];
55 _mainView.delegate = self;
56 self.view = _mainView;
denicija6d6762c2016-10-28 04:53:16 -070057 [self addSettingsBarButton];
Tze Kwang Chin307a0922016-03-21 13:57:40 -070058
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020059 RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *webRTCConfig =
60 [RTC_OBJC_TYPE(RTCAudioSessionConfiguration) webRTCConfiguration];
tkchind2511962016-05-06 18:54:15 -070061 webRTCConfig.categoryOptions = webRTCConfig.categoryOptions |
62 AVAudioSessionCategoryOptionDefaultToSpeaker;
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020063 [RTC_OBJC_TYPE(RTCAudioSessionConfiguration) setWebRTCConfiguration:webRTCConfig];
tkchind2511962016-05-06 18:54:15 -070064
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020065 RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
tkchind2511962016-05-06 18:54:15 -070066 [session addDelegate:self];
67
68 [self configureAudioSession];
Tze Kwang Chin307a0922016-03-21 13:57:40 -070069 [self setupAudioPlayer];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000070}
71
denicija6d6762c2016-10-28 04:53:16 -070072- (void)addSettingsBarButton {
73 UIBarButtonItem *settingsButton =
74 [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:barButtonImageString]
75 style:UIBarButtonItemStylePlain
76 target:self
77 action:@selector(showSettings:)];
78 self.navigationItem.rightBarButtonItem = settingsButton;
79}
80
denicija5db450d2017-03-28 08:27:41 -070081+ (NSString *)loopbackRoomString {
82 NSString *loopbackRoomString =
83 [[NSUUID UUID].UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""];
84 return loopbackRoomString;
85}
86
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000087#pragma mark - ARDMainViewDelegate
88
Anders Carlssone1500582017-06-15 16:05:13 +020089- (void)mainView:(ARDMainView *)mainView didInputRoom:(NSString *)room isLoopback:(BOOL)isLoopback {
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000090 if (!room.length) {
denicija5db450d2017-03-28 08:27:41 -070091 if (isLoopback) {
92 // If this is a loopback call, allow a generated room name.
93 room = [[self class] loopbackRoomString];
94 } else {
95 [self showAlertWithMessage:@"Missing room name."];
96 return;
97 }
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +000098 }
99 // Trim whitespaces.
100 NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceCharacterSet];
101 NSString *trimmedRoom = [room stringByTrimmingCharactersInSet:whitespaceSet];
102
103 // Check that room name is valid.
104 NSError *error = nil;
105 NSRegularExpressionOptions options = NSRegularExpressionCaseInsensitive;
106 NSRegularExpression *regex =
107 [NSRegularExpression regularExpressionWithPattern:@"\\w+"
108 options:options
109 error:&error];
110 if (error) {
111 [self showAlertWithMessage:error.localizedDescription];
112 return;
113 }
114 NSRange matchRange =
115 [regex rangeOfFirstMatchInString:trimmedRoom
116 options:0
117 range:NSMakeRange(0, trimmedRoom.length)];
118 if (matchRange.location == NSNotFound ||
119 matchRange.length != trimmedRoom.length) {
120 [self showAlertWithMessage:@"Invalid room name."];
121 return;
122 }
123
Anders Carlssone1500582017-06-15 16:05:13 +0200124 ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init];
125
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200126 RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
Anders Carlssone1500582017-06-15 16:05:13 +0200127 session.useManualAudio = [settingsModel currentUseManualAudioConfigSettingFromStore];
tkchind2511962016-05-06 18:54:15 -0700128 session.isAudioEnabled = NO;
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700129
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000130 // Kick off the video call.
131 ARDVideoCallViewController *videoCallViewController =
haysc913e6452015-10-02 11:44:03 -0700132 [[ARDVideoCallViewController alloc] initForRoom:trimmedRoom
133 isLoopback:isLoopback
tkchind2511962016-05-06 18:54:15 -0700134 delegate:self];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000135 videoCallViewController.modalTransitionStyle =
136 UIModalTransitionStyleCrossDissolve;
137 [self presentViewController:videoCallViewController
138 animated:YES
139 completion:nil];
140}
141
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700142- (void)mainViewDidToggleAudioLoop:(ARDMainView *)mainView {
143 if (mainView.isAudioLoopPlaying) {
144 [_audioPlayer stop];
145 } else {
146 [_audioPlayer play];
147 }
148 mainView.isAudioLoopPlaying = _audioPlayer.playing;
149}
150
tkchind2511962016-05-06 18:54:15 -0700151#pragma mark - ARDVideoCallViewControllerDelegate
152
153- (void)viewControllerDidFinish:(ARDVideoCallViewController *)viewController {
154 if (![viewController isBeingDismissed]) {
155 RTCLog(@"Dismissing VC");
156 [self dismissViewControllerAnimated:YES completion:^{
157 [self restartAudioPlayerIfNeeded];
158 }];
159 }
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200160 RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
tkchind2511962016-05-06 18:54:15 -0700161 session.isAudioEnabled = NO;
162}
163
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200164#pragma mark - RTC_OBJC_TYPE(RTCAudioSessionDelegate)
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700165
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200166- (void)audioSessionDidStartPlayOrRecord:(RTC_OBJC_TYPE(RTCAudioSession) *)session {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700167 // Stop playback on main queue and then configure WebRTC.
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200168 [RTC_OBJC_TYPE(RTCDispatcher)
169 dispatchAsyncOnType:RTCDispatcherTypeMain
170 block:^{
171 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
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200180- (void)audioSessionDidStopPlayOrRecord:(RTC_OBJC_TYPE(RTCAudioSession) *)session {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700181 // WebRTC is done with the audio session. Restart playback.
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200182 [RTC_OBJC_TYPE(RTCDispatcher) dispatchAsyncOnType:RTCDispatcherTypeMain
183 block:^{
184 RTCLog(@"audioSessionDidStopPlayOrRecord");
185 [self restartAudioPlayerIfNeeded];
186 }];
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700187}
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 {
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200205 RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *configuration =
206 [[RTC_OBJC_TYPE(RTCAudioSessionConfiguration) alloc] init];
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700207 configuration.category = AVAudioSessionCategoryAmbient;
208 configuration.categoryOptions = AVAudioSessionCategoryOptionDuckOthers;
209 configuration.mode = AVAudioSessionModeDefault;
210
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200211 RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(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