Home | History | Annotate | Download | only in base
      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   // 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 
     37 void 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 
     52 void 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 
     61 int 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 
     81 void 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