summaryrefslogtreecommitdiffstats
path: root/media/audio
diff options
context:
space:
mode:
authordalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-15 04:34:16 +0000
committerdalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-15 04:34:16 +0000
commit8754d953bfca98c6dcc0d716dd8408afe5199248 (patch)
treea397bfaf171848d4b4020d09318c2e49a7b0d2a8 /media/audio
parentb8ad39b6f840b7cb91a6d86f101ed1671a7e009f (diff)
downloadchromium_src-8754d953bfca98c6dcc0d716dd8408afe5199248.zip
chromium_src-8754d953bfca98c6dcc0d716dd8408afe5199248.tar.gz
chromium_src-8754d953bfca98c6dcc0d716dd8408afe5199248.tar.bz2
Refactor FakeAudioOutputStream, NullAudioSink into FakeAudioConsumer.
We have two fake audio consumers: FakeAudioOutputStream on the browser side and NullAudioSink on the renderer side. At present we can't remove NullAudioSink since its used for PipelineIntegrationTests. This change collapses the common functionality between both consumers and as an added bonus replaces NullAudioSink's private thread in favor of sharing the MediaThread. BUG=none TEST=unit tests, remote desktop session w/o audio, --disable-audio. Review URL: https://chromiumcodereview.appspot.com/12334061 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@188251 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/audio')
-rw-r--r--media/audio/fake_audio_consumer.cc67
-rw-r--r--media/audio/fake_audio_consumer.h61
-rw-r--r--media/audio/fake_audio_consumer_unittest.cc (renamed from media/audio/fake_audio_output_stream_unittest.cc)93
-rw-r--r--media/audio/fake_audio_output_stream.cc34
-rw-r--r--media/audio/fake_audio_output_stream.h17
-rw-r--r--media/audio/null_audio_sink.cc129
-rw-r--r--media/audio/null_audio_sink.h42
7 files changed, 250 insertions, 193 deletions
diff --git a/media/audio/fake_audio_consumer.cc b/media/audio/fake_audio_consumer.cc
new file mode 100644
index 0000000..95db9cd
--- /dev/null
+++ b/media/audio/fake_audio_consumer.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 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/fake_audio_consumer.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "media/base/audio_bus.h"
+
+namespace media {
+
+FakeAudioConsumer::FakeAudioConsumer(
+ const scoped_refptr<base::MessageLoopProxy>& message_loop,
+ const AudioParameters& params)
+ : message_loop_(message_loop),
+ audio_bus_(AudioBus::Create(params)),
+ buffer_duration_(base::TimeDelta::FromMicroseconds(
+ params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
+ static_cast<float>(params.sample_rate()))) {
+ audio_bus_->Zero();
+}
+
+FakeAudioConsumer::~FakeAudioConsumer() {
+ DCHECK(read_cb_.is_null());
+}
+
+void FakeAudioConsumer::Start(const ReadCB& read_cb) {
+ DCHECK(message_loop_->BelongsToCurrentThread());
+ DCHECK(read_cb_.is_null());
+ DCHECK(!read_cb.is_null());
+ read_cb_ = read_cb;
+ next_read_time_ = base::Time::Now();
+ read_task_cb_.Reset(base::Bind(
+ &FakeAudioConsumer::DoRead, base::Unretained(this)));
+ message_loop_->PostTask(FROM_HERE, read_task_cb_.callback());
+}
+
+void FakeAudioConsumer::Stop() {
+ DCHECK(message_loop_->BelongsToCurrentThread());
+ read_cb_.Reset();
+ read_task_cb_.Cancel();
+}
+
+void FakeAudioConsumer::DoRead() {
+ DCHECK(message_loop_->BelongsToCurrentThread());
+ DCHECK(!read_cb_.is_null());
+
+ read_cb_.Run(audio_bus_.get());
+
+ // Need to account for time spent here due to the cost of |read_cb_| as well
+ // as the imprecision of PostDelayedTask().
+ base::Time now = base::Time::Now();
+ base::TimeDelta delay = next_read_time_ + buffer_duration_ - now;
+
+ // If we're behind, find the next nearest ontime interval.
+ if (delay < base::TimeDelta())
+ delay += buffer_duration_ * (-delay / buffer_duration_ + 1);
+ next_read_time_ = now + delay;
+
+ message_loop_->PostDelayedTask(FROM_HERE, read_task_cb_.callback(), delay);
+}
+
+} // namespace media
diff --git a/media/audio/fake_audio_consumer.h b/media/audio/fake_audio_consumer.h
new file mode 100644
index 0000000..793e553
--- /dev/null
+++ b/media/audio/fake_audio_consumer.h
@@ -0,0 +1,61 @@
+// Copyright (c) 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.
+
+#ifndef MEDIA_AUDIO_FAKE_AUDIO_CONSUMER_H_
+#define MEDIA_AUDIO_FAKE_AUDIO_CONSUMER_H_
+
+#include "base/cancelable_callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time.h"
+#include "media/audio/audio_parameters.h"
+
+namespace base {
+class MessageLoopProxy;
+}
+
+namespace media {
+class AudioBus;
+
+// A fake audio consumer. Using a provided message loop, FakeAudioConsumer will
+// simulate a real time consumer of audio data.
+class MEDIA_EXPORT FakeAudioConsumer {
+ public:
+ // |message_loop| is the loop on which the ReadCB provided to Start() will be
+ // executed on. |params| is used to determine the frequency of callbacks.
+ FakeAudioConsumer(const scoped_refptr<base::MessageLoopProxy>& message_loop,
+ const AudioParameters& params);
+ ~FakeAudioConsumer();
+
+ // Start executing |read_cb| at a regular interval. Must be called on the
+ // message loop provided during construction. Stop() must be called before
+ // destroying FakeAudioConsumer.
+ typedef base::Callback<void(AudioBus* audio_bus)> ReadCB;
+ void Start(const ReadCB& read_cb);
+
+ // Stop executing the ReadCB provided to Start(). Cancels any outstanding
+ // callbacks. Safe to call multiple times. Must be called on the message
+ // loop provided during construction.
+ void Stop();
+
+ private:
+ // Task that regularly calls |read_cb_| according to the playback rate as
+ // determined by the audio parameters given during construction. Runs on
+ // |message_loop_|.
+ void DoRead();
+
+ scoped_refptr<base::MessageLoopProxy> message_loop_;
+ ReadCB read_cb_;
+ scoped_ptr<AudioBus> audio_bus_;
+ base::TimeDelta buffer_duration_;
+ base::Time next_read_time_;
+
+ // Used to post delayed tasks to the AudioThread that we can cancel.
+ base::CancelableClosure read_task_cb_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeAudioConsumer);
+};
+
+} // namespace media
+
+#endif // MEDIA_AUDIO_FAKE_AUDIO_CONSUMER_H_
diff --git a/media/audio/fake_audio_output_stream_unittest.cc b/media/audio/fake_audio_consumer_unittest.cc
index 6599b76..66077d5 100644
--- a/media/audio/fake_audio_output_stream_unittest.cc
+++ b/media/audio/fake_audio_consumer_unittest.cc
@@ -4,10 +4,9 @@
#include "base/bind.h"
#include "base/message_loop.h"
-#include "base/synchronization/waitable_event.h"
#include "base/time.h"
-#include "media/audio/fake_audio_output_stream.h"
-#include "media/audio/audio_manager.h"
+#include "media/audio/audio_buffers_state.h"
+#include "media/audio/fake_audio_consumer.h"
#include "media/audio/simple_sources.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -15,47 +14,47 @@ namespace media {
static const int kTestCallbacks = 5;
-class FakeAudioOutputStreamTest : public testing::Test {
+class FakeAudioConsumerTest : public testing::Test {
public:
- FakeAudioOutputStreamTest()
- : audio_manager_(AudioManager::Create()),
- params_(
+ FakeAudioConsumerTest()
+ : params_(
AudioParameters::AUDIO_FAKE, CHANNEL_LAYOUT_STEREO, 44100, 8, 128),
- source_(params_.channels(), 200.0, params_.sample_rate()),
- done_(false, false) {
- stream_ = audio_manager_->MakeAudioOutputStream(AudioParameters(params_));
- CHECK(stream_);
-
+ fake_consumer_(message_loop_.message_loop_proxy(), params_),
+ source_(params_.channels(), 200.0, params_.sample_rate()) {
time_between_callbacks_ = base::TimeDelta::FromMicroseconds(
params_.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
static_cast<float>(params_.sample_rate()));
}
- virtual ~FakeAudioOutputStreamTest() {}
+ virtual ~FakeAudioConsumerTest() {}
+
+ void ConsumeData(AudioBus* audio_bus) {
+ source_.OnMoreData(audio_bus, AudioBuffersState());
+ }
void RunOnAudioThread() {
- ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
- ASSERT_TRUE(stream_->Open());
- stream_->Start(&source_);
+ ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread());
+ fake_consumer_.Start(base::Bind(
+ &FakeAudioConsumerTest::ConsumeData, base::Unretained(this)));
}
void RunOnceOnAudioThread() {
- ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
+ ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread());
RunOnAudioThread();
// Start() should immediately post a task to run the source callback, so we
// should end up with only a single callback being run.
- audio_manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind(
- &FakeAudioOutputStreamTest::EndTest, base::Unretained(this), 1));
+ message_loop_.PostTask(FROM_HERE, base::Bind(
+ &FakeAudioConsumerTest::EndTest, base::Unretained(this), 1));
}
void StopStartOnAudioThread() {
- ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
- stream_->Stop();
- stream_->Start(&source_);
+ ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread());
+ fake_consumer_.Stop();
+ RunOnAudioThread();
}
void TimeCallbacksOnAudioThread(int callbacks) {
- ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
+ ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread());
if (source_.callbacks() == 0) {
RunOnAudioThread();
@@ -64,8 +63,8 @@ class FakeAudioOutputStreamTest : public testing::Test {
// Keep going until we've seen the requested number of callbacks.
if (source_.callbacks() < callbacks) {
- audio_manager_->GetMessageLoop()->PostDelayedTask(FROM_HERE, base::Bind(
- &FakeAudioOutputStreamTest::TimeCallbacksOnAudioThread,
+ message_loop_.PostDelayedTask(FROM_HERE, base::Bind(
+ &FakeAudioConsumerTest::TimeCallbacksOnAudioThread,
base::Unretained(this), callbacks), time_between_callbacks_ / 2);
} else {
end_time_ = base::Time::Now();
@@ -74,44 +73,40 @@ class FakeAudioOutputStreamTest : public testing::Test {
}
void EndTest(int callbacks) {
- ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
- stream_->Stop();
- stream_->Close();
+ ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread());
+ fake_consumer_.Stop();
EXPECT_LE(callbacks, source_.callbacks());
- EXPECT_EQ(0, source_.errors());
- done_.Signal();
+ message_loop_.PostTask(FROM_HERE, MessageLoop::QuitClosure());
}
protected:
- scoped_ptr<AudioManager> audio_manager_;
+ MessageLoop message_loop_;
AudioParameters params_;
- AudioOutputStream* stream_;
+ FakeAudioConsumer fake_consumer_;
SineWaveAudioSource source_;
- base::WaitableEvent done_;
base::Time start_time_;
base::Time end_time_;
base::TimeDelta time_between_callbacks_;
private:
- DISALLOW_COPY_AND_ASSIGN(FakeAudioOutputStreamTest);
+ DISALLOW_COPY_AND_ASSIGN(FakeAudioConsumerTest);
};
// Ensure the fake audio stream runs on the audio thread and handles fires
// callbacks to the AudioSourceCallback.
-TEST_F(FakeAudioOutputStreamTest, FakeStreamBasicCallback) {
- audio_manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind(
- &FakeAudioOutputStreamTest::RunOnceOnAudioThread,
+TEST_F(FakeAudioConsumerTest, FakeStreamBasicCallback) {
+ message_loop_.PostTask(FROM_HERE, base::Bind(
+ &FakeAudioConsumerTest::RunOnceOnAudioThread,
base::Unretained(this)));
- done_.Wait();
+ message_loop_.Run();
}
// Ensure the time between callbacks is sane.
-TEST_F(FakeAudioOutputStreamTest, TimeBetweenCallbacks) {
- audio_manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind(
- &FakeAudioOutputStreamTest::TimeCallbacksOnAudioThread,
+TEST_F(FakeAudioConsumerTest, TimeBetweenCallbacks) {
+ message_loop_.PostTask(FROM_HERE, base::Bind(
+ &FakeAudioConsumerTest::TimeCallbacksOnAudioThread,
base::Unretained(this), kTestCallbacks));
-
- done_.Wait();
+ message_loop_.Run();
// There are only (kTestCallbacks - 1) intervals between kTestCallbacks.
base::TimeDelta actual_time_between_callbacks =
@@ -129,19 +124,19 @@ TEST_F(FakeAudioOutputStreamTest, TimeBetweenCallbacks) {
// Ensure Start()/Stop() on the stream doesn't generate too many callbacks. See
// http://crbug.com/159049
-TEST_F(FakeAudioOutputStreamTest, StartStopClearsCallbacks) {
- audio_manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind(
- &FakeAudioOutputStreamTest::TimeCallbacksOnAudioThread,
+TEST_F(FakeAudioConsumerTest, StartStopClearsCallbacks) {
+ message_loop_.PostTask(FROM_HERE, base::Bind(
+ &FakeAudioConsumerTest::TimeCallbacksOnAudioThread,
base::Unretained(this), kTestCallbacks));
// Issue a Stop() / Start() in between expected callbacks to maximize the
// chance of catching the FakeAudioOutputStream doing the wrong thing.
- audio_manager_->GetMessageLoop()->PostDelayedTask(FROM_HERE, base::Bind(
- &FakeAudioOutputStreamTest::StopStartOnAudioThread,
+ message_loop_.PostDelayedTask(FROM_HERE, base::Bind(
+ &FakeAudioConsumerTest::StopStartOnAudioThread,
base::Unretained(this)), time_between_callbacks_ / 2);
// EndTest() will ensure the proper number of callbacks have occurred.
- done_.Wait();
+ message_loop_.Run();
}
} // namespace media
diff --git a/media/audio/fake_audio_output_stream.cc b/media/audio/fake_audio_output_stream.cc
index 8db548c..7b85eb0 100644
--- a/media/audio/fake_audio_output_stream.cc
+++ b/media/audio/fake_audio_output_stream.cc
@@ -22,11 +22,7 @@ FakeAudioOutputStream::FakeAudioOutputStream(AudioManagerBase* manager,
const AudioParameters& params)
: audio_manager_(manager),
callback_(NULL),
- audio_bus_(AudioBus::Create(params)),
- buffer_duration_(base::TimeDelta::FromMicroseconds(
- params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
- static_cast<float>(params.sample_rate()))) {
- audio_bus_->Zero();
+ fake_consumer_(manager->GetMessageLoop(), params) {
}
FakeAudioOutputStream::~FakeAudioOutputStream() {
@@ -41,17 +37,14 @@ bool FakeAudioOutputStream::Open() {
void FakeAudioOutputStream::Start(AudioSourceCallback* callback) {
DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
callback_ = callback;
- next_read_time_ = base::Time::Now();
- on_more_data_cb_.Reset(base::Bind(
- &FakeAudioOutputStream::OnMoreDataTask, base::Unretained(this)));
- audio_manager_->GetMessageLoop()->PostTask(
- FROM_HERE, on_more_data_cb_.callback());
+ fake_consumer_.Start(base::Bind(
+ &FakeAudioOutputStream::CallOnMoreData, base::Unretained(this)));
}
void FakeAudioOutputStream::Stop() {
DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
+ fake_consumer_.Stop();
callback_ = NULL;
- on_more_data_cb_.Cancel();
}
void FakeAudioOutputStream::Close() {
@@ -66,24 +59,9 @@ void FakeAudioOutputStream::GetVolume(double* volume) {
*volume = 0;
};
-void FakeAudioOutputStream::OnMoreDataTask() {
+void FakeAudioOutputStream::CallOnMoreData(AudioBus* audio_bus) {
DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
- DCHECK(callback_);
-
- callback_->OnMoreData(audio_bus_.get(), AudioBuffersState());
-
- // Need to account for time spent here due to the cost of OnMoreData() as well
- // as the imprecision of PostDelayedTask().
- base::Time now = base::Time::Now();
- base::TimeDelta delay = next_read_time_ + buffer_duration_ - now;
-
- // If we're behind, find the next nearest ontime interval.
- if (delay < base::TimeDelta())
- delay += buffer_duration_ * (-delay / buffer_duration_ + 1);
- next_read_time_ = now + delay;
-
- audio_manager_->GetMessageLoop()->PostDelayedTask(
- FROM_HERE, on_more_data_cb_.callback(), delay);
+ callback_->OnMoreData(audio_bus, AudioBuffersState());
}
} // namespace media
diff --git a/media/audio/fake_audio_output_stream.h b/media/audio/fake_audio_output_stream.h
index ec3a592..399d72b 100644
--- a/media/audio/fake_audio_output_stream.h
+++ b/media/audio/fake_audio_output_stream.h
@@ -5,11 +5,10 @@
#ifndef MEDIA_AUDIO_FAKE_AUDIO_OUTPUT_STREAM_H_
#define MEDIA_AUDIO_FAKE_AUDIO_OUTOUT_STREAM_H_
-#include "base/cancelable_callback.h"
#include "base/memory/scoped_ptr.h"
-#include "base/time.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_parameters.h"
+#include "media/audio/fake_audio_consumer.h"
namespace media {
@@ -17,6 +16,7 @@ class AudioManagerBase;
// A fake implementation of AudioOutputStream. Used for testing and when a real
// audio output device is unavailable or refusing output (e.g. remote desktop).
+// Callbacks are driven on the AudioManager's message loop.
class MEDIA_EXPORT FakeAudioOutputStream : public AudioOutputStream {
public:
static AudioOutputStream* MakeFakeStream(AudioManagerBase* manager,
@@ -35,19 +35,12 @@ class MEDIA_EXPORT FakeAudioOutputStream : public AudioOutputStream {
const AudioParameters& params);
virtual ~FakeAudioOutputStream();
- // Task that regularly calls |callback_->OnMoreData()| according to the
- // playback rate as determined by the audio parameters given during
- // construction. Runs on AudioManager's message loop.
- void OnMoreDataTask();
+ // Task that periodically calls OnMoreData() to consume audio data.
+ void CallOnMoreData(AudioBus* audio_bus);
AudioManagerBase* audio_manager_;
AudioSourceCallback* callback_;
- scoped_ptr<AudioBus> audio_bus_;
- base::TimeDelta buffer_duration_;
- base::Time next_read_time_;
-
- // Used to post delayed tasks to the AudioThread that we can cancel.
- base::CancelableClosure on_more_data_cb_;
+ FakeAudioConsumer fake_consumer_;
DISALLOW_COPY_AND_ASSIGN(FakeAudioOutputStream);
};
diff --git a/media/audio/null_audio_sink.cc b/media/audio/null_audio_sink.cc
index c93ceb1..37d3ce0 100644
--- a/media/audio/null_audio_sink.cc
+++ b/media/audio/null_audio_sink.cc
@@ -5,30 +5,34 @@
#include "media/audio/null_audio_sink.h"
#include "base/bind.h"
+#include "base/message_loop_proxy.h"
#include "base/stringprintf.h"
#include "base/sys_byteorder.h"
-#include "base/threading/platform_thread.h"
+#include "media/audio/fake_audio_consumer.h"
namespace media {
-NullAudioSink::NullAudioSink()
+NullAudioSink::NullAudioSink(
+ const scoped_refptr<base::MessageLoopProxy>& message_loop)
: initialized_(false),
- playing_(false),
callback_(NULL),
- thread_("NullAudioThread"),
- hash_audio_for_testing_(false) {
+ hash_audio_for_testing_(false),
+ channels_(0),
+ message_loop_(message_loop) {
}
+NullAudioSink::~NullAudioSink() {}
+
void NullAudioSink::Initialize(const AudioParameters& params,
RenderCallback* callback) {
DCHECK(!initialized_);
- params_ = params;
- audio_bus_ = AudioBus::Create(params_);
+ fake_consumer_.reset(new FakeAudioConsumer(message_loop_, params));
if (hash_audio_for_testing_) {
- md5_channel_contexts_.reset(new base::MD5Context[params_.channels()]);
- for (int i = 0; i < params_.channels(); i++)
+ channels_ = params.channels();
+ md5_channel_contexts_.reset(new base::MD5Context[params.channels()]);
+ for (int i = 0; i < params.channels(); i++)
base::MD5Init(&md5_channel_contexts_[i]);
}
@@ -37,24 +41,27 @@ void NullAudioSink::Initialize(const AudioParameters& params,
}
void NullAudioSink::Start() {
- if (!thread_.Start())
- return;
-
- thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
- &NullAudioSink::FillBufferTask, this));
+ DCHECK(message_loop_->BelongsToCurrentThread());
}
void NullAudioSink::Stop() {
- SetPlaying(false);
- thread_.Stop();
+ DCHECK(message_loop_->BelongsToCurrentThread());
+
+ // Stop may be called at any time, so we have to check before stopping.
+ if (fake_consumer_)
+ fake_consumer_->Stop();
}
void NullAudioSink::Play() {
- SetPlaying(true);
+ DCHECK(message_loop_->BelongsToCurrentThread());
+ DCHECK(initialized_);
+ fake_consumer_->Start(base::Bind(
+ &NullAudioSink::CallRender, base::Unretained(this)));
}
void NullAudioSink::Pause(bool /* flush */) {
- SetPlaying(false);
+ DCHECK(message_loop_->BelongsToCurrentThread());
+ fake_consumer_->Stop();
}
bool NullAudioSink::SetVolume(double volume) {
@@ -62,54 +69,24 @@ bool NullAudioSink::SetVolume(double volume) {
return volume == 0.0;
}
-void NullAudioSink::SetPlaying(bool is_playing) {
- base::AutoLock auto_lock(lock_);
- playing_ = is_playing;
-}
+void NullAudioSink::CallRender(AudioBus* audio_bus) {
+ DCHECK(message_loop_->BelongsToCurrentThread());
-NullAudioSink::~NullAudioSink() {
- DCHECK(!thread_.IsRunning());
-}
+ int frames_received = callback_->Render(audio_bus, 0);
+ if (!hash_audio_for_testing_ || frames_received <= 0)
+ return;
-void NullAudioSink::FillBufferTask() {
- base::AutoLock auto_lock(lock_);
-
- base::TimeDelta delay;
- // Only consume buffers when actually playing.
- if (playing_) {
- int frames_received = callback_->Render(audio_bus_.get(), 0);
- int frames_per_millisecond =
- params_.sample_rate() / base::Time::kMillisecondsPerSecond;
-
- if (hash_audio_for_testing_ && frames_received > 0) {
- DCHECK_EQ(sizeof(float), sizeof(uint32));
- int channels = audio_bus_->channels();
- for (int channel_idx = 0; channel_idx < channels; ++channel_idx) {
- float* channel = audio_bus_->channel(channel_idx);
- for (int frame_idx = 0; frame_idx < frames_received; frame_idx++) {
- // Convert float to uint32 w/o conversion loss.
- uint32 frame = base::ByteSwapToLE32(
- bit_cast<uint32>(channel[frame_idx]));
- base::MD5Update(
- &md5_channel_contexts_[channel_idx], base::StringPiece(
- reinterpret_cast<char*>(&frame), sizeof(frame)));
- }
- }
+ DCHECK_EQ(sizeof(float), sizeof(uint32));
+ int channels = audio_bus->channels();
+ for (int channel_idx = 0; channel_idx < channels; ++channel_idx) {
+ float* channel = audio_bus->channel(channel_idx);
+ for (int frame_idx = 0; frame_idx < frames_received; frame_idx++) {
+ // Convert float to uint32 w/o conversion loss.
+ uint32 frame = base::ByteSwapToLE32(bit_cast<uint32>(channel[frame_idx]));
+ base::MD5Update(&md5_channel_contexts_[channel_idx], base::StringPiece(
+ reinterpret_cast<char*>(&frame), sizeof(frame)));
}
-
- // Calculate our sleep duration.
- delay = base::TimeDelta::FromMilliseconds(
- frames_received / frames_per_millisecond);
- } 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)));
}
void NullAudioSink::StartAudioHashForTesting() {
@@ -120,24 +97,22 @@ void NullAudioSink::StartAudioHashForTesting() {
std::string NullAudioSink::GetAudioHashForTesting() {
DCHECK(hash_audio_for_testing_);
- // If initialize failed or was never called, ensure we return an empty hash.
- int channels = 1;
- if (!initialized_) {
- md5_channel_contexts_.reset(new base::MD5Context[1]);
- base::MD5Init(&md5_channel_contexts_[0]);
- } else {
- channels = audio_bus_->channels();
- }
-
- // Hash all channels into the first channel.
base::MD5Digest digest;
- for (int i = 1; i < channels; i++) {
- base::MD5Final(&digest, &md5_channel_contexts_[i]);
- base::MD5Update(&md5_channel_contexts_[0], base::StringPiece(
- reinterpret_cast<char*>(&digest), sizeof(base::MD5Digest)));
+ if (channels_ == 0) {
+ // If initialize failed or was never called, ensure we return an empty hash.
+ base::MD5Context context;
+ base::MD5Init(&context);
+ base::MD5Final(&digest, &context);
+ } else {
+ // Hash all channels into the first channel.
+ for (int i = 1; i < channels_; i++) {
+ base::MD5Final(&digest, &md5_channel_contexts_[i]);
+ base::MD5Update(&md5_channel_contexts_[0], base::StringPiece(
+ reinterpret_cast<char*>(&digest), sizeof(base::MD5Digest)));
+ }
+ base::MD5Final(&digest, &md5_channel_contexts_[0]);
}
- base::MD5Final(&digest, &md5_channel_contexts_[0]);
return base::MD5DigestToBase16(digest);
}
diff --git a/media/audio/null_audio_sink.h b/media/audio/null_audio_sink.h
index c528473..f892ab4 100644
--- a/media/audio/null_audio_sink.h
+++ b/media/audio/null_audio_sink.h
@@ -2,29 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef MEDIA_FILTERS_NULL_AUDIO_RENDERER_H_
-#define MEDIA_FILTERS_NULL_AUDIO_RENDERER_H_
-
-// NullAudioSink effectively uses an extra thread to "throw away" the
-// audio data at a rate resembling normal playback speed. It's just like
-// decoding to /dev/null!
-//
-// NullAudioSink can also be used in situations where the client has no
-// audio device or we haven't written an audio implementation for a particular
-// platform yet.
+#ifndef MEDIA_AUDIO_NULL_AUDIO_SINK_H_
+#define MEDIA_AUDIO_NULL_AUDIO_SINK_H_
#include "base/md5.h"
#include "base/memory/scoped_ptr.h"
-#include "base/threading/thread.h"
#include "media/base/audio_renderer_sink.h"
+namespace base {
+class MessageLoopProxy;
+}
+
namespace media {
class AudioBus;
+class FakeAudioConsumer;
class MEDIA_EXPORT NullAudioSink
: NON_EXPORTED_BASE(public AudioRendererSink) {
public:
- NullAudioSink();
+ NullAudioSink(const scoped_refptr<base::MessageLoopProxy>& message_loop);
// AudioRendererSink implementation.
virtual void Initialize(const AudioParameters& params,
@@ -46,31 +42,23 @@ class MEDIA_EXPORT NullAudioSink
virtual ~NullAudioSink();
private:
- // Audio thread task that periodically calls FillBuffer() to consume
- // audio data.
- void FillBufferTask();
-
- void SetPlaying(bool is_playing);
+ // Task that periodically calls Render() to consume audio data.
+ void CallRender(AudioBus* audio_bus);
- // A buffer passed to FillBuffer to advance playback.
- scoped_ptr<AudioBus> audio_bus_;
-
- AudioParameters params_;
bool initialized_;
- bool playing_;
RenderCallback* callback_;
- // Separate thread used to throw away data.
- base::Thread thread_;
- base::Lock lock_;
-
// Controls whether or not a running MD5 hash is computed for audio frames.
bool hash_audio_for_testing_;
+ int channels_;
scoped_array<base::MD5Context> md5_channel_contexts_;
+ scoped_refptr<base::MessageLoopProxy> message_loop_;
+ scoped_ptr<FakeAudioConsumer> fake_consumer_;
+
DISALLOW_COPY_AND_ASSIGN(NullAudioSink);
};
} // namespace media
-#endif // MEDIA_FILTERS_NULL_AUDIO_RENDERER_H_
+#endif // MEDIA_AUDIO_NULL_AUDIO_SINK_H_