| 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 |