Index: media/audio/audio_output_controller_unittest.cc |
diff --git a/media/audio/audio_output_controller_unittest.cc b/media/audio/audio_output_controller_unittest.cc |
index fe29ce59af3f969a10191e1b5742cbe64acfd389..05077e46afe4ade5050c398e7353fdecec66d483 100644 |
--- a/media/audio/audio_output_controller_unittest.cc |
+++ b/media/audio/audio_output_controller_unittest.cc |
@@ -2,23 +2,23 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include "base/basictypes.h" |
#include "base/bind.h" |
#include "base/environment.h" |
-#include "base/basictypes.h" |
#include "base/logging.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/memory/scoped_ptr.h" |
#include "base/message_loop.h" |
#include "base/synchronization/waitable_event.h" |
#include "media/audio/audio_output_controller.h" |
+#include "media/audio/audio_parameters.h" |
+#include "media/base/audio_bus.h" |
#include "testing/gmock/include/gmock/gmock.h" |
#include "testing/gtest/include/gtest/gtest.h" |
-// TODO(vrk): These tests need to be rewritten! (crbug.com/112500) |
- |
using ::testing::_; |
using ::testing::AtLeast; |
using ::testing::DoAll; |
-using ::testing::Exactly; |
-using ::testing::InvokeWithoutArgs; |
using ::testing::NotNull; |
using ::testing::Return; |
@@ -64,223 +64,296 @@ ACTION_P(SignalEvent, event) { |
event->Signal(); |
} |
-// Custom action to clear a memory buffer. |
-ACTION(ClearBuffer) { |
- arg1->Zero(); |
-} |
- |
-// Closes AudioOutputController synchronously. |
-static void CloseAudioController(AudioOutputController* controller) { |
- controller->Close(MessageLoop::QuitClosure()); |
- MessageLoop::current()->Run(); |
+static const float kBufferZeroData = 0.0f; |
+static const float kBufferNonZeroData = 1.0f; |
+ACTION_P(PopulateBuffer, value) { |
+ // Note: To confirm the buffer will be populated in these tests, it's |
+ // sufficient that only the first float in channel 0 is set to the value. |
+ arg1->channel(0)[0] = value; |
} |
class AudioOutputControllerTest : public testing::Test { |
public: |
- AudioOutputControllerTest() {} |
- virtual ~AudioOutputControllerTest() {} |
+ AudioOutputControllerTest() |
+ : audio_manager_(AudioManager::Create()), |
+ create_event_(false, false), |
+ play_event_(false, false), |
+ read_event_(false, false), |
+ pause_event_(false, false), |
+ diverted_callback_(NULL) { |
+ if (ShouldSkipTest()) { |
DaleCurtis
2012/12/05 23:35:14
Shouldn't be necessary anymore since we have FakeA
miu
2012/12/11 02:30:45
Done.
|
+ DLOG(WARNING) |
+ << "Skipping tests because OS provides no audio output devices."; |
+ } |
+ } |
+ |
+ virtual ~AudioOutputControllerTest() { |
+ ASSERT_FALSE(diverted_callback_); |
+ } |
protected: |
- MessageLoopForIO message_loop_; |
+ bool ShouldSkipTest() { |
+ return !audio_manager_->HasAudioOutputDevices(); |
+ } |
+ |
+ // Returns true if a controller was successfully created. |
+ bool Create(int samples_per_packet) { |
+ params_ = AudioParameters( |
+ AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, |
+ kSampleRate, kBitsPerSample, samples_per_packet); |
+ controller_ = AudioOutputController::Create( |
+ audio_manager_.get(), &mock_event_handler_, params_, |
+ &mock_sync_reader_); |
+ |
+ if (controller_) { |
+ EXPECT_FALSE(create_event_.IsSignaled()); |
+ EXPECT_CALL(mock_event_handler_, OnCreated(NotNull())) |
+ .WillOnce(SignalEvent(&create_event_)); |
+ EXPECT_CALL(mock_sync_reader_, Close()); |
+ } else { |
+ EXPECT_CALL(mock_event_handler_, OnCreated(NotNull())) |
+ .Times(0); |
+ EXPECT_CALL(mock_sync_reader_, Close()) |
+ .Times(0); |
+ } |
+ |
+ EXPECT_FALSE(play_event_.IsSignaled()); |
+ EXPECT_FALSE(read_event_.IsSignaled()); |
+ EXPECT_FALSE(pause_event_.IsSignaled()); |
+ |
+ return controller_ != NULL; |
+ } |
+ |
+ void Play() { |
+ // Expect the event handler to receive one OnPlaying() call. |
+ EXPECT_CALL(mock_event_handler_, OnPlaying(NotNull())) |
+ .WillOnce(SignalEvent(&play_event_)); |
+ |
+ // During playback, the mock pretends to provide audio data rendered and |
+ // sent from the render process. |
+ EXPECT_CALL(mock_sync_reader_, UpdatePendingBytes(_)) |
+ .Times(AtLeast(2)); |
+ EXPECT_CALL(mock_sync_reader_, Read(_, _)) |
+ .WillRepeatedly(DoAll(PopulateBuffer(kBufferNonZeroData), |
+ SignalEvent(&read_event_), |
+ Return(params_.frames_per_buffer()))); |
+ EXPECT_CALL(mock_sync_reader_, DataReady()) |
+ .WillRepeatedly(Return(true)); |
+ |
+ controller_->Play(); |
+ } |
+ |
+ void Pause() { |
+ // Expect the event handler to receive one OnPaused() call. |
+ EXPECT_CALL(mock_event_handler_, OnPaused(NotNull())) |
+ .WillOnce(SignalEvent(&pause_event_)); |
+ |
+ controller_->Pause(); |
+ } |
+ |
+ void ChangeDevice() { |
+ // Expect the event handler to receive one OnPaying() call and no OnPaused() |
+ // call. |
+ EXPECT_CALL(mock_event_handler_, OnPlaying(NotNull())) |
+ .WillOnce(SignalEvent(&play_event_)); |
+ EXPECT_CALL(mock_event_handler_, OnPaused(NotNull())) |
+ .Times(0); |
+ |
+ // Simulate a device change event to AudioOutputController from the |
+ // AudioManager. |
+ audio_manager_->GetMessageLoop()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&AudioOutputController::OnDeviceChange, controller_)); |
+ } |
+ |
+ void Divert() { |
+ EXPECT_FALSE(diverted_callback_); |
+ diverted_callback_ = controller_->Divert(); |
+ EXPECT_TRUE(diverted_callback_); |
+ } |
+ |
+ // |expected_buffer_data| is used to differentiate between: 1) expecting to |
+ // see audio data rendered from the render process; versus 2) expecting |
+ // AudioOutputController to be filling-in zeros (i.e., it is not in a playback |
+ // state). |
+ void ReadDivertedAudioData(float expected_buffer_data) { |
+ ASSERT_TRUE(diverted_callback_); |
+ scoped_ptr<AudioBus> dest = AudioBus::Create(params_); |
+ const int frames_read = |
+ diverted_callback_->OnMoreData(dest.get(), AudioBuffersState()); |
+ EXPECT_EQ(dest->frames(), frames_read); |
+ EXPECT_EQ(expected_buffer_data, dest->channel(0)[0]); |
+ } |
+ |
+ // |expect_playback_restored| is true if the revert happened during the |
+ // playback state. In this case, we expect event handler to receive one call |
+ // to OnPlaying(). |
+ void Revert(bool expect_playback_restored) { |
+ EXPECT_TRUE(diverted_callback_); |
+ if (expect_playback_restored) { |
+ EXPECT_CALL(mock_event_handler_, OnPlaying(NotNull())) |
+ .WillOnce(SignalEvent(&play_event_)); |
+ } else { |
+ EXPECT_CALL(mock_event_handler_, OnPlaying(NotNull())) |
+ .Times(0); |
+ } |
+ controller_->Revert(diverted_callback_); |
+ diverted_callback_ = NULL; |
+ } |
+ |
+ void Close() { |
+ controller_->Close(MessageLoop::QuitClosure()); |
+ MessageLoop::current()->Run(); |
+ } |
+ |
+ // These synchronize the main thread with key events taking place on other |
+ // threads. |
+ void WaitForCreate() { create_event_.Wait(); } |
+ void WaitForPlay() { play_event_.Wait(); } |
+ void WaitForReads() { |
+ // Note: Arbitrarily chosen, but more iterations causes tests to take |
+ // significantly more time. |
+ static const int kNumIterations = 3; |
+ for (int i = 0; i < kNumIterations; ++i) { |
+ read_event_.Wait(); |
+ } |
+ } |
+ void WaitForPause() { pause_event_.Wait(); } |
private: |
+ MessageLoopForIO message_loop_; |
+ scoped_ptr<AudioManager> audio_manager_; |
+ MockAudioOutputControllerEventHandler mock_event_handler_; |
+ MockAudioOutputControllerSyncReader mock_sync_reader_; |
+ base::WaitableEvent create_event_; |
+ base::WaitableEvent play_event_; |
+ base::WaitableEvent read_event_; |
+ base::WaitableEvent pause_event_; |
+ AudioParameters params_; |
+ scoped_refptr<AudioOutputController> controller_; |
+ AudioOutputStream::AudioSourceCallback* diverted_callback_; |
+ |
DISALLOW_COPY_AND_ASSIGN(AudioOutputControllerTest); |
}; |
TEST_F(AudioOutputControllerTest, CreateAndClose) { |
- scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); |
- if (!audio_manager->HasAudioOutputDevices()) |
+ if (ShouldSkipTest()) |
return; |
+ ASSERT_TRUE(Create(kSamplesPerPacket)); |
+ Close(); |
+} |
- MockAudioOutputControllerEventHandler event_handler; |
- |
- EXPECT_CALL(event_handler, OnCreated(NotNull())) |
- .Times(1); |
- |
- MockAudioOutputControllerSyncReader sync_reader; |
- EXPECT_CALL(sync_reader, Close()); |
- |
- AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, |
- kSampleRate, kBitsPerSample, kSamplesPerPacket); |
- scoped_refptr<AudioOutputController> controller = |
- AudioOutputController::Create( |
- audio_manager.get(), &event_handler, params, &sync_reader); |
- ASSERT_TRUE(controller.get()); |
+TEST_F(AudioOutputControllerTest, HardwareBufferTooLarge) { |
+ if (ShouldSkipTest()) |
+ return; |
+ EXPECT_FALSE(Create(kSamplesPerPacket * 1000)); |
+} |
- // Close the controller immediately. |
- CloseAudioController(controller); |
+TEST_F(AudioOutputControllerTest, PlayAndClose) { |
+ if (ShouldSkipTest()) |
+ return; |
+ ASSERT_TRUE(Create(kSamplesPerPacket)); |
+ WaitForCreate(); |
+ Play(); |
+ WaitForPlay(); |
+ WaitForReads(); |
+ Close(); |
} |
TEST_F(AudioOutputControllerTest, PlayPauseClose) { |
- scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); |
- if (!audio_manager->HasAudioOutputDevices()) |
+ if (ShouldSkipTest()) |
return; |
- |
- MockAudioOutputControllerEventHandler event_handler; |
- base::WaitableEvent event(false, false); |
- base::WaitableEvent pause_event(false, false); |
- |
- // If OnCreated is called then signal the event. |
- EXPECT_CALL(event_handler, OnCreated(NotNull())) |
- .WillOnce(InvokeWithoutArgs(&event, &base::WaitableEvent::Signal)); |
- |
- // OnPlaying() will be called only once. |
- EXPECT_CALL(event_handler, OnPlaying(NotNull())); |
- |
- MockAudioOutputControllerSyncReader sync_reader; |
- EXPECT_CALL(sync_reader, UpdatePendingBytes(_)) |
- .Times(AtLeast(2)); |
- EXPECT_CALL(sync_reader, Read(_, _)) |
- .WillRepeatedly(DoAll(ClearBuffer(), SignalEvent(&event), |
- Return(4))); |
- EXPECT_CALL(sync_reader, DataReady()) |
- .WillRepeatedly(Return(true)); |
- EXPECT_CALL(event_handler, OnPaused(NotNull())) |
- .WillOnce(InvokeWithoutArgs(&pause_event, &base::WaitableEvent::Signal)); |
- EXPECT_CALL(sync_reader, Close()); |
- |
- AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, |
- kSampleRate, kBitsPerSample, kSamplesPerPacket); |
- scoped_refptr<AudioOutputController> controller = |
- AudioOutputController::Create( |
- audio_manager.get(), &event_handler, params, &sync_reader); |
- ASSERT_TRUE(controller.get()); |
- |
- // Wait for OnCreated() to be called. |
- event.Wait(); |
- |
- ASSERT_FALSE(pause_event.IsSignaled()); |
- controller->Play(); |
- controller->Pause(); |
- pause_event.Wait(); |
- |
- // Now stop the controller. |
- CloseAudioController(controller); |
+ ASSERT_TRUE(Create(kSamplesPerPacket)); |
+ WaitForCreate(); |
+ Play(); |
+ WaitForPlay(); |
+ WaitForReads(); |
+ Pause(); |
+ WaitForPause(); |
+ Close(); |
} |
-TEST_F(AudioOutputControllerTest, HardwareBufferTooLarge) { |
- scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); |
- if (!audio_manager->HasAudioOutputDevices()) |
+TEST_F(AudioOutputControllerTest, PlayPausePlayClose) { |
+ if (ShouldSkipTest()) |
return; |
- |
- // Create an audio device with a very large hardware buffer size. |
- MockAudioOutputControllerEventHandler event_handler; |
- |
- MockAudioOutputControllerSyncReader sync_reader; |
- AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, |
- kSampleRate, kBitsPerSample, |
- kSamplesPerPacket * 1000); |
- scoped_refptr<AudioOutputController> controller = |
- AudioOutputController::Create( |
- audio_manager.get(), &event_handler, params, &sync_reader); |
- |
- // Use assert because we don't stop the device and assume we can't |
- // create one. |
- ASSERT_FALSE(controller); |
+ ASSERT_TRUE(Create(kSamplesPerPacket)); |
+ WaitForCreate(); |
+ Play(); |
+ WaitForPlay(); |
+ WaitForReads(); |
+ Pause(); |
+ WaitForPause(); |
+ Play(); |
+ WaitForPlay(); |
+ Close(); |
} |
-TEST_F(AudioOutputControllerTest, PlayPausePlayClose) { |
- scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); |
- if (!audio_manager->HasAudioOutputDevices()) |
+TEST_F(AudioOutputControllerTest, PlayDeviceChangeClose) { |
+ if (ShouldSkipTest()) |
return; |
+ ASSERT_TRUE(Create(kSamplesPerPacket)); |
+ WaitForCreate(); |
+ Play(); |
+ WaitForPlay(); |
+ WaitForReads(); |
+ ChangeDevice(); |
+ WaitForPlay(); |
+ WaitForReads(); |
+ Close(); |
+} |
- MockAudioOutputControllerEventHandler event_handler; |
- base::WaitableEvent event(false, false); |
- EXPECT_CALL(event_handler, OnCreated(NotNull())) |
- .WillOnce(InvokeWithoutArgs(&event, &base::WaitableEvent::Signal)); |
- |
- // OnPlaying() will be called only once. |
- base::WaitableEvent play_event(false, false); |
- EXPECT_CALL(event_handler, OnPlaying(NotNull())) |
- .WillOnce(InvokeWithoutArgs(&play_event, &base::WaitableEvent::Signal)); |
- |
- // OnPaused() should never be called since the pause during kStarting is |
- // dropped when the second play comes in. |
- EXPECT_CALL(event_handler, OnPaused(NotNull())) |
- .Times(0); |
- |
- MockAudioOutputControllerSyncReader sync_reader; |
- EXPECT_CALL(sync_reader, UpdatePendingBytes(_)) |
- .Times(AtLeast(1)); |
- EXPECT_CALL(sync_reader, Read(_, _)) |
- .WillRepeatedly(DoAll(ClearBuffer(), SignalEvent(&event), Return(4))); |
- EXPECT_CALL(sync_reader, DataReady()) |
- .WillRepeatedly(Return(true)); |
- EXPECT_CALL(sync_reader, Close()); |
- |
- AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, |
- kSampleRate, kBitsPerSample, kSamplesPerPacket); |
- scoped_refptr<AudioOutputController> controller = |
- AudioOutputController::Create( |
- audio_manager.get(), &event_handler, params, &sync_reader); |
- ASSERT_TRUE(controller.get()); |
- |
- // Wait for OnCreated() to be called. |
- event.Wait(); |
- |
- ASSERT_FALSE(play_event.IsSignaled()); |
- controller->Play(); |
- controller->Pause(); |
- controller->Play(); |
- play_event.Wait(); |
- |
- // Now stop the controller. |
- CloseAudioController(controller); |
+TEST_F(AudioOutputControllerTest, PlayDivertRevertClose) { |
+ if (ShouldSkipTest()) |
+ return; |
+ ASSERT_TRUE(Create(kSamplesPerPacket)); |
+ WaitForCreate(); |
+ Play(); |
+ WaitForPlay(); |
+ WaitForReads(); |
+ Divert(); |
+ ReadDivertedAudioData(kBufferNonZeroData); |
+ Revert(true); |
+ WaitForPlay(); |
+ WaitForReads(); |
+ Close(); |
} |
-// Ensure state change events are handled. |
-TEST_F(AudioOutputControllerTest, PlayStateChangeClose) { |
- scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); |
- if (!audio_manager->HasAudioOutputDevices()) |
+TEST_F(AudioOutputControllerTest, DivertPlayPausePlayRevertClose) { |
+ if (ShouldSkipTest()) |
return; |
+ ASSERT_TRUE(Create(kSamplesPerPacket)); |
+ WaitForCreate(); |
+ Divert(); |
+ // Read back zeros before playback starts. |
+ ReadDivertedAudioData(kBufferZeroData); |
+ Play(); |
+ WaitForPlay(); |
+ // Normal read of audio data from renderer. |
+ ReadDivertedAudioData(kBufferNonZeroData); |
+ Pause(); |
+ WaitForPause(); |
+ // Read back zeros while paused. |
+ ReadDivertedAudioData(kBufferZeroData); |
+ Play(); |
+ WaitForPlay(); |
+ // Normal read of audio data from renderer again. |
+ ReadDivertedAudioData(kBufferNonZeroData); |
+ Revert(true); |
+ WaitForPlay(); |
+ WaitForReads(); |
+ Close(); |
+} |
- MockAudioOutputControllerEventHandler event_handler; |
- base::WaitableEvent event(false, false); |
- EXPECT_CALL(event_handler, OnCreated(NotNull())) |
- .WillOnce(InvokeWithoutArgs(&event, &base::WaitableEvent::Signal)); |
- |
- // OnPlaying() will be called once normally and once after being recreated. |
- base::WaitableEvent play_event(false, false); |
- EXPECT_CALL(event_handler, OnPlaying(NotNull())) |
- .Times(2) |
- .WillRepeatedly(InvokeWithoutArgs( |
- &play_event, &base::WaitableEvent::Signal)); |
- |
- // OnPaused() should not be called during the state change event. |
- EXPECT_CALL(event_handler, OnPaused(NotNull())) |
- .Times(0); |
- |
- MockAudioOutputControllerSyncReader sync_reader; |
- EXPECT_CALL(sync_reader, UpdatePendingBytes(_)) |
- .Times(AtLeast(1)); |
- EXPECT_CALL(sync_reader, Read(_, _)) |
- .WillRepeatedly(DoAll(ClearBuffer(), SignalEvent(&event), Return(4))); |
- EXPECT_CALL(sync_reader, DataReady()) |
- .WillRepeatedly(Return(true)); |
- EXPECT_CALL(sync_reader, Close()); |
- |
- AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, |
- kSampleRate, kBitsPerSample, kSamplesPerPacket); |
- scoped_refptr<AudioOutputController> controller = |
- AudioOutputController::Create( |
- audio_manager.get(), &event_handler, params, &sync_reader); |
- ASSERT_TRUE(controller.get()); |
- |
- // Wait for OnCreated() to be called. |
- event.Wait(); |
- |
- ASSERT_FALSE(play_event.IsSignaled()); |
- controller->Play(); |
- play_event.Wait(); |
- |
- // Force a state change and wait for the stream to come back to playing state. |
- play_event.Reset(); |
- audio_manager->GetMessageLoop()->PostTask(FROM_HERE, |
- base::Bind(&AudioOutputController::OnDeviceChange, controller)); |
- play_event.Wait(); |
- |
- // Now stop the controller. |
- CloseAudioController(controller); |
+TEST_F(AudioOutputControllerTest, DivertRevertClose) { |
+ if (ShouldSkipTest()) |
+ return; |
+ ASSERT_TRUE(Create(kSamplesPerPacket)); |
+ WaitForCreate(); |
+ Divert(); |
+ // Read back zeros since playback was not requested. |
+ ReadDivertedAudioData(kBufferZeroData); |
+ Revert(false); |
+ Close(); |
} |
} // namespace media |