| // 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. |