| 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
|
|
|