普通文本  |  110行  |  2.97 KB

// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/audio/clockless_audio_sink.h"

#include "base/threading/simple_thread.h"
#include "base/time/time.h"
#include "media/base/audio_renderer_sink.h"

namespace media {

// Internal to ClocklessAudioSink. Class is used to call Render() on a seperate
// thread, running as fast as it can read the data.
class ClocklessAudioSinkThread : public base::DelegateSimpleThread::Delegate {
 public:
  explicit ClocklessAudioSinkThread(const AudioParameters& params,
                                    AudioRendererSink::RenderCallback* callback)
      : callback_(callback),
        audio_bus_(AudioBus::Create(params)),
        stop_event_(new base::WaitableEvent(false, false)) {}

  void Start() {
    stop_event_->Reset();
    thread_.reset(new base::DelegateSimpleThread(this, "ClocklessAudioSink"));
    thread_->Start();
  }

  // Generate a signal to stop calling Render().
  base::TimeDelta Stop() {
    stop_event_->Signal();
    thread_->Join();
    return playback_time_;
  }

 private:
   // Call Render() repeatedly, keeping track of the rendering time.
   virtual void Run() OVERRIDE {
     base::TimeTicks start;
     while (!stop_event_->IsSignaled()) {
       int frames_received = callback_->Render(audio_bus_.get(), 0);
       if (frames_received <= 0) {
         // No data received, so let other threads run to provide data.
         base::PlatformThread::YieldCurrentThread();
       } else if (start.is_null()) {
         // First time we processed some audio, so record the starting time.
         start = base::TimeTicks::HighResNow();
       } else {
         // Keep track of the last time data was rendered.
         playback_time_ = base::TimeTicks::HighResNow() - start;
       }
     }
   }

  AudioRendererSink::RenderCallback* callback_;
  scoped_ptr<AudioBus> audio_bus_;
  scoped_ptr<base::WaitableEvent> stop_event_;
  scoped_ptr<base::DelegateSimpleThread> thread_;
  base::TimeDelta playback_time_;
};

ClocklessAudioSink::ClocklessAudioSink()
    : initialized_(false),
      playing_(false) {}

ClocklessAudioSink::~ClocklessAudioSink() {}

void ClocklessAudioSink::Initialize(const AudioParameters& params,
                                    RenderCallback* callback) {
  DCHECK(!initialized_);
  thread_.reset(new ClocklessAudioSinkThread(params, callback));
  initialized_ = true;
}

void ClocklessAudioSink::Start() {
  DCHECK(initialized_);
  DCHECK(!playing_);
}

void ClocklessAudioSink::Stop() {
  Pause();
}

void ClocklessAudioSink::Play() {
  DCHECK(initialized_);

  if (playing_)
    return;

  playing_ = true;
  thread_->Start();
}

void ClocklessAudioSink::Pause() {
  DCHECK(initialized_);

  if (!playing_)
    return;

  playing_ = false;
  playback_time_ = thread_->Stop();
}

bool ClocklessAudioSink::SetVolume(double volume) {
  // Audio is always muted.
  return volume == 0.0;
}

}  // namespace media