Index: media/blink/webaudiosourceprovider_impl.cc |
diff --git a/media/blink/webaudiosourceprovider_impl.cc b/media/blink/webaudiosourceprovider_impl.cc |
index 5b70a3091ba7760878c7f5d9f80147af4a1292c6..d43a16fb5b1b927eab078c7fb7f952b02aafe3b6 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* 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 SetCopyAudioCallback(). |
+ 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: Always using |set_format_cb_| ensures we have the same locking |
+ // 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::SetCopyAudioCallback( |
+ const CopyAudioCB& callback) { |
+ DCHECK(!callback.is_null()); |
+ DCHECK(tee_filter_); |
+ tee_filter_->set_copy_audio_bus_callback(callback); |
+} |
+ |
+void WebAudioSourceProviderImpl::ClearCopyAudioCallback() { |
+ 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, |
+ sample_rate_); |
+ } |
+ |
+ return num_rendered_frames; |
+} |
+ |
+void WebAudioSourceProviderImpl::TeeFilter::OnRenderError() { |
+ renderer_->OnRenderError(); |
} |
} // namespace media |