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 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 // VerifyAudioParametersForActiveAudioSession() for a mismatch between the | 79 // VerifyAudioParametersForActiveAudioSession() for a mismatch between the |
80 // preferred number of channels and the actual number of channels. | 80 // preferred number of channels and the actual number of channels. |
81 const int kPreferredNumberOfChannels = 1; | 81 const int kPreferredNumberOfChannels = 1; |
82 // Number of bytes per audio sample for 16-bit signed integer representation. | 82 // Number of bytes per audio sample for 16-bit signed integer representation. |
83 const UInt32 kBytesPerSample = 2; | 83 const UInt32 kBytesPerSample = 2; |
84 // Hardcoded delay estimates based on real measurements. | 84 // Hardcoded delay estimates based on real measurements. |
85 // TODO(henrika): these value is not used in combination with built-in AEC. | 85 // TODO(henrika): these value is not used in combination with built-in AEC. |
86 // Can most likely be removed. | 86 // Can most likely be removed. |
87 const UInt16 kFixedPlayoutDelayEstimate = 30; | 87 const UInt16 kFixedPlayoutDelayEstimate = 30; |
88 const UInt16 kFixedRecordDelayEstimate = 30; | 88 const UInt16 kFixedRecordDelayEstimate = 30; |
| 89 // Calls to AudioUnitInitialize() can fail if called back-to-back on different |
| 90 // ADM instances. A fall-back solution is to allow multiple sequential calls |
| 91 // with as small delay between each. This factor sets the max number of allowed |
| 92 // initialization attempts. |
| 93 const int kMaxNumberOfAudioUnitInitializeAttempts = 5; |
| 94 |
89 | 95 |
90 using ios::CheckAndLogError; | 96 using ios::CheckAndLogError; |
91 | 97 |
92 // Verifies that the current audio session supports input audio and that the | 98 // Verifies that the current audio session supports input audio and that the |
93 // required category and mode are enabled. | 99 // required category and mode are enabled. |
94 static bool VerifyAudioSession(AVAudioSession* session) { | 100 static bool VerifyAudioSession(AVAudioSession* session) { |
95 LOG(LS_INFO) << "VerifyAudioSession"; | 101 LOG(LS_INFO) << "VerifyAudioSession"; |
96 // Ensure that the device currently supports audio input. | 102 // Ensure that the device currently supports audio input. |
97 if (!session.isInputAvailable) { | 103 if (!session.isInputAvailable) { |
98 LOG(LS_ERROR) << "No audio input path is available!"; | 104 LOG(LS_ERROR) << "No audio input path is available!"; |
(...skipping 635 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
734 LOGI() << "SetupAndInitializeVoiceProcessingAudioUnit"; | 740 LOGI() << "SetupAndInitializeVoiceProcessingAudioUnit"; |
735 RTC_DCHECK(!vpio_unit_) << "VoiceProcessingIO audio unit already exists"; | 741 RTC_DCHECK(!vpio_unit_) << "VoiceProcessingIO audio unit already exists"; |
736 // Create an audio component description to identify the Voice-Processing | 742 // Create an audio component description to identify the Voice-Processing |
737 // I/O audio unit. | 743 // I/O audio unit. |
738 AudioComponentDescription vpio_unit_description; | 744 AudioComponentDescription vpio_unit_description; |
739 vpio_unit_description.componentType = kAudioUnitType_Output; | 745 vpio_unit_description.componentType = kAudioUnitType_Output; |
740 vpio_unit_description.componentSubType = kAudioUnitSubType_VoiceProcessingIO; | 746 vpio_unit_description.componentSubType = kAudioUnitSubType_VoiceProcessingIO; |
741 vpio_unit_description.componentManufacturer = kAudioUnitManufacturer_Apple; | 747 vpio_unit_description.componentManufacturer = kAudioUnitManufacturer_Apple; |
742 vpio_unit_description.componentFlags = 0; | 748 vpio_unit_description.componentFlags = 0; |
743 vpio_unit_description.componentFlagsMask = 0; | 749 vpio_unit_description.componentFlagsMask = 0; |
| 750 |
744 // Obtain an audio unit instance given the description. | 751 // Obtain an audio unit instance given the description. |
745 AudioComponent found_vpio_unit_ref = | 752 AudioComponent found_vpio_unit_ref = |
746 AudioComponentFindNext(nullptr, &vpio_unit_description); | 753 AudioComponentFindNext(nullptr, &vpio_unit_description); |
747 | 754 |
748 // Create a Voice-Processing IO audio unit. | 755 // Create a Voice-Processing IO audio unit. |
749 OSStatus result = noErr; | 756 OSStatus result = noErr; |
750 result = AudioComponentInstanceNew(found_vpio_unit_ref, &vpio_unit_); | 757 result = AudioComponentInstanceNew(found_vpio_unit_ref, &vpio_unit_); |
751 if (result != noErr) { | 758 if (result != noErr) { |
752 vpio_unit_ = nullptr; | 759 vpio_unit_ = nullptr; |
753 LOG(LS_ERROR) << "AudioComponentInstanceNew failed: " << result; | 760 LOG(LS_ERROR) << "AudioComponentInstanceNew failed: " << result; |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
869 kAudioOutputUnitProperty_SetInputCallback, | 876 kAudioOutputUnitProperty_SetInputCallback, |
870 kAudioUnitScope_Global, input_bus, | 877 kAudioUnitScope_Global, input_bus, |
871 &input_callback, sizeof(input_callback)); | 878 &input_callback, sizeof(input_callback)); |
872 if (result != noErr) { | 879 if (result != noErr) { |
873 DisposeAudioUnit(); | 880 DisposeAudioUnit(); |
874 LOG(LS_ERROR) << "Failed to specify the input callback on the input bus: " | 881 LOG(LS_ERROR) << "Failed to specify the input callback on the input bus: " |
875 << result; | 882 << result; |
876 } | 883 } |
877 | 884 |
878 // Initialize the Voice-Processing I/O unit instance. | 885 // Initialize the Voice-Processing I/O unit instance. |
| 886 // Calls to AudioUnitInitialize() can fail if called back-to-back on |
| 887 // different ADM instances. The error message in this case is -66635 which is |
| 888 // undocumented. Tests have shown that calling AudioUnitInitialize a second |
| 889 // time, after a short sleep, avoids this issue. |
| 890 // See webrtc:5166 for details. |
| 891 int failed_initalize_attempts = 0; |
879 result = AudioUnitInitialize(vpio_unit_); | 892 result = AudioUnitInitialize(vpio_unit_); |
880 if (result != noErr) { | 893 while (result != noErr) { |
881 result = AudioUnitUninitialize(vpio_unit_); | |
882 if (result != noErr) { | |
883 LOG_F(LS_ERROR) << "AudioUnitUninitialize failed: " << result; | |
884 } | |
885 DisposeAudioUnit(); | |
886 LOG(LS_ERROR) << "Failed to initialize the Voice-Processing I/O unit: " | 894 LOG(LS_ERROR) << "Failed to initialize the Voice-Processing I/O unit: " |
887 << result; | 895 << result; |
888 return false; | 896 ++failed_initalize_attempts; |
| 897 if (failed_initalize_attempts == kMaxNumberOfAudioUnitInitializeAttempts) { |
| 898 // Max number of initialization attempts exceeded, hence abort. |
| 899 LOG(LS_WARNING) << "Too many initialization attempts"; |
| 900 DisposeAudioUnit(); |
| 901 return false; |
| 902 } |
| 903 LOG(LS_INFO) << "pause 100ms and try audio unit initialization again..."; |
| 904 [NSThread sleepForTimeInterval:0.1f]; |
| 905 result = AudioUnitInitialize(vpio_unit_); |
889 } | 906 } |
| 907 LOG(LS_INFO) << "Voice-Processing I/O unit is now initialized"; |
890 return true; | 908 return true; |
891 } | 909 } |
892 | 910 |
893 bool AudioDeviceIOS::RestartAudioUnitWithNewFormat(float sample_rate) { | 911 bool AudioDeviceIOS::RestartAudioUnitWithNewFormat(float sample_rate) { |
894 LOGI() << "RestartAudioUnitWithNewFormat(sample_rate=" << sample_rate << ")"; | 912 LOGI() << "RestartAudioUnitWithNewFormat(sample_rate=" << sample_rate << ")"; |
895 // Stop the active audio unit. | 913 // Stop the active audio unit. |
896 LOG_AND_RETURN_IF_ERROR(AudioOutputUnitStop(vpio_unit_), | 914 LOG_AND_RETURN_IF_ERROR(AudioOutputUnitStop(vpio_unit_), |
897 "Failed to stop the the Voice-Processing I/O unit"); | 915 "Failed to stop the the Voice-Processing I/O unit"); |
898 | 916 |
899 // The stream format is about to be changed and it requires that we first | 917 // The stream format is about to be changed and it requires that we first |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1077 // Read decoded 16-bit PCM samples from WebRTC (using a size that matches | 1095 // Read decoded 16-bit PCM samples from WebRTC (using a size that matches |
1078 // the native I/O audio unit) to a preallocated intermediate buffer and | 1096 // the native I/O audio unit) to a preallocated intermediate buffer and |
1079 // copy the result to the audio buffer in the |io_data| destination. | 1097 // copy the result to the audio buffer in the |io_data| destination. |
1080 SInt8* source = playout_audio_buffer_.get(); | 1098 SInt8* source = playout_audio_buffer_.get(); |
1081 fine_audio_buffer_->GetPlayoutData(source); | 1099 fine_audio_buffer_->GetPlayoutData(source); |
1082 memcpy(destination, source, dataSizeInBytes); | 1100 memcpy(destination, source, dataSizeInBytes); |
1083 return noErr; | 1101 return noErr; |
1084 } | 1102 } |
1085 | 1103 |
1086 } // namespace webrtc | 1104 } // namespace webrtc |
OLD | NEW |