Home | History | Annotate | Download | only in audio
      1 // Copyright 2013 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/audio/clockless_audio_sink.h"
      6 
      7 #include "base/threading/simple_thread.h"
      8 #include "base/time/time.h"
      9 #include "media/base/audio_renderer_sink.h"
     10 
     11 namespace media {
     12 
     13 // Internal to ClocklessAudioSink. Class is used to call Render() on a seperate
     14 // thread, running as fast as it can read the data.
     15 class ClocklessAudioSinkThread : public base::DelegateSimpleThread::Delegate {
     16  public:
     17   explicit ClocklessAudioSinkThread(const AudioParameters& params,
     18                                     AudioRendererSink::RenderCallback* callback)
     19       : callback_(callback),
     20         audio_bus_(AudioBus::Create(params)),
     21         stop_event_(new base::WaitableEvent(false, false)) {}
     22 
     23   void Start() {
     24     stop_event_->Reset();
     25     thread_.reset(new base::DelegateSimpleThread(this, "ClocklessAudioSink"));
     26     thread_->Start();
     27   }
     28 
     29   // Generate a signal to stop calling Render().
     30   base::TimeDelta Stop() {
     31     stop_event_->Signal();
     32     thread_->Join();
     33     return playback_time_;
     34   }
     35 
     36  private:
     37    // Call Render() repeatedly, keeping track of the rendering time.
     38    virtual void Run() OVERRIDE {
     39      base::TimeTicks start;
     40      while (!stop_event_->IsSignaled()) {
     41        int frames_received = callback_->Render(audio_bus_.get(), 0);
     42        if (frames_received <= 0) {
     43          // No data received, so let other threads run to provide data.
     44          base::PlatformThread::YieldCurrentThread();
     45        } else if (start.is_null()) {
     46          // First time we processed some audio, so record the starting time.
     47          start = base::TimeTicks::HighResNow();
     48        } else {
     49          // Keep track of the last time data was rendered.
     50          playback_time_ = base::TimeTicks::HighResNow() - start;
     51        }
     52      }
     53    }
     54 
     55   AudioRendererSink::RenderCallback* callback_;
     56   scoped_ptr<AudioBus> audio_bus_;
     57   scoped_ptr<base::WaitableEvent> stop_event_;
     58   scoped_ptr<base::DelegateSimpleThread> thread_;
     59   base::TimeDelta playback_time_;
     60 };
     61 
     62 ClocklessAudioSink::ClocklessAudioSink()
     63     : initialized_(false),
     64       playing_(false) {}
     65 
     66 ClocklessAudioSink::~ClocklessAudioSink() {}
     67 
     68 void ClocklessAudioSink::Initialize(const AudioParameters& params,
     69                                     RenderCallback* callback) {
     70   DCHECK(!initialized_);
     71   thread_.reset(new ClocklessAudioSinkThread(params, callback));
     72   initialized_ = true;
     73 }
     74 
     75 void ClocklessAudioSink::Start() {
     76   DCHECK(initialized_);
     77   DCHECK(!playing_);
     78 }
     79 
     80 void ClocklessAudioSink::Stop() {
     81   if (initialized_)
     82     Pause();
     83 }
     84 
     85 void ClocklessAudioSink::Play() {
     86   DCHECK(initialized_);
     87 
     88   if (playing_)
     89     return;
     90 
     91   playing_ = true;
     92   thread_->Start();
     93 }
     94 
     95 void ClocklessAudioSink::Pause() {
     96   DCHECK(initialized_);
     97 
     98   if (!playing_)
     99     return;
    100 
    101   playing_ = false;
    102   playback_time_ = thread_->Stop();
    103 }
    104 
    105 bool ClocklessAudioSink::SetVolume(double volume) {
    106   // Audio is always muted.
    107   return volume == 0.0;
    108 }
    109 
    110 }  // namespace media
    111