xref: /aosp_15_r20/external/webrtc/sdk/objc/components/audio/RTCAudioSessionConfiguration.m (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 "RTCAudioSessionConfiguration.h"
12*d9f75844SAndroid Build Coastguard Worker#import "RTCAudioSession.h"
13*d9f75844SAndroid Build Coastguard Worker
14*d9f75844SAndroid Build Coastguard Worker#import "helpers/RTCDispatcher.h"
15*d9f75844SAndroid Build Coastguard Worker#import "helpers/UIDevice+RTCDevice.h"
16*d9f75844SAndroid Build Coastguard Worker
17*d9f75844SAndroid Build Coastguard Worker// Try to use mono to save resources. Also avoids channel format conversion
18*d9f75844SAndroid Build Coastguard Worker// in the I/O audio unit. Initial tests have shown that it is possible to use
19*d9f75844SAndroid Build Coastguard Worker// mono natively for built-in microphones and for BT headsets but not for
20*d9f75844SAndroid Build Coastguard Worker// wired headsets. Wired headsets only support stereo as native channel format
21*d9f75844SAndroid Build Coastguard Worker// but it is a low cost operation to do a format conversion to mono in the
22*d9f75844SAndroid Build Coastguard Worker// audio unit. Hence, we will not hit a RTC_CHECK in
23*d9f75844SAndroid Build Coastguard Worker// VerifyAudioParametersForActiveAudioSession() for a mismatch between the
24*d9f75844SAndroid Build Coastguard Worker// preferred number of channels and the actual number of channels.
25*d9f75844SAndroid Build Coastguard Workerconst int kRTCAudioSessionPreferredNumberOfChannels = 1;
26*d9f75844SAndroid Build Coastguard Worker
27*d9f75844SAndroid Build Coastguard Worker// Preferred hardware sample rate (unit is in Hertz). The client sample rate
28*d9f75844SAndroid Build Coastguard Worker// will be set to this value as well to avoid resampling the the audio unit's
29*d9f75844SAndroid Build Coastguard Worker// format converter. Note that, some devices, e.g. BT headsets, only supports
30*d9f75844SAndroid Build Coastguard Worker// 8000Hz as native sample rate.
31*d9f75844SAndroid Build Coastguard Workerconst double kRTCAudioSessionHighPerformanceSampleRate = 48000.0;
32*d9f75844SAndroid Build Coastguard Worker
33*d9f75844SAndroid Build Coastguard Worker// A lower sample rate will be used for devices with only one core
34*d9f75844SAndroid Build Coastguard Worker// (e.g. iPhone 4). The goal is to reduce the CPU load of the application.
35*d9f75844SAndroid Build Coastguard Workerconst double kRTCAudioSessionLowComplexitySampleRate = 16000.0;
36*d9f75844SAndroid Build Coastguard Worker
37*d9f75844SAndroid Build Coastguard Worker// Use a hardware I/O buffer size (unit is in seconds) that matches the 10ms
38*d9f75844SAndroid Build Coastguard Worker// size used by WebRTC. The exact actual size will differ between devices.
39*d9f75844SAndroid Build Coastguard Worker// Example: using 48kHz on iPhone 6 results in a native buffer size of
40*d9f75844SAndroid Build Coastguard Worker// ~10.6667ms or 512 audio frames per buffer. The FineAudioBuffer instance will
41*d9f75844SAndroid Build Coastguard Worker// take care of any buffering required to convert between native buffers and
42*d9f75844SAndroid Build Coastguard Worker// buffers used by WebRTC. It is beneficial for the performance if the native
43*d9f75844SAndroid Build Coastguard Worker// size is as an even multiple of 10ms as possible since it results in "clean"
44*d9f75844SAndroid Build Coastguard Worker// callback sequence without bursts of callbacks back to back.
45*d9f75844SAndroid Build Coastguard Workerconst double kRTCAudioSessionHighPerformanceIOBufferDuration = 0.02;
46*d9f75844SAndroid Build Coastguard Worker
47*d9f75844SAndroid Build Coastguard Worker// Use a larger buffer size on devices with only one core (e.g. iPhone 4).
48*d9f75844SAndroid Build Coastguard Worker// It will result in a lower CPU consumption at the cost of a larger latency.
49*d9f75844SAndroid Build Coastguard Worker// The size of 60ms is based on instrumentation that shows a significant
50*d9f75844SAndroid Build Coastguard Worker// reduction in CPU load compared with 10ms on low-end devices.
51*d9f75844SAndroid Build Coastguard Worker// TODO(henrika): monitor this size and determine if it should be modified.
52*d9f75844SAndroid Build Coastguard Workerconst double kRTCAudioSessionLowComplexityIOBufferDuration = 0.06;
53*d9f75844SAndroid Build Coastguard Worker
54*d9f75844SAndroid Build Coastguard Workerstatic RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *gWebRTCConfiguration = nil;
55*d9f75844SAndroid Build Coastguard Worker
56*d9f75844SAndroid Build Coastguard Worker@implementation RTC_OBJC_TYPE (RTCAudioSessionConfiguration)
57*d9f75844SAndroid Build Coastguard Worker
58*d9f75844SAndroid Build Coastguard Worker@synthesize category = _category;
59*d9f75844SAndroid Build Coastguard Worker@synthesize categoryOptions = _categoryOptions;
60*d9f75844SAndroid Build Coastguard Worker@synthesize mode = _mode;
61*d9f75844SAndroid Build Coastguard Worker@synthesize sampleRate = _sampleRate;
62*d9f75844SAndroid Build Coastguard Worker@synthesize ioBufferDuration = _ioBufferDuration;
63*d9f75844SAndroid Build Coastguard Worker@synthesize inputNumberOfChannels = _inputNumberOfChannels;
64*d9f75844SAndroid Build Coastguard Worker@synthesize outputNumberOfChannels = _outputNumberOfChannels;
65*d9f75844SAndroid Build Coastguard Worker
66*d9f75844SAndroid Build Coastguard Worker- (instancetype)init {
67*d9f75844SAndroid Build Coastguard Worker  if (self = [super init]) {
68*d9f75844SAndroid Build Coastguard Worker    // Use a category which supports simultaneous recording and playback.
69*d9f75844SAndroid Build Coastguard Worker    // By default, using this category implies that our app’s audio is
70*d9f75844SAndroid Build Coastguard Worker    // nonmixable, hence activating the session will interrupt any other
71*d9f75844SAndroid Build Coastguard Worker    // audio sessions which are also nonmixable.
72*d9f75844SAndroid Build Coastguard Worker    _category = AVAudioSessionCategoryPlayAndRecord;
73*d9f75844SAndroid Build Coastguard Worker    _categoryOptions = AVAudioSessionCategoryOptionAllowBluetooth;
74*d9f75844SAndroid Build Coastguard Worker
75*d9f75844SAndroid Build Coastguard Worker    // Specify mode for two-way voice communication (e.g. VoIP).
76*d9f75844SAndroid Build Coastguard Worker    _mode = AVAudioSessionModeVoiceChat;
77*d9f75844SAndroid Build Coastguard Worker
78*d9f75844SAndroid Build Coastguard Worker    // Set the session's sample rate or the hardware sample rate.
79*d9f75844SAndroid Build Coastguard Worker    // It is essential that we use the same sample rate as stream format
80*d9f75844SAndroid Build Coastguard Worker    // to ensure that the I/O unit does not have to do sample rate conversion.
81*d9f75844SAndroid Build Coastguard Worker    // Set the preferred audio I/O buffer duration, in seconds.
82*d9f75844SAndroid Build Coastguard Worker    NSUInteger processorCount = [NSProcessInfo processInfo].processorCount;
83*d9f75844SAndroid Build Coastguard Worker    // Use best sample rate and buffer duration if the CPU has more than one
84*d9f75844SAndroid Build Coastguard Worker    // core.
85*d9f75844SAndroid Build Coastguard Worker    if (processorCount > 1 && [UIDevice deviceType] != RTCDeviceTypeIPhone4S) {
86*d9f75844SAndroid Build Coastguard Worker      _sampleRate = kRTCAudioSessionHighPerformanceSampleRate;
87*d9f75844SAndroid Build Coastguard Worker      _ioBufferDuration = kRTCAudioSessionHighPerformanceIOBufferDuration;
88*d9f75844SAndroid Build Coastguard Worker    } else {
89*d9f75844SAndroid Build Coastguard Worker      _sampleRate = kRTCAudioSessionLowComplexitySampleRate;
90*d9f75844SAndroid Build Coastguard Worker      _ioBufferDuration = kRTCAudioSessionLowComplexityIOBufferDuration;
91*d9f75844SAndroid Build Coastguard Worker    }
92*d9f75844SAndroid Build Coastguard Worker
93*d9f75844SAndroid Build Coastguard Worker    // We try to use mono in both directions to save resources and format
94*d9f75844SAndroid Build Coastguard Worker    // conversions in the audio unit. Some devices does only support stereo;
95*d9f75844SAndroid Build Coastguard Worker    // e.g. wired headset on iPhone 6.
96*d9f75844SAndroid Build Coastguard Worker    // TODO(henrika): add support for stereo if needed.
97*d9f75844SAndroid Build Coastguard Worker    _inputNumberOfChannels = kRTCAudioSessionPreferredNumberOfChannels;
98*d9f75844SAndroid Build Coastguard Worker    _outputNumberOfChannels = kRTCAudioSessionPreferredNumberOfChannels;
99*d9f75844SAndroid Build Coastguard Worker  }
100*d9f75844SAndroid Build Coastguard Worker  return self;
101*d9f75844SAndroid Build Coastguard Worker}
102*d9f75844SAndroid Build Coastguard Worker
103*d9f75844SAndroid Build Coastguard Worker+ (void)initialize {
104*d9f75844SAndroid Build Coastguard Worker  gWebRTCConfiguration = [[self alloc] init];
105*d9f75844SAndroid Build Coastguard Worker}
106*d9f75844SAndroid Build Coastguard Worker
107*d9f75844SAndroid Build Coastguard Worker+ (instancetype)currentConfiguration {
108*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
109*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *config =
110*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCAudioSessionConfiguration) alloc] init];
111*d9f75844SAndroid Build Coastguard Worker  config.category = session.category;
112*d9f75844SAndroid Build Coastguard Worker  config.categoryOptions = session.categoryOptions;
113*d9f75844SAndroid Build Coastguard Worker  config.mode = session.mode;
114*d9f75844SAndroid Build Coastguard Worker  config.sampleRate = session.sampleRate;
115*d9f75844SAndroid Build Coastguard Worker  config.ioBufferDuration = session.IOBufferDuration;
116*d9f75844SAndroid Build Coastguard Worker  config.inputNumberOfChannels = session.inputNumberOfChannels;
117*d9f75844SAndroid Build Coastguard Worker  config.outputNumberOfChannels = session.outputNumberOfChannels;
118*d9f75844SAndroid Build Coastguard Worker  return config;
119*d9f75844SAndroid Build Coastguard Worker}
120*d9f75844SAndroid Build Coastguard Worker
121*d9f75844SAndroid Build Coastguard Worker+ (instancetype)webRTCConfiguration {
122*d9f75844SAndroid Build Coastguard Worker  @synchronized(self) {
123*d9f75844SAndroid Build Coastguard Worker    return (RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *)gWebRTCConfiguration;
124*d9f75844SAndroid Build Coastguard Worker  }
125*d9f75844SAndroid Build Coastguard Worker}
126*d9f75844SAndroid Build Coastguard Worker
127*d9f75844SAndroid Build Coastguard Worker+ (void)setWebRTCConfiguration:(RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *)configuration {
128*d9f75844SAndroid Build Coastguard Worker  @synchronized(self) {
129*d9f75844SAndroid Build Coastguard Worker    gWebRTCConfiguration = configuration;
130*d9f75844SAndroid Build Coastguard Worker  }
131*d9f75844SAndroid Build Coastguard Worker}
132*d9f75844SAndroid Build Coastguard Worker
133*d9f75844SAndroid Build Coastguard Worker@end
134