summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorhenrika <henrika@chromium.org>2016-01-13 04:37:48 -0800
committerCommit bot <commit-bot@chromium.org>2016-01-13 12:39:48 +0000
commit054dc5409cbd7dba6560a695ef25965eb157dfc5 (patch)
tree1eab5d18d23f2a72081b6b0ebf84b2473500cb20 /media
parent6175da8042f3a0aa574f0da25e87be342625e603 (diff)
downloadchromium_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.cc92
-rw-r--r--media/audio/mac/audio_manager_mac.cc14
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);
}