| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "services/video_capture/video_source_provider_impl.h" |
| |
| #include "base/functional/bind.h" |
| #include "mojo/public/cpp/bindings/callback_helpers.h" |
| #include "services/video_capture/public/mojom/producer.mojom.h" |
| #include "services/video_capture/video_source_impl.h" |
| #include "services/video_capture/virtual_device_enabled_device_factory.h" |
| |
| namespace video_capture { |
| |
| VideoSourceProviderImpl::VideoSourceProviderImpl( |
| DeviceFactory* device_factory, |
| base::RepeatingClosure on_last_client_disconnected_cb) |
| : device_factory_(device_factory), |
| on_last_client_disconnected_cb_( |
| std::move(on_last_client_disconnected_cb)) { |
| // Unretained |this| is safe because |receivers_| is owned by |this|. |
| receivers_.set_disconnect_handler(base::BindRepeating( |
| &VideoSourceProviderImpl::OnClientDisconnected, base::Unretained(this))); |
| } |
| |
| VideoSourceProviderImpl::~VideoSourceProviderImpl() = default; |
| |
| void VideoSourceProviderImpl::AddClient( |
| mojo::PendingReceiver<mojom::VideoSourceProvider> receiver) { |
| receivers_.Add(this, std::move(receiver)); |
| client_count_++; |
| } |
| |
| void VideoSourceProviderImpl::GetSourceInfos(GetSourceInfosCallback callback) { |
| // The service might be shut down before the callback has a chance to be |
| // executed. This triggers the CHECK in mojo code, which assumes that |
| // callbacks are either executed or the underlying channel is closed. Wrap |
| // the callback to ensure it will be executed on destruction. |
| device_factory_->GetDeviceInfos(mojo::WrapCallbackWithDefaultInvokeIfNotRun( |
| std::move(callback), std::vector<media::VideoCaptureDeviceInfo>())); |
| } |
| |
| void VideoSourceProviderImpl::GetVideoSource( |
| const std::string& device_id, |
| mojo::PendingReceiver<mojom::VideoSource> source_receiver) { |
| auto source_iter = sources_.find(device_id); |
| if (source_iter == sources_.end()) { |
| auto video_source = std::make_unique<VideoSourceImpl>( |
| device_factory_, device_id, |
| base::BindRepeating( |
| &VideoSourceProviderImpl::OnVideoSourceLastClientDisconnected, |
| base::Unretained(this), device_id)); |
| source_iter = |
| sources_.insert(std::make_pair(device_id, std::move(video_source))) |
| .first; |
| } |
| source_iter->second->AddToReceiverSet(std::move(source_receiver)); |
| } |
| |
| void VideoSourceProviderImpl::AddSharedMemoryVirtualDevice( |
| const media::VideoCaptureDeviceInfo& device_info, |
| mojo::PendingRemote<mojom::Producer> producer, |
| mojo::PendingReceiver<mojom::SharedMemoryVirtualDevice> |
| virtual_device_receiver) { |
| device_factory_->AddSharedMemoryVirtualDevice( |
| device_info, std::move(producer), std::move(virtual_device_receiver)); |
| } |
| |
| void VideoSourceProviderImpl::AddTextureVirtualDevice( |
| const media::VideoCaptureDeviceInfo& device_info, |
| mojo::PendingReceiver<mojom::TextureVirtualDevice> |
| virtual_device_receiver) { |
| device_factory_->AddTextureVirtualDevice(device_info, |
| std::move(virtual_device_receiver)); |
| } |
| |
| void VideoSourceProviderImpl::RegisterVirtualDevicesChangedObserver( |
| mojo::PendingRemote<mojom::DevicesChangedObserver> observer, |
| bool raise_event_if_virtual_devices_already_present) { |
| device_factory_->RegisterVirtualDevicesChangedObserver( |
| std::move(observer), raise_event_if_virtual_devices_already_present); |
| } |
| |
| void VideoSourceProviderImpl::RegisterDevicesChangedObserver( |
| mojo::PendingRemote<mojom::DevicesChangedObserver> observer) { |
| if (!devices_changed_notifier_) { |
| devices_changed_notifier_.emplace(); |
| } |
| devices_changed_notifier_->RegisterObserver(std::move(observer)); |
| } |
| |
| void VideoSourceProviderImpl::Close(CloseCallback callback) { |
| closed_but_not_yet_disconnected_client_count_++; |
| // |callback must be run before OnClientDisconnectedOrClosed(), because if the |
| // latter leads to the destruction of |this|, the message pipe to the client |
| // gets severed, and the callback never makes it through. |
| std::move(callback).Run(); |
| OnClientDisconnectedOrClosed(); |
| } |
| |
| void VideoSourceProviderImpl::OnClientDisconnected() { |
| if (closed_but_not_yet_disconnected_client_count_ > 0) { |
| closed_but_not_yet_disconnected_client_count_--; |
| return; |
| } |
| OnClientDisconnectedOrClosed(); |
| } |
| |
| void VideoSourceProviderImpl::OnClientDisconnectedOrClosed() { |
| client_count_--; |
| if (client_count_ == 0) { |
| // No member access allowed after this call, because it may lead to the |
| // destruction of |this|. |
| on_last_client_disconnected_cb_.Run(); |
| } |
| } |
| |
| void VideoSourceProviderImpl::OnVideoSourceLastClientDisconnected( |
| const std::string& device_id) { |
| sources_.erase(device_id); |
| } |
| |
| } // namespace video_capture |