1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "media/base/audio_renderer_mixer.h" 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "base/logging.h" 10 11namespace media { 12 13enum { kPauseDelaySeconds = 10 }; 14 15AudioRendererMixer::AudioRendererMixer( 16 const AudioParameters& input_params, const AudioParameters& output_params, 17 const scoped_refptr<AudioRendererSink>& sink) 18 : audio_sink_(sink), 19 audio_converter_(input_params, output_params, true), 20 pause_delay_(base::TimeDelta::FromSeconds(kPauseDelaySeconds)), 21 last_play_time_(base::TimeTicks::Now()), 22 // Initialize |playing_| to true since Start() results in an auto-play. 23 playing_(true) { 24 audio_sink_->Initialize(output_params, this); 25 audio_sink_->Start(); 26} 27 28AudioRendererMixer::~AudioRendererMixer() { 29 // AudioRendererSinks must be stopped before being destructed. 30 audio_sink_->Stop(); 31 32 // Ensures that all mixer inputs have stopped themselves prior to destruction 33 // and have called RemoveMixerInput(). 34 DCHECK_EQ(mixer_inputs_.size(), 0U); 35} 36 37void AudioRendererMixer::AddMixerInput(AudioConverter::InputCallback* input, 38 const base::Closure& error_cb) { 39 base::AutoLock auto_lock(mixer_inputs_lock_); 40 41 if (!playing_) { 42 playing_ = true; 43 last_play_time_ = base::TimeTicks::Now(); 44 audio_sink_->Play(); 45 } 46 47 DCHECK(mixer_inputs_.find(input) == mixer_inputs_.end()); 48 mixer_inputs_[input] = error_cb; 49 audio_converter_.AddInput(input); 50} 51 52void AudioRendererMixer::RemoveMixerInput( 53 AudioConverter::InputCallback* input) { 54 base::AutoLock auto_lock(mixer_inputs_lock_); 55 audio_converter_.RemoveInput(input); 56 57 DCHECK(mixer_inputs_.find(input) != mixer_inputs_.end()); 58 mixer_inputs_.erase(input); 59} 60 61int AudioRendererMixer::Render(AudioBus* audio_bus, 62 int audio_delay_milliseconds) { 63 base::AutoLock auto_lock(mixer_inputs_lock_); 64 65 // If there are no mixer inputs and we haven't seen one for a while, pause the 66 // sink to avoid wasting resources when media elements are present but remain 67 // in the pause state. 68 const base::TimeTicks now = base::TimeTicks::Now(); 69 if (!mixer_inputs_.empty()) { 70 last_play_time_ = now; 71 } else if (now - last_play_time_ >= pause_delay_ && playing_) { 72 audio_sink_->Pause(); 73 playing_ = false; 74 } 75 76 audio_converter_.ConvertWithDelay( 77 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds), audio_bus); 78 return audio_bus->frames(); 79} 80 81void AudioRendererMixer::OnRenderError() { 82 base::AutoLock auto_lock(mixer_inputs_lock_); 83 84 // Call each mixer input and signal an error. 85 for (AudioRendererMixerInputSet::iterator it = mixer_inputs_.begin(); 86 it != mixer_inputs_.end(); ++it) { 87 it->second.Run(); 88 } 89} 90 91} // namespace media 92