| // Copyright 2016 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 "content/browser/image_capture/image_capture_impl.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/callback_helpers.h" |
| #include "base/unguessable_token.h" |
| #include "content/browser/browser_main_loop.h" |
| #include "content/browser/media/media_devices_permission_checker.h" |
| #include "content/browser/renderer_host/media/media_stream_manager.h" |
| #include "content/browser/renderer_host/media/video_capture_manager.h" |
| #include "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/common/content_features.h" |
| #include "media/base/bind_to_current_loop.h" |
| #include "media/capture/mojom/image_capture_types.h" |
| #include "media/capture/video/video_capture_device.h" |
| #include "mojo/public/cpp/bindings/callback_helpers.h" |
| #include "third_party/blink/public/common/mediastream/media_stream_request.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| void GetPhotoStateOnIOThread(const std::string& source_id, |
| MediaStreamManager* media_stream_manager, |
| ImageCaptureImpl::GetPhotoStateCallback callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| |
| const base::UnguessableToken session_id = |
| media_stream_manager->VideoDeviceIdToSessionId(source_id); |
| if (session_id.is_empty()) |
| return; |
| |
| media_stream_manager->video_capture_manager()->GetPhotoState( |
| session_id, std::move(callback)); |
| } |
| |
| void SetOptionsOnIOThread(const std::string& source_id, |
| MediaStreamManager* media_stream_manager, |
| media::mojom::PhotoSettingsPtr settings, |
| ImageCaptureImpl::SetOptionsCallback callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| |
| const base::UnguessableToken session_id = |
| media_stream_manager->VideoDeviceIdToSessionId(source_id); |
| if (session_id.is_empty()) |
| return; |
| media_stream_manager->video_capture_manager()->SetPhotoOptions( |
| session_id, std::move(settings), std::move(callback)); |
| } |
| |
| void TakePhotoOnIOThread(const std::string& source_id, |
| MediaStreamManager* media_stream_manager, |
| ImageCaptureImpl::TakePhotoCallback callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"), |
| "image_capture_impl.cc::TakePhotoOnIOThread", |
| TRACE_EVENT_SCOPE_PROCESS); |
| |
| const base::UnguessableToken session_id = |
| media_stream_manager->VideoDeviceIdToSessionId(source_id); |
| if (session_id.is_empty()) |
| return; |
| |
| media_stream_manager->video_capture_manager()->TakePhoto(session_id, |
| std::move(callback)); |
| } |
| |
| } // anonymous namespace |
| |
| // static |
| void ImageCaptureImpl::Create( |
| RenderFrameHost* render_frame_host, |
| mojo::PendingReceiver<media::mojom::ImageCapture> receiver) { |
| DCHECK(render_frame_host); |
| // ImageCaptureImpl owns itself. It will self-destruct when a Mojo interface |
| // error occurs, the render frame host is deleted, or the render frame host |
| // navigates to a new document. |
| new ImageCaptureImpl(render_frame_host, std::move(receiver)); |
| } |
| |
| void ImageCaptureImpl::GetPhotoState(const std::string& source_id, |
| GetPhotoStateCallback callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"), |
| "ImageCaptureImpl::GetPhotoState", |
| TRACE_EVENT_SCOPE_PROCESS); |
| |
| GetPhotoStateCallback scoped_callback = |
| mojo::WrapCallbackWithDefaultInvokeIfNotRun( |
| media::BindToCurrentLoop( |
| base::BindOnce(&ImageCaptureImpl::OnGetPhotoState, |
| weak_factory_.GetWeakPtr(), std::move(callback))), |
| mojo::CreateEmptyPhotoState()); |
| GetIOThreadTaskRunner({})->PostTask( |
| FROM_HERE, |
| base::BindOnce(&GetPhotoStateOnIOThread, source_id, |
| BrowserMainLoop::GetInstance()->media_stream_manager(), |
| std::move(scoped_callback))); |
| } |
| |
| void ImageCaptureImpl::SetOptions(const std::string& source_id, |
| media::mojom::PhotoSettingsPtr settings, |
| SetOptionsCallback callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"), |
| "ImageCaptureImpl::SetOptions", |
| TRACE_EVENT_SCOPE_PROCESS); |
| |
| if ((settings->has_pan || settings->has_tilt || settings->has_zoom) && |
| !HasPanTiltZoomPermissionGranted()) { |
| std::move(callback).Run(false); |
| return; |
| } |
| |
| SetOptionsCallback scoped_callback = |
| mojo::WrapCallbackWithDefaultInvokeIfNotRun( |
| media::BindToCurrentLoop(std::move(callback)), false); |
| GetIOThreadTaskRunner({})->PostTask( |
| FROM_HERE, |
| base::BindOnce(&SetOptionsOnIOThread, source_id, |
| BrowserMainLoop::GetInstance()->media_stream_manager(), |
| std::move(settings), std::move(scoped_callback))); |
| } |
| |
| void ImageCaptureImpl::TakePhoto(const std::string& source_id, |
| TakePhotoCallback callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"), |
| "ImageCaptureImpl::TakePhoto", |
| TRACE_EVENT_SCOPE_PROCESS); |
| |
| TakePhotoCallback scoped_callback = |
| mojo::WrapCallbackWithDefaultInvokeIfNotRun( |
| media::BindToCurrentLoop(std::move(callback)), |
| media::mojom::Blob::New()); |
| GetIOThreadTaskRunner({})->PostTask( |
| FROM_HERE, |
| base::BindOnce(&TakePhotoOnIOThread, source_id, |
| BrowserMainLoop::GetInstance()->media_stream_manager(), |
| std::move(scoped_callback))); |
| } |
| |
| ImageCaptureImpl::ImageCaptureImpl( |
| RenderFrameHost* render_frame_host, |
| mojo::PendingReceiver<media::mojom::ImageCapture> receiver) |
| : FrameServiceBase(render_frame_host, std::move(receiver)) {} |
| |
| ImageCaptureImpl::~ImageCaptureImpl() = default; |
| |
| void ImageCaptureImpl::OnGetPhotoState(GetPhotoStateCallback callback, |
| media::mojom::PhotoStatePtr state) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| if (!HasPanTiltZoomPermissionGranted()) { |
| state->pan = media::mojom::Range::New(); |
| state->tilt = media::mojom::Range::New(); |
| state->zoom = media::mojom::Range::New(); |
| } |
| std::move(callback).Run(std::move(state)); |
| } |
| |
| bool ImageCaptureImpl::HasPanTiltZoomPermissionGranted() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| |
| return MediaDevicesPermissionChecker:: |
| HasPanTiltZoomPermissionGrantedOnUIThread( |
| render_frame_host()->GetProcess()->GetID(), |
| render_frame_host()->GetRoutingID()); |
| } |
| } // namespace content |