xref: /aosp_15_r20/external/webrtc/sdk/objc/components/audio/RTCAudioSession+Configuration.mm (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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