OLD | NEW |
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/RTCLogging.h" | 13 #import "WebRTC/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 { | 19 - (BOOL)setConfiguration:(RTCAudioSessionConfiguration *)configuration |
20 return self.savedConfiguration != nil; | 20 error:(NSError **)outError { |
| 21 return [self setConfiguration:configuration |
| 22 active:NO |
| 23 shouldSetActive:NO |
| 24 error:outError]; |
21 } | 25 } |
22 | 26 |
23 - (BOOL)setConfiguration:(RTCAudioSessionConfiguration *)configuration | 27 - (BOOL)setConfiguration:(RTCAudioSessionConfiguration *)configuration |
24 active:(BOOL)active | 28 active:(BOOL)active |
25 error:(NSError **)outError { | 29 error:(NSError **)outError { |
| 30 return [self setConfiguration:configuration |
| 31 active:active |
| 32 shouldSetActive:YES |
| 33 error:outError]; |
| 34 } |
| 35 |
| 36 #pragma mark - Private |
| 37 |
| 38 - (BOOL)setConfiguration:(RTCAudioSessionConfiguration *)configuration |
| 39 active:(BOOL)active |
| 40 shouldSetActive:(BOOL)shouldSetActive |
| 41 error:(NSError **)outError { |
26 NSParameterAssert(configuration); | 42 NSParameterAssert(configuration); |
27 if (outError) { | 43 if (outError) { |
28 *outError = nil; | 44 *outError = nil; |
29 } | 45 } |
30 if (![self checkLock:outError]) { | 46 if (![self checkLock:outError]) { |
31 return NO; | 47 return NO; |
32 } | 48 } |
33 | 49 |
34 // Provide an error even if there isn't one so we can log it. We will not | 50 // Provide an error even if there isn't one so we can log it. We will not |
35 // return immediately on error in this function and instead try to set | 51 // return immediately on error in this function and instead try to set |
(...skipping 18 matching lines...) Expand all Loading... |
54 NSError *modeError = nil; | 70 NSError *modeError = nil; |
55 if (![self setMode:configuration.mode error:&modeError]) { | 71 if (![self setMode:configuration.mode error:&modeError]) { |
56 RTCLogError(@"Failed to set mode: %@", | 72 RTCLogError(@"Failed to set mode: %@", |
57 modeError.localizedDescription); | 73 modeError.localizedDescription); |
58 error = modeError; | 74 error = modeError; |
59 } else { | 75 } else { |
60 RTCLog(@"Set mode to: %@", configuration.mode); | 76 RTCLog(@"Set mode to: %@", configuration.mode); |
61 } | 77 } |
62 } | 78 } |
63 | 79 |
64 // self.sampleRate is accurate only if the audio session is active. | 80 // Sometimes category options don't stick after setting mode. |
65 if (!self.isActive || self.sampleRate != configuration.sampleRate) { | 81 if (self.categoryOptions != configuration.categoryOptions) { |
| 82 NSError *categoryError = nil; |
| 83 if (![self setCategory:configuration.category |
| 84 withOptions:configuration.categoryOptions |
| 85 error:&categoryError]) { |
| 86 RTCLogError(@"Failed to set category options: %@", |
| 87 categoryError.localizedDescription); |
| 88 error = categoryError; |
| 89 } else { |
| 90 RTCLog(@"Set category options to: %ld", |
| 91 (long)configuration.categoryOptions); |
| 92 } |
| 93 } |
| 94 |
| 95 if (self.preferredSampleRate != configuration.sampleRate) { |
66 NSError *sampleRateError = nil; | 96 NSError *sampleRateError = nil; |
67 if (![self setPreferredSampleRate:configuration.sampleRate | 97 if (![self setPreferredSampleRate:configuration.sampleRate |
68 error:&sampleRateError]) { | 98 error:&sampleRateError]) { |
69 RTCLogError(@"Failed to set preferred sample rate: %@", | 99 RTCLogError(@"Failed to set preferred sample rate: %@", |
70 sampleRateError.localizedDescription); | 100 sampleRateError.localizedDescription); |
71 error = sampleRateError; | 101 error = sampleRateError; |
72 } else { | 102 } else { |
73 RTCLog(@"Set preferred sample rate to: %.2f", | 103 RTCLog(@"Set preferred sample rate to: %.2f", |
74 configuration.sampleRate); | 104 configuration.sampleRate); |
75 } | 105 } |
76 } | 106 } |
77 | 107 |
78 // self.IOBufferDuration is accurate only if the audio session is active. | 108 if (self.preferredIOBufferDuration != configuration.ioBufferDuration) { |
79 if (!self.isActive || | |
80 self.IOBufferDuration != configuration.ioBufferDuration) { | |
81 NSError *bufferDurationError = nil; | 109 NSError *bufferDurationError = nil; |
82 if (![self setPreferredIOBufferDuration:configuration.ioBufferDuration | 110 if (![self setPreferredIOBufferDuration:configuration.ioBufferDuration |
83 error:&bufferDurationError]) { | 111 error:&bufferDurationError]) { |
84 RTCLogError(@"Failed to set preferred IO buffer duration: %@", | 112 RTCLogError(@"Failed to set preferred IO buffer duration: %@", |
85 bufferDurationError.localizedDescription); | 113 bufferDurationError.localizedDescription); |
86 error = bufferDurationError; | 114 error = bufferDurationError; |
87 } else { | 115 } else { |
88 RTCLog(@"Set preferred IO buffer duration to: %f", | 116 RTCLog(@"Set preferred IO buffer duration to: %f", |
89 configuration.ioBufferDuration); | 117 configuration.ioBufferDuration); |
90 } | 118 } |
91 } | 119 } |
92 | 120 |
93 NSError *activeError = nil; | 121 if (shouldSetActive) { |
94 if (![self setActive:active error:&activeError]) { | 122 NSError *activeError = nil; |
95 RTCLogError(@"Failed to setActive to %d: %@", | 123 if (![self setActive:active error:&activeError]) { |
96 active, activeError.localizedDescription); | 124 RTCLogError(@"Failed to setActive to %d: %@", |
97 error = activeError; | 125 active, activeError.localizedDescription); |
| 126 error = activeError; |
| 127 } |
98 } | 128 } |
99 | 129 |
100 if (self.isActive && | 130 if (self.isActive && |
101 // TODO(tkchin): Figure out which category/mode numChannels is valid for. | 131 // TODO(tkchin): Figure out which category/mode numChannels is valid for. |
102 [self.mode isEqualToString:AVAudioSessionModeVoiceChat]) { | 132 [self.mode isEqualToString:AVAudioSessionModeVoiceChat]) { |
103 // Try to set the preferred number of hardware audio channels. These calls | 133 // Try to set the preferred number of hardware audio channels. These calls |
104 // must be done after setting the audio session’s category and mode and | 134 // must be done after setting the audio session’s category and mode and |
105 // activating the session. | 135 // activating the session. |
106 NSInteger inputNumberOfChannels = configuration.inputNumberOfChannels; | 136 NSInteger inputNumberOfChannels = configuration.inputNumberOfChannels; |
107 if (self.inputNumberOfChannels != inputNumberOfChannels) { | 137 if (self.inputNumberOfChannels != inputNumberOfChannels) { |
(...skipping 23 matching lines...) Expand all Loading... |
131 } | 161 } |
132 } | 162 } |
133 | 163 |
134 if (outError) { | 164 if (outError) { |
135 *outError = error; | 165 *outError = error; |
136 } | 166 } |
137 | 167 |
138 return error == nil; | 168 return error == nil; |
139 } | 169 } |
140 | 170 |
141 - (BOOL)configureWebRTCSession:(NSError **)outError { | |
142 if (outError) { | |
143 *outError = nil; | |
144 } | |
145 if (![self checkLock:outError]) { | |
146 return NO; | |
147 } | |
148 RTCLog(@"Configuring audio session for WebRTC."); | |
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. | |
160 // Provide an error even if there isn't one so we can log it. | |
161 NSError *error = nil; | |
162 RTCAudioSessionConfiguration *currentConfig = | |
163 [RTCAudioSessionConfiguration currentConfiguration]; | |
164 RTCAudioSessionConfiguration *webRTCConfig = | |
165 [RTCAudioSessionConfiguration webRTCConfiguration]; | |
166 self.savedConfiguration = currentConfig; | |
167 if (![self setConfiguration:webRTCConfig active:YES error:&error]) { | |
168 RTCLogError(@"Failed to set WebRTC audio configuration: %@", | |
169 error.localizedDescription); | |
170 [self unconfigureWebRTCSession:nil]; | |
171 if (outError) { | |
172 *outError = error; | |
173 } | |
174 return NO; | |
175 } | |
176 | |
177 // Ensure that the device currently supports audio input. | |
178 // TODO(tkchin): Figure out if this is really necessary. | |
179 if (!self.inputAvailable) { | |
180 RTCLogError(@"No audio input path is available!"); | |
181 [self unconfigureWebRTCSession:nil]; | |
182 if (outError) { | |
183 *outError = [self configurationErrorWithDescription:@"No input path."]; | |
184 } | |
185 return NO; | |
186 } | |
187 | |
188 // Give delegates a chance to process the event. In particular, the audio | |
189 // devices listening to this event will initialize their audio units. | |
190 [self notifyDidConfigure]; | |
191 | |
192 return YES; | |
193 } | |
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 | |
221 @end | 171 @end |
OLD | NEW |