| // 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 "media/capture/video/chromeos/camera_app_device_bridge_impl.h" |
| |
| #include <string> |
| |
| #include "base/callback_helpers.h" |
| #include "base/command_line.h" |
| #include "media/base/bind_to_current_loop.h" |
| #include "media/base/media_switches.h" |
| #include "media/capture/video/chromeos/public/cros_features.h" |
| #include "media/capture/video/chromeos/video_capture_device_chromeos_halv3.h" |
| |
| namespace media { |
| |
| CameraAppDeviceBridgeImpl::CameraAppDeviceBridgeImpl() { |
| const base::CommandLine* command_line = |
| base::CommandLine::ForCurrentProcess(); |
| bool use_fake_camera = |
| command_line->HasSwitch(switches::kUseFakeDeviceForMediaStream); |
| bool use_file_camera = |
| command_line->HasSwitch(switches::kUseFileForFakeVideoCapture); |
| is_supported_ = |
| ShouldUseCrosCameraService() && !use_fake_camera && !use_file_camera; |
| } |
| |
| CameraAppDeviceBridgeImpl::~CameraAppDeviceBridgeImpl() = default; |
| |
| // static |
| CameraAppDeviceBridgeImpl* CameraAppDeviceBridgeImpl::GetInstance() { |
| return base::Singleton<CameraAppDeviceBridgeImpl>::get(); |
| } |
| |
| void CameraAppDeviceBridgeImpl::BindReceiver( |
| mojo::PendingReceiver<cros::mojom::CameraAppDeviceBridge> receiver) { |
| receivers_.Add(this, std::move(receiver)); |
| } |
| |
| void CameraAppDeviceBridgeImpl::OnVideoCaptureDeviceCreated( |
| const std::string& device_id, |
| scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner) { |
| base::AutoLock lock(task_runner_map_lock_); |
| DCHECK_EQ(ipc_task_runners_.count(device_id), 0u); |
| ipc_task_runners_.emplace(device_id, ipc_task_runner); |
| } |
| |
| void CameraAppDeviceBridgeImpl::OnVideoCaptureDeviceClosing( |
| const std::string& device_id) { |
| auto remove_ipc_task_runner = |
| base::BindOnce(&CameraAppDeviceBridgeImpl::RemoveIpcTaskRunner, |
| base::Unretained(this), device_id); |
| base::AutoLock lock(task_runner_map_lock_); |
| DCHECK_EQ(ipc_task_runners_.count(device_id), 1u); |
| |
| // Since the IPC thread is owned by VCD and the CameraAppBridgeImpl is a |
| // singleton which has longer lifetime than VCD, it is safe to use |
| // base::Unretained(this) here. |
| ipc_task_runners_[device_id]->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &CameraAppDeviceBridgeImpl::InvalidateDevicePtrsOnDeviceIpcThread, |
| base::Unretained(this), device_id, |
| /* should_disable_new_ptrs */ false, |
| std::move(remove_ipc_task_runner))); |
| } |
| |
| void CameraAppDeviceBridgeImpl::OnDeviceMojoDisconnected( |
| const std::string& device_id) { |
| auto remove_device = media::BindToCurrentLoop( |
| base::BindOnce(&CameraAppDeviceBridgeImpl::RemoveCameraAppDevice, |
| base::Unretained(this), device_id)); |
| { |
| base::AutoLock lock(task_runner_map_lock_); |
| auto it = ipc_task_runners_.find(device_id); |
| if (it != ipc_task_runners_.end()) { |
| // Since the IPC thread is owned by VCD and the CameraAppBridgeImpl is a |
| // singleton which has longer lifetime than VCD, it is safe to use |
| // base::Unretained(this) here. |
| it->second->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &CameraAppDeviceBridgeImpl::InvalidateDevicePtrsOnDeviceIpcThread, |
| base::Unretained(this), device_id, |
| /* should_disable_new_ptrs */ true, std::move(remove_device))); |
| return; |
| } |
| } |
| std::move(remove_device).Run(); |
| } |
| |
| void CameraAppDeviceBridgeImpl::InvalidateDevicePtrsOnDeviceIpcThread( |
| const std::string& device_id, |
| bool should_disable_new_ptrs, |
| base::OnceClosure callback) { |
| auto device = GetWeakCameraAppDevice(device_id); |
| if (device) { |
| device->ResetOnDeviceIpcThread(std::move(callback), |
| should_disable_new_ptrs); |
| } else { |
| std::move(callback).Run(); |
| } |
| } |
| |
| void CameraAppDeviceBridgeImpl::SetCameraInfoGetter( |
| CameraInfoGetter camera_info_getter) { |
| base::AutoLock lock(camera_info_getter_lock_); |
| camera_info_getter_ = std::move(camera_info_getter); |
| } |
| |
| void CameraAppDeviceBridgeImpl::UnsetCameraInfoGetter() { |
| base::AutoLock lock(camera_info_getter_lock_); |
| camera_info_getter_ = base::NullCallback(); |
| } |
| |
| void CameraAppDeviceBridgeImpl::SetVirtualDeviceController( |
| VirtualDeviceController virtual_device_controller) { |
| base::AutoLock lock(virtual_device_controller_lock_); |
| virtual_device_controller_ = std::move(virtual_device_controller); |
| } |
| |
| void CameraAppDeviceBridgeImpl::UnsetVirtualDeviceController() { |
| base::AutoLock lock(virtual_device_controller_lock_); |
| virtual_device_controller_ = base::NullCallback(); |
| } |
| |
| base::WeakPtr<CameraAppDeviceImpl> |
| CameraAppDeviceBridgeImpl::GetWeakCameraAppDevice( |
| const std::string& device_id) { |
| base::AutoLock lock(device_map_lock_); |
| auto it = camera_app_devices_.find(device_id); |
| if (it == camera_app_devices_.end()) { |
| return nullptr; |
| } |
| return it->second->GetWeakPtr(); |
| } |
| |
| void CameraAppDeviceBridgeImpl::RemoveCameraAppDevice( |
| const std::string& device_id) { |
| base::AutoLock lock(device_map_lock_); |
| auto it = camera_app_devices_.find(device_id); |
| if (it == camera_app_devices_.end()) { |
| return; |
| } |
| camera_app_devices_.erase(it); |
| } |
| |
| void CameraAppDeviceBridgeImpl::RemoveIpcTaskRunner( |
| const std::string& device_id) { |
| base::AutoLock lock(task_runner_map_lock_); |
| ipc_task_runners_.erase(device_id); |
| } |
| |
| void CameraAppDeviceBridgeImpl::GetCameraAppDevice( |
| const std::string& device_id, |
| GetCameraAppDeviceCallback callback) { |
| DCHECK(is_supported_); |
| |
| mojo::PendingRemote<cros::mojom::CameraAppDevice> device_remote; |
| auto* device = GetOrCreateCameraAppDevice(device_id); |
| DCHECK(device); |
| |
| device->BindReceiver(device_remote.InitWithNewPipeAndPassReceiver()); |
| std::move(callback).Run(cros::mojom::GetCameraAppDeviceStatus::SUCCESS, |
| std::move(device_remote)); |
| } |
| |
| media::CameraAppDeviceImpl* |
| CameraAppDeviceBridgeImpl::GetOrCreateCameraAppDevice( |
| const std::string& device_id) { |
| base::AutoLock lock(device_map_lock_); |
| auto it = camera_app_devices_.find(device_id); |
| if (it != camera_app_devices_.end()) { |
| return it->second.get(); |
| } |
| |
| base::AutoLock camera_info_lock(camera_info_getter_lock_); |
| // Since we ensure that VideoCaptureDeviceFactory is created before binding |
| // CameraAppDeviceBridge and VideoCaptureDeviceFactory is only destroyed when |
| // the video capture service dies, we can guarantee that |camera_info_getter_| |
| // is always valid here. |
| DCHECK(camera_info_getter_); |
| |
| auto device_info = camera_info_getter_.Run(device_id); |
| auto device_impl = std::make_unique<media::CameraAppDeviceImpl>( |
| device_id, std::move(device_info)); |
| auto result = camera_app_devices_.emplace(device_id, std::move(device_impl)); |
| return result.first->second.get(); |
| } |
| |
| void CameraAppDeviceBridgeImpl::IsSupported(IsSupportedCallback callback) { |
| std::move(callback).Run(is_supported_); |
| } |
| |
| void CameraAppDeviceBridgeImpl::SetMultipleStreamsEnabled( |
| const std::string& device_id, |
| bool enabled, |
| SetMultipleStreamsEnabledCallback callback) { |
| base::AutoLock lock(virtual_device_controller_lock_); |
| if (!virtual_device_controller_) { |
| std::move(callback).Run(false); |
| return; |
| } |
| |
| virtual_device_controller_.Run(device_id, enabled); |
| std::move(callback).Run(true); |
| } |
| |
| } // namespace media |