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