| // Copyright (c) 2017 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/memory/ptr_util.h" |
| #include "base/memory/shared_memory.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/process/process_handle.h" |
| #include "base/run_loop.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/sync_socket.h" |
| #include "media/audio/audio_input_device.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gmock_mutant.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using base::CancelableSyncSocket; |
| using base::SharedMemory; |
| using base::SyncSocket; |
| using testing::_; |
| using testing::DoAll; |
| using testing::Invoke; |
| |
| namespace media { |
| |
| namespace { |
| |
| class MockAudioInputIPC : public AudioInputIPC { |
| public: |
| MockAudioInputIPC() {} |
| ~MockAudioInputIPC() override {} |
| |
| MOCK_METHOD5(CreateStream, |
| void(AudioInputIPCDelegate* delegate, |
| int session_id, |
| const AudioParameters& params, |
| bool automatic_gain_control, |
| uint32_t total_segments)); |
| MOCK_METHOD0(RecordStream, void()); |
| MOCK_METHOD1(SetVolume, void(double volume)); |
| MOCK_METHOD0(CloseStream, void()); |
| }; |
| |
| class MockCaptureCallback : public AudioCapturerSource::CaptureCallback { |
| public: |
| MockCaptureCallback() {} |
| ~MockCaptureCallback() override {} |
| |
| MOCK_METHOD0(OnCaptureStarted, void()); |
| MOCK_METHOD4(Capture, |
| void(const AudioBus* audio_source, |
| int audio_delay_milliseconds, |
| double volume, |
| bool key_pressed)); |
| |
| MOCK_METHOD1(OnCaptureError, void(const std::string& message)); |
| }; |
| |
| // Used to terminate a loop from a different thread than the loop belongs to. |
| // |task_runner| should be a SingleThreadTaskRunner. |
| ACTION_P(QuitLoop, task_runner) { |
| task_runner->PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); |
| } |
| |
| } // namespace. |
| |
| // Regular construction. |
| TEST(AudioInputDeviceTest, Noop) { |
| base::MessageLoopForIO io_loop; |
| MockAudioInputIPC* input_ipc = new MockAudioInputIPC(); |
| scoped_refptr<AudioInputDevice> device( |
| new AudioInputDevice(base::WrapUnique(input_ipc), io_loop.task_runner())); |
| } |
| |
| ACTION_P(ReportStateChange, device) { |
| static_cast<AudioInputIPCDelegate*>(device)->OnError(); |
| } |
| |
| // Verify that we get an OnCaptureError() callback if CreateStream fails. |
| TEST(AudioInputDeviceTest, FailToCreateStream) { |
| AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, |
| CHANNEL_LAYOUT_STEREO, 48000, 16, 480); |
| |
| base::MessageLoopForIO io_loop; |
| MockCaptureCallback callback; |
| MockAudioInputIPC* input_ipc = new MockAudioInputIPC(); |
| scoped_refptr<AudioInputDevice> device( |
| new AudioInputDevice(base::WrapUnique(input_ipc), io_loop.task_runner())); |
| device->Initialize(params, &callback, 1); |
| device->Start(); |
| EXPECT_CALL(*input_ipc, CreateStream(_, _, _, _, _)) |
| .WillOnce(ReportStateChange(device.get())); |
| EXPECT_CALL(callback, OnCaptureError(_)) |
| .WillOnce(QuitLoop(io_loop.task_runner())); |
| base::RunLoop().Run(); |
| } |
| |
| ACTION_P5(ReportOnStreamCreated, device, handle, socket, length, segments) { |
| static_cast<AudioInputIPCDelegate*>(device)->OnStreamCreated( |
| handle, socket, length, segments); |
| } |
| |
| TEST(AudioInputDeviceTest, CreateStream) { |
| AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, |
| CHANNEL_LAYOUT_STEREO, 48000, 16, 480); |
| SharedMemory shared_memory; |
| CancelableSyncSocket browser_socket; |
| CancelableSyncSocket renderer_socket; |
| |
| const int memory_size = sizeof(AudioInputBufferParameters) + |
| AudioBus::CalculateMemorySize(params); |
| |
| ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(memory_size)); |
| memset(shared_memory.memory(), 0xff, memory_size); |
| |
| ASSERT_TRUE( |
| CancelableSyncSocket::CreatePair(&browser_socket, &renderer_socket)); |
| SyncSocket::TransitDescriptor audio_device_socket_descriptor; |
| ASSERT_TRUE(renderer_socket.PrepareTransitDescriptor( |
| base::GetCurrentProcessHandle(), &audio_device_socket_descriptor)); |
| base::SharedMemoryHandle duplicated_memory_handle; |
| ASSERT_TRUE(shared_memory.ShareToProcess(base::GetCurrentProcessHandle(), |
| &duplicated_memory_handle)); |
| |
| base::MessageLoopForIO io_loop; |
| MockCaptureCallback callback; |
| MockAudioInputIPC* input_ipc = new MockAudioInputIPC(); |
| scoped_refptr<AudioInputDevice> device( |
| new AudioInputDevice(base::WrapUnique(input_ipc), io_loop.task_runner())); |
| device->Initialize(params, &callback, 1); |
| device->Start(); |
| |
| EXPECT_CALL(*input_ipc, CreateStream(_, _, _, _, _)) |
| .WillOnce(ReportOnStreamCreated( |
| device.get(), duplicated_memory_handle, |
| SyncSocket::UnwrapHandle(audio_device_socket_descriptor), memory_size, |
| 1)); |
| EXPECT_CALL(*input_ipc, RecordStream()); |
| EXPECT_CALL(callback, OnCaptureStarted()) |
| .WillOnce(QuitLoop(io_loop.task_runner())); |
| base::RunLoop().Run(); |
| } |
| } // namespace media. |