blob: fe29ce59af3f969a10191e1b5742cbe64acfd389 [file] [log] [blame]
// 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 "base/bind.h"
#include "base/environment.h"
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/synchronization/waitable_event.h"
#include "media/audio/audio_output_controller.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;
namespace media {
static const int kSampleRate = AudioParameters::kAudioCDSampleRate;
static const int kBitsPerSample = 16;
static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
static const int kSamplesPerPacket = kSampleRate / 10;
static const int kHardwareBufferSize = kSamplesPerPacket *
ChannelLayoutToChannelCount(kChannelLayout) * kBitsPerSample / 8;
class MockAudioOutputControllerEventHandler
: public AudioOutputController::EventHandler {
public:
MockAudioOutputControllerEventHandler() {}
MOCK_METHOD1(OnCreated, void(AudioOutputController* controller));
MOCK_METHOD1(OnPlaying, void(AudioOutputController* controller));
MOCK_METHOD1(OnPaused, void(AudioOutputController* controller));
MOCK_METHOD2(OnError, void(AudioOutputController* controller,
int error_code));
private:
DISALLOW_COPY_AND_ASSIGN(MockAudioOutputControllerEventHandler);
};
class MockAudioOutputControllerSyncReader
: public AudioOutputController::SyncReader {
public:
MockAudioOutputControllerSyncReader() {}
MOCK_METHOD1(UpdatePendingBytes, void(uint32 bytes));
MOCK_METHOD2(Read, int(AudioBus* source, AudioBus* dest));
MOCK_METHOD0(Close, void());
MOCK_METHOD0(DataReady, bool());
private:
DISALLOW_COPY_AND_ASSIGN(MockAudioOutputControllerSyncReader);
};
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();
}
class AudioOutputControllerTest : public testing::Test {
public:
AudioOutputControllerTest() {}
virtual ~AudioOutputControllerTest() {}
protected:
MessageLoopForIO message_loop_;
private:
DISALLOW_COPY_AND_ASSIGN(AudioOutputControllerTest);
};
TEST_F(AudioOutputControllerTest, CreateAndClose) {
scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
if (!audio_manager->HasAudioOutputDevices())
return;
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());
// Close the controller immediately.
CloseAudioController(controller);
}
TEST_F(AudioOutputControllerTest, PlayPauseClose) {
scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
if (!audio_manager->HasAudioOutputDevices())
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);
}
TEST_F(AudioOutputControllerTest, HardwareBufferTooLarge) {
scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
if (!audio_manager->HasAudioOutputDevices())
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);
}
TEST_F(AudioOutputControllerTest, PlayPausePlayClose) {
scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
if (!audio_manager->HasAudioOutputDevices())
return;
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);
}
// Ensure state change events are handled.
TEST_F(AudioOutputControllerTest, PlayStateChangeClose) {
scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
if (!audio_manager->HasAudioOutputDevices())
return;
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);
}
} // namespace media