Chromium Code Reviews| Index: media/audio/null_audio_sink.cc |
| diff --git a/media/audio/null_audio_sink.cc b/media/audio/null_audio_sink.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..064624682f9d40abc9d67574d4838022df90e270 |
| --- /dev/null |
| +++ b/media/audio/null_audio_sink.cc |
| @@ -0,0 +1,110 @@ |
| +// Copyright (c) 2012 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/null_audio_sink.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/threading/platform_thread.h" |
| + |
| +namespace media { |
| + |
| +NullAudioSink::NullAudioSink() |
| + : initialized_(false), |
| + playback_rate_(0.0), |
| + playing_(false), |
| + callback_(NULL), |
| + thread_("AudioThread") { |
|
scherkus (not reviewing)
2012/03/23 15:24:52
nit: NullAudioThread, perhaps?
vrk (LEFT CHROMIUM)
2012/04/02 21:17:54
Done.
|
| +} |
| + |
| +NullAudioSink::~NullAudioSink() { |
| + DCHECK(!thread_.IsRunning()); |
| + for (size_t i = 0; i < audio_data_.size(); ++i) |
| + delete [] audio_data_[i]; |
| +} |
| + |
| + |
| +void NullAudioSink::Start() { |
| + if (!thread_.Start()) |
| + return; |
| + |
| + thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| + &NullAudioSink::FillBufferTask, this)); |
| +} |
| + |
| +void NullAudioSink::Stop() { |
| + SetPlaying(false); |
| + thread_.Stop(); |
| +} |
| + |
| +void NullAudioSink::Play() { |
| + SetPlaying(true); |
| +} |
| + |
| +void NullAudioSink::Pause(bool /* flush */) { |
| + SetPlaying(false); |
| +} |
| + |
| +void NullAudioSink::SetPlaybackRate(float rate) { |
| + base::AutoLock auto_lock(lock_); |
| + playback_rate_ = rate; |
| +} |
| + |
| +bool NullAudioSink::SetVolume(double volume) { |
| + // Audio is always muted. |
| + return volume == 0.0; |
| +} |
| + |
| +void NullAudioSink::GetVolume(double* volume) { |
| + // Audio is always muted. |
| + *volume = 0.0; |
| +} |
| + |
| +void NullAudioSink::SetPlaying(bool is_playing) { |
| + base::AutoLock auto_lock(lock_); |
| + playing_ = is_playing; |
| +} |
| + |
| +void NullAudioSink::Initialize(const AudioParameters& params, |
| + RenderCallback* callback) { |
| + DCHECK(!initialized_); |
| + params_ = params; |
| + |
| + audio_data_.reserve(params.channels()); |
| + for (int i = 0; i < params.channels(); ++i) { |
| + float* channel_data = new float[params.frames_per_buffer()]; |
| + audio_data_.push_back(channel_data); |
| + } |
| + |
| + callback_ = callback; |
| + initialized_ = true; |
| +} |
| + |
| +void NullAudioSink::FillBufferTask() { |
| + base::AutoLock auto_lock(lock_); |
| + |
| + base::TimeDelta delay; |
| + // Only consume buffers when actually playing. |
| + if (playing_) { |
| + DCHECK_GT(playback_rate_, 0.0f); |
| + int requested_frames = params_.frames_per_buffer(); |
| + int frames_received = callback_->Render(audio_data_, requested_frames, 0); |
| + int frames_per_millisecond = |
| + params_.sample_rate() / base::Time::kMillisecondsPerSecond; |
| + |
| + // Calculate our sleep duration, taking playback rate into consideration. |
| + delay = base::TimeDelta::FromMilliseconds( |
| + frames_received / (frames_per_millisecond * playback_rate_)); |
| + } else { |
| + // If paused, sleep for 10 milliseconds before polling again. |
| + delay = base::TimeDelta::FromMilliseconds(10); |
| + } |
| + |
| + // Sleep for at least one millisecond so we don't spin the CPU. |
| + MessageLoop::current()->PostDelayedTask( |
| + FROM_HERE, |
| + base::Bind(&NullAudioSink::FillBufferTask, this), |
| + std::max(delay, base::TimeDelta::FromMilliseconds(1))); |
| +} |
| + |
| +} // namespace media |