blob: 9ac23011d99b3588f78133fd063c7c3f9d90eca7 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/video_capture/virtual_device_enabled_device_factory.h"
#include <utility>
#include "base/bind.h"
#include "media/capture/video/video_capture_device_info.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/video_capture/device_factory.h"
#include "services/video_capture/shared_memory_virtual_device_mojo_adapter.h"
#include "services/video_capture/texture_virtual_device_mojo_adapter.h"
namespace video_capture {
class VirtualDeviceEnabledDeviceFactory::VirtualDeviceEntry {
public:
VirtualDeviceEntry(
const media::VideoCaptureDeviceInfo& device_info,
std::unique_ptr<SharedMemoryVirtualDeviceMojoAdapter> device,
std::unique_ptr<mojo::Receiver<mojom::SharedMemoryVirtualDevice>>
producer_receiver)
: device_info_(device_info),
device_type_(DeviceType::kSharedMemory),
shared_memory_device_(std::move(device)),
shared_memory_producer_receiver_(std::move(producer_receiver)) {}
VirtualDeviceEntry(
const media::VideoCaptureDeviceInfo& device_info,
std::unique_ptr<TextureVirtualDeviceMojoAdapter> device,
std::unique_ptr<mojo::Receiver<mojom::TextureVirtualDevice>>
producer_receiver)
: device_info_(device_info),
device_type_(DeviceType::kTexture),
texture_device_(std::move(device)),
texture_producer_receiver_(std::move(producer_receiver)) {}
VirtualDeviceEntry(VirtualDeviceEntry&& other) = default;
VirtualDeviceEntry& operator=(VirtualDeviceEntry&& other) = default;
bool HasConsumerBinding() { return consumer_receiver_ != nullptr; }
void BindConsumerReceiver(
mojo::PendingReceiver<mojom::Device> device_receiver,
base::OnceClosure connection_error_handler) {
switch (device_type_) {
case DeviceType::kSharedMemory:
consumer_receiver_ = std::make_unique<mojo::Receiver<mojom::Device>>(
shared_memory_device_.get(), std::move(device_receiver));
break;
case DeviceType::kTexture:
consumer_receiver_ = std::make_unique<mojo::Receiver<mojom::Device>>(
texture_device_.get(), std::move(device_receiver));
break;
}
consumer_receiver_->set_disconnect_handler(
std::move(connection_error_handler));
}
void ResetConsumerReceiver() { consumer_receiver_.reset(); }
void StopDevice() {
if (shared_memory_device_)
shared_memory_device_->Stop();
else
texture_device_->Stop();
}
media::VideoCaptureDeviceInfo device_info() const { return device_info_; }
private:
enum class DeviceType { kSharedMemory, kTexture };
media::VideoCaptureDeviceInfo device_info_;
DeviceType device_type_;
// Only valid for |device_type_ == kSharedMemory|
std::unique_ptr<SharedMemoryVirtualDeviceMojoAdapter> shared_memory_device_;
std::unique_ptr<mojo::Receiver<mojom::SharedMemoryVirtualDevice>>
shared_memory_producer_receiver_;
// Only valid for |device_type_ == kTexture|
std::unique_ptr<TextureVirtualDeviceMojoAdapter> texture_device_;
std::unique_ptr<mojo::Receiver<mojom::TextureVirtualDevice>>
texture_producer_receiver_;
std::unique_ptr<mojo::Receiver<mojom::Device>> consumer_receiver_;
};
VirtualDeviceEnabledDeviceFactory::VirtualDeviceEnabledDeviceFactory(
std::unique_ptr<DeviceFactory> device_factory)
: device_factory_(std::move(device_factory)) {}
VirtualDeviceEnabledDeviceFactory::~VirtualDeviceEnabledDeviceFactory() =
default;
void VirtualDeviceEnabledDeviceFactory::GetDeviceInfos(
GetDeviceInfosCallback callback) {
device_factory_->GetDeviceInfos(
base::BindOnce(&VirtualDeviceEnabledDeviceFactory::OnGetDeviceInfos,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void VirtualDeviceEnabledDeviceFactory::CreateDevice(
const std::string& device_id,
mojo::PendingReceiver<mojom::Device> device_receiver,
CreateDeviceCallback callback) {
auto virtual_device_iter = virtual_devices_by_id_.find(device_id);
if (virtual_device_iter != virtual_devices_by_id_.end()) {
VirtualDeviceEntry& device_entry = virtual_device_iter->second;
if (device_entry.HasConsumerBinding()) {
// The requested virtual device is already used by another client.
// Revoke the access for the current client, then bind to the new
// receiver.
device_entry.ResetConsumerReceiver();
device_entry.StopDevice();
}
device_entry.BindConsumerReceiver(
std::move(device_receiver),
base::BindOnce(&VirtualDeviceEnabledDeviceFactory::
OnVirtualDeviceConsumerConnectionErrorOrClose,
base::Unretained(this), device_id));
std::move(callback).Run(mojom::DeviceAccessResultCode::SUCCESS);
return;
}
device_factory_->CreateDevice(device_id, std::move(device_receiver),
std::move(callback));
}
void VirtualDeviceEnabledDeviceFactory::AddSharedMemoryVirtualDevice(
const media::VideoCaptureDeviceInfo& device_info,
mojo::PendingRemote<mojom::Producer> producer_pending_remote,
bool send_buffer_handles_to_producer_as_raw_file_descriptors,
mojo::PendingReceiver<mojom::SharedMemoryVirtualDevice>
virtual_device_receiver) {
auto device_id = device_info.descriptor.device_id;
auto virtual_device_iter = virtual_devices_by_id_.find(device_id);
if (virtual_device_iter != virtual_devices_by_id_.end()) {
// Revoke the access for the current producer and consumer by
// removing it from the list.
virtual_devices_by_id_.erase(virtual_device_iter);
}
mojo::Remote<mojom::Producer> producer(std::move(producer_pending_remote));
producer.set_disconnect_handler(
base::BindOnce(&VirtualDeviceEnabledDeviceFactory::
OnVirtualDeviceProducerConnectionErrorOrClose,
base::Unretained(this), device_id));
auto device = std::make_unique<SharedMemoryVirtualDeviceMojoAdapter>(
std::move(producer),
send_buffer_handles_to_producer_as_raw_file_descriptors);
auto producer_receiver =
std::make_unique<mojo::Receiver<mojom::SharedMemoryVirtualDevice>>(
device.get(), std::move(virtual_device_receiver));
producer_receiver->set_disconnect_handler(
base::BindOnce(&VirtualDeviceEnabledDeviceFactory::
OnVirtualDeviceProducerConnectionErrorOrClose,
base::Unretained(this), device_id));
VirtualDeviceEntry device_entry(device_info, std::move(device),
std::move(producer_receiver));
virtual_devices_by_id_.insert(
std::make_pair(device_id, std::move(device_entry)));
EmitDevicesChangedEvent();
}
void VirtualDeviceEnabledDeviceFactory::AddTextureVirtualDevice(
const media::VideoCaptureDeviceInfo& device_info,
mojo::PendingReceiver<mojom::TextureVirtualDevice>
virtual_device_receiver) {
auto device_id = device_info.descriptor.device_id;
auto virtual_device_iter = virtual_devices_by_id_.find(device_id);
if (virtual_device_iter != virtual_devices_by_id_.end()) {
// Revoke the access for the current producer and consumer by
// removing it from the list.
virtual_devices_by_id_.erase(virtual_device_iter);
}
auto device = std::make_unique<TextureVirtualDeviceMojoAdapter>();
auto producer_receiver =
std::make_unique<mojo::Receiver<mojom::TextureVirtualDevice>>(
device.get(), std::move(virtual_device_receiver));
producer_receiver->set_disconnect_handler(
base::BindOnce(&VirtualDeviceEnabledDeviceFactory::
OnVirtualDeviceProducerConnectionErrorOrClose,
base::Unretained(this), device_id));
VirtualDeviceEntry device_entry(device_info, std::move(device),
std::move(producer_receiver));
virtual_devices_by_id_.insert(
std::make_pair(device_id, std::move(device_entry)));
EmitDevicesChangedEvent();
}
void VirtualDeviceEnabledDeviceFactory::RegisterVirtualDevicesChangedObserver(
mojo::PendingRemote<mojom::DevicesChangedObserver> observer_pending_remote,
bool raise_event_if_virtual_devices_already_present) {
mojo::Remote<mojom::DevicesChangedObserver> observer(
std::move(observer_pending_remote));
observer.set_disconnect_handler(base::BindOnce(
&VirtualDeviceEnabledDeviceFactory::OnDevicesChangedObserverDisconnected,
weak_factory_.GetWeakPtr(), observer.get()));
if (!virtual_devices_by_id_.empty() &&
raise_event_if_virtual_devices_already_present) {
observer->OnDevicesChanged();
}
devices_changed_observers_.push_back(std::move(observer));
}
void VirtualDeviceEnabledDeviceFactory::OnGetDeviceInfos(
GetDeviceInfosCallback callback,
const std::vector<media::VideoCaptureDeviceInfo>& device_infos) {
std::vector<media::VideoCaptureDeviceInfo> all_device_infos;
for (const auto& device_entry : virtual_devices_by_id_) {
all_device_infos.push_back(device_entry.second.device_info());
}
all_device_infos.insert(std::end(all_device_infos), std::begin(device_infos),
std::end(device_infos));
std::move(callback).Run(all_device_infos);
}
void VirtualDeviceEnabledDeviceFactory::
OnVirtualDeviceProducerConnectionErrorOrClose(
const std::string& device_id) {
virtual_devices_by_id_.at(device_id).StopDevice();
virtual_devices_by_id_.erase(device_id);
EmitDevicesChangedEvent();
}
void VirtualDeviceEnabledDeviceFactory::
OnVirtualDeviceConsumerConnectionErrorOrClose(
const std::string& device_id) {
virtual_devices_by_id_.at(device_id).StopDevice();
}
void VirtualDeviceEnabledDeviceFactory::EmitDevicesChangedEvent() {
for (auto& observer : devices_changed_observers_)
observer->OnDevicesChanged();
}
void VirtualDeviceEnabledDeviceFactory::OnDevicesChangedObserverDisconnected(
mojom::DevicesChangedObserver* observer) {
for (auto iter = devices_changed_observers_.begin();
iter != devices_changed_observers_.end(); ++iter) {
if (iter->get() == observer) {
devices_changed_observers_.erase(iter);
break;
}
}
}
} // namespace video_capture