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 11 namespace media { 12 13 enum { kPauseDelaySeconds = 10 }; 14 15 AudioRendererMixer::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 28 AudioRendererMixer::~AudioRendererMixer() { 29 // AudioRendererSinks must be stopped before being destructed. 30 audio_sink_->Stop(); 31 32 // Ensure that all mixer inputs have removed themselves prior to destruction. 33 DCHECK(audio_converter_.empty()); 34 DCHECK_EQ(error_callbacks_.size(), 0U); 35 } 36 37 void AudioRendererMixer::AddMixerInput(AudioConverter::InputCallback* input) { 38 base::AutoLock auto_lock(lock_); 39 if (!playing_) { 40 playing_ = true; 41 last_play_time_ = base::TimeTicks::Now(); 42 audio_sink_->Play(); 43 } 44 45 audio_converter_.AddInput(input); 46 } 47 48 void AudioRendererMixer::RemoveMixerInput( 49 AudioConverter::InputCallback* input) { 50 base::AutoLock auto_lock(lock_); 51 audio_converter_.RemoveInput(input); 52 } 53 54 void AudioRendererMixer::AddErrorCallback(const base::Closure& error_cb) { 55 base::AutoLock auto_lock(lock_); 56 error_callbacks_.push_back(error_cb); 57 } 58 59 void AudioRendererMixer::RemoveErrorCallback(const base::Closure& error_cb) { 60 base::AutoLock auto_lock(lock_); 61 for (ErrorCallbackList::iterator it = error_callbacks_.begin(); 62 it != error_callbacks_.end(); 63 ++it) { 64 if (it->Equals(error_cb)) { 65 error_callbacks_.erase(it); 66 return; 67 } 68 } 69 70 // An error callback should always exist when called. 71 NOTREACHED(); 72 } 73 74 int AudioRendererMixer::Render(AudioBus* audio_bus, 75 int audio_delay_milliseconds) { 76 base::AutoLock auto_lock(lock_); 77 78 // If there are no mixer inputs and we haven't seen one for a while, pause the 79 // sink to avoid wasting resources when media elements are present but remain 80 // in the pause state. 81 const base::TimeTicks now = base::TimeTicks::Now(); 82 if (!audio_converter_.empty()) { 83 last_play_time_ = now; 84 } else if (now - last_play_time_ >= pause_delay_ && playing_) { 85 audio_sink_->Pause(); 86 playing_ = false; 87 } 88 89 audio_converter_.ConvertWithDelay( 90 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds), audio_bus); 91 return audio_bus->frames(); 92 } 93 94 void AudioRendererMixer::OnRenderError() { 95 // Call each mixer input and signal an error. 96 base::AutoLock auto_lock(lock_); 97 for (ErrorCallbackList::const_iterator it = error_callbacks_.begin(); 98 it != error_callbacks_.end(); 99 ++it) { 100 it->Run(); 101 } 102 } 103 104 } // namespace media 105