diff options
author | dalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-03 00:04:52 +0000 |
---|---|---|
committer | dalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-03 00:04:52 +0000 |
commit | a20200cb67b9126f4224f6c20305f6a3bf37f20c (patch) | |
tree | b83ee3dbca3329629cf07fa6c0aa3b77a6fb2b2c | |
parent | a95d5307e16b960914a92b110cc68abf1ed8a88d (diff) | |
download | chromium_src-a20200cb67b9126f4224f6c20305f6a3bf37f20c.zip chromium_src-a20200cb67b9126f4224f6c20305f6a3bf37f20c.tar.gz chromium_src-a20200cb67b9126f4224f6c20305f6a3bf37f20c.tar.bz2 |
Switch fake audio output streams over to CancelableClosure.
Prevents multiple audio callback chains from running concurrently.
BUG=159049
TEST=multiple audio streams w/o audio hardware. media_unittests.
Review URL: https://chromiumcodereview.appspot.com/11365053
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@165803 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | media/audio/fake_audio_output_stream.cc | 25 | ||||
-rw-r--r-- | media/audio/fake_audio_output_stream.h | 4 | ||||
-rw-r--r-- | media/audio/fake_audio_output_stream_unittest.cc | 81 |
3 files changed, 90 insertions, 20 deletions
diff --git a/media/audio/fake_audio_output_stream.cc b/media/audio/fake_audio_output_stream.cc index 38b5437..c21026d 100644 --- a/media/audio/fake_audio_output_stream.cc +++ b/media/audio/fake_audio_output_stream.cc @@ -25,8 +25,7 @@ FakeAudioOutputStream::FakeAudioOutputStream(AudioManagerBase* manager, audio_bus_(AudioBus::Create(params)), frames_per_millisecond_( params.sample_rate() / static_cast<float>( - base::Time::kMillisecondsPerSecond)), - ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) { + base::Time::kMillisecondsPerSecond)) { } FakeAudioOutputStream::~FakeAudioOutputStream() { @@ -41,19 +40,21 @@ bool FakeAudioOutputStream::Open() { void FakeAudioOutputStream::Start(AudioSourceCallback* callback) { DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); callback_ = callback; - audio_manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind( - &FakeAudioOutputStream::OnMoreDataTask, weak_this_.GetWeakPtr())); + on_more_data_cb_.Reset(base::Bind( + &FakeAudioOutputStream::OnMoreDataTask, base::Unretained(this))); + audio_manager_->GetMessageLoop()->PostTask( + FROM_HERE, on_more_data_cb_.callback()); } void FakeAudioOutputStream::Stop() { DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); callback_ = NULL; + on_more_data_cb_.Cancel(); } void FakeAudioOutputStream::Close() { DCHECK(!callback_); DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); - weak_this_.InvalidateWeakPtrs(); audio_manager_->ReleaseOutputStream(this); } @@ -65,20 +66,16 @@ void FakeAudioOutputStream::GetVolume(double* volume) { void FakeAudioOutputStream::OnMoreDataTask() { DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); + DCHECK(callback_); audio_bus_->Zero(); - int frames_received = audio_bus_->frames(); - if (callback_) { - frames_received = callback_->OnMoreData( - audio_bus_.get(), AudioBuffersState()); - } + int frames_received = callback_->OnMoreData( + audio_bus_.get(), AudioBuffersState()); // Calculate our sleep duration for simulated playback. Sleep for at least // one millisecond so we don't spin the CPU. - MessageLoop::current()->PostDelayedTask( - FROM_HERE, base::Bind( - &FakeAudioOutputStream::OnMoreDataTask, weak_this_.GetWeakPtr()), - base::TimeDelta::FromMilliseconds( + audio_manager_->GetMessageLoop()->PostDelayedTask( + FROM_HERE, on_more_data_cb_.callback(), base::TimeDelta::FromMilliseconds( std::max(1.0f, frames_received / frames_per_millisecond_))); } diff --git a/media/audio/fake_audio_output_stream.h b/media/audio/fake_audio_output_stream.h index 6d4f19b..d188b9f 100644 --- a/media/audio/fake_audio_output_stream.h +++ b/media/audio/fake_audio_output_stream.h @@ -5,8 +5,8 @@ #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/memory/weak_ptr.h" #include "media/audio/audio_io.h" #include "media/audio/audio_parameters.h" @@ -45,7 +45,7 @@ class MEDIA_EXPORT FakeAudioOutputStream : public AudioOutputStream { float frames_per_millisecond_; // Used to post delayed tasks to the AudioThread that we can cancel. - base::WeakPtrFactory<FakeAudioOutputStream> weak_this_; + base::CancelableClosure on_more_data_cb_; DISALLOW_COPY_AND_ASSIGN(FakeAudioOutputStream); }; diff --git a/media/audio/fake_audio_output_stream_unittest.cc b/media/audio/fake_audio_output_stream_unittest.cc index 8318c2b..6838e3f 100644 --- a/media/audio/fake_audio_output_stream_unittest.cc +++ b/media/audio/fake_audio_output_stream_unittest.cc @@ -5,6 +5,7 @@ #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/simple_sources.h" @@ -22,6 +23,10 @@ class FakeAudioOutputStreamTest : public testing::Test { done_(false, false) { stream_ = audio_manager_->MakeAudioOutputStream(AudioParameters(params_)); CHECK(stream_); + + time_between_callbacks_ = base::TimeDelta::FromMilliseconds( + params_.frames_per_buffer() * base::Time::kMillisecondsPerSecond / + static_cast<float>(params_.sample_rate())); } virtual ~FakeAudioOutputStreamTest() {} @@ -30,17 +35,48 @@ class FakeAudioOutputStreamTest : public testing::Test { ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); ASSERT_TRUE(stream_->Open()); stream_->Start(&source_); + } + + void RunOnceOnAudioThread() { + ASSERT_TRUE(audio_manager_->GetMessageLoop()->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))); + &FakeAudioOutputStreamTest::EndTest, base::Unretained(this), 1)); } - void EndTest() { + void StopStartOnAudioThread() { + ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); + stream_->Stop(); + stream_->Start(&source_); + } + + void TimeCallbacksOnAudioThread(int callbacks) { + ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); + + if (source_.callbacks() == 0) { + RunOnAudioThread(); + start_time_ = base::Time::Now(); + } + + // 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, + base::Unretained(this), callbacks), time_between_callbacks_); + } else { + audio_manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind( + &FakeAudioOutputStreamTest::EndTest, base::Unretained(this), + callbacks)); + } + } + + void EndTest(int callbacks) { ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); stream_->Stop(); stream_->Close(); - EXPECT_EQ(1, source_.callbacks()); + EXPECT_EQ(callbacks, source_.callbacks()); EXPECT_EQ(0, source_.errors()); done_.Signal(); } @@ -51,6 +87,8 @@ class FakeAudioOutputStreamTest : public testing::Test { AudioOutputStream* stream_; SineWaveAudioSource source_; base::WaitableEvent done_; + base::Time start_time_; + base::TimeDelta time_between_callbacks_; private: DISALLOW_COPY_AND_ASSIGN(FakeAudioOutputStreamTest); @@ -60,8 +98,43 @@ class FakeAudioOutputStreamTest : public testing::Test { // callbacks to the AudioSourceCallback. TEST_F(FakeAudioOutputStreamTest, FakeStreamBasicCallback) { audio_manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind( - &FakeAudioOutputStreamTest::RunOnAudioThread, base::Unretained(this))); + &FakeAudioOutputStreamTest::RunOnceOnAudioThread, + base::Unretained(this))); + done_.Wait(); +} + +// Ensure the time between callbacks is sane. +TEST_F(FakeAudioOutputStreamTest, TimeBetweenCallbacks) { + static const int kTestCallbacks = 5; + + audio_manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind( + &FakeAudioOutputStreamTest::TimeCallbacksOnAudioThread, + base::Unretained(this), kTestCallbacks)); + + // Let the loop run for a second or two then issue Stop() / Start(). + audio_manager_->GetMessageLoop()->PostDelayedTask(FROM_HERE, base::Bind( + &FakeAudioOutputStreamTest::StopStartOnAudioThread, + base::Unretained(this)), time_between_callbacks_); + done_.Wait(); + + base::TimeDelta elapsed = base::Time::Now() - start_time_; + + // There are only (kTestCallbacks - 1) intervals between kTestCallbacks. + float actual_time_between_callbacks_ms = + elapsed.InMillisecondsF() / (kTestCallbacks - 1); + float expected_time_between_callbacks_ms = + time_between_callbacks_.InMillisecondsF(); + + // Ensure callback time is no faster than the expected time between callbacks. + EXPECT_GE(actual_time_between_callbacks_ms, + expected_time_between_callbacks_ms); + + // Softly check if the callback time is no slower than twice the expected time + // between callbacks. Since this test runs on the bots we can't be too strict + // with the bounds. + if (actual_time_between_callbacks_ms > 2 * expected_time_between_callbacks_ms) + LOG(ERROR) << "Time between fake audio callbacks is too large!"; } } // namespace media |