| Index: content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc
|
| diff --git a/content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc b/content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..74997b221d2cba40950e5c2554af392f8f8427aa
|
| --- /dev/null
|
| +++ b/content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc
|
| @@ -0,0 +1,571 @@
|
| +// Copyright 2016 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 "content/browser/renderer_host/media/audio_input_renderer_host.h"
|
| +
|
| +#include <vector>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/command_line.h"
|
| +#include "base/run_loop.h"
|
| +#include "content/browser/bad_message.h"
|
| +#include "content/browser/media/capture/audio_mirroring_manager.h"
|
| +#include "content/browser/renderer_host/media/audio_input_device_manager.h"
|
| +#include "content/browser/renderer_host/media/media_stream_manager.h"
|
| +#include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +#include "content/public/common/content_switches.h"
|
| +#include "content/public/test/mock_render_process_host.h"
|
| +#include "content/public/test/test_browser_context.h"
|
| +#include "content/public/test/test_browser_thread.h"
|
| +#include "content/public/test/test_browser_thread_bundle.h"
|
| +#include "media/audio/audio_device_description.h"
|
| +#include "media/audio/audio_input_writer.h"
|
| +#include "media/audio/fake_audio_log_factory.h"
|
| +#include "media/audio/fake_audio_manager.h"
|
| +#include "media/base/media_switches.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "url/gurl.h"
|
| +#include "url/origin.h"
|
| +
|
| +using ::media::AudioInputController;
|
| +using ::testing::_;
|
| +using ::testing::Assign;
|
| +using ::testing::InSequence;
|
| +using ::testing::Invoke;
|
| +using ::testing::Mock;
|
| +using ::testing::NotNull;
|
| +using ::testing::SaveArg;
|
| +using ::testing::StrictMock;
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +const int kStreamId = 100;
|
| +const int kRenderProcessId = 42;
|
| +const int kRendererPid = 21718;
|
| +const int kRenderFrameId = 31415;
|
| +const int kSharedMemoryCount = 11;
|
| +const char kSecurityOrigin[] = "http://localhost";
|
| +#if defined(OS_WIN)
|
| +const wchar_t kBaseFileName[] = L"some_file_name";
|
| +#else
|
| +const char kBaseFileName[] = "some_file_name";
|
| +#endif
|
| +
|
| +url::Origin SecurityOrigin() {
|
| + return url::Origin(GURL(kSecurityOrigin));
|
| +}
|
| +
|
| +AudioInputHostMsg_CreateStream_Config DefaultConfig() {
|
| + AudioInputHostMsg_CreateStream_Config config;
|
| + config.params = media::AudioParameters::UnavailableDeviceParams();
|
| + config.automatic_gain_control = false;
|
| + config.shared_memory_count = kSharedMemoryCount;
|
| + return config;
|
| +}
|
| +
|
| +class MockRenderer {
|
| + public:
|
| + MOCK_METHOD5(NotifyStreamCreated,
|
| + void(int /*stream_id*/,
|
| + base::SharedMemoryHandle /*handle*/,
|
| + base::SyncSocket::TransitDescriptor /*socket_desriptor*/,
|
| + uint32_t /*length*/,
|
| + uint32_t /*total_segments*/));
|
| + MOCK_METHOD2(NotifyStreamVolume, void(int /*stream_id*/, double /*volume*/));
|
| + MOCK_METHOD2(NotifyStreamStateChanged,
|
| + void(int /*stream_id*/,
|
| + media::AudioInputIPCDelegateState /*state*/));
|
| + MOCK_METHOD0(WasShutDown, void());
|
| +};
|
| +
|
| +// This class overrides Send to intercept the messages that the
|
| +// AudioInputRendererHost sends to the renderer. They are sent to
|
| +// the provided MockRenderer instead.
|
| +class AudioInputRendererHostWithInterception : public AudioInputRendererHost {
|
| + public:
|
| + AudioInputRendererHostWithInterception(
|
| + int render_process_id,
|
| + int32_t renderer_pid,
|
| + media::AudioManager* audio_manager,
|
| + MediaStreamManager* media_stream_manager,
|
| + AudioMirroringManager* audio_mirroring_manager,
|
| + media::UserInputMonitor* user_input_monitor,
|
| + MockRenderer* renderer)
|
| + : AudioInputRendererHost(render_process_id,
|
| + renderer_pid,
|
| + audio_manager,
|
| + media_stream_manager,
|
| + audio_mirroring_manager,
|
| + user_input_monitor),
|
| + renderer_(renderer) {
|
| + set_peer_process_for_testing(base::Process::Current());
|
| + }
|
| +
|
| + protected:
|
| + ~AudioInputRendererHostWithInterception() override = default;
|
| +
|
| + private:
|
| + bool Send(IPC::Message* message) override {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + bool handled = true;
|
| +
|
| + IPC_BEGIN_MESSAGE_MAP(AudioInputRendererHostWithInterception, *message)
|
| + IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamCreated,
|
| + NotifyRendererStreamCreated)
|
| + IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamVolume,
|
| + NotifyRendererStreamVolume)
|
| + IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamStateChanged,
|
| + NotifyRendererStreamStateChanged)
|
| + IPC_MESSAGE_UNHANDLED(handled = false)
|
| + IPC_END_MESSAGE_MAP()
|
| +
|
| + EXPECT_TRUE(handled);
|
| + delete message;
|
| + return true;
|
| + }
|
| +
|
| + void ShutdownForBadMessage() override { renderer_->WasShutDown(); }
|
| +
|
| + void NotifyRendererStreamCreated(
|
| + int stream_id,
|
| + base::SharedMemoryHandle handle,
|
| + base::SyncSocket::TransitDescriptor socket_descriptor,
|
| + uint32_t length,
|
| + uint32_t total_segments) {
|
| + // It's difficult to check that the sync socket and shared memory is
|
| + // valid in the gmock macros, so we check them here.
|
| + EXPECT_NE(base::SyncSocket::UnwrapHandle(socket_descriptor),
|
| + base::SyncSocket::kInvalidHandle);
|
| + base::SharedMemory memory(handle, /*read_only*/ true);
|
| + EXPECT_TRUE(memory.Map(length));
|
| + renderer_->NotifyStreamCreated(stream_id, handle, socket_descriptor, length,
|
| + total_segments);
|
| + EXPECT_TRUE(memory.Unmap());
|
| + memory.Close();
|
| + }
|
| +
|
| + void NotifyRendererStreamVolume(int stream_id, double volume) {
|
| + renderer_->NotifyStreamVolume(stream_id, volume);
|
| + }
|
| +
|
| + void NotifyRendererStreamStateChanged(
|
| + int stream_id,
|
| + media::AudioInputIPCDelegateState state) {
|
| + renderer_->NotifyStreamStateChanged(stream_id, state);
|
| + }
|
| +
|
| + MockRenderer* renderer_;
|
| +};
|
| +
|
| +class MockAudioInputController : public AudioInputController {
|
| + public:
|
| + MockAudioInputController(
|
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner,
|
| + AudioInputController::SyncWriter* writer,
|
| + media::AudioManager* audio_manager,
|
| + AudioInputController::EventHandler* event_handler,
|
| + media::UserInputMonitor* user_input_monitor)
|
| + : AudioInputController(event_handler,
|
| + writer,
|
| + /*debug_writer*/ nullptr,
|
| + user_input_monitor,
|
| + /*agc*/ false) {
|
| + task_runner_ = std::move(task_runner);
|
| + task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&AudioInputController::EventHandler::OnCreated,
|
| + base::Unretained(event_handler), base::Unretained(this)));
|
| + ON_CALL(*this, Close(_))
|
| + .WillByDefault(Invoke(this, &MockAudioInputController::ExecuteClose));
|
| + ON_CALL(*this, EnableDebugRecording(_))
|
| + .WillByDefault(SaveArg<0>(&file_name));
|
| + }
|
| +
|
| + EventHandler* handler() { return handler_; }
|
| +
|
| + // File name that we pretend to do a debug recording to, if any.
|
| + base::FilePath debug_file_name() { return file_name; }
|
| +
|
| + MOCK_METHOD0(Record, void());
|
| + MOCK_METHOD1(Close, void(const base::Closure&));
|
| + MOCK_METHOD1(SetVolume, void(double));
|
| + MOCK_METHOD1(EnableDebugRecording, void(const base::FilePath&));
|
| + MOCK_METHOD0(DisableDebugRecording, void());
|
| +
|
| + // AudioInputCallback impl, irrelevant to us.
|
| + MOCK_METHOD4(
|
| + OnData,
|
| + void(media::AudioInputStream*, const media::AudioBus*, uint32_t, double));
|
| + MOCK_METHOD1(OnError, void(media::AudioInputStream*));
|
| +
|
| + protected:
|
| + ~MockAudioInputController() override = default;
|
| +
|
| + private:
|
| + void ExecuteClose(const base::Closure& task) {
|
| + // Hop to audio manager thread before calling task, since this is the real
|
| + // behavior.
|
| + task_runner_->PostTaskAndReply(FROM_HERE, base::Bind([]() {}), task);
|
| + }
|
| +
|
| + base::FilePath file_name;
|
| +};
|
| +
|
| +class MockControllerFactory : public AudioInputController::Factory {
|
| + public:
|
| + using MockController = StrictMock<MockAudioInputController>;
|
| +
|
| + MockControllerFactory() {
|
| + AudioInputController::set_factory_for_testing(this);
|
| + }
|
| +
|
| + ~MockControllerFactory() override {
|
| + AudioInputController::set_factory_for_testing(nullptr);
|
| + }
|
| +
|
| + // AudioInputController::Factory implementaion:
|
| + AudioInputController* Create(
|
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner,
|
| + AudioInputController::SyncWriter* sync_writer,
|
| + media::AudioManager* audio_manager,
|
| + AudioInputController::EventHandler* event_handler,
|
| + media::AudioParameters params,
|
| + media::UserInputMonitor* user_input_monitor) override {
|
| + ControllerCreated();
|
| + scoped_refptr<MockController> controller =
|
| + new MockController(std::move(task_runner), sync_writer, audio_manager,
|
| + event_handler, user_input_monitor);
|
| + controller_list_.push_back(controller);
|
| + return controller.get();
|
| + }
|
| +
|
| + MockController* controller(size_t i) {
|
| + EXPECT_GT(controller_list_.size(), i);
|
| + return controller_list_[i].get();
|
| + }
|
| +
|
| + MOCK_METHOD0(ControllerCreated, void());
|
| +
|
| + private:
|
| + std::vector<scoped_refptr<MockController>> controller_list_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +class AudioInputRendererHostTest : public testing::Test {
|
| + public:
|
| + AudioInputRendererHostTest() {
|
| + base::CommandLine* flags = base::CommandLine::ForCurrentProcess();
|
| + flags->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
|
| + flags->AppendSwitch(switches::kUseFakeUIForMediaStream);
|
| +
|
| + audio_manager_.reset(new media::FakeAudioManager(
|
| + base::ThreadTaskRunnerHandle::Get(),
|
| + base::ThreadTaskRunnerHandle::Get(), &log_factory_));
|
| + media_stream_manager_ =
|
| + base::MakeUnique<MediaStreamManager>(audio_manager_.get());
|
| + airh_ = new AudioInputRendererHostWithInterception(
|
| + kRenderProcessId, kRendererPid, media::AudioManager::Get(),
|
| + media_stream_manager_.get(), AudioMirroringManager::GetInstance(),
|
| + nullptr, &renderer_);
|
| + }
|
| +
|
| + ~AudioInputRendererHostTest() override {
|
| + airh_->OnChannelClosing();
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + protected:
|
| + // Makes device |device_id| with name |name| available to open with the
|
| + // session id returned.
|
| + int Open(const std::string& device_id, const std::string& name) {
|
| + int session_id = media_stream_manager_->audio_input_device_manager()->Open(
|
| + StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE, name, device_id));
|
| + base::RunLoop().RunUntilIdle();
|
| + return session_id;
|
| + }
|
| +
|
| + std::string GetRawNondefaultId() {
|
| + std::string id;
|
| + MediaDevicesManager::BoolDeviceTypes devices_to_enumerate;
|
| + devices_to_enumerate[MEDIA_DEVICE_TYPE_AUDIO_INPUT] = true;
|
| +
|
| + media_stream_manager_->media_devices_manager()->EnumerateDevices(
|
| + devices_to_enumerate,
|
| + base::Bind(
|
| + [](std::string* id, const MediaDeviceEnumeration& result) {
|
| + // Index 0 is default, so use 1.
|
| + CHECK(result[MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_INPUT]
|
| + .size() > 1)
|
| + << "Expected to have a nondefault device.";
|
| + *id = result[MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_INPUT][1]
|
| + .device_id;
|
| + },
|
| + base::Unretained(&id)));
|
| + base::RunLoop().RunUntilIdle();
|
| + return id;
|
| + }
|
| +
|
| + media::FakeAudioLogFactory log_factory_;
|
| + StrictMock<MockControllerFactory> controller_factory_;
|
| + std::unique_ptr<MediaStreamManager> media_stream_manager_;
|
| + TestBrowserThreadBundle thread_bundle_;
|
| + media::ScopedAudioManagerPtr audio_manager_;
|
| + StrictMock<MockRenderer> renderer_;
|
| + scoped_refptr<AudioInputRendererHost> airh_;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(AudioInputRendererHostTest);
|
| +};
|
| +
|
| +// Checks that a controller is created and a reply is sent when creating a
|
| +// stream.
|
| +TEST_F(AudioInputRendererHostTest, CreateWithDefaultDevice) {
|
| + int session_id =
|
| + Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
|
| +
|
| + EXPECT_CALL(renderer_,
|
| + NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
|
| + EXPECT_CALL(controller_factory_, ControllerCreated());
|
| +
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
|
| + kStreamId, kRenderFrameId, session_id, DefaultConfig()));
|
| +
|
| + base::RunLoop().RunUntilIdle();
|
| + EXPECT_CALL(*controller_factory_.controller(0), Close(_));
|
| +}
|
| +
|
| +// If authorization hasn't been granted, only reply with and error and do
|
| +// nothing else.
|
| +TEST_F(AudioInputRendererHostTest, CreateWithoutAuthorization_Error) {
|
| + EXPECT_CALL(renderer_,
|
| + NotifyStreamStateChanged(
|
| + kStreamId, media::AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR));
|
| +
|
| + int session_id = 0;
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
|
| + kStreamId, kRenderFrameId, session_id, DefaultConfig()));
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +// Like CreateWithDefaultDevice but with a nondefault device.
|
| +TEST_F(AudioInputRendererHostTest, CreateWithNonDefaultDevice) {
|
| + int session_id = Open("Nondefault device", GetRawNondefaultId());
|
| +
|
| + EXPECT_CALL(renderer_,
|
| + NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
|
| + EXPECT_CALL(controller_factory_, ControllerCreated());
|
| +
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
|
| + kStreamId, kRenderFrameId, session_id, DefaultConfig()));
|
| +
|
| + base::RunLoop().RunUntilIdle();
|
| + EXPECT_CALL(*controller_factory_.controller(0), Close(_));
|
| +}
|
| +
|
| +// Checks that stream is started when calling record.
|
| +TEST_F(AudioInputRendererHostTest, CreateRecordClose) {
|
| + int session_id =
|
| + Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
|
| +
|
| + EXPECT_CALL(renderer_,
|
| + NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
|
| + EXPECT_CALL(controller_factory_, ControllerCreated());
|
| +
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
|
| + kStreamId, kRenderFrameId, session_id, DefaultConfig()));
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_CALL(*controller_factory_.controller(0), Record());
|
| + EXPECT_CALL(*controller_factory_.controller(0), Close(_));
|
| +
|
| + airh_->OnMessageReceived(AudioInputHostMsg_RecordStream(kStreamId));
|
| + base::RunLoop().RunUntilIdle();
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CloseStream(kStreamId));
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +// In addition to the above, also check that a SetVolume message is propagated
|
| +// to the controller.
|
| +TEST_F(AudioInputRendererHostTest, CreateSetVolumeRecordClose) {
|
| + int session_id =
|
| + Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
|
| +
|
| + EXPECT_CALL(renderer_,
|
| + NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
|
| + EXPECT_CALL(controller_factory_, ControllerCreated());
|
| +
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
|
| + kStreamId, kRenderFrameId, session_id, DefaultConfig()));
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_CALL(*controller_factory_.controller(0), SetVolume(0.5));
|
| + EXPECT_CALL(*controller_factory_.controller(0), Record());
|
| + EXPECT_CALL(*controller_factory_.controller(0), Close(_));
|
| +
|
| + airh_->OnMessageReceived(AudioInputHostMsg_SetVolume(kStreamId, 0.5));
|
| + airh_->OnMessageReceived(AudioInputHostMsg_RecordStream(kStreamId));
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CloseStream(kStreamId));
|
| +
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +// Check that a too large volume is treated like a bad message and doesn't
|
| +// reach the controller.
|
| +TEST_F(AudioInputRendererHostTest, SetVolumeTooLarge_BadMessage) {
|
| + int session_id =
|
| + Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
|
| +
|
| + EXPECT_CALL(renderer_,
|
| + NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
|
| + EXPECT_CALL(controller_factory_, ControllerCreated());
|
| +
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
|
| + kStreamId, kRenderFrameId, session_id, DefaultConfig()));
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_CALL(*controller_factory_.controller(0), Close(_));
|
| + EXPECT_CALL(renderer_, WasShutDown());
|
| +
|
| + airh_->OnMessageReceived(AudioInputHostMsg_SetVolume(kStreamId, 5));
|
| +
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +// Like above.
|
| +TEST_F(AudioInputRendererHostTest, SetVolumeNegative_BadMessage) {
|
| + int session_id =
|
| + Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
|
| +
|
| + EXPECT_CALL(renderer_,
|
| + NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
|
| + EXPECT_CALL(controller_factory_, ControllerCreated());
|
| +
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
|
| + kStreamId, kRenderFrameId, session_id, DefaultConfig()));
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_CALL(*controller_factory_.controller(0), Close(_));
|
| + EXPECT_CALL(renderer_, WasShutDown());
|
| +
|
| + airh_->OnMessageReceived(AudioInputHostMsg_SetVolume(kStreamId, -0.5));
|
| +
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +// Checks that a stream_id cannot be reused.
|
| +TEST_F(AudioInputRendererHostTest, CreateTwice_Error) {
|
| + int session_id =
|
| + Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
|
| +
|
| + EXPECT_CALL(renderer_,
|
| + NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
|
| + EXPECT_CALL(renderer_,
|
| + NotifyStreamStateChanged(
|
| + kStreamId, media::AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR));
|
| + EXPECT_CALL(controller_factory_, ControllerCreated());
|
| +
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
|
| + kStreamId, kRenderFrameId, session_id, DefaultConfig()));
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
|
| + kStreamId, kRenderFrameId, session_id, DefaultConfig()));
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_CALL(*controller_factory_.controller(0), Close(_));
|
| +}
|
| +
|
| +// Checks that when two streams are created, messages are routed to the correct
|
| +// stream. Also checks that when enabling debug recording, the streams get
|
| +// different file names.
|
| +TEST_F(AudioInputRendererHostTest, TwoStreams) {
|
| + int session_id =
|
| + Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
|
| +
|
| + EXPECT_CALL(renderer_,
|
| + NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
|
| + EXPECT_CALL(renderer_,
|
| + NotifyStreamCreated(kStreamId + 1, _, _, _, kSharedMemoryCount));
|
| + EXPECT_CALL(controller_factory_, ControllerCreated()).Times(2);
|
| +
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
|
| + kStreamId, kRenderFrameId, session_id, DefaultConfig()));
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
|
| + kStreamId + 1, kRenderFrameId, session_id, DefaultConfig()));
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| +#if BUILDFLAG(ENABLE_WEBRTC)
|
| + EXPECT_CALL(*controller_factory_.controller(0), EnableDebugRecording(_));
|
| + EXPECT_CALL(*controller_factory_.controller(1), EnableDebugRecording(_));
|
| +
|
| + airh_->EnableDebugRecording(base::FilePath(kBaseFileName));
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_NE(controller_factory_.controller(0)->debug_file_name(),
|
| + controller_factory_.controller(1)->debug_file_name());
|
| + EXPECT_CALL(*controller_factory_.controller(0), DisableDebugRecording());
|
| + EXPECT_CALL(*controller_factory_.controller(1), DisableDebugRecording());
|
| +
|
| + airh_->DisableDebugRecording();
|
| +#endif // ENABLE_WEBRTC
|
| +
|
| + EXPECT_CALL(*controller_factory_.controller(0), Close(_));
|
| + EXPECT_CALL(*controller_factory_.controller(1), Close(_));
|
| +}
|
| +
|
| +// Checks that the stream is properly cleaned up and a notification is sent to
|
| +// the renderer when the stream encounters an error.
|
| +TEST_F(AudioInputRendererHostTest, Error_ClosesController) {
|
| + int session_id =
|
| + Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
|
| +
|
| + EXPECT_CALL(renderer_,
|
| + NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
|
| + EXPECT_CALL(controller_factory_, ControllerCreated());
|
| +
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
|
| + kStreamId, kRenderFrameId, session_id, DefaultConfig()));
|
| +
|
| + base::RunLoop().RunUntilIdle();
|
| + EXPECT_CALL(*controller_factory_.controller(0), Close(_));
|
| + EXPECT_CALL(renderer_,
|
| + NotifyStreamStateChanged(
|
| + kStreamId, media::AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR));
|
| +
|
| + controller_factory_.controller(0)->handler()->OnError(
|
| + controller_factory_.controller(0), AudioInputController::UNKNOWN_ERROR);
|
| +
|
| + // Check Close expectation before the destructor.
|
| + base::RunLoop().RunUntilIdle();
|
| + Mock::VerifyAndClear(controller_factory_.controller(0));
|
| +}
|
| +
|
| +// Checks that tab capture streams can be created.
|
| +TEST_F(AudioInputRendererHostTest, TabCaptureStream) {
|
| + StreamControls controls(/* request_audio */ true, /* request_video */ false);
|
| + controls.audio.device_id = base::StringPrintf(
|
| + "web-contents-media-stream://%d:%d", kRenderProcessId, kRenderFrameId);
|
| + controls.audio.stream_source = kMediaStreamSourceTab;
|
| + std::string request_label = media_stream_manager_->MakeMediaAccessRequest(
|
| + kRenderProcessId, kRenderFrameId, 0, controls, SecurityOrigin(),
|
| + base::Bind([](const MediaStreamDevices& devices,
|
| + std::unique_ptr<MediaStreamUIProxy>) {}));
|
| + base::RunLoop().RunUntilIdle();
|
| + int session_id = Open("Tab capture", controls.audio.device_id);
|
| +
|
| + EXPECT_CALL(renderer_,
|
| + NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
|
| + EXPECT_CALL(controller_factory_, ControllerCreated());
|
| +
|
| + airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
|
| + kStreamId, kRenderFrameId, session_id, DefaultConfig()));
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_CALL(*controller_factory_.controller(0), Close(_));
|
| +}
|
| +
|
| +} // namespace content
|
|
|