1*d9f75844SAndroid Build Coastguard Worker/* 2*d9f75844SAndroid Build Coastguard Worker * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3*d9f75844SAndroid Build Coastguard Worker * 4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license 5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source 6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found 7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may 8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree. 9*d9f75844SAndroid Build Coastguard Worker */ 10*d9f75844SAndroid Build Coastguard Worker 11*d9f75844SAndroid Build Coastguard Worker#import "RTCAudioSession+Private.h" 12*d9f75844SAndroid Build Coastguard Worker#import "RTCAudioSessionConfiguration.h" 13*d9f75844SAndroid Build Coastguard Worker 14*d9f75844SAndroid Build Coastguard Worker#import "base/RTCLogging.h" 15*d9f75844SAndroid Build Coastguard Worker 16*d9f75844SAndroid Build Coastguard Worker@implementation RTC_OBJC_TYPE (RTCAudioSession) 17*d9f75844SAndroid Build Coastguard Worker(Configuration) 18*d9f75844SAndroid Build Coastguard Worker 19*d9f75844SAndroid Build Coastguard Worker - (BOOL)setConfiguration : (RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *)configuration error 20*d9f75844SAndroid Build Coastguard Worker : (NSError **)outError { 21*d9f75844SAndroid Build Coastguard Worker return [self setConfiguration:configuration 22*d9f75844SAndroid Build Coastguard Worker active:NO 23*d9f75844SAndroid Build Coastguard Worker shouldSetActive:NO 24*d9f75844SAndroid Build Coastguard Worker error:outError]; 25*d9f75844SAndroid Build Coastguard Worker} 26*d9f75844SAndroid Build Coastguard Worker 27*d9f75844SAndroid Build Coastguard Worker- (BOOL)setConfiguration:(RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *)configuration 28*d9f75844SAndroid Build Coastguard Worker active:(BOOL)active 29*d9f75844SAndroid Build Coastguard Worker error:(NSError **)outError { 30*d9f75844SAndroid Build Coastguard Worker return [self setConfiguration:configuration 31*d9f75844SAndroid Build Coastguard Worker active:active 32*d9f75844SAndroid Build Coastguard Worker shouldSetActive:YES 33*d9f75844SAndroid Build Coastguard Worker error:outError]; 34*d9f75844SAndroid Build Coastguard Worker} 35*d9f75844SAndroid Build Coastguard Worker 36*d9f75844SAndroid Build Coastguard Worker#pragma mark - Private 37*d9f75844SAndroid Build Coastguard Worker 38*d9f75844SAndroid Build Coastguard Worker- (BOOL)setConfiguration:(RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *)configuration 39*d9f75844SAndroid Build Coastguard Worker active:(BOOL)active 40*d9f75844SAndroid Build Coastguard Worker shouldSetActive:(BOOL)shouldSetActive 41*d9f75844SAndroid Build Coastguard Worker error:(NSError **)outError { 42*d9f75844SAndroid Build Coastguard Worker NSParameterAssert(configuration); 43*d9f75844SAndroid Build Coastguard Worker if (outError) { 44*d9f75844SAndroid Build Coastguard Worker *outError = nil; 45*d9f75844SAndroid Build Coastguard Worker } 46*d9f75844SAndroid Build Coastguard Worker 47*d9f75844SAndroid Build Coastguard Worker // Provide an error even if there isn't one so we can log it. We will not 48*d9f75844SAndroid Build Coastguard Worker // return immediately on error in this function and instead try to set 49*d9f75844SAndroid Build Coastguard Worker // everything we can. 50*d9f75844SAndroid Build Coastguard Worker NSError *error = nil; 51*d9f75844SAndroid Build Coastguard Worker 52*d9f75844SAndroid Build Coastguard Worker if (self.category != configuration.category || 53*d9f75844SAndroid Build Coastguard Worker self.categoryOptions != configuration.categoryOptions) { 54*d9f75844SAndroid Build Coastguard Worker NSError *categoryError = nil; 55*d9f75844SAndroid Build Coastguard Worker if (![self setCategory:configuration.category 56*d9f75844SAndroid Build Coastguard Worker withOptions:configuration.categoryOptions 57*d9f75844SAndroid Build Coastguard Worker error:&categoryError]) { 58*d9f75844SAndroid Build Coastguard Worker RTCLogError(@"Failed to set category: %@", 59*d9f75844SAndroid Build Coastguard Worker categoryError.localizedDescription); 60*d9f75844SAndroid Build Coastguard Worker error = categoryError; 61*d9f75844SAndroid Build Coastguard Worker } else { 62*d9f75844SAndroid Build Coastguard Worker RTCLog(@"Set category to: %@", configuration.category); 63*d9f75844SAndroid Build Coastguard Worker } 64*d9f75844SAndroid Build Coastguard Worker } 65*d9f75844SAndroid Build Coastguard Worker 66*d9f75844SAndroid Build Coastguard Worker if (self.mode != configuration.mode) { 67*d9f75844SAndroid Build Coastguard Worker NSError *modeError = nil; 68*d9f75844SAndroid Build Coastguard Worker if (![self setMode:configuration.mode error:&modeError]) { 69*d9f75844SAndroid Build Coastguard Worker RTCLogError(@"Failed to set mode: %@", 70*d9f75844SAndroid Build Coastguard Worker modeError.localizedDescription); 71*d9f75844SAndroid Build Coastguard Worker error = modeError; 72*d9f75844SAndroid Build Coastguard Worker } else { 73*d9f75844SAndroid Build Coastguard Worker RTCLog(@"Set mode to: %@", configuration.mode); 74*d9f75844SAndroid Build Coastguard Worker } 75*d9f75844SAndroid Build Coastguard Worker } 76*d9f75844SAndroid Build Coastguard Worker 77*d9f75844SAndroid Build Coastguard Worker // Sometimes category options don't stick after setting mode. 78*d9f75844SAndroid Build Coastguard Worker if (self.categoryOptions != configuration.categoryOptions) { 79*d9f75844SAndroid Build Coastguard Worker NSError *categoryError = nil; 80*d9f75844SAndroid Build Coastguard Worker if (![self setCategory:configuration.category 81*d9f75844SAndroid Build Coastguard Worker withOptions:configuration.categoryOptions 82*d9f75844SAndroid Build Coastguard Worker error:&categoryError]) { 83*d9f75844SAndroid Build Coastguard Worker RTCLogError(@"Failed to set category options: %@", 84*d9f75844SAndroid Build Coastguard Worker categoryError.localizedDescription); 85*d9f75844SAndroid Build Coastguard Worker error = categoryError; 86*d9f75844SAndroid Build Coastguard Worker } else { 87*d9f75844SAndroid Build Coastguard Worker RTCLog(@"Set category options to: %ld", 88*d9f75844SAndroid Build Coastguard Worker (long)configuration.categoryOptions); 89*d9f75844SAndroid Build Coastguard Worker } 90*d9f75844SAndroid Build Coastguard Worker } 91*d9f75844SAndroid Build Coastguard Worker 92*d9f75844SAndroid Build Coastguard Worker if (self.preferredSampleRate != configuration.sampleRate) { 93*d9f75844SAndroid Build Coastguard Worker NSError *sampleRateError = nil; 94*d9f75844SAndroid Build Coastguard Worker if (![self setPreferredSampleRate:configuration.sampleRate 95*d9f75844SAndroid Build Coastguard Worker error:&sampleRateError]) { 96*d9f75844SAndroid Build Coastguard Worker RTCLogError(@"Failed to set preferred sample rate: %@", 97*d9f75844SAndroid Build Coastguard Worker sampleRateError.localizedDescription); 98*d9f75844SAndroid Build Coastguard Worker if (!self.ignoresPreferredAttributeConfigurationErrors) { 99*d9f75844SAndroid Build Coastguard Worker error = sampleRateError; 100*d9f75844SAndroid Build Coastguard Worker } 101*d9f75844SAndroid Build Coastguard Worker } else { 102*d9f75844SAndroid Build Coastguard Worker RTCLog(@"Set preferred sample rate to: %.2f", 103*d9f75844SAndroid Build Coastguard Worker configuration.sampleRate); 104*d9f75844SAndroid Build Coastguard Worker } 105*d9f75844SAndroid Build Coastguard Worker } 106*d9f75844SAndroid Build Coastguard Worker 107*d9f75844SAndroid Build Coastguard Worker if (self.preferredIOBufferDuration != configuration.ioBufferDuration) { 108*d9f75844SAndroid Build Coastguard Worker NSError *bufferDurationError = nil; 109*d9f75844SAndroid Build Coastguard Worker if (![self setPreferredIOBufferDuration:configuration.ioBufferDuration 110*d9f75844SAndroid Build Coastguard Worker error:&bufferDurationError]) { 111*d9f75844SAndroid Build Coastguard Worker RTCLogError(@"Failed to set preferred IO buffer duration: %@", 112*d9f75844SAndroid Build Coastguard Worker bufferDurationError.localizedDescription); 113*d9f75844SAndroid Build Coastguard Worker if (!self.ignoresPreferredAttributeConfigurationErrors) { 114*d9f75844SAndroid Build Coastguard Worker error = bufferDurationError; 115*d9f75844SAndroid Build Coastguard Worker } 116*d9f75844SAndroid Build Coastguard Worker } else { 117*d9f75844SAndroid Build Coastguard Worker RTCLog(@"Set preferred IO buffer duration to: %f", 118*d9f75844SAndroid Build Coastguard Worker configuration.ioBufferDuration); 119*d9f75844SAndroid Build Coastguard Worker } 120*d9f75844SAndroid Build Coastguard Worker } 121*d9f75844SAndroid Build Coastguard Worker 122*d9f75844SAndroid Build Coastguard Worker if (shouldSetActive) { 123*d9f75844SAndroid Build Coastguard Worker NSError *activeError = nil; 124*d9f75844SAndroid Build Coastguard Worker if (![self setActive:active error:&activeError]) { 125*d9f75844SAndroid Build Coastguard Worker RTCLogError(@"Failed to setActive to %d: %@", 126*d9f75844SAndroid Build Coastguard Worker active, activeError.localizedDescription); 127*d9f75844SAndroid Build Coastguard Worker error = activeError; 128*d9f75844SAndroid Build Coastguard Worker } 129*d9f75844SAndroid Build Coastguard Worker } 130*d9f75844SAndroid Build Coastguard Worker 131*d9f75844SAndroid Build Coastguard Worker if (self.isActive && 132*d9f75844SAndroid Build Coastguard Worker // TODO(tkchin): Figure out which category/mode numChannels is valid for. 133*d9f75844SAndroid Build Coastguard Worker [self.mode isEqualToString:AVAudioSessionModeVoiceChat]) { 134*d9f75844SAndroid Build Coastguard Worker // Try to set the preferred number of hardware audio channels. These calls 135*d9f75844SAndroid Build Coastguard Worker // must be done after setting the audio session’s category and mode and 136*d9f75844SAndroid Build Coastguard Worker // activating the session. 137*d9f75844SAndroid Build Coastguard Worker NSInteger inputNumberOfChannels = configuration.inputNumberOfChannels; 138*d9f75844SAndroid Build Coastguard Worker if (self.inputNumberOfChannels != inputNumberOfChannels) { 139*d9f75844SAndroid Build Coastguard Worker NSError *inputChannelsError = nil; 140*d9f75844SAndroid Build Coastguard Worker if (![self setPreferredInputNumberOfChannels:inputNumberOfChannels 141*d9f75844SAndroid Build Coastguard Worker error:&inputChannelsError]) { 142*d9f75844SAndroid Build Coastguard Worker RTCLogError(@"Failed to set preferred input number of channels: %@", 143*d9f75844SAndroid Build Coastguard Worker inputChannelsError.localizedDescription); 144*d9f75844SAndroid Build Coastguard Worker if (!self.ignoresPreferredAttributeConfigurationErrors) { 145*d9f75844SAndroid Build Coastguard Worker error = inputChannelsError; 146*d9f75844SAndroid Build Coastguard Worker } 147*d9f75844SAndroid Build Coastguard Worker } else { 148*d9f75844SAndroid Build Coastguard Worker RTCLog(@"Set input number of channels to: %ld", 149*d9f75844SAndroid Build Coastguard Worker (long)inputNumberOfChannels); 150*d9f75844SAndroid Build Coastguard Worker } 151*d9f75844SAndroid Build Coastguard Worker } 152*d9f75844SAndroid Build Coastguard Worker NSInteger outputNumberOfChannels = configuration.outputNumberOfChannels; 153*d9f75844SAndroid Build Coastguard Worker if (self.outputNumberOfChannels != outputNumberOfChannels) { 154*d9f75844SAndroid Build Coastguard Worker NSError *outputChannelsError = nil; 155*d9f75844SAndroid Build Coastguard Worker if (![self setPreferredOutputNumberOfChannels:outputNumberOfChannels 156*d9f75844SAndroid Build Coastguard Worker error:&outputChannelsError]) { 157*d9f75844SAndroid Build Coastguard Worker RTCLogError(@"Failed to set preferred output number of channels: %@", 158*d9f75844SAndroid Build Coastguard Worker outputChannelsError.localizedDescription); 159*d9f75844SAndroid Build Coastguard Worker if (!self.ignoresPreferredAttributeConfigurationErrors) { 160*d9f75844SAndroid Build Coastguard Worker error = outputChannelsError; 161*d9f75844SAndroid Build Coastguard Worker } 162*d9f75844SAndroid Build Coastguard Worker } else { 163*d9f75844SAndroid Build Coastguard Worker RTCLog(@"Set output number of channels to: %ld", 164*d9f75844SAndroid Build Coastguard Worker (long)outputNumberOfChannels); 165*d9f75844SAndroid Build Coastguard Worker } 166*d9f75844SAndroid Build Coastguard Worker } 167*d9f75844SAndroid Build Coastguard Worker } 168*d9f75844SAndroid Build Coastguard Worker 169*d9f75844SAndroid Build Coastguard Worker if (outError) { 170*d9f75844SAndroid Build Coastguard Worker *outError = error; 171*d9f75844SAndroid Build Coastguard Worker } 172*d9f75844SAndroid Build Coastguard Worker 173*d9f75844SAndroid Build Coastguard Worker return error == nil; 174*d9f75844SAndroid Build Coastguard Worker} 175*d9f75844SAndroid Build Coastguard Worker 176*d9f75844SAndroid Build Coastguard Worker@end 177