// Copyright 2021 The Chromium Authors. All rights reserved. // 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) { DCHECK_EQ(audio_bus->channels(), params_.channels()); TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("audio"), "SyncMixingGraphInput::ProvideInput", "frames_delayed", frames_delayed, "bus frames", audio_bus->frames()); if (!fifo_ && audio_bus->frames() != params_.frames_per_buffer()) { fifo_ = std::make_unique( 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_BEGIN1(TRACE_DISABLED_BY_DEFAULT("audio"), "SyncMixingGraphInput::Render", "this", static_cast(this)); base::TimeDelta delay = media::AudioTimestampHelper::FramesToTime( converter_render_frame_delay_ + fifo_frame_delay, params_.sample_rate()); source_callback_->OnMoreData(delay, base::TimeTicks::Now(), 0, audio_bus, /*is_mixing=*/true); TRACE_EVENT_END2(TRACE_DISABLED_BY_DEFAULT("audio"), "SyncMixingGraphInput::Render", "total frames delay", converter_render_frame_delay_ + fifo_frame_delay, "bus frames", audio_bus->frames()); } } // namespace audio