OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 OSStatus err = error; \ | 45 OSStatus err = error; \ |
46 if (err) { \ | 46 if (err) { \ |
47 LOG(LS_ERROR) << message << ": " << err; \ | 47 LOG(LS_ERROR) << message << ": " << err; \ |
48 } \ | 48 } \ |
49 } while (0) | 49 } while (0) |
50 | 50 |
51 // Preferred hardware sample rate (unit is in Hertz). The client sample rate | 51 // Preferred hardware sample rate (unit is in Hertz). The client sample rate |
52 // will be set to this value as well to avoid resampling the the audio unit's | 52 // will be set to this value as well to avoid resampling the the audio unit's |
53 // format converter. Note that, some devices, e.g. BT headsets, only supports | 53 // format converter. Note that, some devices, e.g. BT headsets, only supports |
54 // 8000Hz as native sample rate. | 54 // 8000Hz as native sample rate. |
55 const double kPreferredSampleRate = 48000.0; | 55 const double kHighPerformanceSampleRate = 48000.0; |
| 56 // A lower sample rate will be used for devices with only one core |
| 57 // (e.g. iPhone 4). The goal is to reduce the CPU load of the application. |
| 58 const double kLowComplexitySampleRate = 16000.0; |
56 // Use a hardware I/O buffer size (unit is in seconds) that matches the 10ms | 59 // Use a hardware I/O buffer size (unit is in seconds) that matches the 10ms |
57 // size used by WebRTC. The exact actual size will differ between devices. | 60 // size used by WebRTC. The exact actual size will differ between devices. |
58 // Example: using 48kHz on iPhone 6 results in a native buffer size of | 61 // Example: using 48kHz on iPhone 6 results in a native buffer size of |
59 // ~10.6667ms or 512 audio frames per buffer. The FineAudioBuffer instance will | 62 // ~10.6667ms or 512 audio frames per buffer. The FineAudioBuffer instance will |
60 // take care of any buffering required to convert between native buffers and | 63 // take care of any buffering required to convert between native buffers and |
61 // buffers used by WebRTC. It is beneficial for the performance if the native | 64 // buffers used by WebRTC. It is beneficial for the performance if the native |
62 // size is as close to 10ms as possible since it results in "clean" callback | 65 // size is as close to 10ms as possible since it results in "clean" callback |
63 // sequence without bursts of callbacks back to back. | 66 // sequence without bursts of callbacks back to back. |
64 const double kPreferredIOBufferDuration = 0.01; | 67 const double kHighPerformanceIOBufferDuration = 0.01; |
| 68 // Use a larger buffer size on devices with only one core (e.g. iPhone 4). |
| 69 // It will result in a lower CPU consumption at the cost of a larger latency. |
| 70 // The size of 60ms is based on instrumentation that shows a significant |
| 71 // reduction in CPU load compared with 10ms on low-end devices. |
| 72 // TODO(henrika): monitor this size and determine if it should be modified. |
| 73 const double kLowComplexityIOBufferDuration = 0.06; |
65 // Try to use mono to save resources. Also avoids channel format conversion | 74 // Try to use mono to save resources. Also avoids channel format conversion |
66 // in the I/O audio unit. Initial tests have shown that it is possible to use | 75 // in the I/O audio unit. Initial tests have shown that it is possible to use |
67 // mono natively for built-in microphones and for BT headsets but not for | 76 // mono natively for built-in microphones and for BT headsets but not for |
68 // wired headsets. Wired headsets only support stereo as native channel format | 77 // wired headsets. Wired headsets only support stereo as native channel format |
69 // but it is a low cost operation to do a format conversion to mono in the | 78 // but it is a low cost operation to do a format conversion to mono in the |
70 // audio unit. Hence, we will not hit a RTC_CHECK in | 79 // audio unit. Hence, we will not hit a RTC_CHECK in |
71 // VerifyAudioParametersForActiveAudioSession() for a mismatch between the | 80 // VerifyAudioParametersForActiveAudioSession() for a mismatch between the |
72 // preferred number of channels and the actual number of channels. | 81 // preferred number of channels and the actual number of channels. |
73 const int kPreferredNumberOfChannels = 1; | 82 const int kPreferredNumberOfChannels = 1; |
74 // Number of bytes per audio sample for 16-bit signed integer representation. | 83 // Number of bytes per audio sample for 16-bit signed integer representation. |
75 const UInt32 kBytesPerSample = 2; | 84 const UInt32 kBytesPerSample = 2; |
76 // Hardcoded delay estimates based on real measurements. | 85 // Hardcoded delay estimates based on real measurements. |
77 // TODO(henrika): these value is not used in combination with built-in AEC. | 86 // TODO(henrika): these value is not used in combination with built-in AEC. |
78 // Can most likely be removed. | 87 // Can most likely be removed. |
79 const UInt16 kFixedPlayoutDelayEstimate = 30; | 88 const UInt16 kFixedPlayoutDelayEstimate = 30; |
80 const UInt16 kFixedRecordDelayEstimate = 30; | 89 const UInt16 kFixedRecordDelayEstimate = 30; |
81 // Calls to AudioUnitInitialize() can fail if called back-to-back on different | 90 // Calls to AudioUnitInitialize() can fail if called back-to-back on different |
82 // ADM instances. A fall-back solution is to allow multiple sequential calls | 91 // ADM instances. A fall-back solution is to allow multiple sequential calls |
83 // with as small delay between each. This factor sets the max number of allowed | 92 // with as small delay between each. This factor sets the max number of allowed |
84 // initialization attempts. | 93 // initialization attempts. |
85 const int kMaxNumberOfAudioUnitInitializeAttempts = 5; | 94 const int kMaxNumberOfAudioUnitInitializeAttempts = 5; |
86 | 95 |
| 96 using ios::CheckAndLogError; |
87 | 97 |
88 using ios::CheckAndLogError; | 98 // Return the preferred sample rate given number of CPU cores. Use highest |
| 99 // possible if the CPU has more than one core. |
| 100 static double GetPreferredSampleRate() { |
| 101 return (ios::GetProcessorCount() > 1) ? kHighPerformanceSampleRate |
| 102 : kLowComplexitySampleRate; |
| 103 } |
| 104 |
| 105 // Return the preferred I/O buffer size given number of CPU cores. Use smallest |
| 106 // possible if the CPU has more than one core. |
| 107 static double GetPreferredIOBufferDuration() { |
| 108 return (ios::GetProcessorCount() > 1) ? kHighPerformanceIOBufferDuration |
| 109 : kLowComplexityIOBufferDuration; |
| 110 } |
89 | 111 |
90 // Verifies that the current audio session supports input audio and that the | 112 // Verifies that the current audio session supports input audio and that the |
91 // required category and mode are enabled. | 113 // required category and mode are enabled. |
92 static bool VerifyAudioSession(RTCAudioSession* session) { | 114 static bool VerifyAudioSession(RTCAudioSession* session) { |
93 LOG(LS_INFO) << "VerifyAudioSession"; | 115 LOG(LS_INFO) << "VerifyAudioSession"; |
94 // Ensure that the device currently supports audio input. | 116 // Ensure that the device currently supports audio input. |
95 if (!session.inputAvailable) { | 117 if (!session.inputAvailable) { |
96 LOG(LS_ERROR) << "No audio input path is available!"; | 118 LOG(LS_ERROR) << "No audio input path is available!"; |
97 return false; | 119 return false; |
98 } | 120 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 error = nil; | 167 error = nil; |
146 success = [session setMode:AVAudioSessionModeVoiceChat error:&error]; | 168 success = [session setMode:AVAudioSessionModeVoiceChat error:&error]; |
147 RTC_DCHECK(CheckAndLogError(success, error)); | 169 RTC_DCHECK(CheckAndLogError(success, error)); |
148 } | 170 } |
149 | 171 |
150 // Set the session's sample rate or the hardware sample rate. | 172 // Set the session's sample rate or the hardware sample rate. |
151 // It is essential that we use the same sample rate as stream format | 173 // It is essential that we use the same sample rate as stream format |
152 // to ensure that the I/O unit does not have to do sample rate conversion. | 174 // to ensure that the I/O unit does not have to do sample rate conversion. |
153 error = nil; | 175 error = nil; |
154 success = | 176 success = |
155 [session setPreferredSampleRate:kPreferredSampleRate error:&error]; | 177 [session setPreferredSampleRate:GetPreferredSampleRate() error:&error]; |
156 RTC_DCHECK(CheckAndLogError(success, error)); | 178 RTC_DCHECK(CheckAndLogError(success, error)); |
157 | 179 |
158 // Set the preferred audio I/O buffer duration, in seconds. | 180 // Set the preferred audio I/O buffer duration, in seconds. |
159 error = nil; | 181 error = nil; |
160 success = [session setPreferredIOBufferDuration:kPreferredIOBufferDuration | 182 success = [session setPreferredIOBufferDuration:GetPreferredIOBufferDuration() |
161 error:&error]; | 183 error:&error]; |
162 RTC_DCHECK(CheckAndLogError(success, error)); | 184 RTC_DCHECK(CheckAndLogError(success, error)); |
163 | 185 |
164 // Activate the audio session. Activation can fail if another active audio | 186 // Activate the audio session. Activation can fail if another active audio |
165 // session (e.g. phone call) has higher priority than ours. | 187 // session (e.g. phone call) has higher priority than ours. |
166 error = nil; | 188 error = nil; |
167 success = [session setActive:YES error:&error]; | 189 success = [session setActive:YES error:&error]; |
168 if (!CheckAndLogError(success, error)) { | 190 if (!CheckAndLogError(success, error)) { |
169 [session unlockForConfiguration]; | 191 [session unlockForConfiguration]; |
170 return false; | 192 return false; |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 } | 258 } |
237 | 259 |
238 // Helper method that logs essential device information strings. | 260 // Helper method that logs essential device information strings. |
239 static void LogDeviceInfo() { | 261 static void LogDeviceInfo() { |
240 LOG(LS_INFO) << "LogDeviceInfo"; | 262 LOG(LS_INFO) << "LogDeviceInfo"; |
241 @autoreleasepool { | 263 @autoreleasepool { |
242 LOG(LS_INFO) << " system name: " << ios::GetSystemName(); | 264 LOG(LS_INFO) << " system name: " << ios::GetSystemName(); |
243 LOG(LS_INFO) << " system version: " << ios::GetSystemVersion(); | 265 LOG(LS_INFO) << " system version: " << ios::GetSystemVersion(); |
244 LOG(LS_INFO) << " device type: " << ios::GetDeviceType(); | 266 LOG(LS_INFO) << " device type: " << ios::GetDeviceType(); |
245 LOG(LS_INFO) << " device name: " << ios::GetDeviceName(); | 267 LOG(LS_INFO) << " device name: " << ios::GetDeviceName(); |
| 268 LOG(LS_INFO) << " process name: " << ios::GetProcessName(); |
| 269 LOG(LS_INFO) << " process ID: " << ios::GetProcessID(); |
| 270 LOG(LS_INFO) << " OS version: " << ios::GetOSVersionString(); |
| 271 LOG(LS_INFO) << " processing cores: " << ios::GetProcessorCount(); |
| 272 LOG(LS_INFO) << " low power mode: " << ios::GetLowPowerModeEnabled(); |
246 } | 273 } |
247 } | 274 } |
248 #endif // !defined(NDEBUG) | 275 #endif // !defined(NDEBUG) |
249 | 276 |
250 AudioDeviceIOS::AudioDeviceIOS() | 277 AudioDeviceIOS::AudioDeviceIOS() |
251 : audio_device_buffer_(nullptr), | 278 : audio_device_buffer_(nullptr), |
252 vpio_unit_(nullptr), | 279 vpio_unit_(nullptr), |
253 recording_(0), | 280 recording_(0), |
254 playing_(0), | 281 playing_(0), |
255 initialized_(false), | 282 initialized_(false), |
(...skipping 23 matching lines...) Expand all Loading... |
279 if (initialized_) { | 306 if (initialized_) { |
280 return 0; | 307 return 0; |
281 } | 308 } |
282 #if !defined(NDEBUG) | 309 #if !defined(NDEBUG) |
283 LogDeviceInfo(); | 310 LogDeviceInfo(); |
284 #endif | 311 #endif |
285 // Store the preferred sample rate and preferred number of channels already | 312 // Store the preferred sample rate and preferred number of channels already |
286 // here. They have not been set and confirmed yet since ActivateAudioSession() | 313 // here. They have not been set and confirmed yet since ActivateAudioSession() |
287 // is not called until audio is about to start. However, it makes sense to | 314 // is not called until audio is about to start. However, it makes sense to |
288 // store the parameters now and then verify at a later stage. | 315 // store the parameters now and then verify at a later stage. |
289 playout_parameters_.reset(kPreferredSampleRate, kPreferredNumberOfChannels); | 316 playout_parameters_.reset(GetPreferredSampleRate(), |
290 record_parameters_.reset(kPreferredSampleRate, kPreferredNumberOfChannels); | 317 kPreferredNumberOfChannels); |
| 318 record_parameters_.reset(GetPreferredSampleRate(), |
| 319 kPreferredNumberOfChannels); |
291 // Ensure that the audio device buffer (ADB) knows about the internal audio | 320 // Ensure that the audio device buffer (ADB) knows about the internal audio |
292 // parameters. Note that, even if we are unable to get a mono audio session, | 321 // parameters. Note that, even if we are unable to get a mono audio session, |
293 // we will always tell the I/O audio unit to do a channel format conversion | 322 // we will always tell the I/O audio unit to do a channel format conversion |
294 // to guarantee mono on the "input side" of the audio unit. | 323 // to guarantee mono on the "input side" of the audio unit. |
295 UpdateAudioDeviceBuffer(); | 324 UpdateAudioDeviceBuffer(); |
296 initialized_ = true; | 325 initialized_ = true; |
297 return 0; | 326 return 0; |
298 } | 327 } |
299 | 328 |
300 int32_t AudioDeviceIOS::Terminate() { | 329 int32_t AudioDeviceIOS::Terminate() { |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
634 LOG(LS_INFO) << " IO buffer duration: " << session.IOBufferDuration; | 663 LOG(LS_INFO) << " IO buffer duration: " << session.IOBufferDuration; |
635 LOG(LS_INFO) << " output channels: " << session.outputNumberOfChannels; | 664 LOG(LS_INFO) << " output channels: " << session.outputNumberOfChannels; |
636 LOG(LS_INFO) << " input channels: " << session.inputNumberOfChannels; | 665 LOG(LS_INFO) << " input channels: " << session.inputNumberOfChannels; |
637 LOG(LS_INFO) << " output latency: " << session.outputLatency; | 666 LOG(LS_INFO) << " output latency: " << session.outputLatency; |
638 LOG(LS_INFO) << " input latency: " << session.inputLatency; | 667 LOG(LS_INFO) << " input latency: " << session.inputLatency; |
639 | 668 |
640 // Log a warning message for the case when we are unable to set the preferred | 669 // Log a warning message for the case when we are unable to set the preferred |
641 // hardware sample rate but continue and use the non-ideal sample rate after | 670 // hardware sample rate but continue and use the non-ideal sample rate after |
642 // reinitializing the audio parameters. Most BT headsets only support 8kHz or | 671 // reinitializing the audio parameters. Most BT headsets only support 8kHz or |
643 // 16kHz. | 672 // 16kHz. |
644 if (session.sampleRate != kPreferredSampleRate) { | 673 if (session.sampleRate != GetPreferredSampleRate()) { |
645 LOG(LS_WARNING) << "Unable to set the preferred sample rate"; | 674 LOG(LS_WARNING) << "Unable to set the preferred sample rate"; |
646 } | 675 } |
647 | 676 |
648 // At this stage, we also know the exact IO buffer duration and can add | 677 // At this stage, we also know the exact IO buffer duration and can add |
649 // that info to the existing audio parameters where it is converted into | 678 // that info to the existing audio parameters where it is converted into |
650 // number of audio frames. | 679 // number of audio frames. |
651 // Example: IO buffer size = 0.008 seconds <=> 128 audio frames at 16kHz. | 680 // Example: IO buffer size = 0.008 seconds <=> 128 audio frames at 16kHz. |
652 // Hence, 128 is the size we expect to see in upcoming render callbacks. | 681 // Hence, 128 is the size we expect to see in upcoming render callbacks. |
653 playout_parameters_.reset(session.sampleRate, playout_parameters_.channels(), | 682 playout_parameters_.reset(session.sampleRate, playout_parameters_.channels(), |
654 session.IOBufferDuration); | 683 session.IOBufferDuration); |
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1060 // Read decoded 16-bit PCM samples from WebRTC (using a size that matches | 1089 // Read decoded 16-bit PCM samples from WebRTC (using a size that matches |
1061 // the native I/O audio unit) to a preallocated intermediate buffer and | 1090 // the native I/O audio unit) to a preallocated intermediate buffer and |
1062 // copy the result to the audio buffer in the |io_data| destination. | 1091 // copy the result to the audio buffer in the |io_data| destination. |
1063 SInt8* source = playout_audio_buffer_.get(); | 1092 SInt8* source = playout_audio_buffer_.get(); |
1064 fine_audio_buffer_->GetPlayoutData(source); | 1093 fine_audio_buffer_->GetPlayoutData(source); |
1065 memcpy(destination, source, dataSizeInBytes); | 1094 memcpy(destination, source, dataSizeInBytes); |
1066 return noErr; | 1095 return noErr; |
1067 } | 1096 } |
1068 | 1097 |
1069 } // namespace webrtc | 1098 } // namespace webrtc |
OLD | NEW |