diff options
author | henrika <henrika@chromium.org> | 2016-01-13 04:37:48 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-13 12:39:48 +0000 |
commit | 054dc5409cbd7dba6560a695ef25965eb157dfc5 (patch) | |
tree | 1eab5d18d23f2a72081b6b0ebf84b2473500cb20 /media | |
parent | 6175da8042f3a0aa574f0da25e87be342625e603 (diff) | |
download | chromium_src-054dc5409cbd7dba6560a695ef25965eb157dfc5.zip chromium_src-054dc5409cbd7dba6560a695ef25965eb157dfc5.tar.gz chromium_src-054dc5409cbd7dba6560a695ef25965eb157dfc5.tar.bz2 |
Relands selected parts of previously reverted IO buffer CL for Mac OSX.
This CL restores most parts of what was previously reverted in https://codereview.chromium.org/1575893002/. It has also been verified that we don't break
the Web Speech API which was the case before the initial revert.
BUG=549021
TESTS=media_unittests on real hardware and different WebRTC clients plus Web Speech demo
Review URL: https://codereview.chromium.org/1579993002
Cr-Commit-Position: refs/heads/master@{#369151}
Diffstat (limited to 'media')
-rw-r--r-- | media/audio/mac/audio_low_latency_input_mac.cc | 92 | ||||
-rw-r--r-- | media/audio/mac/audio_manager_mac.cc | 14 |
2 files changed, 89 insertions, 17 deletions
diff --git a/media/audio/mac/audio_low_latency_input_mac.cc b/media/audio/mac/audio_low_latency_input_mac.cc index d9185b8..65ca6a5 100644 --- a/media/audio/mac/audio_low_latency_input_mac.cc +++ b/media/audio/mac/audio_low_latency_input_mac.cc @@ -122,6 +122,10 @@ bool AUAudioInputStream::Open() { // Start by obtaining an AudioOuputUnit using an AUHAL component description. // Description for the Audio Unit we want to use (AUHAL in this case). + // The kAudioUnitSubType_HALOutput audio unit interfaces to any audio device. + // The user specifies which audio device to track. The audio unit can do + // input from the device as well as output to the device. Bus 0 is used for + // the output side, bus 1 is used to get audio input from the device. AudioComponentDescription desc = { kAudioUnitType_Output, kAudioUnitSubType_HALOutput, @@ -140,7 +144,22 @@ bool AUAudioInputStream::Open() { return false; } + // Initialize the AUHAL before making any changes or using it. The audio unit + // will be initialized once more as last operation in this method but that is + // intentional. This approach is based on a comment in the CAPlayThrough + // example from Apple, which states that "AUHAL needs to be initialized + // *before* anything is done to it". + // TODO(henrika): remove this extra call if we are unable to see any positive + // effects of it in our UMA stats. + result = AudioUnitInitialize(audio_unit_); + if (result != noErr) { + HandleError(result); + return false; + } + // Enable IO on the input scope of the Audio Unit. + // Note that, these changes must be done *before* setting the AUHAL's + // current device. // After creating the AUHAL object, we must enable IO on the input scope // of the Audio Unit to obtain the device input. Input must be explicitly @@ -188,17 +207,41 @@ bool AUAudioInputStream::Open() { return false; } - // Set up the the desired (output) format. - // For obtaining input from a device, the device format is always expressed - // on the output scope of the AUHAL's Element 1. - result = AudioUnitSetProperty(audio_unit_, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, 1, &format_, - sizeof(format_)); + // Register the input procedure for the AUHAL. + // This procedure will be called when the AUHAL has received new data + // from the input device. + AURenderCallbackStruct callback; + callback.inputProc = InputProc; + callback.inputProcRefCon = this; + result = AudioUnitSetProperty( + audio_unit_, kAudioOutputUnitProperty_SetInputCallback, + kAudioUnitScope_Global, 0, &callback, sizeof(callback)); if (result != noErr) { HandleError(result); return false; } + // Get the stream format for the selected input device and ensure that the + // sample rate of the selected input device matches the desired (given at + // construction) sample rate. We should not rely on sample rate conversion + // in the AUHAL, only *simple* conversions, e.g., 32-bit float to 16-bit + // signed integer format. + AudioStreamBasicDescription input_device_format = {0}; + UInt32 property_size = sizeof(input_device_format); + result = AudioUnitGetProperty(audio_unit_, kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, 1, &input_device_format, + &property_size); + DVLOG(1) << "Input device format: " << input_device_format; + if (input_device_format.mSampleRate != format_.mSampleRate) { + LOG(ERROR) + << "Input device's sample rate does not match the client's sample rate"; + result = kAudioUnitErr_FormatNotSupported; + HandleError(result); + return false; + } + + // Modify the IO buffer size if not already set correctly for the selected + // device. if (!manager_->MaybeChangeBufferSize(input_device_id_, audio_unit_, 1, number_of_frames_, &buffer_size_was_changed_)) { @@ -209,15 +252,33 @@ bool AUAudioInputStream::Open() { DLOG_IF(WARNING, buffer_size_was_changed_) << "IO buffer size was changed to " << number_of_frames_; - // Register the input procedure for the AUHAL. - // This procedure will be called when the AUHAL has received new data - // from the input device. - AURenderCallbackStruct callback; - callback.inputProc = InputProc; - callback.inputProcRefCon = this; - result = AudioUnitSetProperty( - audio_unit_, kAudioOutputUnitProperty_SetInputCallback, - kAudioUnitScope_Global, 0, &callback, sizeof(callback)); + // Verify that the IO buffer size is set correctly. + // TODO(henrika): perhaps add to UMA stat to track if this can happen. + UInt32 io_buffer_size_frames; + property_size = sizeof(io_buffer_size_frames); + result = AudioUnitGetProperty( + audio_unit_, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, + 0, &io_buffer_size_frames, &property_size); + if (io_buffer_size_frames != number_of_frames_) { + LOG(ERROR) << "AUHAL uses an invalid IO buffer size: " + << io_buffer_size_frames; + result = kAudioUnitErr_FormatNotSupported; + HandleError(result); + return false; + } + + // Channel mapping should be supported but add a warning just in case. + // TODO(henrika): perhaps add to UMA stat to track if this can happen. + DLOG_IF(WARNING, + input_device_format.mChannelsPerFrame != format_.mChannelsPerFrame) + << "AUHAL's audio converter must do channel conversion"; + + // Set up the the desired (output) format. + // For obtaining input from a device, the device format is always expressed + // on the output scope of the AUHAL's Element 1. + result = AudioUnitSetProperty(audio_unit_, kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, 1, &format_, + sizeof(format_)); if (result != noErr) { HandleError(result); return false; @@ -761,6 +822,7 @@ void AUAudioInputStream::CheckInputStartupSuccess() { void AUAudioInputStream::CloseAudioUnit() { DCHECK(thread_checker_.CalledOnValidThread()); + DVLOG(1) << "CloseAudioUnit"; if (!audio_unit_) return; OSStatus result = AudioUnitUninitialize(audio_unit_); diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc index 08e4f3e..13797e7 100644 --- a/media/audio/mac/audio_manager_mac.cc +++ b/media/audio/mac/audio_manager_mac.cc @@ -755,17 +755,25 @@ bool AudioManagerMac::MaybeChangeBufferSize(AudioDeviceID device_id, AudioUnitElement element, size_t desired_buffer_size, bool* size_was_changed) { + const bool is_input = (element == 1); + DVLOG(1) << "MaybeChangeBufferSize(id=0x" << std::hex << device_id + << ", is_input=" << is_input << ", buffer_size=" << std::dec + << desired_buffer_size << ")"; + *size_was_changed = false; + + // Get the current size of the I/O buffer for the specified device and scope. UInt32 buffer_size = 0; UInt32 property_size = sizeof(buffer_size); OSStatus result = AudioUnitGetProperty( - audio_unit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Output, + audio_unit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, element, &buffer_size, &property_size); if (result != noErr) { OSSTATUS_DLOG(ERROR, result) << "AudioUnitGetProperty(kAudioDevicePropertyBufferFrameSize) failed."; return false; } + DVLOG(1) << "Current IO buffer size: " << buffer_size; // The lowest buffer size always wins. For larger buffer sizes, we have // to perform some checks to see if the size can actually be changed. @@ -801,14 +809,16 @@ bool AudioManagerMac::MaybeChangeBufferSize(AudioDeviceID device_id, if (buffer_size == desired_buffer_size) return true; + // Set new I/O buffer size for the specified device and scope. buffer_size = desired_buffer_size; result = AudioUnitSetProperty(audio_unit, kAudioDevicePropertyBufferFrameSize, - kAudioUnitScope_Output, element, &buffer_size, + kAudioUnitScope_Global, element, &buffer_size, sizeof(buffer_size)); OSSTATUS_DLOG_IF(ERROR, result != noErr, result) << "AudioUnitSetProperty(kAudioDevicePropertyBufferFrameSize) failed. " << "Size:: " << buffer_size; *size_was_changed = (result == noErr); + DVLOG_IF(1, result == noErr) << "IO buffer size changed to: " << buffer_size; return (result == noErr); } |