Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(314)

Side by Side Diff: webrtc/modules/audio_device/ios/objc/RTCAudioSession+Configuration.mm

Issue 1822543002: Support delayed AudioUnit initialization. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Rebase Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. 2 * Copyright 2016 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 "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h" 11 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h"
12 12
13 #import "webrtc/base/objc/RTCLogging.h" 13 #import "webrtc/base/objc/RTCLogging.h"
14 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h" 14 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h"
15 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSessionConfiguration.h" 15 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSessionConfiguration.h"
16 16
17 @implementation RTCAudioSession (Configuration) 17 @implementation RTCAudioSession (Configuration)
18 18
19 - (BOOL)isConfiguredForWebRTC {
20 return self.savedConfiguration != nil;
21 }
22
19 - (BOOL)setConfiguration:(RTCAudioSessionConfiguration *)configuration 23 - (BOOL)setConfiguration:(RTCAudioSessionConfiguration *)configuration
20 active:(BOOL)active 24 active:(BOOL)active
21 error:(NSError **)outError { 25 error:(NSError **)outError {
26 NSParameterAssert(configuration);
27 if (outError) {
28 *outError = nil;
29 }
22 if (![self checkLock:outError]) { 30 if (![self checkLock:outError]) {
23 return NO; 31 return NO;
24 } 32 }
25 33
26 // Provide an error even if there isn't one so we can log it. We will not 34 // Provide an error even if there isn't one so we can log it. We will not
27 // return immediately on error in this function and instead try to set 35 // return immediately on error in this function and instead try to set
28 // everything we can. 36 // everything we can.
29 NSError *error = nil; 37 NSError *error = nil;
30 38
31 if (self.category != configuration.category || 39 if (self.category != configuration.category ||
32 self.categoryOptions != configuration.categoryOptions) { 40 self.categoryOptions != configuration.categoryOptions) {
33 NSError *categoryError = nil; 41 NSError *categoryError = nil;
34 if (![self setCategory:configuration.category 42 if (![self setCategory:configuration.category
35 withOptions:configuration.categoryOptions 43 withOptions:configuration.categoryOptions
36 error:&categoryError]) { 44 error:&categoryError]) {
37 RTCLogError(@"Failed to set category: %@", 45 RTCLogError(@"Failed to set category: %@",
38 categoryError.localizedDescription); 46 categoryError.localizedDescription);
39 error = categoryError; 47 error = categoryError;
48 } else {
49 RTCLog(@"Set category to: %@", configuration.category);
40 } 50 }
41 } 51 }
42 52
43 if (self.mode != configuration.mode) { 53 if (self.mode != configuration.mode) {
44 NSError *modeError = nil; 54 NSError *modeError = nil;
45 if (![self setMode:configuration.mode error:&modeError]) { 55 if (![self setMode:configuration.mode error:&modeError]) {
46 RTCLogError(@"Failed to set mode: %@", 56 RTCLogError(@"Failed to set mode: %@",
47 modeError.localizedDescription); 57 modeError.localizedDescription);
48 error = modeError; 58 error = modeError;
59 } else {
60 RTCLog(@"Set mode to: %@", configuration.mode);
49 } 61 }
50 } 62 }
51 63
52 // self.sampleRate is accurate only if the audio session is active. 64 // self.sampleRate is accurate only if the audio session is active.
53 if (!self.isActive || self.sampleRate != configuration.sampleRate) { 65 if (!self.isActive || self.sampleRate != configuration.sampleRate) {
54 NSError *sampleRateError = nil; 66 NSError *sampleRateError = nil;
55 if (![self setPreferredSampleRate:configuration.sampleRate 67 if (![self setPreferredSampleRate:configuration.sampleRate
56 error:&sampleRateError]) { 68 error:&sampleRateError]) {
57 RTCLogError(@"Failed to set preferred sample rate: %@", 69 RTCLogError(@"Failed to set preferred sample rate: %@",
58 sampleRateError.localizedDescription); 70 sampleRateError.localizedDescription);
59 error = sampleRateError; 71 error = sampleRateError;
72 } else {
73 RTCLog(@"Set preferred sample rate to: %.2f",
74 configuration.sampleRate);
60 } 75 }
61 } 76 }
62 77
63 // self.IOBufferDuration is accurate only if the audio session is active. 78 // self.IOBufferDuration is accurate only if the audio session is active.
64 if (!self.isActive || 79 if (!self.isActive ||
65 self.IOBufferDuration != configuration.ioBufferDuration) { 80 self.IOBufferDuration != configuration.ioBufferDuration) {
66 NSError *bufferDurationError = nil; 81 NSError *bufferDurationError = nil;
67 if (![self setPreferredIOBufferDuration:configuration.ioBufferDuration 82 if (![self setPreferredIOBufferDuration:configuration.ioBufferDuration
68 error:&bufferDurationError]) { 83 error:&bufferDurationError]) {
69 RTCLogError(@"Failed to set preferred IO buffer duration: %@", 84 RTCLogError(@"Failed to set preferred IO buffer duration: %@",
70 bufferDurationError.localizedDescription); 85 bufferDurationError.localizedDescription);
71 error = bufferDurationError; 86 error = bufferDurationError;
87 } else {
88 RTCLog(@"Set preferred IO buffer duration to: %f",
89 configuration.ioBufferDuration);
72 } 90 }
73 } 91 }
74 92
75 NSError *activeError = nil; 93 NSError *activeError = nil;
76 if (![self setActive:active error:&activeError]) { 94 if (![self setActive:active error:&activeError]) {
77 RTCLogError(@"Failed to setActive to %d: %@", 95 RTCLogError(@"Failed to setActive to %d: %@",
78 active, activeError.localizedDescription); 96 active, activeError.localizedDescription);
79 error = activeError; 97 error = activeError;
80 } 98 }
81 99
82 if (self.isActive) { 100 if (self.isActive &&
101 // TODO(tkchin): Figure out which category/mode numChannels is valid for.
102 [self.mode isEqualToString:AVAudioSessionModeVoiceChat]) {
83 // Try to set the preferred number of hardware audio channels. These calls 103 // Try to set the preferred number of hardware audio channels. These calls
84 // must be done after setting the audio session’s category and mode and 104 // must be done after setting the audio session’s category and mode and
85 // activating the session. 105 // activating the session.
86 NSInteger inputNumberOfChannels = configuration.inputNumberOfChannels; 106 NSInteger inputNumberOfChannels = configuration.inputNumberOfChannels;
87 if (self.inputNumberOfChannels != inputNumberOfChannels) { 107 if (self.inputNumberOfChannels != inputNumberOfChannels) {
88 NSError *inputChannelsError = nil; 108 NSError *inputChannelsError = nil;
89 if (![self setPreferredInputNumberOfChannels:inputNumberOfChannels 109 if (![self setPreferredInputNumberOfChannels:inputNumberOfChannels
90 error:&inputChannelsError]) { 110 error:&inputChannelsError]) {
91 RTCLogError(@"Failed to set preferred input number of channels: %@", 111 RTCLogError(@"Failed to set preferred input number of channels: %@",
92 inputChannelsError.localizedDescription); 112 inputChannelsError.localizedDescription);
93 error = inputChannelsError; 113 error = inputChannelsError;
114 } else {
115 RTCLog(@"Set input number of channels to: %ld",
116 (long)inputNumberOfChannels);
94 } 117 }
95 } 118 }
96 NSInteger outputNumberOfChannels = configuration.outputNumberOfChannels; 119 NSInteger outputNumberOfChannels = configuration.outputNumberOfChannels;
97 if (self.outputNumberOfChannels != outputNumberOfChannels) { 120 if (self.outputNumberOfChannels != outputNumberOfChannels) {
98 NSError *outputChannelsError = nil; 121 NSError *outputChannelsError = nil;
99 if (![self setPreferredOutputNumberOfChannels:outputNumberOfChannels 122 if (![self setPreferredOutputNumberOfChannels:outputNumberOfChannels
100 error:&outputChannelsError]) { 123 error:&outputChannelsError]) {
101 RTCLogError(@"Failed to set preferred output number of channels: %@", 124 RTCLogError(@"Failed to set preferred output number of channels: %@",
102 outputChannelsError.localizedDescription); 125 outputChannelsError.localizedDescription);
103 error = outputChannelsError; 126 error = outputChannelsError;
127 } else {
128 RTCLog(@"Set output number of channels to: %ld",
129 (long)outputNumberOfChannels);
104 } 130 }
105 } 131 }
106 } 132 }
107 133
108 if (outError) { 134 if (outError) {
109 *outError = error; 135 *outError = error;
110 } 136 }
111 137
112 return error == nil; 138 return error == nil;
113 } 139 }
114 140
115 - (BOOL)configureWebRTCSession:(NSError **)outError { 141 - (BOOL)configureWebRTCSession:(NSError **)outError {
142 if (outError) {
143 *outError = nil;
144 }
116 if (![self checkLock:outError]) { 145 if (![self checkLock:outError]) {
117 return NO; 146 return NO;
118 } 147 }
119 RTCLog(@"Configuring audio session for WebRTC."); 148 RTCLog(@"Configuring audio session for WebRTC.");
120 149
150 if (self.isConfiguredForWebRTC) {
151 RTCLogError(@"Already configured.");
152 if (outError) {
153 *outError =
154 [self configurationErrorWithDescription:@"Already configured."];
155 }
156 return NO;
157 }
158
159 // Configure the AVAudioSession and activate it.
121 // Provide an error even if there isn't one so we can log it. 160 // Provide an error even if there isn't one so we can log it.
122 BOOL hasSucceeded = YES;
123 NSError *error = nil; 161 NSError *error = nil;
124 RTCAudioSessionConfiguration *currentConfig = 162 RTCAudioSessionConfiguration *currentConfig =
125 [RTCAudioSessionConfiguration currentConfiguration]; 163 [RTCAudioSessionConfiguration currentConfiguration];
126 RTCAudioSessionConfiguration *webRTCConfig = 164 RTCAudioSessionConfiguration *webRTCConfig =
127 [RTCAudioSessionConfiguration webRTCConfiguration]; 165 [RTCAudioSessionConfiguration webRTCConfiguration];
166 self.savedConfiguration = currentConfig;
128 if (![self setConfiguration:webRTCConfig active:YES error:&error]) { 167 if (![self setConfiguration:webRTCConfig active:YES error:&error]) {
129 RTCLogError(@"Failed to set WebRTC audio configuration: %@", 168 RTCLogError(@"Failed to set WebRTC audio configuration: %@",
130 error.localizedDescription); 169 error.localizedDescription);
131 // Attempt to restore previous state. 170 [self unconfigureWebRTCSession:nil];
132 [self setConfiguration:currentConfig active:NO error:nil]; 171 if (outError) {
133 hasSucceeded = NO; 172 *outError = error;
134 } else if (![self isConfiguredForWebRTC]) { 173 }
135 // Ensure that the active audio session has the correct category and mode.
136 // This should never happen - this means that we succeeded earlier but
137 // somehow the settings didn't apply.
138 RTCLogError(@"Failed to configure audio session.");
139 // Attempt to restore previous state.
140 [self setConfiguration:currentConfig active:NO error:nil];
141 error =
142 [[NSError alloc] initWithDomain:kRTCAudioSessionErrorDomain
143 code:kRTCAudioSessionErrorConfiguration
144 userInfo:nil];
145 hasSucceeded = NO;
146 }
147
148 if (outError) {
149 *outError = error;
150 }
151
152 return hasSucceeded;
153 }
154
155 #pragma mark - Private
156
157 - (BOOL)isConfiguredForWebRTC {
158 // Ensure that the device currently supports audio input.
159 if (!self.inputAvailable) {
160 RTCLogError(@"No audio input path is available!");
161 return NO; 174 return NO;
162 } 175 }
163 176
164 // Only check a minimal list of requirements for whether we have 177 // Ensure that the device currently supports audio input.
165 // what we want. 178 // TODO(tkchin): Figure out if this is really necessary.
166 RTCAudioSessionConfiguration *currentConfig = 179 if (!self.inputAvailable) {
167 [RTCAudioSessionConfiguration currentConfiguration]; 180 RTCLogError(@"No audio input path is available!");
168 RTCAudioSessionConfiguration *webRTCConfig = 181 [self unconfigureWebRTCSession:nil];
169 [RTCAudioSessionConfiguration webRTCConfiguration]; 182 if (outError) {
170 183 *outError = [self configurationErrorWithDescription:@"No input path."];
171 if (![currentConfig.category isEqualToString:webRTCConfig.category]) { 184 }
172 RTCLog(@"Current category %@ does not match %@",
173 currentConfig.category,
174 webRTCConfig.category);
175 return NO; 185 return NO;
176 } 186 }
177 187
178 if (![currentConfig.mode isEqualToString:webRTCConfig.mode]) { 188 // Give delegates a chance to process the event. In particular, the audio
179 RTCLog(@"Current mode %@ does not match %@", 189 // devices listening to this event will initialize their audio units.
180 currentConfig.mode, 190 [self notifyDidConfigure];
181 webRTCConfig.mode);
182 return NO;
183 }
184 191
185 return YES; 192 return YES;
186 } 193 }
187 194
195 - (BOOL)unconfigureWebRTCSession:(NSError **)outError {
196 if (outError) {
197 *outError = nil;
198 }
199 if (![self checkLock:outError]) {
200 return NO;
201 }
202 RTCLog(@"Unconfiguring audio session for WebRTC.");
203
204 if (!self.isConfiguredForWebRTC) {
205 RTCLogError(@"Already unconfigured.");
206 if (outError) {
207 *outError =
208 [self configurationErrorWithDescription:@"Already unconfigured."];
209 }
210 return NO;
211 }
212
213 [self setConfiguration:self.savedConfiguration active:NO error:outError];
214 self.savedConfiguration = nil;
215
216 [self notifyDidUnconfigure];
217
218 return YES;
219 }
220
188 @end 221 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698