| // 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 |