Chromium Code Reviews| 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..aeea39c83dceacc45cc88e43b9601b6b78c24cd6 100644 |
| --- a/media/audio/mac/audio_auhal_mac.cc |
| +++ b/media/audio/mac/audio_auhal_mac.cc |
| @@ -58,8 +58,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 +150,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 +200,68 @@ 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 our pipeline can't handle frame size changes. Generally this is a |
|
scherkus (not reviewing)
2013/11/13 18:35:19
is this referring to media::Pipeline, or something
DaleCurtis
2013/11/13 20:06:24
Comment clarified.
The shared memory is sized to
|
| + // 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_) { |
| + audio_fifo_.reset(new AudioPullFifo( |
|
scherkus (not reviewing)
2013/11/13 18:35:19
OOC does using the fifo have a perf impact? (i.e.,
DaleCurtis
2013/11/13 20:06:24
Yes it has a perf impact of at least 6.5% (see Aud
|
| + 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. |