| /* |
| * Copyright 2015 The WebRTC Project Authors. All rights reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #import "ARDMainViewController.h" |
| |
| #import <AVFoundation/AVFoundation.h> |
| |
| #import "sdk/objc/base/RTCLogging.h" |
| #import "sdk/objc/components/audio/RTCAudioSession.h" |
| #import "sdk/objc/components/audio/RTCAudioSessionConfiguration.h" |
| #import "sdk/objc/helpers/RTCDispatcher.h" |
| |
| #import "ARDAppClient.h" |
| #import "ARDMainView.h" |
| #import "ARDSettingsModel.h" |
| #import "ARDSettingsViewController.h" |
| #import "ARDVideoCallViewController.h" |
| |
| static NSString *const barButtonImageString = @"ic_settings_black_24dp.png"; |
| |
| // Launch argument to be passed to indicate that the app should start loopback immediatly |
| static NSString *const loopbackLaunchProcessArgument = @"loopback"; |
| |
| @interface ARDMainViewController () <ARDMainViewDelegate, |
| ARDVideoCallViewControllerDelegate, |
| RTC_OBJC_TYPE (RTCAudioSessionDelegate)> |
| @property(nonatomic, strong) ARDMainView *mainView; |
| @property(nonatomic, strong) AVAudioPlayer *audioPlayer; |
| @end |
| |
| @implementation ARDMainViewController { |
| BOOL _useManualAudio; |
| } |
| |
| @synthesize mainView = _mainView; |
| @synthesize audioPlayer = _audioPlayer; |
| |
| - (void)viewDidLoad { |
| [super viewDidLoad]; |
| if ([[[NSProcessInfo processInfo] arguments] containsObject:loopbackLaunchProcessArgument]) { |
| [self mainView:nil didInputRoom:@"" isLoopback:YES]; |
| } |
| } |
| |
| - (void)loadView { |
| self.title = @"AppRTC Mobile"; |
| _mainView = [[ARDMainView alloc] initWithFrame:CGRectZero]; |
| _mainView.delegate = self; |
| self.view = _mainView; |
| [self addSettingsBarButton]; |
| |
| RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *webRTCConfig = |
| [RTC_OBJC_TYPE(RTCAudioSessionConfiguration) webRTCConfiguration]; |
| webRTCConfig.categoryOptions = webRTCConfig.categoryOptions | |
| AVAudioSessionCategoryOptionDefaultToSpeaker; |
| [RTC_OBJC_TYPE(RTCAudioSessionConfiguration) setWebRTCConfiguration:webRTCConfig]; |
| |
| RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; |
| [session addDelegate:self]; |
| |
| [self configureAudioSession]; |
| [self setupAudioPlayer]; |
| } |
| |
| - (void)addSettingsBarButton { |
| UIBarButtonItem *settingsButton = |
| [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:barButtonImageString] |
| style:UIBarButtonItemStylePlain |
| target:self |
| action:@selector(showSettings:)]; |
| self.navigationItem.rightBarButtonItem = settingsButton; |
| } |
| |
| + (NSString *)loopbackRoomString { |
| NSString *loopbackRoomString = |
| [[NSUUID UUID].UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""]; |
| return loopbackRoomString; |
| } |
| |
| #pragma mark - ARDMainViewDelegate |
| |
| - (void)mainView:(ARDMainView *)mainView didInputRoom:(NSString *)room isLoopback:(BOOL)isLoopback { |
| if (!room.length) { |
| if (isLoopback) { |
| // If this is a loopback call, allow a generated room name. |
| room = [[self class] loopbackRoomString]; |
| } else { |
| [self showAlertWithMessage:@"Missing room name."]; |
| return; |
| } |
| } |
| // Trim whitespaces. |
| NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceCharacterSet]; |
| NSString *trimmedRoom = [room stringByTrimmingCharactersInSet:whitespaceSet]; |
| |
| // Check that room name is valid. |
| NSError *error = nil; |
| NSRegularExpressionOptions options = NSRegularExpressionCaseInsensitive; |
| NSRegularExpression *regex = |
| [NSRegularExpression regularExpressionWithPattern:@"\\w+" |
| options:options |
| error:&error]; |
| if (error) { |
| [self showAlertWithMessage:error.localizedDescription]; |
| return; |
| } |
| NSRange matchRange = |
| [regex rangeOfFirstMatchInString:trimmedRoom |
| options:0 |
| range:NSMakeRange(0, trimmedRoom.length)]; |
| if (matchRange.location == NSNotFound || |
| matchRange.length != trimmedRoom.length) { |
| [self showAlertWithMessage:@"Invalid room name."]; |
| return; |
| } |
| |
| ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init]; |
| |
| RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; |
| session.useManualAudio = [settingsModel currentUseManualAudioConfigSettingFromStore]; |
| session.isAudioEnabled = NO; |
| |
| // Kick off the video call. |
| ARDVideoCallViewController *videoCallViewController = |
| [[ARDVideoCallViewController alloc] initForRoom:trimmedRoom |
| isLoopback:isLoopback |
| delegate:self]; |
| videoCallViewController.modalTransitionStyle = |
| UIModalTransitionStyleCrossDissolve; |
| videoCallViewController.modalPresentationStyle = UIModalPresentationFullScreen; |
| [self presentViewController:videoCallViewController |
| animated:YES |
| completion:nil]; |
| } |
| |
| - (void)mainViewDidToggleAudioLoop:(ARDMainView *)mainView { |
| if (mainView.isAudioLoopPlaying) { |
| [_audioPlayer stop]; |
| } else { |
| [_audioPlayer play]; |
| } |
| mainView.isAudioLoopPlaying = _audioPlayer.playing; |
| } |
| |
| #pragma mark - ARDVideoCallViewControllerDelegate |
| |
| - (void)viewControllerDidFinish:(ARDVideoCallViewController *)viewController { |
| if (![viewController isBeingDismissed]) { |
| RTCLog(@"Dismissing VC"); |
| [self dismissViewControllerAnimated:YES completion:^{ |
| [self restartAudioPlayerIfNeeded]; |
| }]; |
| } |
| RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; |
| session.isAudioEnabled = NO; |
| } |
| |
| #pragma mark - RTC_OBJC_TYPE(RTCAudioSessionDelegate) |
| |
| - (void)audioSessionDidStartPlayOrRecord:(RTC_OBJC_TYPE(RTCAudioSession) *)session { |
| // Stop playback on main queue and then configure WebRTC. |
| [RTC_OBJC_TYPE(RTCDispatcher) |
| dispatchAsyncOnType:RTCDispatcherTypeMain |
| block:^{ |
| if (self.mainView.isAudioLoopPlaying) { |
| RTCLog(@"Stopping audio loop due to WebRTC start."); |
| [self.audioPlayer stop]; |
| } |
| RTCLog(@"Setting isAudioEnabled to YES."); |
| session.isAudioEnabled = YES; |
| }]; |
| } |
| |
| - (void)audioSessionDidStopPlayOrRecord:(RTC_OBJC_TYPE(RTCAudioSession) *)session { |
| // WebRTC is done with the audio session. Restart playback. |
| [RTC_OBJC_TYPE(RTCDispatcher) dispatchAsyncOnType:RTCDispatcherTypeMain |
| block:^{ |
| RTCLog(@"audioSessionDidStopPlayOrRecord"); |
| [self restartAudioPlayerIfNeeded]; |
| }]; |
| } |
| |
| #pragma mark - Private |
| - (void)showSettings:(id)sender { |
| ARDSettingsViewController *settingsController = |
| [[ARDSettingsViewController alloc] initWithStyle:UITableViewStyleGrouped |
| settingsModel:[[ARDSettingsModel alloc] init]]; |
| |
| UINavigationController *navigationController = |
| [[UINavigationController alloc] initWithRootViewController:settingsController]; |
| [self presentViewControllerAsModal:navigationController]; |
| } |
| |
| - (void)presentViewControllerAsModal:(UIViewController *)viewController { |
| [self presentViewController:viewController animated:YES completion:nil]; |
| } |
| |
| - (void)configureAudioSession { |
| RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *configuration = |
| [[RTC_OBJC_TYPE(RTCAudioSessionConfiguration) alloc] init]; |
| configuration.category = AVAudioSessionCategoryAmbient; |
| configuration.categoryOptions = AVAudioSessionCategoryOptionDuckOthers; |
| configuration.mode = AVAudioSessionModeDefault; |
| |
| RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; |
| [session lockForConfiguration]; |
| BOOL hasSucceeded = NO; |
| NSError *error = nil; |
| if (session.isActive) { |
| hasSucceeded = [session setConfiguration:configuration error:&error]; |
| } else { |
| hasSucceeded = [session setConfiguration:configuration |
| active:YES |
| error:&error]; |
| } |
| if (!hasSucceeded) { |
| RTCLogError(@"Error setting configuration: %@", error.localizedDescription); |
| } |
| [session unlockForConfiguration]; |
| } |
| |
| - (void)setupAudioPlayer { |
| NSString *audioFilePath = |
| [[NSBundle mainBundle] pathForResource:@"mozart" ofType:@"mp3"]; |
| NSURL *audioFileURL = [NSURL URLWithString:audioFilePath]; |
| _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL |
| error:nil]; |
| _audioPlayer.numberOfLoops = -1; |
| _audioPlayer.volume = 1.0; |
| [_audioPlayer prepareToPlay]; |
| } |
| |
| - (void)restartAudioPlayerIfNeeded { |
| [self configureAudioSession]; |
| if (_mainView.isAudioLoopPlaying && !self.presentedViewController) { |
| RTCLog(@"Starting audio loop due to WebRTC end."); |
| [_audioPlayer play]; |
| } |
| } |
| |
| - (void)showAlertWithMessage:(NSString*)message { |
| UIAlertController *alert = |
| [UIAlertController alertControllerWithTitle:nil |
| message:message |
| preferredStyle:UIAlertControllerStyleAlert]; |
| |
| UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK" |
| style:UIAlertActionStyleDefault |
| handler:^(UIAlertAction *action){ |
| }]; |
| |
| [alert addAction:defaultAction]; |
| [self presentViewController:alert animated:YES completion:nil]; |
| } |
| |
| @end |