| Index: media/audio/mac/audio_auhal_mac.cc
|
| diff --git a/media/audio/mac/audio_auhal_mac.cc b/media/audio/mac/audio_auhal_mac.cc
|
| index 6badbe9d285a20bbf54f9eb1e0f5c6802b241a65..9fcd46a6a95a71fdd63a3680bb76d91f6277c487 100644
|
| --- a/media/audio/mac/audio_auhal_mac.cc
|
| +++ b/media/audio/mac/audio_auhal_mac.cc
|
| @@ -7,12 +7,11 @@
|
| #include <CoreServices/CoreServices.h>
|
|
|
| #include "base/basictypes.h"
|
| -#include "base/command_line.h"
|
| #include "base/debug/trace_event.h"
|
| #include "base/logging.h"
|
| #include "base/mac/mac_logging.h"
|
| #include "media/audio/mac/audio_manager_mac.h"
|
| -#include "media/base/media_switches.h"
|
| +#include "media/base/audio_pull_fifo.h"
|
|
|
| namespace media {
|
|
|
| @@ -58,8 +57,8 @@ AUHALStream::AUHALStream(
|
| volume_(1),
|
| hardware_latency_frames_(0),
|
| stopped_(false),
|
| - notified_for_possible_device_change_(false),
|
| - input_buffer_list_(NULL) {
|
| + input_buffer_list_(NULL),
|
| + current_hardware_pending_bytes_(0) {
|
| // We must have a manager.
|
| DCHECK(manager_);
|
|
|
| @@ -150,7 +149,7 @@ void AUHALStream::Start(AudioSourceCallback* callback) {
|
| }
|
|
|
| stopped_ = false;
|
| - notified_for_possible_device_change_ = false;
|
| + audio_fifo_.reset();
|
| {
|
| base::AutoLock auto_lock(source_lock_);
|
| source_ = callback;
|
| @@ -200,63 +199,69 @@ OSStatus AUHALStream::Render(
|
| AudioBufferList* io_data) {
|
| TRACE_EVENT0("audio", "AUHALStream::Render");
|
|
|
| + // If the stream parameters change for any reason, we need to insert a FIFO
|
| + // since the OnMoreData() pipeline can't handle frame size changes. Generally
|
| + // this is a temporary situation which can occur after a device change has
|
| + // occurred but the AudioManager hasn't received the notification yet.
|
| if (number_of_frames != number_of_frames_) {
|
| - // This can happen if we've suddenly changed sample-rates.
|
| - // The stream should be stopping very soon.
|
| - //
|
| - // Unfortunately AUAudioInputStream and AUHALStream share the frame
|
| - // size set by kAudioDevicePropertyBufferFrameSize above on a per process
|
| - // basis. What this means is that the |number_of_frames| value may be
|
| - // larger or smaller than the value set during ConfigureAUHAL().
|
| - // In this case either audio input or audio output will be broken,
|
| - // so just output silence.
|
| - ZeroBufferList(io_data);
|
| - return noErr;
|
| - }
|
| + // Create a FIFO on the fly to handle any discrepancies in callback rates.
|
| + if (!audio_fifo_) {
|
| + VLOG(1) << "Audio frame size change detected; adding FIFO to compensate.";
|
| + audio_fifo_.reset(new AudioPullFifo(
|
| + output_channels_,
|
| + number_of_frames_,
|
| + base::Bind(&AUHALStream::ProvideInput, base::Unretained(this))));
|
| + }
|
|
|
| - if (input_channels_ > 0 && input_buffer_list_) {
|
| - // Get the input data. |input_buffer_list_| is wrapped
|
| - // to point to the data allocated in |input_bus_|.
|
| - OSStatus result = AudioUnitRender(
|
| - audio_unit_,
|
| - flags,
|
| - output_time_stamp,
|
| - 1,
|
| - number_of_frames,
|
| - input_buffer_list_);
|
| - if (result != noErr)
|
| - ZeroBufferList(input_buffer_list_);
|
| + // Synchronous IO is not supported in this state.
|
| + if (input_channels_ > 0)
|
| + input_bus_->Zero();
|
| + } else {
|
| + if (input_channels_ > 0 && input_buffer_list_) {
|
| + // Get the input data. |input_buffer_list_| is wrapped
|
| + // to point to the data allocated in |input_bus_|.
|
| + OSStatus result = AudioUnitRender(audio_unit_,
|
| + flags,
|
| + output_time_stamp,
|
| + 1,
|
| + number_of_frames,
|
| + input_buffer_list_);
|
| + if (result != noErr)
|
| + ZeroBufferList(input_buffer_list_);
|
| + }
|
| }
|
|
|
| // Make |output_bus_| wrap the output AudioBufferList.
|
| WrapBufferList(io_data, output_bus_.get(), number_of_frames);
|
|
|
| // Update the playout latency.
|
| - double playout_latency_frames = GetPlayoutLatency(output_time_stamp);
|
| + const double playout_latency_frames = GetPlayoutLatency(output_time_stamp);
|
| + current_hardware_pending_bytes_ = static_cast<uint32>(
|
| + (playout_latency_frames + 0.5) * params_.GetBytesPerFrame());
|
|
|
| - uint32 hardware_pending_bytes = static_cast<uint32>
|
| - ((playout_latency_frames + 0.5) * output_format_.mBytesPerFrame);
|
| + if (audio_fifo_)
|
| + audio_fifo_->Consume(output_bus_.get(), output_bus_->frames());
|
| + else
|
| + ProvideInput(0, output_bus_.get());
|
|
|
| - {
|
| - // Render() shouldn't be called except between AudioOutputUnitStart() and
|
| - // AudioOutputUnitStop() calls, but crash reports have shown otherwise:
|
| - // http://crbug.com/178765. We use |source_lock_| to prevent races and
|
| - // crashes in Render() when |source_| is cleared.
|
| - base::AutoLock auto_lock(source_lock_);
|
| - if (!source_) {
|
| - ZeroBufferList(io_data);
|
| - return noErr;
|
| - }
|
| + return noErr;
|
| +}
|
|
|
| - // Supply the input data and render the output data.
|
| - source_->OnMoreIOData(
|
| - input_bus_.get(),
|
| - output_bus_.get(),
|
| - AudioBuffersState(0, hardware_pending_bytes));
|
| - output_bus_->Scale(volume_);
|
| +void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) {
|
| + base::AutoLock auto_lock(source_lock_);
|
| + if (!source_) {
|
| + dest->Zero();
|
| + return;
|
| }
|
|
|
| - return noErr;
|
| + // Supply the input data and render the output data.
|
| + source_->OnMoreIOData(
|
| + input_bus_.get(),
|
| + dest,
|
| + AudioBuffersState(0,
|
| + current_hardware_pending_bytes_ +
|
| + frame_delay * params_.GetBytesPerFrame()));
|
| + dest->Scale(volume_);
|
| }
|
|
|
| // AUHAL callback.
|
|
|