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