blob: 1499f18012365ca24f3b3a181b4020bce6f430d7 [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 "media/audio/audio_input_controller.h"
#include <memory>
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/timer/timer.h"
#include "media/audio/audio_manager.h"
#include "media/audio/fake_audio_input_stream.h"
#include "media/audio/test_audio_thread.h"
#include "media/base/user_input_monitor.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::AtLeast;
using ::testing::Exactly;
using ::testing::InvokeWithoutArgs;
using ::testing::NotNull;
using base::WaitableEvent;
namespace media {
namespace {
const int kSampleRate = AudioParameters::kAudioCDSampleRate;
const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
const int kSamplesPerPacket = kSampleRate / 10;
const double kMaxVolume = 1.0;
// AudioInputController will poll once every second, so wait at most a bit
// more than that for the callbacks.
constexpr base::TimeDelta kOnMuteWaitTimeout =
base::TimeDelta::FromMilliseconds(1500);
// Runs |quit_closure| after the |count| of calls reaches |limit|.
ACTION_P3(CheckCountAndPostQuitTask, count, limit, quit_closure) {
if (++*count >= limit)
quit_closure.Run();
}
void RunLoopWithTimeout(base::RunLoop* run_loop, base::TimeDelta timeout) {
base::OneShotTimer timeout_timer;
timeout_timer.Start(FROM_HERE, timeout, run_loop->QuitClosure());
run_loop->Run();
}
} // namespace
class MockAudioInputControllerEventHandler
: public AudioInputController::EventHandler {
public:
MockAudioInputControllerEventHandler() = default;
void OnLog(base::StringPiece) override {}
MOCK_METHOD1(OnCreated, void(bool initially_muted));
MOCK_METHOD1(OnError, void(AudioInputController::ErrorCode error_code));
MOCK_METHOD1(OnMuted, void(bool is_muted));
private:
DISALLOW_COPY_AND_ASSIGN(MockAudioInputControllerEventHandler);
};
class MockSyncWriter : public AudioInputController::SyncWriter {
public:
MockSyncWriter() = default;
MOCK_METHOD4(Write,
void(const AudioBus* data,
double volume,
bool key_pressed,
base::TimeTicks capture_time));
MOCK_METHOD0(Close, void());
};
class MockUserInputMonitor : public UserInputMonitor {
public:
MockUserInputMonitor() = default;
uint32_t GetKeyPressCount() const override { return 0; }
MOCK_METHOD0(EnableKeyPressMonitoring, void());
MOCK_METHOD0(DisableKeyPressMonitoring, void());
};
class MockAudioInputStream : public AudioInputStream {
public:
MockAudioInputStream() {}
~MockAudioInputStream() override {}
void Start(AudioInputCallback*) override {}
void Stop() override {}
void Close() override {}
double GetMaxVolume() override { return kMaxVolume; }
double GetVolume() override { return 0; }
bool SetAutomaticGainControl(bool) override { return false; }
bool GetAutomaticGainControl() override { return false; }
bool IsMuted() override { return false; }
void SetOutputDeviceForAec(const std::string&) override {}
MOCK_METHOD0(Open, bool());
MOCK_METHOD1(SetVolume, void(double));
};
class AudioInputControllerTest : public testing::TestWithParam<bool> {
public:
AudioInputControllerTest()
: run_on_audio_thread_(GetParam()),
audio_manager_(AudioManager::CreateForTesting(
std::make_unique<TestAudioThread>(!run_on_audio_thread_))),
params_(AudioParameters::AUDIO_FAKE,
kChannelLayout,
kSampleRate,
kSamplesPerPacket) {}
~AudioInputControllerTest() override {
audio_manager_->Shutdown();
base::RunLoop().RunUntilIdle();
}
protected:
void CreateAudioController() {
controller_ = AudioInputController::Create(
audio_manager_.get(), &event_handler_, &sync_writer_,
&user_input_monitor_, params_, AudioDeviceDescription::kDefaultDeviceId,
false);
}
void CloseAudioController() {
if (run_on_audio_thread_) {
controller_->Close(base::OnceClosure());
return;
}
base::RunLoop run_loop;
controller_->Close(run_loop.QuitClosure());
run_loop.Run();
}
base::MessageLoop message_loop_;
// Parameterize tests to run AudioInputController either on audio thread
// (synchronously), or on a different thread (non-blocking).
bool run_on_audio_thread_;
scoped_refptr<AudioInputController> controller_;
std::unique_ptr<AudioManager> audio_manager_;
MockAudioInputControllerEventHandler event_handler_;
MockSyncWriter sync_writer_;
MockUserInputMonitor user_input_monitor_;
AudioParameters params_;
MockAudioInputStream stream_;
private:
DISALLOW_COPY_AND_ASSIGN(AudioInputControllerTest);
};
TEST_P(AudioInputControllerTest, CreateAndCloseWithoutRecording) {
EXPECT_CALL(event_handler_, OnCreated(_));
CreateAudioController();
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(controller_.get());
EXPECT_CALL(sync_writer_, Close());
CloseAudioController();
}
// Test a normal call sequence of create, record and close.
TEST_P(AudioInputControllerTest, CreateRecordAndClose) {
int count = 0;
EXPECT_CALL(event_handler_, OnCreated(_));
CreateAudioController();
ASSERT_TRUE(controller_.get());
// Write() should be called ten times.
base::RunLoop run_loop;
EXPECT_CALL(sync_writer_, Write(NotNull(), _, _, _))
.Times(AtLeast(10))
.WillRepeatedly(
CheckCountAndPostQuitTask(&count, 10, run_loop.QuitClosure()));
EXPECT_CALL(user_input_monitor_, EnableKeyPressMonitoring());
controller_->Record();
// Record and wait until ten Write() callbacks are received.
run_loop.Run();
EXPECT_CALL(user_input_monitor_, DisableKeyPressMonitoring());
EXPECT_CALL(sync_writer_, Close());
CloseAudioController();
}
TEST_P(AudioInputControllerTest, CloseTwice) {
EXPECT_CALL(event_handler_, OnCreated(_));
CreateAudioController();
ASSERT_TRUE(controller_.get());
EXPECT_CALL(user_input_monitor_, EnableKeyPressMonitoring());
controller_->Record();
EXPECT_CALL(user_input_monitor_, DisableKeyPressMonitoring());
EXPECT_CALL(sync_writer_, Close());
CloseAudioController();
CloseAudioController();
}
// Test that AudioInputController sends OnMute callbacks properly.
TEST_P(AudioInputControllerTest, TestOnmutedCallbackInitiallyUnmuted) {
const auto timeout = kOnMuteWaitTimeout;
WaitableEvent callback_event(WaitableEvent::ResetPolicy::AUTOMATIC,
WaitableEvent::InitialState::NOT_SIGNALED);
base::RunLoop unmute_run_loop;
base::RunLoop mute_run_loop;
base::RunLoop setup_run_loop;
EXPECT_CALL(event_handler_, OnCreated(false)).WillOnce(InvokeWithoutArgs([&] {
setup_run_loop.QuitWhenIdle();
}));
EXPECT_CALL(sync_writer_, Close());
EXPECT_CALL(event_handler_, OnMuted(true)).WillOnce(InvokeWithoutArgs([&] {
mute_run_loop.Quit();
}));
EXPECT_CALL(event_handler_, OnMuted(false)).WillOnce(InvokeWithoutArgs([&] {
unmute_run_loop.Quit();
}));
FakeAudioInputStream::SetGlobalMutedState(false);
CreateAudioController();
ASSERT_TRUE(controller_.get());
RunLoopWithTimeout(&setup_run_loop, timeout);
FakeAudioInputStream::SetGlobalMutedState(true);
RunLoopWithTimeout(&mute_run_loop, timeout);
FakeAudioInputStream::SetGlobalMutedState(false);
RunLoopWithTimeout(&unmute_run_loop, timeout);
CloseAudioController();
}
TEST_P(AudioInputControllerTest, TestOnmutedCallbackInitiallyMuted) {
const auto timeout = kOnMuteWaitTimeout;
WaitableEvent callback_event(WaitableEvent::ResetPolicy::AUTOMATIC,
WaitableEvent::InitialState::NOT_SIGNALED);
base::RunLoop unmute_run_loop;
base::RunLoop setup_run_loop;
EXPECT_CALL(event_handler_, OnCreated(true)).WillOnce(InvokeWithoutArgs([&] {
setup_run_loop.QuitWhenIdle();
}));
EXPECT_CALL(sync_writer_, Close());
EXPECT_CALL(event_handler_, OnMuted(false)).WillOnce(InvokeWithoutArgs([&] {
unmute_run_loop.Quit();
}));
FakeAudioInputStream::SetGlobalMutedState(true);
CreateAudioController();
ASSERT_TRUE(controller_.get());
RunLoopWithTimeout(&setup_run_loop, timeout);
FakeAudioInputStream::SetGlobalMutedState(false);
RunLoopWithTimeout(&unmute_run_loop, timeout);
CloseAudioController();
}
TEST_P(AudioInputControllerTest, CreateForStream) {
EXPECT_CALL(event_handler_, OnCreated(_));
EXPECT_CALL(stream_, Open()).WillOnce(InvokeWithoutArgs([] { return true; }));
controller_ = AudioInputController::CreateForStream(
audio_manager_->GetTaskRunner(), &event_handler_, &stream_, &sync_writer_,
&user_input_monitor_);
EXPECT_CALL(sync_writer_, Close());
CloseAudioController();
}
TEST_P(AudioInputControllerTest, SetVolume) {
EXPECT_CALL(event_handler_, OnCreated(_));
EXPECT_CALL(stream_, Open()).WillOnce(InvokeWithoutArgs([] { return true; }));
controller_ = AudioInputController::CreateForStream(
audio_manager_->GetTaskRunner(), &event_handler_, &stream_, &sync_writer_,
&user_input_monitor_);
const double volume = 0.5;
EXPECT_CALL(stream_, SetVolume(volume));
controller_->SetVolume(volume);
EXPECT_CALL(sync_writer_, Close());
CloseAudioController();
}
INSTANTIATE_TEST_SUITE_P(SyncAsync, AudioInputControllerTest, testing::Bool());
} // namespace media