blob: e8b8112e41b24e42ca70232af860f231916e7422 [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
Mirko Bonadei19640aa2020-10-19 16:12:43 +020015#import "sdk/objc/base/RTCLogging.h"
16#import "sdk/objc/components/audio/RTCAudioSession.h"
17#import "sdk/objc/components/audio/RTCAudioSessionConfiguration.h"
18#import "sdk/objc/helpers/RTCDispatcher.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;
dharmesh13fbc082020-07-11 08:47:45 +0530137 videoCallViewController.modalPresentationStyle = UIModalPresentationFullScreen;
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000138 [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 }
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200161 RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
tkchind2511962016-05-06 18:54:15 -0700162 session.isAudioEnabled = NO;
163}
164
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200165#pragma mark - RTC_OBJC_TYPE(RTCAudioSessionDelegate)
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700166
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200167- (void)audioSessionDidStartPlayOrRecord:(RTC_OBJC_TYPE(RTCAudioSession) *)session {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700168 // Stop playback on main queue and then configure WebRTC.
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200169 [RTC_OBJC_TYPE(RTCDispatcher)
170 dispatchAsyncOnType:RTCDispatcherTypeMain
171 block:^{
172 if (self.mainView.isAudioLoopPlaying) {
173 RTCLog(@"Stopping audio loop due to WebRTC start.");
174 [self.audioPlayer stop];
175 }
176 RTCLog(@"Setting isAudioEnabled to YES.");
177 session.isAudioEnabled = YES;
178 }];
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700179}
180
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200181- (void)audioSessionDidStopPlayOrRecord:(RTC_OBJC_TYPE(RTCAudioSession) *)session {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700182 // WebRTC is done with the audio session. Restart playback.
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200183 [RTC_OBJC_TYPE(RTCDispatcher) dispatchAsyncOnType:RTCDispatcherTypeMain
184 block:^{
185 RTCLog(@"audioSessionDidStopPlayOrRecord");
186 [self restartAudioPlayerIfNeeded];
187 }];
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700188}
189
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000190#pragma mark - Private
denicija6d6762c2016-10-28 04:53:16 -0700191- (void)showSettings:(id)sender {
denicijad17d5362016-11-02 02:56:09 -0700192 ARDSettingsViewController *settingsController =
denicijab04b5c22016-11-09 04:28:46 -0800193 [[ARDSettingsViewController alloc] initWithStyle:UITableViewStyleGrouped
denicija2256e042016-11-09 06:26:18 -0800194 settingsModel:[[ARDSettingsModel alloc] init]];
195
denicijad17d5362016-11-02 02:56:09 -0700196 UINavigationController *navigationController =
197 [[UINavigationController alloc] initWithRootViewController:settingsController];
198 [self presentViewControllerAsModal:navigationController];
199}
200
201- (void)presentViewControllerAsModal:(UIViewController *)viewController {
202 [self presentViewController:viewController animated:YES completion:nil];
denicija6d6762c2016-10-28 04:53:16 -0700203}
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000204
tkchind2511962016-05-06 18:54:15 -0700205- (void)configureAudioSession {
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200206 RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *configuration =
207 [[RTC_OBJC_TYPE(RTCAudioSessionConfiguration) alloc] init];
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700208 configuration.category = AVAudioSessionCategoryAmbient;
209 configuration.categoryOptions = AVAudioSessionCategoryOptionDuckOthers;
210 configuration.mode = AVAudioSessionModeDefault;
211
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200212 RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700213 [session lockForConfiguration];
tkchind2511962016-05-06 18:54:15 -0700214 BOOL hasSucceeded = NO;
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700215 NSError *error = nil;
tkchind2511962016-05-06 18:54:15 -0700216 if (session.isActive) {
217 hasSucceeded = [session setConfiguration:configuration error:&error];
218 } else {
219 hasSucceeded = [session setConfiguration:configuration
220 active:YES
221 error:&error];
222 }
223 if (!hasSucceeded) {
Tze Kwang Chin307a0922016-03-21 13:57:40 -0700224 RTCLogError(@"Error setting configuration: %@", error.localizedDescription);
225 }
226 [session unlockForConfiguration];
227}
228
229- (void)setupAudioPlayer {
230 NSString *audioFilePath =
231 [[NSBundle mainBundle] pathForResource:@"mozart" ofType:@"mp3"];
232 NSURL *audioFileURL = [NSURL URLWithString:audioFilePath];
233 _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL
234 error:nil];
235 _audioPlayer.numberOfLoops = -1;
236 _audioPlayer.volume = 1.0;
237 [_audioPlayer prepareToPlay];
238}
239
tkchind2511962016-05-06 18:54:15 -0700240- (void)restartAudioPlayerIfNeeded {
Anders Carlsson30593782017-06-22 14:27:27 +0200241 [self configureAudioSession];
tkchind2511962016-05-06 18:54:15 -0700242 if (_mainView.isAudioLoopPlaying && !self.presentedViewController) {
243 RTCLog(@"Starting audio loop due to WebRTC end.");
tkchind2511962016-05-06 18:54:15 -0700244 [_audioPlayer play];
245 }
246}
247
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000248- (void)showAlertWithMessage:(NSString*)message {
kthelgasonb13237b2017-03-30 04:56:05 -0700249 UIAlertController *alert =
250 [UIAlertController alertControllerWithTitle:nil
251 message:message
252 preferredStyle:UIAlertControllerStyleAlert];
253
254 UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK"
255 style:UIAlertActionStyleDefault
256 handler:^(UIAlertAction *action){
257 }];
258
259 [alert addAction:defaultAction];
260 [self presentViewController:alert animated:YES completion:nil];
tkchin@webrtc.orgef2a5dd2015-01-15 22:38:21 +0000261}
262
263@end