Chromium Code Reviews| Index: media/blink/webaudiosourceprovider_impl.cc |
| diff --git a/media/blink/webaudiosourceprovider_impl.cc b/media/blink/webaudiosourceprovider_impl.cc |
| index 5b70a3091ba7760878c7f5d9f80147af4a1292c6..93ee7846d1051ed2b1e1bf9870e77db1906cd398 100644 |
| --- a/media/blink/webaudiosourceprovider_impl.cc |
| +++ b/media/blink/webaudiosourceprovider_impl.cc |
| @@ -47,14 +47,50 @@ class AutoTryLock { |
| } // namespace |
| +// TeeFilter is a RenderCallback implementation that allows for a client to get |
| +// a copy of the data being rendered by the |renderer_| on Render(). This class |
| +// also holds to the necessary audio parameters. |
| +class WebAudioSourceProviderImpl::TeeFilter |
| + : public AudioRendererSink::RenderCallback { |
| + public: |
| + TeeFilter(AudioRendererSink::RenderCallback* const renderer, |
| + int channels, |
| + int sample_rate) |
| + : renderer_(renderer), channels_(channels), sample_rate_(sample_rate) { |
| + DCHECK(renderer_); |
| + } |
| + ~TeeFilter() override {} |
| + |
| + // AudioRendererSink::RenderCallback implementation. |
| + // These are forwarders to |renderer_| and are here to allow for a client to |
| + // get a copy of the rendered audio by RegisterCopyAudioCallback(). |
| + int Render(AudioBus* audio_bus, |
| + uint32_t delay_milliseconds, |
| + uint32_t frames_skipped) override; |
| + void OnRenderError() override; |
| + |
| + int channels() const { return channels_; } |
| + int sample_rate() const { return sample_rate_; } |
| + void set_copy_audio_bus_callback( |
| + const WebAudioSourceProviderImpl::CopyAudioCB& callback) { |
| + copy_audio_bus_callback_ = callback; |
| + } |
| + |
| + private: |
| + AudioRendererSink::RenderCallback* const renderer_; |
| + const int channels_; |
| + const int sample_rate_; |
| + |
| + WebAudioSourceProviderImpl::CopyAudioCB copy_audio_bus_callback_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(TeeFilter); |
| +}; |
| + |
| WebAudioSourceProviderImpl::WebAudioSourceProviderImpl( |
| const scoped_refptr<RestartableAudioRendererSink>& sink) |
| - : channels_(0), |
| - sample_rate_(0), |
| - volume_(1.0), |
| + : volume_(1.0), |
| state_(kStopped), |
| - renderer_(NULL), |
| - client_(NULL), |
| + client_(nullptr), |
| sink_(sink), |
| weak_factory_(this) {} |
| @@ -74,16 +110,16 @@ void WebAudioSourceProviderImpl::setClient( |
| set_format_cb_ = BindToCurrentLoop(base::Bind( |
| &WebAudioSourceProviderImpl::OnSetFormat, weak_factory_.GetWeakPtr())); |
| - // If |renderer_| is set, then run |set_format_cb_| to send |client_| |
| - // the current format info. If |renderer_| is not set, then |set_format_cb_| |
| - // will get called when Initialize() is called. |
| - // Note: Always using |set_format_cb_| ensures we have the same |
| - // locking order when calling into |client_|. |
| - if (renderer_) |
| + // If |tee_filter_| is set, it means we have been Initialize()d - then run |
| + // |set_format_cb_| to send |client_| the current format info. Otherwise |
| + // |set_format_cb_| will get called when Initialize() is called. |
| + // Note: using always |set_format_cb_| ensures we have the same locking |
|
DaleCurtis
2016/03/11 18:45:59
You flipped using and always? Intentional? Doesn't
mcasas
2016/03/11 19:40:32
Done.
|
| + // order when calling into |client_|. |
| + if (tee_filter_) |
| base::ResetAndReturn(&set_format_cb_).Run(); |
| } else if (!client && client_) { |
| // Restore normal playback. |
| - client_ = NULL; |
| + client_ = nullptr; |
| sink_->SetVolume(volume_); |
| if (state_ >= kStarted) |
| sink_->Start(); |
| @@ -99,7 +135,8 @@ void WebAudioSourceProviderImpl::provideInput( |
| bus_wrapper_ = AudioBus::CreateWrapper(static_cast<int>(audio_data.size())); |
| } |
| - bus_wrapper_->set_frames(static_cast<int>(number_of_frames)); |
| + const int incoming_number_of_frames = static_cast<int>(number_of_frames); |
| + bus_wrapper_->set_frames(incoming_number_of_frames); |
| for (size_t i = 0; i < audio_data.size(); ++i) |
| bus_wrapper_->SetChannelData(static_cast<int>(i), audio_data[i]); |
| @@ -112,22 +149,19 @@ void WebAudioSourceProviderImpl::provideInput( |
| return; |
| } |
| - DCHECK(renderer_); |
| DCHECK(client_); |
| - DCHECK_EQ(channels_, bus_wrapper_->channels()); |
| - const int frames = renderer_->Render(bus_wrapper_.get(), 0, 0); |
| - if (frames < static_cast<int>(number_of_frames)) { |
| - bus_wrapper_->ZeroFramesPartial( |
| - frames, |
| - static_cast<int>(number_of_frames - frames)); |
| - } |
| + DCHECK(tee_filter_); |
| + DCHECK_EQ(tee_filter_->channels(), bus_wrapper_->channels()); |
| + const int frames = tee_filter_->Render(bus_wrapper_.get(), 0, 0); |
| + if (frames < incoming_number_of_frames) |
| + bus_wrapper_->ZeroFramesPartial(frames, incoming_number_of_frames - frames); |
| bus_wrapper_->Scale(volume_); |
| } |
| void WebAudioSourceProviderImpl::Start() { |
| base::AutoLock auto_lock(sink_lock_); |
| - DCHECK(renderer_); |
| + DCHECK(tee_filter_); |
| DCHECK_EQ(state_, kStopped); |
| state_ = kStarted; |
| if (!client_) |
| @@ -170,30 +204,64 @@ OutputDevice* WebAudioSourceProviderImpl::GetOutputDevice() { |
| return sink_->GetOutputDevice(); |
| } |
| -void WebAudioSourceProviderImpl::Initialize( |
| - const AudioParameters& params, |
| - RenderCallback* renderer) { |
| +void WebAudioSourceProviderImpl::Initialize(const AudioParameters& params, |
| + RenderCallback* renderer) { |
| base::AutoLock auto_lock(sink_lock_); |
| - renderer_ = renderer; |
| - |
| DCHECK_EQ(state_, kStopped); |
| - sink_->Initialize(params, renderer); |
| - // Keep track of the format in case the client hasn't yet been set. |
| - channels_ = params.channels(); |
| - sample_rate_ = params.sample_rate(); |
| + tee_filter_ = make_scoped_ptr( |
| + new TeeFilter(renderer, params.channels(), params.sample_rate())); |
| + |
| + sink_->Initialize(params, tee_filter_.get()); |
| if (!set_format_cb_.is_null()) |
| base::ResetAndReturn(&set_format_cb_).Run(); |
| } |
| +void WebAudioSourceProviderImpl::RegisterCopyAudioCallback( |
| + const CopyAudioCB& callback) { |
| + DCHECK(!callback.is_null()); |
| + DCHECK(tee_filter_); |
| + tee_filter_->set_copy_audio_bus_callback(callback); |
| +} |
| + |
| +void WebAudioSourceProviderImpl::ResetCopyAudioCallback() { |
| + DCHECK(tee_filter_); |
| + tee_filter_->set_copy_audio_bus_callback(CopyAudioCB()); |
| +} |
| + |
| void WebAudioSourceProviderImpl::OnSetFormat() { |
| base::AutoLock auto_lock(sink_lock_); |
| if (!client_) |
| return; |
| // Inform Blink about the audio stream format. |
| - client_->setFormat(channels_, sample_rate_); |
| + client_->setFormat(tee_filter_->channels(), tee_filter_->sample_rate()); |
| +} |
| + |
| +int WebAudioSourceProviderImpl::RenderForTesting(AudioBus* audio_bus) { |
| + return tee_filter_->Render(audio_bus, 0, 0); |
| +} |
| + |
| +int WebAudioSourceProviderImpl::TeeFilter::Render(AudioBus* audio_bus, |
| + uint32_t delay_milliseconds, |
| + uint32_t frames_skipped) { |
| + const int num_rendered_frames = |
| + renderer_->Render(audio_bus, delay_milliseconds, frames_skipped); |
| + |
| + if (!copy_audio_bus_callback_.is_null()) { |
| + scoped_ptr<AudioBus> bus_copy = |
| + AudioBus::Create(audio_bus->channels(), audio_bus->frames()); |
| + audio_bus->CopyTo(bus_copy.get()); |
| + copy_audio_bus_callback_.Run(std::move(bus_copy), delay_milliseconds, |
| + channels_, sample_rate_); |
| + } |
| + |
| + return num_rendered_frames; |
| +} |
| + |
| +void WebAudioSourceProviderImpl::TeeFilter::OnRenderError() { |
| + renderer_->OnRenderError(); |
| } |
| } // namespace media |