Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: webrtc/modules/audio_device/ios/audio_device_ios.mm

Issue 1723163002: Adds low complexity audio mode for single core CPUs (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | webrtc/modules/utility/include/helpers_ios.h » ('j') | webrtc/modules/utility/source/helpers_ios.mm » ('J')

Powered by Google App Engine
This is Rietveld 408576698