blob: 77c35f1e0f9b4f0c5c727061f513d1f4014e7f71 [file] [log] [blame]
// Copyright 2019 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/command_line.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/service_manager_connection.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "media/base/media_switches.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/video_capture/public/cpp/mock_receiver.h"
#include "services/video_capture/public/mojom/constants.mojom.h"
#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
#include "services/video_capture/public/mojom/video_source.mojom.h"
#include "services/video_capture/public/mojom/video_source_provider.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
using testing::_;
using testing::AtLeast;
using testing::Invoke;
using testing::InvokeWithoutArgs;
using testing::Return;
namespace content {
namespace {
static const char kVideoCaptureHtmlFile[] = "/media/video_capture_test.html";
static const char kStartVideoCaptureAndVerify[] =
"startVideoCaptureAndVerifySize(%d, %d)";
static const gfx::Size kVideoSize(320, 200);
} // namespace
// Integration test sets up a single fake device and obtains a connection to the
// video capture service via the Browser process' service manager. It then
// opens the device from clients. One client is the test calling into the
// video capture service directly. The second client is the Browser, which the
// test exercises through JavaScript.
class WebRtcVideoCaptureSharedDeviceBrowserTest : public ContentBrowserTest {
public:
WebRtcVideoCaptureSharedDeviceBrowserTest() : weak_factory_(this) {
scoped_feature_list_.InitAndEnableFeature(features::kMojoVideoCapture);
}
~WebRtcVideoCaptureSharedDeviceBrowserTest() override {}
void OpenDeviceViaService(
media::VideoCaptureBufferType buffer_type_to_request,
base::OnceClosure done_cb) {
connector_->BindInterface(video_capture::mojom::kServiceName,
&device_factory_provider_);
device_factory_provider_->ConnectToVideoSourceProvider(
mojo::MakeRequest(&video_source_provider_));
video_source_provider_->GetSourceInfos(base::BindOnce(
&WebRtcVideoCaptureSharedDeviceBrowserTest::OnSourceInfosReceived,
weak_factory_.GetWeakPtr(), buffer_type_to_request,
std::move(done_cb)));
}
void OpenDeviceInRendererAndWaitForPlaying() {
DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
embedded_test_server()->StartAcceptingConnections();
GURL url(embedded_test_server()->GetURL(kVideoCaptureHtmlFile));
NavigateToURL(shell(), url);
const std::string javascript_to_execute = base::StringPrintf(
kStartVideoCaptureAndVerify, kVideoSize.width(), kVideoSize.height());
std::string result;
// Start video capture and wait until it started rendering
ASSERT_TRUE(
ExecuteScriptAndExtractString(shell(), javascript_to_execute, &result));
ASSERT_EQ("OK", result);
}
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
command_line->AppendSwitch(switches::kUseFakeUIForMediaStream);
}
void SetUp() override {
ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
EnablePixelOutput();
ContentBrowserTest::SetUp();
}
void Initialize() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
main_task_runner_ = base::ThreadTaskRunnerHandle::Get();
auto* connection = content::ServiceManagerConnection::GetForProcess();
ASSERT_TRUE(connection);
auto* connector = connection->GetConnector();
ASSERT_TRUE(connector);
// We need to clone it so that we can use the clone on a different thread.
connector_ = connector->Clone();
mock_receiver_ = std::make_unique<video_capture::MockReceiver>(
mojo::MakeRequest(&receiver_proxy_));
}
scoped_refptr<base::TaskRunner> main_task_runner_;
std::unique_ptr<service_manager::Connector> connector_;
std::unique_ptr<video_capture::MockReceiver> mock_receiver_;
private:
void OnSourceInfosReceived(
media::VideoCaptureBufferType buffer_type_to_request,
base::OnceClosure done_cb,
const std::vector<media::VideoCaptureDeviceInfo>& infos) {
ASSERT_FALSE(infos.empty());
video_source_provider_->GetVideoSource(infos[0].descriptor.device_id,
mojo::MakeRequest(&video_source_));
media::VideoCaptureParams requestable_settings;
ASSERT_FALSE(infos[0].supported_formats.empty());
requestable_settings.requested_format = infos[0].supported_formats[0];
requestable_settings.requested_format.frame_size = kVideoSize;
requestable_settings.buffer_type = buffer_type_to_request;
video_capture::mojom::PushVideoStreamSubscriptionPtr subscription;
video_source_->CreatePushSubscription(
std::move(receiver_proxy_), requestable_settings,
false /*force_reopen_with_new_settings*/,
mojo::MakeRequest(&subscription_),
base::BindOnce(&WebRtcVideoCaptureSharedDeviceBrowserTest::
OnCreatePushSubscriptionCallback,
weak_factory_.GetWeakPtr(), std::move(done_cb)));
}
void OnCreatePushSubscriptionCallback(
base::OnceClosure done_cb,
video_capture::mojom::CreatePushSubscriptionResultCode result_code,
const media::VideoCaptureParams& params) {
ASSERT_NE(video_capture::mojom::CreatePushSubscriptionResultCode::kFailed,
result_code);
subscription_->Activate();
std::move(done_cb).Run();
}
base::test::ScopedFeatureList scoped_feature_list_;
video_capture::mojom::DeviceFactoryProviderPtr device_factory_provider_;
video_capture::mojom::VideoSourceProviderPtr video_source_provider_;
video_capture::mojom::VideoSourcePtr video_source_;
video_capture::mojom::PushVideoStreamSubscriptionPtr subscription_;
video_capture::mojom::ReceiverPtr receiver_proxy_;
base::WeakPtrFactory<WebRtcVideoCaptureSharedDeviceBrowserTest> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(WebRtcVideoCaptureSharedDeviceBrowserTest);
};
// Tests that a single fake video capture device can be opened via JavaScript
// by the Renderer while it is already in use by a direct client of the
// video capture service.
IN_PROC_BROWSER_TEST_F(
WebRtcVideoCaptureSharedDeviceBrowserTest,
ReceiveFrameInRendererWhileDeviceAlreadyInUseViaDirectServiceClient) {
Initialize();
base::RunLoop receive_frame_from_service_wait_loop;
ON_CALL(*mock_receiver_, DoOnNewBuffer(_, _))
.WillByDefault(Invoke(
[](int32_t, media::mojom::VideoBufferHandlePtr* buffer_handle) {
ASSERT_EQ(
media::mojom::VideoBufferHandle::Tag::SHARED_BUFFER_HANDLE,
(*buffer_handle)->which());
}));
EXPECT_CALL(*mock_receiver_, DoOnFrameReadyInBuffer(_, _, _, _))
.WillOnce(InvokeWithoutArgs([&receive_frame_from_service_wait_loop]() {
receive_frame_from_service_wait_loop.Quit();
}))
.WillRepeatedly(Return());
base::RunLoop open_device_via_service_run_loop;
OpenDeviceViaService(media::VideoCaptureBufferType::kSharedMemory,
open_device_via_service_run_loop.QuitClosure());
open_device_via_service_run_loop.Run();
OpenDeviceInRendererAndWaitForPlaying();
receive_frame_from_service_wait_loop.Run();
}
#if defined(OS_LINUX)
// Tests that a single fake video capture device can be opened via JavaScript
// by the Renderer while it is already in use by a direct client of the
// video capture service that requested to get buffers as raw file handles.
IN_PROC_BROWSER_TEST_F(
WebRtcVideoCaptureSharedDeviceBrowserTest,
ReceiveFrameInRendererWhileDeviceAlreadyInUseUsingRawFileHandleBuffers) {
Initialize();
base::RunLoop receive_frame_from_service_wait_loop;
ON_CALL(*mock_receiver_, DoOnNewBuffer(_, _))
.WillByDefault(Invoke(
[](int32_t, media::mojom::VideoBufferHandlePtr* buffer_handle) {
ASSERT_EQ(media::mojom::VideoBufferHandle::Tag::
SHARED_MEMORY_VIA_RAW_FILE_DESCRIPTOR,
(*buffer_handle)->which());
}));
EXPECT_CALL(*mock_receiver_, DoOnFrameReadyInBuffer(_, _, _, _))
.WillOnce(InvokeWithoutArgs([&receive_frame_from_service_wait_loop]() {
receive_frame_from_service_wait_loop.Quit();
}))
.WillRepeatedly(Return());
base::RunLoop open_device_via_service_run_loop;
OpenDeviceViaService(
media::VideoCaptureBufferType::kSharedMemoryViaRawFileDescriptor,
open_device_via_service_run_loop.QuitClosure());
open_device_via_service_run_loop.Run();
OpenDeviceInRendererAndWaitForPlaying();
receive_frame_from_service_wait_loop.Run();
}
// Tests that a single fake video capture device can be opened by a direct
// client of the video capture service that requests to get buffers as raw
// file handles while it is already in use via JavaScript by the Renderer.
IN_PROC_BROWSER_TEST_F(
WebRtcVideoCaptureSharedDeviceBrowserTest,
ReceiveFrameFromServiceViaRawFileHandlesWhileDeviceAlreadyInUseByRenderer) {
Initialize();
OpenDeviceInRendererAndWaitForPlaying();
base::RunLoop receive_frame_from_service_wait_loop;
ON_CALL(*mock_receiver_, DoOnNewBuffer(_, _))
.WillByDefault(Invoke(
[](int32_t, media::mojom::VideoBufferHandlePtr* buffer_handle) {
ASSERT_EQ(media::mojom::VideoBufferHandle::Tag::
SHARED_MEMORY_VIA_RAW_FILE_DESCRIPTOR,
(*buffer_handle)->which());
}));
EXPECT_CALL(*mock_receiver_, DoOnFrameReadyInBuffer(_, _, _, _))
.WillOnce(InvokeWithoutArgs([&receive_frame_from_service_wait_loop]() {
receive_frame_from_service_wait_loop.Quit();
}))
.WillRepeatedly(Return());
base::RunLoop open_device_via_service_run_loop;
OpenDeviceViaService(
media::VideoCaptureBufferType::kSharedMemoryViaRawFileDescriptor,
open_device_via_service_run_loop.QuitClosure());
open_device_via_service_run_loop.Run();
receive_frame_from_service_wait_loop.Run();
}
#endif // defined(OS_LINUX)
} // namespace content