OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. |
| 3 * |
| 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 |
| 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ |
| 10 |
| 11 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h" |
| 12 |
| 13 #import "webrtc/base/objc/RTCLogging.h" |
| 14 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h" |
| 15 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSessionConfiguration.h" |
| 16 |
| 17 @implementation RTCAudioSession (Configuration) |
| 18 |
| 19 - (BOOL)setConfiguration:(RTCAudioSessionConfiguration *)configuration |
| 20 active:(BOOL)active |
| 21 error:(NSError **)outError { |
| 22 if (![self checkLock:outError]) { |
| 23 return NO; |
| 24 } |
| 25 |
| 26 // 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 |
| 28 // everything we can. |
| 29 NSError *error = nil; |
| 30 |
| 31 if (self.category != configuration.category || |
| 32 self.categoryOptions != configuration.categoryOptions) { |
| 33 NSError *categoryError = nil; |
| 34 if (![self setCategory:configuration.category |
| 35 withOptions:configuration.categoryOptions |
| 36 error:&categoryError]) { |
| 37 RTCLogError(@"Failed to set category: %@", |
| 38 categoryError.localizedDescription); |
| 39 error = categoryError; |
| 40 } |
| 41 } |
| 42 |
| 43 if (self.mode != configuration.mode) { |
| 44 NSError *modeError = nil; |
| 45 if (![self setMode:configuration.mode error:&modeError]) { |
| 46 RTCLogError(@"Failed to set mode: %@", |
| 47 modeError.localizedDescription); |
| 48 error = modeError; |
| 49 } |
| 50 } |
| 51 |
| 52 if (self.sampleRate != configuration.sampleRate) { |
| 53 NSError *sampleRateError = nil; |
| 54 if (![self setPreferredSampleRate:configuration.sampleRate |
| 55 error:&sampleRateError]) { |
| 56 RTCLogError(@"Failed to set preferred sample rate: %@", |
| 57 sampleRateError.localizedDescription); |
| 58 error = sampleRateError; |
| 59 } |
| 60 } |
| 61 |
| 62 if (self.IOBufferDuration != configuration.ioBufferDuration) { |
| 63 NSError *bufferDurationError = nil; |
| 64 if (![self setPreferredIOBufferDuration:configuration.ioBufferDuration |
| 65 error:&bufferDurationError]) { |
| 66 RTCLogError(@"Failed to set preferred IO buffer duration: %@", |
| 67 bufferDurationError.localizedDescription); |
| 68 error = bufferDurationError; |
| 69 } |
| 70 } |
| 71 |
| 72 NSError *activeError = nil; |
| 73 if (![self setActive:active error:&activeError]) { |
| 74 RTCLogError(@"Failed to setActive to %d: %@", |
| 75 active, activeError.localizedDescription); |
| 76 error = activeError; |
| 77 } |
| 78 |
| 79 if (self.isActive) { |
| 80 // Try to set the preferred number of hardware audio channels. These calls |
| 81 // must be done after setting the audio session’s category and mode and |
| 82 // activating the session. |
| 83 NSInteger inputNumberOfChannels = configuration.inputNumberOfChannels; |
| 84 if (self.inputNumberOfChannels != inputNumberOfChannels) { |
| 85 NSError *inputChannelsError = nil; |
| 86 if (![self setPreferredInputNumberOfChannels:inputNumberOfChannels |
| 87 error:&inputChannelsError]) { |
| 88 RTCLogError(@"Failed to set preferred input number of channels: %@", |
| 89 inputChannelsError.localizedDescription); |
| 90 error = inputChannelsError; |
| 91 } |
| 92 } |
| 93 NSInteger outputNumberOfChannels = configuration.outputNumberOfChannels; |
| 94 if (self.outputNumberOfChannels != outputNumberOfChannels) { |
| 95 NSError *outputChannelsError = nil; |
| 96 if (![self setPreferredOutputNumberOfChannels:outputNumberOfChannels |
| 97 error:&outputChannelsError]) { |
| 98 RTCLogError(@"Failed to set preferred output number of channels: %@", |
| 99 outputChannelsError.localizedDescription); |
| 100 error = outputChannelsError; |
| 101 } |
| 102 } |
| 103 } |
| 104 |
| 105 if (outError) { |
| 106 *outError = error; |
| 107 } |
| 108 |
| 109 return error == nil; |
| 110 } |
| 111 |
| 112 - (BOOL)configureWebRTCSession:(NSError **)outError { |
| 113 if (![self checkLock:outError]) { |
| 114 return NO; |
| 115 } |
| 116 RTCLog(@"Configuring audio session for WebRTC."); |
| 117 |
| 118 // Provide an error even if there isn't one so we can log it. |
| 119 BOOL hasSucceeded = YES; |
| 120 NSError *error = nil; |
| 121 RTCAudioSessionConfiguration *currentConfig = |
| 122 [RTCAudioSessionConfiguration currentConfiguration]; |
| 123 RTCAudioSessionConfiguration *webRTCConfig = |
| 124 [RTCAudioSessionConfiguration webRTCConfiguration]; |
| 125 if (![self setConfiguration:webRTCConfig active:YES error:&error]) { |
| 126 RTCLogError(@"Failed to set WebRTC audio configuration: %@", |
| 127 error.localizedDescription); |
| 128 // Attempt to restore previous state. |
| 129 [self setConfiguration:currentConfig active:NO error:nil]; |
| 130 hasSucceeded = NO; |
| 131 } else if (![self isConfiguredForWebRTC]) { |
| 132 // Ensure that the active audio session has the correct category and mode. |
| 133 // This should never happen - this means that we succeeded earlier but |
| 134 // somehow the settings didn't apply. |
| 135 RTCLogError(@"Failed to configure audio session."); |
| 136 // Attempt to restore previous state. |
| 137 [self setConfiguration:currentConfig active:NO error:nil]; |
| 138 error = |
| 139 [[NSError alloc] initWithDomain:kRTCAudioSessionErrorDomain |
| 140 code:kRTCAudioSessionErrorConfiguration |
| 141 userInfo:nil]; |
| 142 hasSucceeded = NO; |
| 143 } |
| 144 |
| 145 if (outError) { |
| 146 *outError = error; |
| 147 } |
| 148 |
| 149 return hasSucceeded; |
| 150 } |
| 151 |
| 152 #pragma mark - Private |
| 153 |
| 154 - (BOOL)isConfiguredForWebRTC { |
| 155 // Ensure that the device currently supports audio input. |
| 156 if (!self.inputAvailable) { |
| 157 RTCLogError(@"No audio input path is available!"); |
| 158 return NO; |
| 159 } |
| 160 |
| 161 // Only check a minimal list of requirements for whether we have |
| 162 // what we want. |
| 163 RTCAudioSessionConfiguration *currentConfig = |
| 164 [RTCAudioSessionConfiguration currentConfiguration]; |
| 165 RTCAudioSessionConfiguration *webRTCConfig = |
| 166 [RTCAudioSessionConfiguration webRTCConfiguration]; |
| 167 |
| 168 if (![currentConfig.category isEqualToString:webRTCConfig.category]) { |
| 169 RTCLog(@"Current category %@ does not match %@", |
| 170 currentConfig.category, |
| 171 webRTCConfig.category); |
| 172 return NO; |
| 173 } |
| 174 |
| 175 if (![currentConfig.mode isEqualToString:webRTCConfig.mode]) { |
| 176 RTCLog(@"Current mode %@ does not match %@", |
| 177 currentConfig.mode, |
| 178 webRTCConfig.mode); |
| 179 return NO; |
| 180 } |
| 181 |
| 182 return YES; |
| 183 } |
| 184 |
| 185 @end |
OLD | NEW |