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 "RTCAudioSession+Private.h" 12#import "RTCAudioSessionConfiguration.h" 13 14#import "base/RTCLogging.h" 15 16@implementation RTC_OBJC_TYPE (RTCAudioSession) 17(Configuration) 18 19 - (BOOL)setConfiguration : (RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *)configuration error 20 : (NSError **)outError { 21 return [self setConfiguration:configuration 22 active:NO 23 shouldSetActive:NO 24 error:outError]; 25} 26 27- (BOOL)setConfiguration:(RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *)configuration 28 active:(BOOL)active 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:(RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *)configuration 39 active:(BOOL)active 40 shouldSetActive:(BOOL)shouldSetActive 41 error:(NSError **)outError { 42 NSParameterAssert(configuration); 43 if (outError) { 44 *outError = nil; 45 } 46 if (![self checkLock:outError]) { 47 return NO; 48 } 49 50 // Provide an error even if there isn't one so we can log it. We will not 51 // return immediately on error in this function and instead try to set 52 // everything we can. 53 NSError *error = nil; 54 55 if (self.category != configuration.category || 56 self.categoryOptions != configuration.categoryOptions) { 57 NSError *categoryError = nil; 58 if (![self setCategory:configuration.category 59 withOptions:configuration.categoryOptions 60 error:&categoryError]) { 61 RTCLogError(@"Failed to set category: %@", 62 categoryError.localizedDescription); 63 error = categoryError; 64 } else { 65 RTCLog(@"Set category to: %@", configuration.category); 66 } 67 } 68 69 if (self.mode != configuration.mode) { 70 NSError *modeError = nil; 71 if (![self setMode:configuration.mode error:&modeError]) { 72 RTCLogError(@"Failed to set mode: %@", 73 modeError.localizedDescription); 74 error = modeError; 75 } else { 76 RTCLog(@"Set mode to: %@", configuration.mode); 77 } 78 } 79 80 // Sometimes category options don't stick after setting mode. 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) { 96 NSError *sampleRateError = nil; 97 if (![self setPreferredSampleRate:configuration.sampleRate 98 error:&sampleRateError]) { 99 RTCLogError(@"Failed to set preferred sample rate: %@", 100 sampleRateError.localizedDescription); 101 if (!self.ignoresPreferredAttributeConfigurationErrors) { 102 error = sampleRateError; 103 } 104 } else { 105 RTCLog(@"Set preferred sample rate to: %.2f", 106 configuration.sampleRate); 107 } 108 } 109 110 if (self.preferredIOBufferDuration != configuration.ioBufferDuration) { 111 NSError *bufferDurationError = nil; 112 if (![self setPreferredIOBufferDuration:configuration.ioBufferDuration 113 error:&bufferDurationError]) { 114 RTCLogError(@"Failed to set preferred IO buffer duration: %@", 115 bufferDurationError.localizedDescription); 116 if (!self.ignoresPreferredAttributeConfigurationErrors) { 117 error = bufferDurationError; 118 } 119 } else { 120 RTCLog(@"Set preferred IO buffer duration to: %f", 121 configuration.ioBufferDuration); 122 } 123 } 124 125 if (shouldSetActive) { 126 NSError *activeError = nil; 127 if (![self setActive:active error:&activeError]) { 128 RTCLogError(@"Failed to setActive to %d: %@", 129 active, activeError.localizedDescription); 130 error = activeError; 131 } 132 } 133 134 if (self.isActive && 135 // TODO(tkchin): Figure out which category/mode numChannels is valid for. 136 [self.mode isEqualToString:AVAudioSessionModeVoiceChat]) { 137 // Try to set the preferred number of hardware audio channels. These calls 138 // must be done after setting the audio session’s category and mode and 139 // activating the session. 140 NSInteger inputNumberOfChannels = configuration.inputNumberOfChannels; 141 if (self.inputNumberOfChannels != inputNumberOfChannels) { 142 NSError *inputChannelsError = nil; 143 if (![self setPreferredInputNumberOfChannels:inputNumberOfChannels 144 error:&inputChannelsError]) { 145 RTCLogError(@"Failed to set preferred input number of channels: %@", 146 inputChannelsError.localizedDescription); 147 if (!self.ignoresPreferredAttributeConfigurationErrors) { 148 error = inputChannelsError; 149 } 150 } else { 151 RTCLog(@"Set input number of channels to: %ld", 152 (long)inputNumberOfChannels); 153 } 154 } 155 NSInteger outputNumberOfChannels = configuration.outputNumberOfChannels; 156 if (self.outputNumberOfChannels != outputNumberOfChannels) { 157 NSError *outputChannelsError = nil; 158 if (![self setPreferredOutputNumberOfChannels:outputNumberOfChannels 159 error:&outputChannelsError]) { 160 RTCLogError(@"Failed to set preferred output number of channels: %@", 161 outputChannelsError.localizedDescription); 162 if (!self.ignoresPreferredAttributeConfigurationErrors) { 163 error = outputChannelsError; 164 } 165 } else { 166 RTCLog(@"Set output number of channels to: %ld", 167 (long)outputNumberOfChannels); 168 } 169 } 170 } 171 172 if (outError) { 173 *outError = error; 174 } 175 176 return error == nil; 177} 178 179@end 180