Commit 00025a37 authored by Christian Fremerey's avatar Christian Fremerey Committed by Commit Bot

Reland "[Video Capture] Switch usage in Chromium Browser process to the new multi-client API"

This is a reland of 86e7aa88

Revert was due to flaky test failures on MacOS 10.12.
The flakiness already existed before this CL.
The flaky test has been disabled.
https://chromium-review.googlesource.com/c/chromium/src/+/1501213

This reland is identical to the original attempt.

TBR=emircan@chromium.org, meacer@chromium.org

Original change's description:
> [Video Capture] Switch usage in Chromium Browser process to the new multi-client API
>
> The video capture service offers a new API for opening capture devices
> in a way that allows them to be shared by multiple clients. This CL
> switches one such client, i.e. the Chromium Browser process, over to
> that new API. This enables other clients to share access to capture
> devices with the Chromium Browser process.
>
> Design Doc: https://docs.google.com/document/d/1mYnsZfLBRmbsDpUtfb6C7dzhfw2Kcxg_-uiG_6MnWVQ/edit?usp=sharing
>
> Test: content_browsertests --gtest_filter=WebRtcVideoCaptureSharedDeviceBrowserTest.*
> Bug: 783442
> Change-Id: I9c236f03e315cdafdc07429f3213fa4d11b43b34
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1399454
> Commit-Queue: Christian Fremerey <chfremer@chromium.org>
> Reviewed-by: Mustafa Emre Acer <meacer@chromium.org>
> Reviewed-by: Emircan Uysaler <emircan@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#637405}

Bug: 783442
Change-Id: I7dca38334bc78e400daa311fa0444173add9548d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1504230
Commit-Queue: Christian Fremerey <chfremer@chromium.org>
Reviewed-by: default avatarMustafa Emre Acer <meacer@chromium.org>
Reviewed-by: default avatarChristian Fremerey <chfremer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#637873}
parent fb96126c
......@@ -1492,8 +1492,8 @@ jumbo_source_set("browser") {
"renderer_host/media/old_render_frame_audio_output_stream_factory.h",
"renderer_host/media/peer_connection_tracker_host.cc",
"renderer_host/media/peer_connection_tracker_host.h",
"renderer_host/media/ref_counted_video_capture_factory.cc",
"renderer_host/media/ref_counted_video_capture_factory.h",
"renderer_host/media/ref_counted_video_source_provider.cc",
"renderer_host/media/ref_counted_video_source_provider.h",
"renderer_host/media/render_frame_audio_input_stream_factory.cc",
"renderer_host/media/render_frame_audio_input_stream_factory.h",
"renderer_host/media/render_frame_audio_output_stream_factory.cc",
......
......@@ -2,34 +2,34 @@
// 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/ref_counted_video_capture_factory.h"
#include "content/browser/renderer_host/media/ref_counted_video_source_provider.h"
namespace content {
RefCountedVideoCaptureFactory::RefCountedVideoCaptureFactory(
video_capture::mojom::DeviceFactoryPtr device_factory,
RefCountedVideoSourceProvider::RefCountedVideoSourceProvider(
video_capture::mojom::VideoSourceProviderPtr source_provider,
video_capture::mojom::DeviceFactoryProviderPtr device_factory_provider,
base::OnceClosure destruction_cb)
: device_factory_(std::move(device_factory)),
: source_provider_(std::move(source_provider)),
device_factory_provider_(std::move(device_factory_provider)),
destruction_cb_(std::move(destruction_cb)),
weak_ptr_factory_(this) {}
RefCountedVideoCaptureFactory::~RefCountedVideoCaptureFactory() {
RefCountedVideoSourceProvider::~RefCountedVideoSourceProvider() {
std::move(destruction_cb_).Run();
}
base::WeakPtr<RefCountedVideoCaptureFactory>
RefCountedVideoCaptureFactory::GetWeakPtr() {
base::WeakPtr<RefCountedVideoSourceProvider>
RefCountedVideoSourceProvider::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void RefCountedVideoCaptureFactory::ShutdownServiceAsap() {
void RefCountedVideoSourceProvider::ShutdownServiceAsap() {
device_factory_provider_->ShutdownServiceAsap();
}
void RefCountedVideoCaptureFactory::ReleaseFactoryForTesting() {
device_factory_.reset();
void RefCountedVideoSourceProvider::ReleaseProviderForTesting() {
source_provider_.reset();
}
} // namespace content
......@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_REF_COUNTED_VIDEO_CAPTURE_FACTORY_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_REF_COUNTED_VIDEO_CAPTURE_FACTORY_H_
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_REF_COUNTED_VIDEO_SOURCE_PROVIDER_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_REF_COUNTED_VIDEO_SOURCE_PROVIDER_H_
#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
#include "services/video_capture/public/mojom/device_factory.mojom.h"
#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
#include "services/video_capture/public/mojom/video_source_provider.mojom.h"
namespace content {
......@@ -17,36 +17,35 @@ namespace content {
// Since instances of this class do not guarantee that the connection stays open
// for its entire lifetime, clients must verify that the connection is bound
// before using it.
class CONTENT_EXPORT RefCountedVideoCaptureFactory
: public base::RefCounted<RefCountedVideoCaptureFactory> {
class CONTENT_EXPORT RefCountedVideoSourceProvider
: public base::RefCounted<RefCountedVideoSourceProvider> {
public:
RefCountedVideoCaptureFactory(
video_capture::mojom::DeviceFactoryPtr device_factory,
RefCountedVideoSourceProvider(
video_capture::mojom::VideoSourceProviderPtr source_provider,
video_capture::mojom::DeviceFactoryProviderPtr device_factory_provider,
base::OnceClosure destruction_cb);
base::WeakPtr<RefCountedVideoCaptureFactory> GetWeakPtr();
base::WeakPtr<RefCountedVideoSourceProvider> GetWeakPtr();
const video_capture::mojom::DeviceFactoryPtr& device_factory() {
return device_factory_;
const video_capture::mojom::VideoSourceProviderPtr& source_provider() {
return source_provider_;
}
void ShutdownServiceAsap();
void ReleaseFactoryForTesting();
void ReleaseProviderForTesting();
private:
friend class base::RefCounted<RefCountedVideoCaptureFactory>;
~RefCountedVideoCaptureFactory();
friend class base::RefCounted<RefCountedVideoSourceProvider>;
~RefCountedVideoSourceProvider();
video_capture::mojom::DeviceFactoryPtr device_factory_;
video_capture::mojom::VideoSourceProviderPtr source_provider_;
video_capture::mojom::DeviceFactoryProviderPtr device_factory_provider_;
base::OnceClosure destruction_cb_;
base::WeakPtrFactory<RefCountedVideoCaptureFactory> weak_ptr_factory_;
base::WeakPtrFactory<RefCountedVideoSourceProvider> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(RefCountedVideoCaptureFactory);
DISALLOW_COPY_AND_ASSIGN(RefCountedVideoSourceProvider);
};
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_REF_COUNTED_VIDEO_CAPTURE_FACTORY_H_
#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_REF_COUNTED_VIDEO_SOURCE_PROVIDER_H_
......@@ -3,19 +3,29 @@
// found in the LICENSE file.
#include "content/browser/renderer_host/media/service_launched_video_capture_device.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
namespace content {
ServiceLaunchedVideoCaptureDevice::ServiceLaunchedVideoCaptureDevice(
video_capture::mojom::DevicePtr device,
video_capture::mojom::VideoSourcePtr source,
video_capture::mojom::PushVideoStreamSubscriptionPtr subscription,
base::OnceClosure connection_lost_cb)
: device_(std::move(device)),
: source_(std::move(source)),
subscription_(std::move(subscription)),
connection_lost_cb_(std::move(connection_lost_cb)) {
// Unretained |this| is safe, because |this| owns |device_|.
device_.set_connection_error_handler(base::BindOnce(
&ServiceLaunchedVideoCaptureDevice::OnLostConnectionToDevice,
base::Unretained(this)));
// Unretained |this| is safe, because |this| owns |source_|.
source_.set_connection_error_handler(
base::BindOnce(&ServiceLaunchedVideoCaptureDevice::
OnLostConnectionToSourceOrSubscription,
base::Unretained(this)));
// Unretained |this| is safe, because |this| owns |subscription_|.
subscription_.set_connection_error_handler(
base::BindOnce(&ServiceLaunchedVideoCaptureDevice::
OnLostConnectionToSourceOrSubscription,
base::Unretained(this)));
}
ServiceLaunchedVideoCaptureDevice::~ServiceLaunchedVideoCaptureDevice() {
......@@ -25,7 +35,7 @@ ServiceLaunchedVideoCaptureDevice::~ServiceLaunchedVideoCaptureDevice() {
void ServiceLaunchedVideoCaptureDevice::GetPhotoState(
media::VideoCaptureDevice::GetPhotoStateCallback callback) const {
DCHECK(sequence_checker_.CalledOnValidSequence());
device_->GetPhotoState(base::BindOnce(
subscription_->GetPhotoState(base::BindOnce(
&ServiceLaunchedVideoCaptureDevice::OnGetPhotoStateResponse,
base::Unretained(this), std::move(callback)));
}
......@@ -34,7 +44,7 @@ void ServiceLaunchedVideoCaptureDevice::SetPhotoOptions(
media::mojom::PhotoSettingsPtr settings,
media::VideoCaptureDevice::SetPhotoOptionsCallback callback) {
DCHECK(sequence_checker_.CalledOnValidSequence());
device_->SetPhotoOptions(
subscription_->SetPhotoOptions(
std::move(settings),
base::BindOnce(
&ServiceLaunchedVideoCaptureDevice::OnSetPhotoOptionsResponse,
......@@ -47,23 +57,25 @@ void ServiceLaunchedVideoCaptureDevice::TakePhoto(
TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
"ServiceLaunchedVideoCaptureDevice::TakePhoto",
TRACE_EVENT_SCOPE_PROCESS);
device_->TakePhoto(
subscription_->TakePhoto(
base::BindOnce(&ServiceLaunchedVideoCaptureDevice::OnTakePhotoResponse,
base::Unretained(this), std::move(callback)));
}
void ServiceLaunchedVideoCaptureDevice::MaybeSuspendDevice() {
DCHECK(sequence_checker_.CalledOnValidSequence());
device_->MaybeSuspend();
subscription_->Suspend(base::DoNothing());
}
void ServiceLaunchedVideoCaptureDevice::ResumeDevice() {
DCHECK(sequence_checker_.CalledOnValidSequence());
device_->Resume();
subscription_->Resume();
}
void ServiceLaunchedVideoCaptureDevice::RequestRefreshFrame() {
// Ignore this call.
DCHECK(sequence_checker_.CalledOnValidSequence());
// Nothing to do here. The video capture service does not support refresh
// frames.
}
void ServiceLaunchedVideoCaptureDevice::SetDesktopCaptureWindowIdAsync(
......@@ -78,11 +90,16 @@ void ServiceLaunchedVideoCaptureDevice::SetDesktopCaptureWindowIdAsync(
void ServiceLaunchedVideoCaptureDevice::OnUtilizationReport(
int frame_feedback_id,
double utilization) {
// Ignore this call.
DCHECK(sequence_checker_.CalledOnValidSequence());
// Nothing to do here. The video capture service does not support utilization
// reporting.
}
void ServiceLaunchedVideoCaptureDevice::OnLostConnectionToDevice() {
void ServiceLaunchedVideoCaptureDevice::
OnLostConnectionToSourceOrSubscription() {
DCHECK(sequence_checker_.CalledOnValidSequence());
source_.reset();
subscription_.reset();
base::ResetAndReturn(&connection_lost_cb_).Run();
}
......
......@@ -7,7 +7,7 @@
#include "content/browser/renderer_host/media/video_capture_provider.h"
#include "content/public/browser/video_capture_device_launcher.h"
#include "services/video_capture/public/mojom/device.mojom.h"
#include "services/video_capture/public/mojom/video_source.mojom.h"
namespace content {
......@@ -15,8 +15,10 @@ namespace content {
// service.
class ServiceLaunchedVideoCaptureDevice : public LaunchedVideoCaptureDevice {
public:
ServiceLaunchedVideoCaptureDevice(video_capture::mojom::DevicePtr device,
base::OnceClosure connection_lost_cb);
ServiceLaunchedVideoCaptureDevice(
video_capture::mojom::VideoSourcePtr source,
video_capture::mojom::PushVideoStreamSubscriptionPtr subscription,
base::OnceClosure connection_lost_cb);
~ServiceLaunchedVideoCaptureDevice() override;
// LaunchedVideoCaptureDevice implementation.
......@@ -37,7 +39,7 @@ class ServiceLaunchedVideoCaptureDevice : public LaunchedVideoCaptureDevice {
void OnUtilizationReport(int frame_feedback_id, double utilization) override;
private:
void OnLostConnectionToDevice();
void OnLostConnectionToSourceOrSubscription();
void OnGetPhotoStateResponse(
media::VideoCaptureDevice::GetPhotoStateCallback callback,
media::mojom::PhotoStatePtr capabilities) const;
......@@ -48,7 +50,8 @@ class ServiceLaunchedVideoCaptureDevice : public LaunchedVideoCaptureDevice {
media::VideoCaptureDevice::TakePhotoCallback callback,
media::mojom::BlobPtr blob);
video_capture::mojom::DevicePtr device_;
video_capture::mojom::VideoSourcePtr source_;
video_capture::mojom::PushVideoStreamSubscriptionPtr subscription_;
base::OnceClosure connection_lost_cb_;
base::SequenceChecker sequence_checker_;
};
......
......@@ -20,37 +20,26 @@ namespace content {
namespace {
void ConcludeLaunchDeviceWithSuccess(
const media::VideoCaptureParams& params,
video_capture::mojom::DevicePtr device,
base::WeakPtr<media::VideoFrameReceiver> receiver,
video_capture::mojom::VideoSourcePtr source,
video_capture::mojom::PushVideoStreamSubscriptionPtr subscription,
base::OnceClosure connection_lost_cb,
VideoCaptureDeviceLauncher::Callbacks* callbacks,
base::OnceClosure done_cb) {
auto receiver_adapter =
std::make_unique<video_capture::ReceiverMediaToMojoAdapter>(
std::make_unique<media::VideoFrameReceiverOnTaskRunner>(
std::move(receiver), base::CreateSingleThreadTaskRunnerWithTraits(
{BrowserThread::IO})));
video_capture::mojom::ReceiverPtr receiver_proxy;
mojo::MakeStrongBinding<video_capture::mojom::Receiver>(
std::move(receiver_adapter), mojo::MakeRequest(&receiver_proxy));
media::VideoCaptureParams new_params = params;
new_params.power_line_frequency =
media::VideoCaptureDevice::GetPowerLineFrequency(params);
device->Start(new_params, std::move(receiver_proxy));
subscription->Activate();
callbacks->OnDeviceLaunched(
std::make_unique<ServiceLaunchedVideoCaptureDevice>(
std::move(device), std::move(connection_lost_cb)));
std::move(source), std::move(subscription),
std::move(connection_lost_cb)));
base::ResetAndReturn(&done_cb).Run();
}
void ConcludeLaunchDeviceWithFailure(
bool abort_requested,
media::VideoCaptureError error,
scoped_refptr<RefCountedVideoCaptureFactory> device_factory,
scoped_refptr<RefCountedVideoSourceProvider> service_connection,
VideoCaptureDeviceLauncher::Callbacks* callbacks,
base::OnceClosure done_cb) {
device_factory.reset();
service_connection.reset();
if (abort_requested)
callbacks->OnDeviceLaunchAborted();
else
......@@ -61,8 +50,8 @@ void ConcludeLaunchDeviceWithFailure(
} // anonymous namespace
ServiceVideoCaptureDeviceLauncher::ServiceVideoCaptureDeviceLauncher(
ConnectToDeviceFactoryCB connect_to_device_factory_cb)
: connect_to_device_factory_cb_(std::move(connect_to_device_factory_cb)),
ConnectToDeviceFactoryCB connect_to_source_provider_cb)
: connect_to_source_provider_cb_(std::move(connect_to_source_provider_cb)),
state_(State::READY_TO_LAUNCH),
callbacks_(nullptr) {}
......@@ -88,16 +77,14 @@ void ServiceVideoCaptureDeviceLauncher::LaunchDeviceAsync(
return;
}
connect_to_device_factory_cb_.Run(&device_factory_);
if (!device_factory_->device_factory().is_bound()) {
// This can happen when the ServiceVideoCaptureProvider owning
// |device_factory_| loses connection to the service process and resets
// |device_factory_|.
connect_to_source_provider_cb_.Run(&service_connection_);
if (!service_connection_->source_provider().is_bound()) {
// This can happen when the connection to the service was lost.
ConcludeLaunchDeviceWithFailure(
false,
media::VideoCaptureError::
kServiceDeviceLauncherLostConnectionToDeviceFactoryDuringDeviceStart,
std::move(device_factory_), callbacks, std::move(done_cb));
std::move(service_connection_), callbacks, std::move(done_cb));
return;
}
......@@ -105,32 +92,62 @@ void ServiceVideoCaptureDeviceLauncher::LaunchDeviceAsync(
std::ostringstream string_stream;
string_stream
<< "ServiceVideoCaptureDeviceLauncher::LaunchDeviceAsync: Asking "
"video capture service to create device for device_id = "
"video capture service to create source for device_id = "
<< device_id;
receiver->OnLog(string_stream.str());
}
video_capture::mojom::DevicePtr device;
auto device_request = mojo::MakeRequest(&device);
// Ownership of |done_cb| is moved to |this|. It is not sufficient to attach
// it to the callback passed to |device_factory_->CreateDevice()|, because
// |device_factory_| may get torn down before the callback is invoked.
// it to the callback passed to CreatePushSubscription(), because the
// connection to the service may get torn down before |callbacks| are
// invoked.
done_cb_ = std::move(done_cb);
callbacks_ = callbacks;
video_capture::mojom::VideoSourcePtr source;
service_connection_->source_provider()->GetVideoSource(
device_id, mojo::MakeRequest(&source));
auto receiver_adapter =
std::make_unique<video_capture::ReceiverMediaToMojoAdapter>(
std::make_unique<media::VideoFrameReceiverOnTaskRunner>(
std::move(receiver), base::CreateSingleThreadTaskRunnerWithTraits(
{BrowserThread::IO})));
video_capture::mojom::ReceiverPtr receiver_proxy;
mojo::MakeStrongBinding<video_capture::mojom::Receiver>(
std::move(receiver_adapter), mojo::MakeRequest(&receiver_proxy));
video_capture::mojom::PushVideoStreamSubscriptionPtr subscription;
// Create message pipe so that we can subsequently call
// subscription.set_connection_error_handler().
auto subscription_request = mojo::MakeRequest(&subscription);
// Use of Unretained(this) is safe, because |done_cb_| guarantees that |this|
// stays alive.
device.set_connection_error_handler(
subscription.set_connection_error_handler(
base::BindOnce(&ServiceVideoCaptureDeviceLauncher::
OnConnectionLostWhileWaitingForCallback,
base::Unretained(this)));
device_factory_->device_factory()->CreateDevice(
device_id, std::move(device_request),
// TODO(crbug.com/925083)
media::VideoCaptureParams new_params = params;
new_params.power_line_frequency =
media::VideoCaptureDevice::GetPowerLineFrequency(params);
// Note that we set |force_reopen_with_new_settings| to true in order
// to avoid the situation that a requests to open (or reopen) a device
// that has just been closed with different settings ends up getting the old
// settings, because from the perspective of the service, the device was still
// in use. In order to be able to set |force_reopen_with_new_settings|, we
// have to refactor code here and upstream to wait for a callback from the
// service indicating that the device closing is complete.
source->CreatePushSubscription(
std::move(receiver_proxy), new_params,
true /*force_reopen_with_new_settings*/, std::move(subscription_request),
base::BindOnce(
// Use of Unretained |this| is safe, because |done_cb_| guarantees
// that |this| stays alive.
&ServiceVideoCaptureDeviceLauncher::OnCreateDeviceCallback,
base::Unretained(this), params, std::move(device),
std::move(receiver), std::move(connection_lost_cb)));
&ServiceVideoCaptureDeviceLauncher::OnCreatePushSubscriptionCallback,
base::Unretained(this), std::move(source), std::move(subscription),
std::move(connection_lost_cb)));
state_ = State::DEVICE_START_IN_PROGRESS;
}
......@@ -140,40 +157,43 @@ void ServiceVideoCaptureDeviceLauncher::AbortLaunch() {
state_ = State::DEVICE_START_ABORTING;
}
void ServiceVideoCaptureDeviceLauncher::OnCreateDeviceCallback(
const media::VideoCaptureParams& params,
video_capture::mojom::DevicePtr device,
base::WeakPtr<media::VideoFrameReceiver> receiver,
void ServiceVideoCaptureDeviceLauncher::OnCreatePushSubscriptionCallback(
video_capture::mojom::VideoSourcePtr source,
video_capture::mojom::PushVideoStreamSubscriptionPtr subscription,
base::OnceClosure connection_lost_cb,
video_capture::mojom::DeviceAccessResultCode result_code) {
video_capture::mojom::CreatePushSubscriptionResultCode result_code,
const media::VideoCaptureParams& params) {
DCHECK(sequence_checker_.CalledOnValidSequence());
DCHECK(callbacks_);
DCHECK(done_cb_);
device.set_connection_error_handler(base::DoNothing());
subscription.set_connection_error_handler(base::DoNothing());
const bool abort_requested = (state_ == State::DEVICE_START_ABORTING);
state_ = State::READY_TO_LAUNCH;
Callbacks* callbacks = callbacks_;
callbacks_ = nullptr;
switch (result_code) {
case video_capture::mojom::DeviceAccessResultCode::SUCCESS:
case video_capture::mojom::CreatePushSubscriptionResultCode::
kCreatedWithRequestedSettings: // Fall through.
case video_capture::mojom::CreatePushSubscriptionResultCode::
kCreatedWithDifferentSettings:
if (abort_requested) {
device.reset();
device_factory_.reset();
subscription.reset();
source.reset();
service_connection_.reset();
callbacks->OnDeviceLaunchAborted();
base::ResetAndReturn(&done_cb_).Run();
return;
}
ConcludeLaunchDeviceWithSuccess(
params, std::move(device), std::move(receiver),
std::move(source), std::move(subscription),
std::move(connection_lost_cb), callbacks, std::move(done_cb_));
return;
case video_capture::mojom::DeviceAccessResultCode::ERROR_DEVICE_NOT_FOUND:
case video_capture::mojom::DeviceAccessResultCode::NOT_INITIALIZED:
case video_capture::mojom::CreatePushSubscriptionResultCode::kFailed:
ConcludeLaunchDeviceWithFailure(
abort_requested,
media::VideoCaptureError::
kServiceDeviceLauncherServiceRespondedWithDeviceNotFound,
std::move(device_factory_), callbacks, std::move(done_cb_));
std::move(service_connection_), callbacks, std::move(done_cb_));
return;
}
}
......@@ -190,7 +210,7 @@ void ServiceVideoCaptureDeviceLauncher::
abort_requested,
media::VideoCaptureError::
kServiceDeviceLauncherConnectionLostWhileWaitingForCallback,
std::move(device_factory_), callbacks, std::move(done_cb_));
std::move(service_connection_), callbacks, std::move(done_cb_));
}
} // namespace content
......@@ -5,7 +5,7 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_SERVICE_VIDEO_CAPTURE_DEVICE_LAUNCHER_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_SERVICE_VIDEO_CAPTURE_DEVICE_LAUNCHER_H_
#include "content/browser/renderer_host/media/ref_counted_video_capture_factory.h"
#include "content/browser/renderer_host/media/ref_counted_video_source_provider.h"
#include "content/browser/renderer_host/media/video_capture_provider.h"
#include "content/public/browser/video_capture_device_launcher.h"
#include "services/video_capture/public/mojom/device_factory.mojom.h"
......@@ -18,12 +18,12 @@ namespace content {
class CONTENT_EXPORT ServiceVideoCaptureDeviceLauncher
: public VideoCaptureDeviceLauncher {
public:
// Receives an instance via output parameter |factory|.
// Receives an instance via output parameter |out_provider|.
using ConnectToDeviceFactoryCB = base::RepeatingCallback<void(
scoped_refptr<RefCountedVideoCaptureFactory>*)>;
scoped_refptr<RefCountedVideoSourceProvider>* out_provider)>;
explicit ServiceVideoCaptureDeviceLauncher(
ConnectToDeviceFactoryCB connect_to_device_factory_cb);
ConnectToDeviceFactoryCB connect_to_source_provider_cb);
~ServiceVideoCaptureDeviceLauncher() override;
// VideoCaptureDeviceLauncher implementation.
......@@ -45,17 +45,17 @@ class CONTENT_EXPORT ServiceVideoCaptureDeviceLauncher
DEVICE_START_ABORTING
};
void OnCreateDeviceCallback(
const media::VideoCaptureParams& params,
video_capture::mojom::DevicePtr device,
base::WeakPtr<media::VideoFrameReceiver> receiver,
void OnCreatePushSubscriptionCallback(
video_capture::mojom::VideoSourcePtr source,
video_capture::mojom::PushVideoStreamSubscriptionPtr subscription,
base::OnceClosure connection_lost_cb,
video_capture::mojom::DeviceAccessResultCode result_code);
video_capture::mojom::CreatePushSubscriptionResultCode result_code,
const media::VideoCaptureParams& params);
void OnConnectionLostWhileWaitingForCallback();
ConnectToDeviceFactoryCB connect_to_device_factory_cb_;
scoped_refptr<RefCountedVideoCaptureFactory> device_factory_;
ConnectToDeviceFactoryCB connect_to_source_provider_cb_;
scoped_refptr<RefCountedVideoSourceProvider> service_connection_;
State state_;
base::SequenceChecker sequence_checker_;
base::OnceClosure done_cb_;
......
......@@ -9,17 +9,20 @@
#include "base/run_loop.h"
#include "base/test/mock_callback.h"
#include "base/threading/thread.h"
#include "content/browser/renderer_host/media/ref_counted_video_capture_factory.h"
#include "content/browser/renderer_host/media/ref_counted_video_source_provider.h"
#include "content/browser/renderer_host/media/service_launched_video_capture_device.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/video_capture/public/cpp/mock_device_factory.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/video_capture/public/cpp/mock_push_subscription.h"
#include "services/video_capture/public/cpp/mock_video_source.h"
#include "services/video_capture/public/cpp/mock_video_source_provider.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::Invoke;
using testing::InvokeWithoutArgs;
using testing::_;
namespace content {
......@@ -46,46 +49,87 @@ class ServiceVideoCaptureDeviceLauncherTest : public testing::Test {
ServiceVideoCaptureDeviceLauncherTest() {}
~ServiceVideoCaptureDeviceLauncherTest() override {}
void CloseSourceBinding() { source_binding_.reset(); }
void CloseSubscriptionBindings() {
subscription_bindings_.CloseAllBindings();
}
protected:
void SetUp() override {
video_capture::mojom::DeviceFactoryPtr device_factory;
factory_binding_ =
std::make_unique<mojo::Binding<video_capture::mojom::DeviceFactory>>(
&mock_device_factory_, mojo::MakeRequest(&device_factory));
factory_delegate_ = base::MakeRefCounted<RefCountedVideoCaptureFactory>(
std::move(device_factory),
source_provider_binding_ = std::make_unique<
mojo::Binding<video_capture::mojom::VideoSourceProvider>>(
&mock_source_provider_, mojo::MakeRequest(&source_provider_));
service_connection_ = base::MakeRefCounted<RefCountedVideoSourceProvider>(
std::move(source_provider_),
video_capture::mojom::DeviceFactoryProviderPtr(),
release_connection_cb_.Get());
launcher_ = std::make_unique<ServiceVideoCaptureDeviceLauncher>(
connect_to_device_factory_cb_.Get());
launcher_has_connected_to_device_factory_ = false;
launcher_has_released_device_factory_ = false;
launcher_has_connected_to_source_provider_ = false;
launcher_has_released_source_provider_ = false;
ON_CALL(connect_to_device_factory_cb_, Run(_))
.WillByDefault(Invoke(
[this](scoped_refptr<RefCountedVideoCaptureFactory>* out_factory) {
launcher_has_connected_to_device_factory_ = true;
*out_factory = factory_delegate_;
[this](scoped_refptr<RefCountedVideoSourceProvider>* out_provider) {
launcher_has_connected_to_source_provider_ = true;
*out_provider = service_connection_;
}));
ON_CALL(release_connection_cb_, Run())
.WillByDefault(InvokeWithoutArgs([this]() {
launcher_has_released_device_factory_ = true;
launcher_has_released_source_provider_ = true;
wait_for_release_connection_cb_.Quit();
}));
ON_CALL(mock_source_provider_, DoGetVideoSource(kStubDeviceId, _))
.WillByDefault(Invoke(
[this](const std::string& device_id,
video_capture::mojom::VideoSourceRequest* source_request) {
source_binding_ = std::make_unique<
mojo::Binding<video_capture::mojom::VideoSource>>(
&mock_source_, std::move(*source_request));
}));
ON_CALL(mock_source_, DoCreatePushSubscription(_, _, _, _, _))
.WillByDefault(Invoke(
[this](video_capture::mojom::ReceiverPtr& subscriber,
const media::VideoCaptureParams& requested_settings,
bool force_reopen_with_new_settings,
video_capture::mojom::PushVideoStreamSubscriptionRequest&
subscription,
video_capture::mojom::VideoSource::
CreatePushSubscriptionCallback& callback) {
subscription_bindings_.AddBinding(&mock_subscription_,
std::move(subscription));
std::move(callback).Run(
video_capture::mojom::CreatePushSubscriptionResultCode::
kCreatedWithRequestedSettings,
requested_settings);
}));
}
void TearDown() override {}
void RunLaunchingDeviceIsAbortedTest(
video_capture::mojom::DeviceAccessResultCode service_result_code);
video_capture::mojom::CreatePushSubscriptionResultCode
service_result_code);
void RunConnectionLostAfterSuccessfulStartTest(
base::OnceClosure close_connection_cb);
TestBrowserThreadBundle thread_bundle_;
video_capture::MockDeviceFactory mock_device_factory_;
MockVideoCaptureDeviceLauncherCallbacks mock_callbacks_;
std::unique_ptr<mojo::Binding<video_capture::mojom::DeviceFactory>>
factory_binding_;
video_capture::mojom::VideoSourceProviderPtr source_provider_;
video_capture::MockVideoSourceProvider mock_source_provider_;
std::unique_ptr<mojo::Binding<video_capture::mojom::VideoSourceProvider>>
source_provider_binding_;
video_capture::MockVideoSource mock_source_;
std::unique_ptr<mojo::Binding<video_capture::mojom::VideoSource>>
source_binding_;
video_capture::MockPushSubcription mock_subscription_;
mojo::BindingSet<video_capture::mojom::PushVideoStreamSubscription>
subscription_bindings_;
std::unique_ptr<ServiceVideoCaptureDeviceLauncher> launcher_;
base::MockCallback<base::OnceClosure> connection_lost_cb_;
base::MockCallback<base::OnceClosure> done_cb_;
......@@ -93,11 +137,11 @@ class ServiceVideoCaptureDeviceLauncherTest : public testing::Test {
ServiceVideoCaptureDeviceLauncher::ConnectToDeviceFactoryCB>
connect_to_device_factory_cb_;
base::MockCallback<base::OnceClosure> release_connection_cb_;
// |factory_delegate_| needs to go below |release_connection_cb_|, because its
// destructor will call |release_connection_cb_|.
scoped_refptr<RefCountedVideoCaptureFactory> factory_delegate_;
bool launcher_has_connected_to_device_factory_;
bool launcher_has_released_device_factory_;
// |service_connection_| needs to go below |release_connection_cb_|, because
// its destructor will call |release_connection_cb_|.
scoped_refptr<RefCountedVideoSourceProvider> service_connection_;
bool launcher_has_connected_to_source_provider_;
bool launcher_has_released_source_provider_;
base::RunLoop wait_for_release_connection_cb_;
private:
......@@ -105,26 +149,6 @@ class ServiceVideoCaptureDeviceLauncherTest : public testing::Test {
};
TEST_F(ServiceVideoCaptureDeviceLauncherTest, LaunchingDeviceSucceeds) {
EXPECT_CALL(mock_device_factory_, DoCreateDevice(kStubDeviceId, _, _))
.WillOnce(Invoke([](const std::string& device_id,
video_capture::mojom::DeviceRequest* device_request,
video_capture::mojom::DeviceFactory::
CreateDeviceCallback& callback) {
// Note: We must keep |device_request| alive at least until we have
// sent out the callback. Otherwise, |launcher_| may interpret this
// as the connection having been lost before receiving the callback.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(
[](video_capture::mojom::DeviceRequest device_request,
video_capture::mojom::DeviceFactory::CreateDeviceCallback
callback) {
std::move(callback).Run(
video_capture::mojom::DeviceAccessResultCode::SUCCESS);
},
std::move(*device_request), std::move(callback)));
}));
EXPECT_CALL(mock_callbacks_, DoOnDeviceLaunched(_)).Times(1);
EXPECT_CALL(mock_callbacks_, OnDeviceLaunchAborted()).Times(0);
EXPECT_CALL(mock_callbacks_, OnDeviceLaunchFailed(_)).Times(0);
......@@ -142,55 +166,64 @@ TEST_F(ServiceVideoCaptureDeviceLauncherTest, LaunchingDeviceSucceeds) {
wait_for_done_cb.Run();
launcher_.reset();
factory_delegate_.reset();
service_connection_.reset();
wait_for_release_connection_cb_.Run();
EXPECT_TRUE(launcher_has_connected_to_device_factory_);
EXPECT_TRUE(launcher_has_released_device_factory_);
EXPECT_TRUE(launcher_has_connected_to_source_provider_);
EXPECT_TRUE(launcher_has_released_source_provider_);
}
TEST_F(ServiceVideoCaptureDeviceLauncherTest,
LaunchingDeviceIsAbortedBeforeServiceRespondsWithSuccess) {
RunLaunchingDeviceIsAbortedTest(
video_capture::mojom::DeviceAccessResultCode::SUCCESS);
video_capture::mojom::CreatePushSubscriptionResultCode::
kCreatedWithRequestedSettings);
}
TEST_F(ServiceVideoCaptureDeviceLauncherTest,
LaunchingDeviceIsAbortedBeforeServiceRespondsWithNotFound) {
RunLaunchingDeviceIsAbortedTest(
video_capture::mojom::DeviceAccessResultCode::ERROR_DEVICE_NOT_FOUND);
video_capture::mojom::CreatePushSubscriptionResultCode::
kCreatedWithDifferentSettings);
}
TEST_F(ServiceVideoCaptureDeviceLauncherTest,
LaunchingDeviceIsAbortedBeforeServiceRespondsWithNotInitialized) {
RunLaunchingDeviceIsAbortedTest(
video_capture::mojom::DeviceAccessResultCode::NOT_INITIALIZED);
video_capture::mojom::CreatePushSubscriptionResultCode::kFailed);
}
void ServiceVideoCaptureDeviceLauncherTest::RunLaunchingDeviceIsAbortedTest(
video_capture::mojom::DeviceAccessResultCode service_result_code) {
video_capture::mojom::CreatePushSubscriptionResultCode
service_result_code) {
base::RunLoop step_1_run_loop;
base::RunLoop step_2_run_loop;
base::OnceClosure create_device_success_answer_cb;
EXPECT_CALL(mock_device_factory_, DoCreateDevice(kStubDeviceId, _, _))
.WillOnce(
Invoke([&create_device_success_answer_cb, &step_1_run_loop,
service_result_code](
const std::string& device_id,
video_capture::mojom::DeviceRequest* device_request,
video_capture::mojom::DeviceFactory::CreateDeviceCallback&
callback) {
base::OnceClosure create_push_subscription_success_answer_cb;
EXPECT_CALL(mock_source_, DoCreatePushSubscription(_, _, _, _, _))
.WillOnce(Invoke(
[&create_push_subscription_success_answer_cb, &step_1_run_loop,
service_result_code](
video_capture::mojom::ReceiverPtr& subscriber,
const media::VideoCaptureParams& requested_settings,
bool force_reopen_with_new_settings,
video_capture::mojom::PushVideoStreamSubscriptionRequest&
subscription,
video_capture::mojom::VideoSource::CreatePushSubscriptionCallback&
callback) {
// Prepare the callback, but save it for now instead of invoking it.
create_device_success_answer_cb = base::BindOnce(
[](video_capture::mojom::DeviceRequest device_request,
video_capture::mojom::DeviceFactory::CreateDeviceCallback
callback,
video_capture::mojom::DeviceAccessResultCode
create_push_subscription_success_answer_cb = base::BindOnce(
[](const media::VideoCaptureParams& requested_settings,
video_capture::mojom::PushVideoStreamSubscriptionRequest
subscription,
video_capture::mojom::VideoSource::
CreatePushSubscriptionCallback callback,
video_capture::mojom::CreatePushSubscriptionResultCode
service_result_code) {
std::move(callback).Run(service_result_code);
std::move(callback).Run(service_result_code,
requested_settings);
},
std::move(*device_request), std::move(callback),
service_result_code);
requested_settings, std::move(subscription),
std::move(callback), service_result_code);
step_1_run_loop.Quit();
}));
EXPECT_CALL(mock_callbacks_, DoOnDeviceLaunched(_)).Times(0);
......@@ -209,39 +242,46 @@ void ServiceVideoCaptureDeviceLauncherTest::RunLaunchingDeviceIsAbortedTest(
step_1_run_loop.Run();
launcher_->AbortLaunch();
std::move(create_device_success_answer_cb).Run();
std::move(create_push_subscription_success_answer_cb).Run();
step_2_run_loop.Run();
factory_delegate_.reset();
service_connection_.reset();
EXPECT_TRUE(launcher_has_connected_to_device_factory_);
EXPECT_TRUE(launcher_has_released_device_factory_);
EXPECT_TRUE(launcher_has_connected_to_source_provider_);
EXPECT_TRUE(launcher_has_released_source_provider_);
}
TEST_F(ServiceVideoCaptureDeviceLauncherTest,
LaunchingDeviceFailsBecauseDeviceNotFound) {
base::RunLoop run_loop;
EXPECT_CALL(mock_device_factory_, DoCreateDevice(kStubDeviceId, _, _))
.WillOnce(
Invoke([](const std::string& device_id,
video_capture::mojom::DeviceRequest* device_request,
video_capture::mojom::DeviceFactory::CreateDeviceCallback&
callback) {
// Note: We must keep |device_request| alive at least until we have
// sent out the callback. Otherwise, |launcher_| may interpret this
// as the connection having been lost before receiving the callback.
EXPECT_CALL(mock_source_, DoCreatePushSubscription(_, _, _, _, _))
.WillOnce(Invoke(
[](video_capture::mojom::ReceiverPtr& subscriber,
const media::VideoCaptureParams& requested_settings,
bool force_reopen_with_new_settings,
video_capture::mojom::PushVideoStreamSubscriptionRequest&
subscription,
video_capture::mojom::VideoSource::CreatePushSubscriptionCallback&
callback) {
// Note: We post this to the end of the message queue to make it
// asynchronous.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(
[](video_capture::mojom::DeviceRequest device_request,
video_capture::mojom::DeviceFactory::CreateDeviceCallback
callback) {
[](video_capture::mojom::ReceiverPtr subscriber,
const media::VideoCaptureParams& requested_settings,
video_capture::mojom::PushVideoStreamSubscriptionRequest
subscription,
video_capture::mojom::VideoSource::
CreatePushSubscriptionCallback callback) {
std::move(callback).Run(
video_capture::mojom::DeviceAccessResultCode::
ERROR_DEVICE_NOT_FOUND);
video_capture::mojom::
CreatePushSubscriptionResultCode::kFailed,
requested_settings);
},
std::move(*device_request), std::move(callback)));
std::move(subscriber), requested_settings,
std::move(subscription), std::move(callback)));
}));
EXPECT_CALL(mock_callbacks_, DoOnDeviceLaunched(_)).Times(0);
EXPECT_CALL(mock_callbacks_, OnDeviceLaunchAborted()).Times(0);
......@@ -264,7 +304,7 @@ TEST_F(ServiceVideoCaptureDeviceLauncherTest,
}
TEST_F(ServiceVideoCaptureDeviceLauncherTest,
LaunchingDeviceFailsBecauseFactoryIsUnbound) {
LaunchingDeviceFailsBecauseSourceProviderIsUnbound) {
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
EXPECT_CALL(mock_callbacks_, DoOnDeviceLaunched(_)).Times(0);
......@@ -276,7 +316,7 @@ TEST_F(ServiceVideoCaptureDeviceLauncherTest,
}));
// Exercise
factory_delegate_->ReleaseFactoryForTesting();
service_connection_->ReleaseProviderForTesting();
launcher_->LaunchDeviceAsync(kStubDeviceId, blink::MEDIA_DEVICE_VIDEO_CAPTURE,
kArbitraryParams, kNullReceiver,
......@@ -290,18 +330,22 @@ TEST_F(ServiceVideoCaptureDeviceLauncherTest,
LaunchingDeviceFailsBecauseConnectionLostWhileLaunching) {
base::RunLoop run_loop;
video_capture::mojom::DeviceFactory::CreateDeviceCallback create_device_cb;
EXPECT_CALL(mock_device_factory_, DoCreateDevice(kStubDeviceId, _, _))
.WillOnce(
Invoke([&create_device_cb](
const std::string& device_id,
video_capture::mojom::DeviceRequest* device_request,
video_capture::mojom::DeviceFactory::CreateDeviceCallback&
callback) {
video_capture::mojom::VideoSource::CreatePushSubscriptionCallback
create_subscription_cb;
EXPECT_CALL(mock_source_, DoCreatePushSubscription(_, _, _, _, _))
.WillOnce(Invoke(
[&create_subscription_cb](
video_capture::mojom::ReceiverPtr& subscriber,
const media::VideoCaptureParams& requested_settings,
bool force_reopen_with_new_settings,
video_capture::mojom::PushVideoStreamSubscriptionRequest&
subscription,
video_capture::mojom::VideoSource::CreatePushSubscriptionCallback&
callback) {
// Simulate connection lost by not invoking |callback| and releasing
// |device_request|. We have to save |callback| and invoke it later
// |subscription|. We have to save |callback| and invoke it later
// to avoid hitting a DCHECK.
create_device_cb = std::move(callback);
create_subscription_cb = std::move(callback);
}));
EXPECT_CALL(mock_callbacks_, DoOnDeviceLaunched(_)).Times(0);
EXPECT_CALL(mock_callbacks_, OnDeviceLaunchAborted()).Times(0);
......@@ -321,36 +365,35 @@ TEST_F(ServiceVideoCaptureDeviceLauncherTest,
run_loop.Run();
// Cut the connection to the factory, so that the outstanding
// |create_device_cb| will be dropped.
factory_binding_.reset();
// Cleanup
// Cut the connection to the source, so that the outstanding
// |create_subscription_cb| will be dropped when we invoke it below.
source_binding_.reset();
// We have to invoke the callback, because not doing so triggers a DCHECK.
const video_capture::mojom::DeviceAccessResultCode arbitrary_result_code =
video_capture::mojom::DeviceAccessResultCode::SUCCESS;
std::move(create_device_cb).Run(arbitrary_result_code);
const video_capture::mojom::CreatePushSubscriptionResultCode
arbitrary_result_code = video_capture::mojom::
CreatePushSubscriptionResultCode::kCreatedWithRequestedSettings;
std::move(create_subscription_cb)
.Run(arbitrary_result_code, kArbitraryParams);
}
TEST_F(ServiceVideoCaptureDeviceLauncherTest,
ConnectionLostAfterSuccessfulLaunch) {
video_capture::mojom::DeviceRequest device_request_owned_by_service;
EXPECT_CALL(mock_device_factory_, DoCreateDevice(kStubDeviceId, _, _))
.WillOnce(Invoke([&device_request_owned_by_service](
const std::string& device_id,
video_capture::mojom::DeviceRequest* device_request,
video_capture::mojom::DeviceFactory::
CreateDeviceCallback& callback) {
// The service holds on to the |device_request|.
device_request_owned_by_service = std::move(*device_request);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(
[](video_capture::mojom::DeviceFactory::CreateDeviceCallback
callback) {
std::move(callback).Run(
video_capture::mojom::DeviceAccessResultCode::SUCCESS);
},
std::move(callback)));
}));
ConnectionToSubscriptionLostAfterSuccessfulLaunch) {
RunConnectionLostAfterSuccessfulStartTest(
base::BindOnce(&ServiceVideoCaptureDeviceLauncherTest::CloseSourceBinding,
base::Unretained(this)));
}
TEST_F(ServiceVideoCaptureDeviceLauncherTest,
ConnectionToSourceLostAfterSuccessfulLaunch) {
RunConnectionLostAfterSuccessfulStartTest(base::BindOnce(
&ServiceVideoCaptureDeviceLauncherTest::CloseSubscriptionBindings,
base::Unretained(this)));
}
void ServiceVideoCaptureDeviceLauncherTest::
RunConnectionLostAfterSuccessfulStartTest(
base::OnceClosure close_connection_cb) {
std::unique_ptr<LaunchedVideoCaptureDevice> launched_device;
EXPECT_CALL(mock_callbacks_, DoOnDeviceLaunched(_))
.WillOnce(
......@@ -376,14 +419,14 @@ TEST_F(ServiceVideoCaptureDeviceLauncherTest,
step_2_run_loop.Quit();
}));
// Exercise step 2: The service cuts/loses the connection
device_request_owned_by_service = nullptr;
std::move(close_connection_cb).Run();
step_2_run_loop.Run();
launcher_.reset();
factory_delegate_.reset();
service_connection_.reset();
wait_for_release_connection_cb_.Run();
EXPECT_TRUE(launcher_has_connected_to_device_factory_);
EXPECT_TRUE(launcher_has_released_device_factory_);
EXPECT_TRUE(launcher_has_connected_to_source_provider_);
EXPECT_TRUE(launcher_has_released_source_provider_);
}
} // namespace content
......@@ -59,7 +59,7 @@ ServiceVideoCaptureProvider::ServiceVideoCaptureProvider(
: connector_(connector ? connector->Clone() : nullptr),
create_accelerator_factory_cb_(std::move(create_accelerator_factory_cb)),
emit_log_message_cb_(std::move(emit_log_message_cb)),
launcher_has_connected_to_device_factory_(false),
launcher_has_connected_to_source_provider_(false),
service_listener_binding_(this),
weak_ptr_factory_(this) {
base::PostTaskWithTraits(
......@@ -86,7 +86,7 @@ ServiceVideoCaptureProvider::CreateDeviceLauncher() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
return std::make_unique<ServiceVideoCaptureDeviceLauncher>(
base::BindRepeating(
&ServiceVideoCaptureProvider::OnLauncherConnectingToDeviceFactory,
&ServiceVideoCaptureProvider::OnLauncherConnectingToSourceProvider,
weak_ptr_factory_.GetWeakPtr()));
}
......@@ -106,7 +106,7 @@ void ServiceVideoCaptureProvider::OnServiceStarted(
mojo::MakeStrongBinding(
std::make_unique<VirtualVideoCaptureDevicesChangedObserver>(),
mojo::MakeRequest(&observer));
service_connection->device_factory()->RegisterVirtualDevicesChangedObserver(
service_connection->source_provider()->RegisterVirtualDevicesChangedObserver(
std::move(observer),
true /*raise_event_if_virtual_devices_already_present*/);
}
......@@ -144,14 +144,14 @@ void ServiceVideoCaptureProvider::RegisterServiceListenerOnIOThread() {
service_manager->AddListener(std::move(listener));
}
void ServiceVideoCaptureProvider::OnLauncherConnectingToDeviceFactory(
scoped_refptr<RefCountedVideoCaptureFactory>* out_factory) {
void ServiceVideoCaptureProvider::OnLauncherConnectingToSourceProvider(
scoped_refptr<RefCountedVideoSourceProvider>* out_provider) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
launcher_has_connected_to_device_factory_ = true;
*out_factory = LazyConnectToService();
launcher_has_connected_to_source_provider_ = true;
*out_provider = LazyConnectToService();
}
scoped_refptr<RefCountedVideoCaptureFactory>
scoped_refptr<RefCountedVideoSourceProvider>
ServiceVideoCaptureProvider::LazyConnectToService() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
......@@ -163,7 +163,7 @@ ServiceVideoCaptureProvider::LazyConnectToService() {
video_capture::uma::LogVideoCaptureServiceEvent(
video_capture::uma::BROWSER_CONNECTING_TO_SERVICE);
if (time_of_last_uninitialize_ != base::TimeTicks()) {
if (launcher_has_connected_to_device_factory_) {
if (launcher_has_connected_to_source_provider_) {
video_capture::uma::LogDurationUntilReconnectAfterCapture(
base::TimeTicks::Now() - time_of_last_uninitialize_);
} else {
......@@ -172,7 +172,7 @@ ServiceVideoCaptureProvider::LazyConnectToService() {
}
}
launcher_has_connected_to_device_factory_ = false;
launcher_has_connected_to_source_provider_ = false;
time_of_last_connect_ = base::TimeTicks::Now();
video_capture::mojom::AcceleratorFactoryPtr accelerator_factory;
......@@ -189,14 +189,14 @@ ServiceVideoCaptureProvider::LazyConnectToService() {
device_factory_provider->InjectGpuDependencies(
std::move(accelerator_factory));
video_capture::mojom::DeviceFactoryPtr device_factory;
device_factory_provider->ConnectToDeviceFactory(
mojo::MakeRequest(&device_factory));
device_factory.set_connection_error_handler(base::BindOnce(
&ServiceVideoCaptureProvider::OnLostConnectionToDeviceFactory,
video_capture::mojom::VideoSourceProviderPtr source_provider;
device_factory_provider->ConnectToVideoSourceProvider(
mojo::MakeRequest(&source_provider));
source_provider.set_connection_error_handler(base::BindOnce(
&ServiceVideoCaptureProvider::OnLostConnectionToSourceProvider,
weak_ptr_factory_.GetWeakPtr()));
auto result = base::MakeRefCounted<RefCountedVideoCaptureFactory>(
std::move(device_factory), std::move(device_factory_provider),
auto result = base::MakeRefCounted<RefCountedVideoSourceProvider>(
std::move(source_provider), std::move(device_factory_provider),
base::BindOnce(&ServiceVideoCaptureProvider::OnServiceConnectionClosed,
weak_ptr_factory_.GetWeakPtr(),
ReasonForDisconnect::kUnused));
......@@ -211,7 +211,7 @@ void ServiceVideoCaptureProvider::GetDeviceInfosAsyncForRetry(
auto service_connection = LazyConnectToService();
// Use a ScopedCallbackRunner to make sure that |result_callback| gets
// invoked with an empty result in case that the service drops the request.
service_connection->device_factory()->GetDeviceInfos(
service_connection->source_provider()->GetSourceInfos(
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
base::BindOnce(&ServiceVideoCaptureProvider::OnDeviceInfosReceived,
weak_ptr_factory_.GetWeakPtr(), service_connection,
......@@ -220,7 +220,7 @@ void ServiceVideoCaptureProvider::GetDeviceInfosAsyncForRetry(
}
void ServiceVideoCaptureProvider::OnDeviceInfosReceived(
scoped_refptr<RefCountedVideoCaptureFactory> service_connection,
scoped_refptr<RefCountedVideoSourceProvider> service_connection,
GetDeviceInfosCallback result_callback,
int retry_count,
const std::vector<media::VideoCaptureDeviceInfo>& infos) {
......@@ -254,10 +254,10 @@ void ServiceVideoCaptureProvider::OnDeviceInfosReceived(
base::ResetAndReturn(&result_callback).Run(infos);
}
void ServiceVideoCaptureProvider::OnLostConnectionToDeviceFactory() {
void ServiceVideoCaptureProvider::OnLostConnectionToSourceProvider() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
emit_log_message_cb_.Run(
"ServiceVideoCaptureProvider::OnLostConnectionToDeviceFactory");
"ServiceVideoCaptureProvider::OnLostConnectionToSourceProvider");
// This may indicate that the video capture service has crashed. Uninitialize
// here, so that a new connection will be established when clients try to
// reconnect.
......@@ -272,7 +272,7 @@ void ServiceVideoCaptureProvider::OnServiceConnectionClosed(
switch (reason) {
case ReasonForDisconnect::kShutdown:
case ReasonForDisconnect::kUnused:
if (launcher_has_connected_to_device_factory_) {
if (launcher_has_connected_to_source_provider_) {
video_capture::uma::LogVideoCaptureServiceEvent(
video_capture::uma::
BROWSER_CLOSING_CONNECTION_TO_SERVICE_AFTER_CAPTURE);
......
......@@ -7,7 +7,7 @@
#include "base/threading/thread_checker.h"
#include "build/build_config.h"
#include "content/browser/renderer_host/media/ref_counted_video_capture_factory.h"
#include "content/browser/renderer_host/media/ref_counted_video_source_provider.h"
#include "content/browser/renderer_host/media/video_capture_provider.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/service_manager/public/cpp/connector.h"
......@@ -66,31 +66,31 @@ class CONTENT_EXPORT ServiceVideoCaptureProvider
void RegisterServiceListenerOnIOThread();
// Note, this needs to have void return value because of "weak_ptrs can only
// bind to methods without return values".
void OnLauncherConnectingToDeviceFactory(
scoped_refptr<RefCountedVideoCaptureFactory>* out_factory);
// Discarding the returned RefCountedVideoCaptureFactory indicates that the
void OnLauncherConnectingToSourceProvider(
scoped_refptr<RefCountedVideoSourceProvider>* out_provider);
// Discarding the returned RefCountedVideoSourceProvider indicates that the
// caller no longer requires the connection to the service and allows it to
// disconnect.
scoped_refptr<RefCountedVideoCaptureFactory> LazyConnectToService()
scoped_refptr<RefCountedVideoSourceProvider> LazyConnectToService()
WARN_UNUSED_RESULT;
void GetDeviceInfosAsyncForRetry(GetDeviceInfosCallback result_callback,
int retry_count);
void OnDeviceInfosReceived(
scoped_refptr<RefCountedVideoCaptureFactory> service_connection,
scoped_refptr<RefCountedVideoSourceProvider> service_connection,
GetDeviceInfosCallback result_callback,
int retry_count,
const std::vector<media::VideoCaptureDeviceInfo>& infos);
void OnLostConnectionToDeviceFactory();
void OnLostConnectionToSourceProvider();
void OnServiceConnectionClosed(ReasonForDisconnect reason);
std::unique_ptr<service_manager::Connector> connector_;
CreateAcceleratorFactoryCallback create_accelerator_factory_cb_;
base::RepeatingCallback<void(const std::string&)> emit_log_message_cb_;
base::WeakPtr<RefCountedVideoCaptureFactory> weak_service_connection_;
base::WeakPtr<RefCountedVideoSourceProvider> weak_service_connection_;
bool launcher_has_connected_to_device_factory_;
bool launcher_has_connected_to_source_provider_;
base::TimeTicks time_of_last_connect_;
base::TimeTicks time_of_last_uninitialize_;
......
......@@ -12,12 +12,15 @@
#include "content/public/browser/video_capture_device_launcher.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_binding.h"
#include "services/service_manager/public/cpp/test/test_connector_factory.h"
#include "services/video_capture/public/cpp/mock_device_factory.h"
#include "services/video_capture/public/cpp/mock_device_factory_provider.h"
#include "services/video_capture/public/cpp/mock_push_subscription.h"
#include "services/video_capture/public/cpp/mock_video_source.h"
#include "services/video_capture/public/cpp/mock_video_source_provider.h"
#include "services/video_capture/public/mojom/constants.mojom.h"
#include "services/video_capture/public/mojom/producer.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
......@@ -101,7 +104,7 @@ class ServiceVideoCaptureProviderTest : public testing::Test {
service_manager::mojom::kServiceName)),
factory_provider_binding_(&mock_device_factory_provider_),
factory_provider_is_bound_(false),
device_factory_binding_(&mock_device_factory_) {}
source_provider_binding_(&mock_source_provider_) {}
~ServiceVideoCaptureProviderTest() override {}
protected:
......@@ -127,14 +130,45 @@ class ServiceVideoCaptureProviderTest : public testing::Test {
},
&factory_provider_is_bound_));
}));
ON_CALL(mock_device_factory_provider_, DoConnectToDeviceFactory(_))
.WillByDefault(
Invoke([this](video_capture::mojom::DeviceFactoryRequest& request) {
if (device_factory_binding_.is_bound())
device_factory_binding_.Close();
device_factory_binding_.Bind(std::move(request));
ON_CALL(mock_device_factory_provider_, DoConnectToVideoSourceProvider(_))
.WillByDefault(Invoke(
[this](video_capture::mojom::VideoSourceProviderRequest& request) {
if (source_provider_binding_.is_bound())
source_provider_binding_.Close();
source_provider_binding_.Bind(std::move(request));
wait_for_connection_to_service_.Quit();
}));
ON_CALL(mock_source_provider_, DoGetSourceInfos(_))
.WillByDefault(Invoke([](video_capture::mojom::VideoSourceProvider::
GetSourceInfosCallback& callback) {
std::vector<media::VideoCaptureDeviceInfo> arbitrarily_empty_results;
base::ResetAndReturn(&callback).Run(arbitrarily_empty_results);
}));
ON_CALL(mock_source_provider_, DoGetVideoSource(_, _))
.WillByDefault(
Invoke([this](const std::string& device_id,
video_capture::mojom::VideoSourceRequest* request) {
source_bindings_.AddBinding(&mock_source_, std::move(*request));
}));
ON_CALL(mock_source_, DoCreatePushSubscription(_, _, _, _, _))
.WillByDefault(Invoke(
[this](video_capture::mojom::ReceiverPtr& subscriber,
const media::VideoCaptureParams& requested_settings,
bool force_reopen_with_new_settings,
video_capture::mojom::PushVideoStreamSubscriptionRequest&
subscription,
video_capture::mojom::VideoSource::
CreatePushSubscriptionCallback& callback) {
subscription_bindings_.AddBinding(&mock_subscription_,
std::move(subscription));
std::move(callback).Run(
video_capture::mojom::CreatePushSubscriptionResultCode::
kCreatedWithRequestedSettings,
requested_settings);
}));
}
void TearDown() override {}
......@@ -147,12 +181,18 @@ class ServiceVideoCaptureProviderTest : public testing::Test {
mojo::Binding<video_capture::mojom::DeviceFactoryProvider>
factory_provider_binding_;
bool factory_provider_is_bound_;
video_capture::MockDeviceFactory mock_device_factory_;
mojo::Binding<video_capture::mojom::DeviceFactory> device_factory_binding_;
video_capture::MockVideoSourceProvider mock_source_provider_;
mojo::Binding<video_capture::mojom::VideoSourceProvider>
source_provider_binding_;
video_capture::MockVideoSource mock_source_;
mojo::BindingSet<video_capture::mojom::VideoSource> source_bindings_;
video_capture::MockPushSubcription mock_subscription_;
mojo::BindingSet<video_capture::mojom::PushVideoStreamSubscription>
subscription_bindings_;
std::unique_ptr<ServiceVideoCaptureProvider> provider_;
base::MockCallback<VideoCaptureProvider::GetDeviceInfosCallback> results_cb_;
base::MockCallback<
video_capture::mojom::DeviceFactory::GetDeviceInfosCallback>
video_capture::mojom::VideoSourceProvider::GetSourceInfosCallback>
service_cb_;
base::RunLoop wait_for_connection_to_service_;
......@@ -167,14 +207,14 @@ TEST_F(ServiceVideoCaptureProviderTest,
GetDeviceInfosAsyncInvokesCallbackWhenLosingConnection) {
base::RunLoop run_loop;
video_capture::mojom::DeviceFactory::GetDeviceInfosCallback
video_capture::mojom::VideoSourceProvider::GetSourceInfosCallback
callback_to_be_called_by_service;
base::RunLoop wait_for_call_to_arrive_at_service;
EXPECT_CALL(mock_device_factory_, DoGetDeviceInfos(_))
EXPECT_CALL(mock_source_provider_, DoGetSourceInfos(_))
.WillOnce(Invoke(
[&callback_to_be_called_by_service,
&wait_for_call_to_arrive_at_service](
video_capture::mojom::DeviceFactory::GetDeviceInfosCallback&
video_capture::mojom::VideoSourceProvider::GetSourceInfosCallback&
callback) {
// Hold on to the callback so we can drop it later.
callback_to_be_called_by_service = std::move(callback);
......@@ -194,7 +234,7 @@ TEST_F(ServiceVideoCaptureProviderTest,
wait_for_call_to_arrive_at_service.Run();
// Simulate that the service goes down by cutting the connections.
device_factory_binding_.Close();
source_provider_binding_.Close();
factory_provider_binding_.Close();
wait_for_callback_from_service.Run();
......@@ -205,14 +245,14 @@ TEST_F(ServiceVideoCaptureProviderTest,
TEST_F(ServiceVideoCaptureProviderTest,
ClosesServiceConnectionAfterGetDeviceInfos) {
// Setup part 1
video_capture::mojom::DeviceFactory::GetDeviceInfosCallback
video_capture::mojom::VideoSourceProvider::GetSourceInfosCallback
callback_to_be_called_by_service;
base::RunLoop wait_for_call_to_arrive_at_service;
EXPECT_CALL(mock_device_factory_, DoGetDeviceInfos(_))
EXPECT_CALL(mock_source_provider_, DoGetSourceInfos(_))
.WillOnce(Invoke(
[&callback_to_be_called_by_service,
&wait_for_call_to_arrive_at_service](
video_capture::mojom::DeviceFactory::GetDeviceInfosCallback&
video_capture::mojom::VideoSourceProvider::GetSourceInfosCallback&
callback) {
// Hold on to the callback so we can drop it later.
callback_to_be_called_by_service = std::move(callback);
......@@ -225,11 +265,11 @@ TEST_F(ServiceVideoCaptureProviderTest,
// Setup part 2: Now that the connection to the service is established, we can
// listen for disconnects.
base::RunLoop wait_for_connection_to_device_factory_to_close;
base::RunLoop wait_for_connection_to_source_provider_to_close;
base::RunLoop wait_for_connection_to_device_factory_provider_to_close;
device_factory_binding_.set_connection_error_handler(
source_provider_binding_.set_connection_error_handler(
base::BindOnce([](base::RunLoop* run_loop) { run_loop->Quit(); },
&wait_for_connection_to_device_factory_to_close));
&wait_for_connection_to_source_provider_to_close));
factory_provider_binding_.set_connection_error_handler(
base::BindOnce([](base::RunLoop* run_loop) { run_loop->Quit(); },
&wait_for_connection_to_device_factory_provider_to_close));
......@@ -240,7 +280,7 @@ TEST_F(ServiceVideoCaptureProviderTest,
.Run(arbitrarily_empty_results);
// Verification: Expect |provider_| to close the connection to the service.
wait_for_connection_to_device_factory_to_close.Run();
wait_for_connection_to_source_provider_to_close.Run();
if (factory_provider_is_bound_) {
wait_for_connection_to_device_factory_provider_to_close.Run();
}
......@@ -252,21 +292,6 @@ TEST_F(ServiceVideoCaptureProviderTest,
// soon as the last VideoCaptureDeviceLauncher instance is released.
TEST_F(ServiceVideoCaptureProviderTest,
KeepsServiceConnectionWhileDeviceLauncherAlive) {
ON_CALL(mock_device_factory_, DoGetDeviceInfos(_))
.WillByDefault(Invoke([](video_capture::mojom::DeviceFactory::
GetDeviceInfosCallback& callback) {
std::vector<media::VideoCaptureDeviceInfo> arbitrarily_empty_results;
base::ResetAndReturn(&callback).Run(arbitrarily_empty_results);
}));
ON_CALL(mock_device_factory_, DoCreateDevice(_, _, _))
.WillByDefault(
Invoke([](const std::string& device_id,
video_capture::mojom::DeviceRequest* device_request,
video_capture::mojom::DeviceFactory::CreateDeviceCallback&
callback) {
base::ResetAndReturn(&callback).Run(
video_capture::mojom::DeviceAccessResultCode::SUCCESS);
}));
MockVideoCaptureDeviceLauncherCallbacks mock_callbacks;
// Exercise part 1: Create a device launcher and hold on to it.
......@@ -281,7 +306,7 @@ TEST_F(ServiceVideoCaptureProviderTest,
// Monitor if connection gets closed
bool connection_has_been_closed = false;
device_factory_binding_.set_connection_error_handler(base::BindOnce(
source_provider_binding_.set_connection_error_handler(base::BindOnce(
[](bool* connection_has_been_closed) {
*connection_has_been_closed = true;
},
......@@ -335,7 +360,7 @@ TEST_F(ServiceVideoCaptureProviderTest,
}
ASSERT_FALSE(connection_has_been_closed);
// Exercise part 3: Release the initial device launcher.
// Exercise part 4: Release the initial device launcher.
device_launcher_1.reset();
{
base::RunLoop give_provider_chance_to_disconnect;
......@@ -352,12 +377,12 @@ TEST_F(ServiceVideoCaptureProviderTest,
DoesNotCloseServiceConnectionWhileGetDeviceInfoResponsePending) {
// When GetDeviceInfos gets called, hold on to the callbacks, but do not
// yet invoke them.
std::vector<video_capture::mojom::DeviceFactory::GetDeviceInfosCallback>
std::vector<video_capture::mojom::VideoSourceProvider::GetSourceInfosCallback>
callbacks_to_be_called_by_service;
ON_CALL(mock_device_factory_, DoGetDeviceInfos(_))
ON_CALL(mock_source_provider_, DoGetSourceInfos(_))
.WillByDefault(Invoke(
[&callbacks_to_be_called_by_service](
video_capture::mojom::DeviceFactory::GetDeviceInfosCallback&
video_capture::mojom::VideoSourceProvider::GetSourceInfosCallback&
callback) {
callbacks_to_be_called_by_service.push_back(std::move(callback));
}));
......@@ -377,7 +402,7 @@ TEST_F(ServiceVideoCaptureProviderTest,
// Monitor if connection gets closed
bool connection_has_been_closed = false;
device_factory_binding_.set_connection_error_handler(base::BindOnce(
source_provider_binding_.set_connection_error_handler(base::BindOnce(
[](bool* connection_has_been_closed) {
*connection_has_been_closed = true;
},
......
......@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIRTUAL_VIDEO_CAPTURE_DEVICES_CHANGED_OBSERVER_H_
#include "services/video_capture/public/mojom/device_factory.mojom.h"
#include "services/video_capture/public/mojom/devices_changed_observer.mojom.h"
namespace content {
......
......@@ -20,6 +20,7 @@
#include "services/video_capture/public/mojom/constants.mojom.h"
#include "services/video_capture/public/mojom/device_factory.mojom.h"
#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
#include "services/video_capture/public/mojom/devices_changed_observer.mojom.h"
#include "services/video_capture/public/mojom/virtual_device.mojom.h"
namespace content {
......
// 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 "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::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(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(), 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(
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;
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_EQ(video_capture::mojom::CreatePushSubscriptionResultCode::
kCreatedWithRequestedSettings,
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);
};
IN_PROC_BROWSER_TEST_F(WebRtcVideoCaptureSharedDeviceBrowserTest,
ReceiveFrameFromServiceAndInRenderer) {
Initialize();
base::RunLoop receive_frame_from_service_wait_loop;
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(open_device_via_service_run_loop.QuitClosure());
open_device_via_service_run_loop.Run();
OpenDeviceInRendererAndWaitForPlaying();
receive_frame_from_service_wait_loop.Run();
}
} // namespace content
......@@ -935,6 +935,7 @@ test("content_browsertests") {
"../browser/webrtc/webrtc_video_capture_browsertest.cc",
"../browser/webrtc/webrtc_video_capture_service_browsertest.cc",
"../browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc",
"../browser/webrtc/webrtc_video_capture_shared_device_browsertest.cc",
"../browser/webrtc/webrtc_webcam_browsertest.cc",
"../browser/webrtc/webrtc_webcam_browsertest.h",
"../browser/webui/web_ui_mojo_browsertest.cc",
......@@ -1030,6 +1031,7 @@ test("content_browsertests") {
"//services/service_manager/public/cpp",
"//services/test/echo/public/mojom",
"//services/video_capture/public/cpp",
"//services/video_capture/public/cpp:mocks",
"//services/video_capture/public/mojom:constants",
"//services/viz/privileged/interfaces",
"//services/ws/public/cpp/gpu",
......
......@@ -49,7 +49,7 @@ void BroadcastingReceiver::ClientContext::OnStartedUsingGpuDecode() {
if (on_started_using_gpu_decode_has_been_called_)
return;
on_started_using_gpu_decode_has_been_called_ = true;
client_->OnStarted();
client_->OnStartedUsingGpuDecode();
}
BroadcastingReceiver::BufferContext::BufferContext(
......@@ -156,8 +156,10 @@ int32_t BroadcastingReceiver::AddClient(mojom::ReceiverPtr client) {
if (status_ == Status::kOnStartedHasBeenCalled) {
added_client_context.OnStarted();
}
if (status_ == Status::kOnStartedUsingGpuDecodeHasBeenCalled)
if (status_ == Status::kOnStartedUsingGpuDecodeHasBeenCalled) {
added_client_context.OnStarted();
added_client_context.OnStartedUsingGpuDecode();
}
for (auto& buffer_context : buffer_contexts_) {
added_client_context.client()->OnNewBuffer(
......
......@@ -12,6 +12,7 @@
#include "mojo/public/cpp/bindings/binding.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
#include "services/video_capture/device_factory.h"
#include "services/video_capture/public/mojom/devices_changed_observer.mojom.h"
#if defined(OS_CHROMEOS)
#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
......
......@@ -110,8 +110,6 @@ void DeviceFactoryProviderImpl::ConnectToDeviceFactory(
mojom::DeviceFactoryRequest request) {
DCHECK(service_ref_);
LazyInitializeDeviceFactory();
if (factory_bindings_.empty())
device_factory_->SetServiceRef(service_ref_->Clone());
factory_bindings_.AddBinding(device_factory_.get(), std::move(request));
}
......@@ -156,6 +154,7 @@ void DeviceFactoryProviderImpl::LazyInitializeDeviceFactory() {
&GpuDependenciesContext::CreateJpegDecodeAccelerator,
gpu_dependencies_context_->GetWeakPtr()),
gpu_dependencies_context_->GetTaskRunner()));
device_factory_->SetServiceRef(service_ref_->Clone());
}
void DeviceFactoryProviderImpl::LazyInitializeVideoSourceProvider() {
......
......@@ -6,6 +6,7 @@
#define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_MOCK_DEVICE_FACTORY_H_
#include "services/video_capture/public/mojom/device_factory.mojom.h"
#include "services/video_capture/public/mojom/devices_changed_observer.mojom.h"
#include "services/video_capture/public/mojom/producer.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
......
......@@ -5,6 +5,7 @@
#ifndef SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_MOCK_VIDEO_SOURCE_PROVIDER_H_
#define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_MOCK_VIDEO_SOURCE_PROVIDER_H_
#include "services/video_capture/public/mojom/devices_changed_observer.mojom.h"
#include "services/video_capture/public/mojom/producer.mojom.h"
#include "services/video_capture/public/mojom/video_source_provider.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
......@@ -33,6 +34,11 @@ class MockVideoSourceProvider
void AddTextureVirtualDevice(const media::VideoCaptureDeviceInfo& device_info,
video_capture::mojom::TextureVirtualDeviceRequest
virtual_device) override;
void RegisterVirtualDevicesChangedObserver(
video_capture::mojom::DevicesChangedObserverPtr observer,
bool raise_event_if_virtual_devices_already_present) override {
NOTIMPLEMENTED();
}
MOCK_METHOD1(DoGetSourceInfos, void(GetSourceInfosCallback& callback));
MOCK_METHOD2(DoGetVideoSource,
......
......@@ -9,6 +9,7 @@ mojom("mojom") {
"device.mojom",
"device_factory.mojom",
"device_factory_provider.mojom",
"devices_changed_observer.mojom",
"producer.mojom",
"receiver.mojom",
"scoped_access_permission.mojom",
......
......@@ -6,6 +6,7 @@ module video_capture.mojom;
import "media/capture/mojom/video_capture_types.mojom";
import "services/video_capture/public/mojom/device.mojom";
import "services/video_capture/public/mojom/devices_changed_observer.mojom";
import "services/video_capture/public/mojom/producer.mojom";
import "services/video_capture/public/mojom/virtual_device.mojom";
......@@ -15,10 +16,6 @@ enum DeviceAccessResultCode {
ERROR_DEVICE_NOT_FOUND
};
interface DevicesChangedObserver {
OnDevicesChanged();
};
// Enables access to a set of video capture devices.
// Typical operation is to first call GetDeviceInfos() to obtain
// information about available devices. The |device_id| of the infos can
......
// 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.
module video_capture.mojom;
// Callback interface for clients who wnat to get notified when virtual devices
// are added or removed.
interface DevicesChangedObserver {
OnDevicesChanged();
};
......@@ -5,6 +5,7 @@
module video_capture.mojom;
import "media/capture/mojom/video_capture_types.mojom";
import "services/video_capture/public/mojom/devices_changed_observer.mojom";
import "services/video_capture/public/mojom/producer.mojom";
import "services/video_capture/public/mojom/video_source.mojom";
import "services/video_capture/public/mojom/virtual_device.mojom";
......@@ -41,4 +42,12 @@ interface VideoSourceProvider {
AddTextureVirtualDevice(
media.mojom.VideoCaptureDeviceInfo device_info,
TextureVirtualDevice& virtual_device);
// Registered observers will get notified whenever a virtual device is added
// or removed. Note: Changes to non-virtual devices are currently being
// monitored outside the video capture service, and therefore the service
// does not offer such monitoring.
RegisterVirtualDevicesChangedObserver(
DevicesChangedObserver observer,
bool raise_event_if_virtual_devices_already_present);
};
......@@ -6,6 +6,7 @@
#define SERVICES_VIDEO_CAPTURE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
#include "services/video_capture/public/mojom/device_factory.mojom.h"
#include "services/video_capture/public/mojom/devices_changed_observer.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace video_capture {
......
......@@ -64,6 +64,13 @@ void VideoSourceProviderImpl::AddTextureVirtualDevice(
std::move(virtual_device));
}
void VideoSourceProviderImpl::RegisterVirtualDevicesChangedObserver(
mojom::DevicesChangedObserverPtr observer,
bool raise_event_if_virtual_devices_already_present) {
device_factory_->RegisterVirtualDevicesChangedObserver(
std::move(observer), raise_event_if_virtual_devices_already_present);
}
void VideoSourceProviderImpl::OnVideoSourceLastClientDisconnected(
const std::string& device_id) {
sources_.erase(device_id);
......
......@@ -34,6 +34,9 @@ class VideoSourceProviderImpl : public mojom::VideoSourceProvider {
void AddTextureVirtualDevice(
const media::VideoCaptureDeviceInfo& device_info,
mojom::TextureVirtualDeviceRequest virtual_device) override;
void RegisterVirtualDevicesChangedObserver(
mojom::DevicesChangedObserverPtr observer,
bool raise_event_if_virtual_devices_already_present) override;
private:
void OnVideoSourceLastClientDisconnected(const std::string& device_id);
......
......@@ -12,6 +12,7 @@
#include "services/service_manager/public/cpp/service_context_ref.h"
#include "services/video_capture/device_factory.h"
#include "services/video_capture/public/mojom/device.mojom.h"
#include "services/video_capture/public/mojom/devices_changed_observer.mojom.h"
#include "services/video_capture/public/mojom/virtual_device.mojom.h"
#if defined(OS_CHROMEOS)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment