123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- // Copyright (c) 2012 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 "media/base/audio_renderer_mixer.h"
- #include <cmath>
- #include "base/check_op.h"
- #include "base/memory/ptr_util.h"
- #include "base/time/time.h"
- #include "base/trace_event/trace_event.h"
- #include "media/base/audio_renderer_mixer_input.h"
- #include "media/base/audio_timestamp_helper.h"
- namespace media {
- constexpr base::TimeDelta kPauseDelay = base::Seconds(10);
- AudioRendererMixer::AudioRendererMixer(const AudioParameters& output_params,
- scoped_refptr<AudioRendererSink> sink)
- : output_params_(output_params),
- audio_sink_(std::move(sink)),
- aggregate_converter_(output_params, output_params, true),
- pause_delay_(kPauseDelay),
- last_play_time_(base::TimeTicks::Now()),
- // Initialize |playing_| to true since Start() results in an auto-play.
- playing_(true) {
- DCHECK(audio_sink_);
- // If enabled we will disable the real audio output stream for muted/silent
- // playbacks after some time elapses.
- RenderCallback* callback = this;
- audio_sink_->Initialize(output_params, callback);
- audio_sink_->Start();
- }
- AudioRendererMixer::~AudioRendererMixer() {
- // AudioRendererSink must be stopped before mixer is destructed.
- audio_sink_->Stop();
- // Ensure that all mixer inputs have removed themselves prior to destruction.
- DCHECK(aggregate_converter_.empty());
- DCHECK(converters_.empty());
- DCHECK(error_callbacks_.empty());
- }
- void AudioRendererMixer::AddMixerInput(const AudioParameters& input_params,
- AudioConverter::InputCallback* input) {
- base::AutoLock auto_lock(lock_);
- if (!playing_) {
- playing_ = true;
- last_play_time_ = base::TimeTicks::Now();
- audio_sink_->Play();
- }
- int input_sample_rate = input_params.sample_rate();
- if (can_passthrough(input_sample_rate)) {
- aggregate_converter_.AddInput(input);
- } else {
- auto converter = converters_.find(input_sample_rate);
- if (converter == converters_.end()) {
- std::pair<AudioConvertersMap::iterator, bool> result =
- converters_.insert(std::make_pair(
- input_sample_rate, std::make_unique<LoopbackAudioConverter>(
- // We expect all InputCallbacks to be
- // capable of handling arbitrary buffer
- // size requests, disabling FIFO.
- input_params, output_params_, true)));
- converter = result.first;
- // Add newly-created resampler as an input to the aggregate mixer.
- aggregate_converter_.AddInput(converter->second.get());
- }
- converter->second->AddInput(input);
- }
- }
- void AudioRendererMixer::RemoveMixerInput(
- const AudioParameters& input_params,
- AudioConverter::InputCallback* input) {
- base::AutoLock auto_lock(lock_);
- int input_sample_rate = input_params.sample_rate();
- if (can_passthrough(input_sample_rate)) {
- aggregate_converter_.RemoveInput(input);
- } else {
- auto converter = converters_.find(input_sample_rate);
- DCHECK(converter != converters_.end());
- converter->second->RemoveInput(input);
- if (converter->second->empty()) {
- // Remove converter when it's empty.
- aggregate_converter_.RemoveInput(converter->second.get());
- converters_.erase(converter);
- }
- }
- }
- void AudioRendererMixer::AddErrorCallback(AudioRendererMixerInput* input) {
- base::AutoLock auto_lock(lock_);
- error_callbacks_.insert(input);
- }
- void AudioRendererMixer::RemoveErrorCallback(AudioRendererMixerInput* input) {
- base::AutoLock auto_lock(lock_);
- error_callbacks_.erase(input);
- }
- bool AudioRendererMixer::CurrentThreadIsRenderingThread() {
- return audio_sink_->CurrentThreadIsRenderingThread();
- }
- void AudioRendererMixer::SetPauseDelayForTesting(base::TimeDelta delay) {
- base::AutoLock auto_lock(lock_);
- pause_delay_ = delay;
- }
- int AudioRendererMixer::Render(base::TimeDelta delay,
- base::TimeTicks delay_timestamp,
- int prior_frames_skipped,
- AudioBus* audio_bus) {
- TRACE_EVENT0("audio", "AudioRendererMixer::Render");
- base::AutoLock auto_lock(lock_);
- // If there are no mixer inputs and we haven't seen one for a while, pause the
- // sink to avoid wasting resources when media elements are present but remain
- // in the pause state.
- const base::TimeTicks now = base::TimeTicks::Now();
- if (!aggregate_converter_.empty()) {
- last_play_time_ = now;
- } else if (now - last_play_time_ >= pause_delay_ && playing_) {
- audio_sink_->Pause();
- playing_ = false;
- }
- // Since AudioConverter uses uint32_t for delay calculations, we must drop
- // negative delay values (which are incorrect anyways).
- if (delay.is_negative())
- delay = base::TimeDelta();
- uint32_t frames_delayed =
- AudioTimestampHelper::TimeToFrames(delay, output_params_.sample_rate());
- aggregate_converter_.ConvertWithDelay(frames_delayed, audio_bus);
- return audio_bus->frames();
- }
- void AudioRendererMixer::OnRenderError() {
- // Call each mixer input and signal an error.
- base::AutoLock auto_lock(lock_);
- for (auto* input : error_callbacks_)
- input->OnRenderError();
- }
- } // namespace media
|