| 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 |