OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #import "ARDMainViewController.h" | 11 #import "ARDMainViewController.h" |
12 | 12 |
13 #import <AVFoundation/AVFoundation.h> | 13 #import <AVFoundation/AVFoundation.h> |
14 | 14 |
15 #import "WebRTC/RTCDispatcher.h" | 15 #import "WebRTC/RTCDispatcher.h" |
16 #import "WebRTC/RTCLogging.h" | 16 #import "WebRTC/RTCLogging.h" |
17 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h" | 17 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h" |
18 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSessionConfiguration.h" | 18 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSessionConfiguration.h" |
19 | 19 |
20 #import "ARDAppClient.h" | 20 #import "ARDAppClient.h" |
21 #import "ARDMainView.h" | 21 #import "ARDMainView.h" |
22 #import "ARDVideoCallViewController.h" | 22 #import "ARDVideoCallViewController.h" |
23 | 23 |
24 @interface ARDMainViewController () < | 24 @interface ARDMainViewController () < |
25 ARDMainViewDelegate, | 25 ARDMainViewDelegate, |
| 26 ARDVideoCallViewControllerDelegate, |
26 RTCAudioSessionDelegate> | 27 RTCAudioSessionDelegate> |
27 @end | 28 @end |
28 | 29 |
29 @implementation ARDMainViewController { | 30 @implementation ARDMainViewController { |
30 ARDMainView *_mainView; | 31 ARDMainView *_mainView; |
31 AVAudioPlayer *_audioPlayer; | 32 AVAudioPlayer *_audioPlayer; |
32 BOOL _shouldDelayAudioConfig; | 33 BOOL _useManualAudio; |
33 } | 34 } |
34 | 35 |
35 - (void)loadView { | 36 - (void)loadView { |
36 _mainView = [[ARDMainView alloc] initWithFrame:CGRectZero]; | 37 _mainView = [[ARDMainView alloc] initWithFrame:CGRectZero]; |
37 _mainView.delegate = self; | 38 _mainView.delegate = self; |
38 self.view = _mainView; | 39 self.view = _mainView; |
39 | 40 |
40 [self setupAudioSession]; | 41 RTCAudioSessionConfiguration *webRTCConfig = |
| 42 [RTCAudioSessionConfiguration webRTCConfiguration]; |
| 43 webRTCConfig.categoryOptions = webRTCConfig.categoryOptions | |
| 44 AVAudioSessionCategoryOptionDefaultToSpeaker; |
| 45 [RTCAudioSessionConfiguration setWebRTCConfiguration:webRTCConfig]; |
| 46 |
| 47 RTCAudioSession *session = [RTCAudioSession sharedInstance]; |
| 48 [session addDelegate:self]; |
| 49 |
| 50 [self configureAudioSession]; |
41 [self setupAudioPlayer]; | 51 [self setupAudioPlayer]; |
42 } | 52 } |
43 | 53 |
44 #pragma mark - ARDMainViewDelegate | 54 #pragma mark - ARDMainViewDelegate |
45 | 55 |
46 - (void)mainView:(ARDMainView *)mainView | 56 - (void)mainView:(ARDMainView *)mainView |
47 didInputRoom:(NSString *)room | 57 didInputRoom:(NSString *)room |
48 isLoopback:(BOOL)isLoopback | 58 isLoopback:(BOOL)isLoopback |
49 isAudioOnly:(BOOL)isAudioOnly | 59 isAudioOnly:(BOOL)isAudioOnly |
50 shouldDelayAudioConfig:(BOOL)shouldDelayAudioConfig { | 60 useManualAudio:(BOOL)useManualAudio { |
51 if (!room.length) { | 61 if (!room.length) { |
52 [self showAlertWithMessage:@"Missing room name."]; | 62 [self showAlertWithMessage:@"Missing room name."]; |
53 return; | 63 return; |
54 } | 64 } |
55 // Trim whitespaces. | 65 // Trim whitespaces. |
56 NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceCharacterSet]; | 66 NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceCharacterSet]; |
57 NSString *trimmedRoom = [room stringByTrimmingCharactersInSet:whitespaceSet]; | 67 NSString *trimmedRoom = [room stringByTrimmingCharactersInSet:whitespaceSet]; |
58 | 68 |
59 // Check that room name is valid. | 69 // Check that room name is valid. |
60 NSError *error = nil; | 70 NSError *error = nil; |
61 NSRegularExpressionOptions options = NSRegularExpressionCaseInsensitive; | 71 NSRegularExpressionOptions options = NSRegularExpressionCaseInsensitive; |
62 NSRegularExpression *regex = | 72 NSRegularExpression *regex = |
63 [NSRegularExpression regularExpressionWithPattern:@"\\w+" | 73 [NSRegularExpression regularExpressionWithPattern:@"\\w+" |
64 options:options | 74 options:options |
65 error:&error]; | 75 error:&error]; |
66 if (error) { | 76 if (error) { |
67 [self showAlertWithMessage:error.localizedDescription]; | 77 [self showAlertWithMessage:error.localizedDescription]; |
68 return; | 78 return; |
69 } | 79 } |
70 NSRange matchRange = | 80 NSRange matchRange = |
71 [regex rangeOfFirstMatchInString:trimmedRoom | 81 [regex rangeOfFirstMatchInString:trimmedRoom |
72 options:0 | 82 options:0 |
73 range:NSMakeRange(0, trimmedRoom.length)]; | 83 range:NSMakeRange(0, trimmedRoom.length)]; |
74 if (matchRange.location == NSNotFound || | 84 if (matchRange.location == NSNotFound || |
75 matchRange.length != trimmedRoom.length) { | 85 matchRange.length != trimmedRoom.length) { |
76 [self showAlertWithMessage:@"Invalid room name."]; | 86 [self showAlertWithMessage:@"Invalid room name."]; |
77 return; | 87 return; |
78 } | 88 } |
79 | 89 |
80 _shouldDelayAudioConfig = shouldDelayAudioConfig; | |
81 RTCAudioSession *session = [RTCAudioSession sharedInstance]; | 90 RTCAudioSession *session = [RTCAudioSession sharedInstance]; |
82 session.shouldDelayAudioConfiguration = _shouldDelayAudioConfig; | 91 session.useManualAudio = useManualAudio; |
| 92 session.isAudioEnabled = NO; |
83 | 93 |
84 // Kick off the video call. | 94 // Kick off the video call. |
85 ARDVideoCallViewController *videoCallViewController = | 95 ARDVideoCallViewController *videoCallViewController = |
86 [[ARDVideoCallViewController alloc] initForRoom:trimmedRoom | 96 [[ARDVideoCallViewController alloc] initForRoom:trimmedRoom |
87 isLoopback:isLoopback | 97 isLoopback:isLoopback |
88 isAudioOnly:isAudioOnly]; | 98 isAudioOnly:isAudioOnly |
| 99 delegate:self]; |
89 videoCallViewController.modalTransitionStyle = | 100 videoCallViewController.modalTransitionStyle = |
90 UIModalTransitionStyleCrossDissolve; | 101 UIModalTransitionStyleCrossDissolve; |
91 [self presentViewController:videoCallViewController | 102 [self presentViewController:videoCallViewController |
92 animated:YES | 103 animated:YES |
93 completion:nil]; | 104 completion:nil]; |
94 } | 105 } |
95 | 106 |
96 - (void)mainViewDidToggleAudioLoop:(ARDMainView *)mainView { | 107 - (void)mainViewDidToggleAudioLoop:(ARDMainView *)mainView { |
97 if (mainView.isAudioLoopPlaying) { | 108 if (mainView.isAudioLoopPlaying) { |
98 [_audioPlayer stop]; | 109 [_audioPlayer stop]; |
99 } else { | 110 } else { |
100 [_audioPlayer play]; | 111 [_audioPlayer play]; |
101 } | 112 } |
102 mainView.isAudioLoopPlaying = _audioPlayer.playing; | 113 mainView.isAudioLoopPlaying = _audioPlayer.playing; |
103 } | 114 } |
104 | 115 |
| 116 #pragma mark - ARDVideoCallViewControllerDelegate |
| 117 |
| 118 - (void)viewControllerDidFinish:(ARDVideoCallViewController *)viewController { |
| 119 if (![viewController isBeingDismissed]) { |
| 120 RTCLog(@"Dismissing VC"); |
| 121 [self dismissViewControllerAnimated:YES completion:^{ |
| 122 [self restartAudioPlayerIfNeeded]; |
| 123 }]; |
| 124 } |
| 125 RTCAudioSession *session = [RTCAudioSession sharedInstance]; |
| 126 session.isAudioEnabled = NO; |
| 127 } |
| 128 |
105 #pragma mark - RTCAudioSessionDelegate | 129 #pragma mark - RTCAudioSessionDelegate |
106 | 130 |
107 - (void)audioSessionShouldConfigure:(RTCAudioSession *)session { | 131 - (void)audioSessionDidStartPlayOrRecord:(RTCAudioSession *)session { |
108 // Won't get called unless audio config is delayed. | |
109 // Stop playback on main queue and then configure WebRTC. | 132 // Stop playback on main queue and then configure WebRTC. |
110 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeMain | 133 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeMain |
111 block:^{ | 134 block:^{ |
112 if (_mainView.isAudioLoopPlaying) { | 135 if (_mainView.isAudioLoopPlaying) { |
113 RTCLog(@"Stopping audio loop due to WebRTC start."); | 136 RTCLog(@"Stopping audio loop due to WebRTC start."); |
114 [_audioPlayer stop]; | 137 [_audioPlayer stop]; |
115 } | 138 } |
116 // TODO(tkchin): Shouldn't lock on main queue. Figure out better way to | 139 RTCLog(@"Setting isAudioEnabled to YES."); |
117 // check audio loop state. | 140 session.isAudioEnabled = YES; |
118 [session lockForConfiguration]; | |
119 [session configureWebRTCSession:nil]; | |
120 [session unlockForConfiguration]; | |
121 }]; | 141 }]; |
122 } | 142 } |
123 | 143 |
124 - (void)audioSessionShouldUnconfigure:(RTCAudioSession *)session { | 144 - (void)audioSessionDidStopPlayOrRecord:(RTCAudioSession *)session { |
125 // Won't get called unless audio config is delayed. | |
126 [session lockForConfiguration]; | |
127 [session unconfigureWebRTCSession:nil]; | |
128 [session unlockForConfiguration]; | |
129 } | |
130 | |
131 - (void)audioSessionDidUnconfigure:(RTCAudioSession *)session { | |
132 // WebRTC is done with the audio session. Restart playback. | 145 // WebRTC is done with the audio session. Restart playback. |
133 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeMain | 146 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeMain |
134 block:^{ | 147 block:^{ |
135 if (_mainView.isAudioLoopPlaying) { | 148 RTCLog(@"audioSessionDidStopPlayOrRecord"); |
136 RTCLog(@"Starting audio loop due to WebRTC end."); | 149 [self restartAudioPlayerIfNeeded]; |
137 [_audioPlayer play]; | |
138 } | |
139 }]; | 150 }]; |
140 } | 151 } |
141 | 152 |
142 #pragma mark - Private | 153 #pragma mark - Private |
143 | 154 |
144 - (void)setupAudioSession { | 155 - (void)configureAudioSession { |
145 RTCAudioSessionConfiguration *configuration = | 156 RTCAudioSessionConfiguration *configuration = |
146 [[RTCAudioSessionConfiguration alloc] init]; | 157 [[RTCAudioSessionConfiguration alloc] init]; |
147 configuration.category = AVAudioSessionCategoryAmbient; | 158 configuration.category = AVAudioSessionCategoryAmbient; |
148 configuration.categoryOptions = AVAudioSessionCategoryOptionDuckOthers; | 159 configuration.categoryOptions = AVAudioSessionCategoryOptionDuckOthers; |
149 configuration.mode = AVAudioSessionModeDefault; | 160 configuration.mode = AVAudioSessionModeDefault; |
150 | 161 |
151 RTCAudioSession *session = [RTCAudioSession sharedInstance]; | 162 RTCAudioSession *session = [RTCAudioSession sharedInstance]; |
152 [session addDelegate:self]; | |
153 [session lockForConfiguration]; | 163 [session lockForConfiguration]; |
| 164 BOOL hasSucceeded = NO; |
154 NSError *error = nil; | 165 NSError *error = nil; |
155 if (![session setConfiguration:configuration active:YES error:&error]) { | 166 if (session.isActive) { |
| 167 hasSucceeded = [session setConfiguration:configuration error:&error]; |
| 168 } else { |
| 169 hasSucceeded = [session setConfiguration:configuration |
| 170 active:YES |
| 171 error:&error]; |
| 172 } |
| 173 if (!hasSucceeded) { |
156 RTCLogError(@"Error setting configuration: %@", error.localizedDescription); | 174 RTCLogError(@"Error setting configuration: %@", error.localizedDescription); |
157 } | 175 } |
158 [session unlockForConfiguration]; | 176 [session unlockForConfiguration]; |
159 } | 177 } |
160 | 178 |
161 - (void)setupAudioPlayer { | 179 - (void)setupAudioPlayer { |
162 NSString *audioFilePath = | 180 NSString *audioFilePath = |
163 [[NSBundle mainBundle] pathForResource:@"mozart" ofType:@"mp3"]; | 181 [[NSBundle mainBundle] pathForResource:@"mozart" ofType:@"mp3"]; |
164 NSURL *audioFileURL = [NSURL URLWithString:audioFilePath]; | 182 NSURL *audioFileURL = [NSURL URLWithString:audioFilePath]; |
165 _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL | 183 _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL |
166 error:nil]; | 184 error:nil]; |
167 _audioPlayer.numberOfLoops = -1; | 185 _audioPlayer.numberOfLoops = -1; |
168 _audioPlayer.volume = 1.0; | 186 _audioPlayer.volume = 1.0; |
169 [_audioPlayer prepareToPlay]; | 187 [_audioPlayer prepareToPlay]; |
170 } | 188 } |
171 | 189 |
| 190 - (void)restartAudioPlayerIfNeeded { |
| 191 if (_mainView.isAudioLoopPlaying && !self.presentedViewController) { |
| 192 RTCLog(@"Starting audio loop due to WebRTC end."); |
| 193 [self configureAudioSession]; |
| 194 [_audioPlayer play]; |
| 195 } |
| 196 } |
| 197 |
172 - (void)showAlertWithMessage:(NSString*)message { | 198 - (void)showAlertWithMessage:(NSString*)message { |
173 UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:nil | 199 UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:nil |
174 message:message | 200 message:message |
175 delegate:nil | 201 delegate:nil |
176 cancelButtonTitle:@"OK" | 202 cancelButtonTitle:@"OK" |
177 otherButtonTitles:nil]; | 203 otherButtonTitles:nil]; |
178 [alertView show]; | 204 [alertView show]; |
179 } | 205 } |
180 | 206 |
181 @end | 207 @end |
OLD | NEW |