blob: 794db51274705d1f5259098599c8c260e6c19891 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// 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_device.h"
#include <utility>
#include "base/memory/ptr_util.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/process/process_handle.h"
#include "base/run_loop.h"
#include "base/sync_socket.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::CancelableSyncSocket;
using base::SyncSocket;
using testing::_;
using testing::DoAll;
using testing::Invoke;
using testing::InvokeWithoutArgs;
namespace media {
namespace {
const size_t kMemorySegmentCount = 10u;
class MockAudioInputIPC : public AudioInputIPC {
public:
MockAudioInputIPC() = default;
~MockAudioInputIPC() override = default;
MOCK_METHOD4(CreateStream,
void(AudioInputIPCDelegate* delegate,
const AudioParameters& params,
bool automatic_gain_control,
uint32_t total_segments));
MOCK_METHOD0(RecordStream, void());
MOCK_METHOD1(SetVolume, void(double volume));
MOCK_METHOD1(SetOutputDeviceForAec, void(const std::string&));
MOCK_METHOD0(CloseStream, void());
};
class MockCaptureCallback : public AudioCapturerSource::CaptureCallback {
public:
MockCaptureCallback() = default;
~MockCaptureCallback() override = default;
MOCK_METHOD0(OnCaptureStarted, void());
MOCK_METHOD4(Capture,
void(const AudioBus* audio_source,
base::TimeTicks audio_capture_time,
double volume,
bool key_pressed));
MOCK_METHOD2(OnCaptureError,
void(AudioCapturerSource::ErrorCode code,
const std::string& message));
MOCK_METHOD1(OnCaptureMuted, void(bool is_muted));
};
} // namespace.
class AudioInputDeviceTest
: public ::testing::TestWithParam<AudioInputDevice::DeadStreamDetection> {};
// Regular construction.
TEST_P(AudioInputDeviceTest, Noop) {
base::test::SingleThreadTaskEnvironment task_environment(
base::test::SingleThreadTaskEnvironment::MainThreadType::IO);
MockAudioInputIPC* input_ipc = new MockAudioInputIPC();
scoped_refptr<AudioInputDevice> device(new AudioInputDevice(
base::WrapUnique(input_ipc), AudioInputDevice::Purpose::kUserInput,
AudioInputDeviceTest::GetParam()));
}
ACTION_P(ReportStateChange, device) {
static_cast<AudioInputIPCDelegate*>(device)->OnError(
media::AudioCapturerSource::ErrorCode::kUnknown);
}
// Verify that we get an OnCaptureError() callback if CreateStream fails.
TEST_P(AudioInputDeviceTest, FailToCreateStream) {
AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
ChannelLayoutConfig::Stereo(), 48000, 480);
MockCaptureCallback callback;
MockAudioInputIPC* input_ipc = new MockAudioInputIPC();
scoped_refptr<AudioInputDevice> device(new AudioInputDevice(
base::WrapUnique(input_ipc), AudioInputDevice::Purpose::kUserInput,
AudioInputDeviceTest::GetParam()));
device->Initialize(params, &callback);
EXPECT_CALL(*input_ipc, CreateStream(_, _, _, _))
.WillOnce(ReportStateChange(device.get()));
EXPECT_CALL(callback,
OnCaptureError(AudioCapturerSource::ErrorCode::kUnknown, _));
EXPECT_CALL(*input_ipc, CloseStream());
device->Start();
device->Stop();
}
TEST_P(AudioInputDeviceTest, CreateStream) {
AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
ChannelLayoutConfig::Stereo(), 48000, 480);
base::MappedReadOnlyRegion shared_memory;
CancelableSyncSocket browser_socket;
CancelableSyncSocket renderer_socket;
const uint32_t memory_size =
media::ComputeAudioInputBufferSize(params, kMemorySegmentCount);
shared_memory = base::ReadOnlySharedMemoryRegion::Create(memory_size);
ASSERT_TRUE(shared_memory.IsValid());
memset(shared_memory.mapping.memory(), 0xff, memory_size);
ASSERT_TRUE(
CancelableSyncSocket::CreatePair(&browser_socket, &renderer_socket));
base::ReadOnlySharedMemoryRegion duplicated_shared_memory_region =
shared_memory.region.Duplicate();
ASSERT_TRUE(duplicated_shared_memory_region.IsValid());
base::test::TaskEnvironment ste;
MockCaptureCallback callback;
MockAudioInputIPC* input_ipc = new MockAudioInputIPC();
scoped_refptr<AudioInputDevice> device(new AudioInputDevice(
base::WrapUnique(input_ipc), AudioInputDevice::Purpose::kUserInput,
AudioInputDeviceTest::GetParam()));
device->Initialize(params, &callback);
EXPECT_CALL(*input_ipc, CreateStream(_, _, _, _))
.WillOnce(InvokeWithoutArgs([&]() {
static_cast<AudioInputIPCDelegate*>(device.get())
->OnStreamCreated(std::move(duplicated_shared_memory_region),
renderer_socket.Take(), false);
}));
EXPECT_CALL(*input_ipc, RecordStream());
EXPECT_CALL(callback, OnCaptureStarted());
device->Start();
EXPECT_CALL(*input_ipc, CloseStream());
device->Stop();
}
INSTANTIATE_TEST_SUITE_P(
AudioInputDeviceGroup,
AudioInputDeviceTest,
::testing::Values(AudioInputDevice::DeadStreamDetection::kDisabled,
AudioInputDevice::DeadStreamDetection::kEnabled));
} // namespace media.