Chromium Code Reviews| Index: media/base/audio_renderer_mixer.cc |
| diff --git a/media/base/audio_renderer_mixer.cc b/media/base/audio_renderer_mixer.cc |
| index 5b89aa41daebe06c3e5fcd40b1105db64a6f3fb8..56524cac2ab4ecd812ab6ab259236785b48813dd 100644 |
| --- a/media/base/audio_renderer_mixer.cc |
| +++ b/media/base/audio_renderer_mixer.cc |
| @@ -5,16 +5,39 @@ |
| #include "media/base/audio_renderer_mixer.h" |
| #include "base/logging.h" |
| +#include "media/audio/audio_util.h" |
| namespace media { |
| AudioRendererMixer::AudioRendererMixer( |
| const AudioParameters& params, const scoped_refptr<AudioRendererSink>& sink) |
| - : audio_parameters_(params), |
| - audio_sink_(sink) { |
| - // TODO(dalecurtis): Once we have resampling we'll need to pass on a different |
| - // set of AudioParameters than the ones we're given. |
| - audio_sink_->Initialize(audio_parameters_, this); |
| + : audio_sink_(sink), |
| + current_audio_delay_milliseconds_(0) { |
| + // Create output parameters for passing on to the output sink. |
| + // TODO(dalecurtis): There's a lot of buffer trickery to figure out here... |
| + // TODO(dalecurtis): What about the values set in AudioRendererImpl? |
| + // TODO(dalecurtis): All this buffer logic should be shared between WebRTC, |
| + // Pepper, etc. |
| + int output_sample_rate = GetAudioHardwareSampleRate(); |
| + output_parameters_ = AudioParameters( |
| + AudioParameters::AUDIO_PCM_LOW_LATENCY, params.channel_layout(), |
| + output_sample_rate, 16, output_sample_rate / 100); |
|
Chris Rogers
2012/07/02 22:53:50
Instead of output_sample_rate / 100, better to use
DaleCurtis
2012/07/12 00:40:44
Done.
|
| + |
| + // Only resample if necessary since it's expensive. |
| + if (params.sample_rate() != output_sample_rate) |
|
Chris Rogers
2012/07/02 22:53:50
Maybe some basic sanity checking on params.sample_
DaleCurtis
2012/07/12 00:40:44
Done.
|
| + resampler_.reset(new MultiChannelResampler( |
| + this, params.sample_rate() / static_cast<float>(output_sample_rate), |
| + output_parameters_.channels())); |
| + |
| + // Preallocate staging area for collecting each mixer input's audio data. |
| + // TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to |
| + // allocate these on 32-byte boundaries and ensure they're sized % 32 bytes. |
| + mixer_input_audio_data_.reserve(output_parameters_.channels()); |
| + for (int i = 0; i < output_parameters_.channels(); ++i) |
| + mixer_input_audio_data_.push_back( |
| + new float[output_parameters_.frames_per_buffer()]); |
| + |
| + audio_sink_->Initialize(output_parameters_, this); |
| audio_sink_->Start(); |
| } |
| @@ -22,6 +45,11 @@ AudioRendererMixer::~AudioRendererMixer() { |
| // AudioRendererSinks must be stopped before being destructed. |
| audio_sink_->Stop(); |
| + // Clean up |mixer_input_audio_data_|. |
| + for (size_t i = 0; i < mixer_input_audio_data_.size(); ++i) |
| + delete [] mixer_input_audio_data_[i]; |
| + mixer_input_audio_data_.clear(); |
| + |
| // Ensures that all mixer inputs have stopped themselves prior to destruction |
| // and have called RemoveMixerInput(). |
| DCHECK_EQ(mixer_inputs_.size(), 0U); |
| @@ -42,11 +70,29 @@ void AudioRendererMixer::RemoveMixerInput( |
| int AudioRendererMixer::Render(const std::vector<float*>& audio_data, |
| int number_of_frames, |
| int audio_delay_milliseconds) { |
| + current_audio_delay_milliseconds_ = audio_delay_milliseconds; |
| + |
| + if (resampler_ != NULL) |
| + resampler_->Resample(audio_data, number_of_frames); |
| + else |
| + ProvideInput(audio_data, number_of_frames); |
| + |
| + // Always return the full number of frames requested, we padded with silence |
| + // if we couldn't get enough data. |
|
Chris Rogers
2012/07/02 22:53:50
nit: fix up grammar here
DaleCurtis
2012/07/12 00:40:44
Done.
|
| + return number_of_frames; |
| +} |
| + |
| +void AudioRendererMixer::ProvideInput(const std::vector<float*>& audio_data, |
| + int number_of_frames) { |
| base::AutoLock auto_lock(mixer_inputs_lock_); |
| + // Sanity check our inputs. |
| + DCHECK_LE(number_of_frames, output_parameters_.frames_per_buffer()); |
| + DCHECK_EQ(static_cast<int>(audio_data.size()), output_parameters_.channels()); |
| + |
| // Zero |audio_data| so we're mixing into a clean buffer and return silence if |
| // we couldn't get enough data from our inputs. |
| - for (int i = 0; i < audio_parameters_.channels(); ++i) |
| + for (size_t i = 0; i < audio_data.size(); ++i) |
| memset(audio_data[i], 0, number_of_frames * sizeof(*audio_data[i])); |
| // Have each mixer render its data into an output buffer then mix the result. |
| @@ -57,35 +103,29 @@ int AudioRendererMixer::Render(const std::vector<float*>& audio_data, |
| double volume; |
| input->GetVolume(&volume); |
| - // Nothing to do if the input isn't playing or the volume is zero. |
| - if (!input->playing() || volume == 0.0f) |
| + // Nothing to do if the input isn't playing. |
| + if (!input->playing()) |
| continue; |
| - const std::vector<float*>& mixer_input_audio_data = input->audio_data(); |
| - |
| int frames_filled = input->callback()->Render( |
|
Chris Rogers
2012/07/02 22:53:50
small nit: this isn't new to this patch, but it st
|
| - mixer_input_audio_data, number_of_frames, audio_delay_milliseconds); |
| + mixer_input_audio_data_, number_of_frames, |
| + current_audio_delay_milliseconds_); |
| if (frames_filled == 0) |
| continue; |
| - // TODO(dalecurtis): Resample audio data. |
| - |
| // Volume adjust and mix each mixer input into |audio_data| after rendering. |
| // TODO(dalecurtis): Optimize with NEON/SSE/AVX vector_fmac from FFmpeg. |
| - for (int j = 0; j < audio_parameters_.channels(); ++j) { |
| + for (size_t j = 0; j < audio_data.size(); ++j) { |
| float* dest = audio_data[j]; |
| - float* source = mixer_input_audio_data[j]; |
| + float* source = mixer_input_audio_data_[j]; |
| for (int k = 0; k < frames_filled; ++k) |
| dest[k] += source[k] * static_cast<float>(volume); |
| } |
| // No need to clamp values as InterleaveFloatToInt() will take care of this |
| // for us later when data is transferred to the browser process. |
| + // TODO(dalecurtis): Does the resampler need values betwen [-1, 1] ? |
|
Chris Rogers
2012/07/02 22:53:50
The resampler will be fine. I'd just entirely rem
|
| } |
| - |
| - // Always return the full number of frames requested, padded with silence if |
| - // we couldn't get enough data. |
| - return number_of_frames; |
| } |
| void AudioRendererMixer::OnRenderError() { |