| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "services/audio/sync_mixing_graph_input.h" |
| |
| #include "base/trace_event/trace_event.h" |
| #include "media/base/audio_pull_fifo.h" |
| #include "media/base/audio_timestamp_helper.h" |
| |
| namespace audio { |
| |
| SyncMixingGraphInput::SyncMixingGraphInput(MixingGraph* graph, |
| const media::AudioParameters& params) |
| : graph_(graph), params_(params) { |
| DCHECK(graph); |
| CHECK(params_.IsValid()); |
| } |
| |
| SyncMixingGraphInput::~SyncMixingGraphInput() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_); |
| } |
| |
| // Either calls Render() directly to produce the requested input audio, or - in |
| // the case of a frames per buffer mismatch - pulls audio from the |fifo_| which |
| // in turn calls Render() as needed. |
| double SyncMixingGraphInput::ProvideInput( |
| media::AudioBus* audio_bus, |
| uint32_t frames_delayed, |
| const media::AudioGlitchInfo& glitch_info) { |
| DCHECK_EQ(audio_bus->channels(), params_.channels()); |
| TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("audio"), |
| "SyncMixingGraphInput::ProvideInput", "delay (frames)", |
| frames_delayed, "bus frames", audio_bus->frames()); |
| |
| glitch_info_accumulator_.Add(glitch_info); |
| |
| // TODO(crbug.com/406867864): Consider removing the unnecessary FIFO if the |
| // render call can directly handle all buffer size variations. |
| if (!fifo_ && audio_bus->frames() != params_.frames_per_buffer()) { |
| fifo_ = std::make_unique<media::AudioPullFifo>( |
| params_.channels(), params_.frames_per_buffer(), |
| base::BindRepeating(&SyncMixingGraphInput::Render, |
| base::Unretained(this))); |
| } |
| |
| // Used by Render() for delay calculation. |
| converter_render_frame_delay_ = frames_delayed; |
| if (fifo_) |
| fifo_->Consume(audio_bus, audio_bus->frames()); |
| else |
| Render(0, audio_bus); |
| converter_render_frame_delay_ = 0; |
| |
| return volume_; |
| } |
| |
| const media::AudioParameters& SyncMixingGraphInput::GetParams() const { |
| return params_; |
| } |
| |
| void SyncMixingGraphInput::SetVolume(double volume) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_); |
| volume_ = volume; |
| } |
| |
| void SyncMixingGraphInput::Start( |
| media::AudioOutputStream::AudioSourceCallback* source_callback) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_); |
| DCHECK(!fifo_); |
| DCHECK(!source_callback_); |
| source_callback_ = source_callback; |
| graph_->AddInput(this); |
| } |
| |
| void SyncMixingGraphInput::Stop() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_); |
| graph_->RemoveInput(this); |
| if (fifo_) |
| fifo_.reset(); |
| source_callback_ = nullptr; |
| } |
| |
| void SyncMixingGraphInput::Render(int fifo_frame_delay, |
| media::AudioBus* audio_bus) { |
| DCHECK(source_callback_); |
| TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("audio"), |
| "SyncMixingGraphInput::Render", "this", static_cast<void*>(this), |
| "delay (frames)", fifo_frame_delay, "bus frames", |
| audio_bus->frames()); |
| |
| base::TimeDelta delay = media::AudioTimestampHelper::FramesToTime( |
| converter_render_frame_delay_ + fifo_frame_delay, params_.sample_rate()); |
| source_callback_->OnMoreData(delay, base::TimeTicks::Now(), |
| glitch_info_accumulator_.GetAndReset(), |
| audio_bus, |
| /*is_mixing=*/true); |
| } |
| |
| } // namespace audio |