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   // 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