1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/image_capture/image_capture_impl.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/unguessable_token.h"
12 #include "content/browser/browser_main_loop.h"
13 #include "content/browser/media/media_devices_permission_checker.h"
14 #include "content/browser/renderer_host/media/media_stream_manager.h"
15 #include "content/browser/renderer_host/media/video_capture_manager.h"
16 #include "content/public/browser/browser_task_traits.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/render_frame_host.h"
19 #include "content/public/browser/render_process_host.h"
20 #include "content/public/common/content_features.h"
21 #include "media/base/bind_to_current_loop.h"
22 #include "media/capture/mojom/image_capture_types.h"
23 #include "media/capture/video/video_capture_device.h"
24 #include "mojo/public/cpp/bindings/callback_helpers.h"
25 #include "third_party/blink/public/common/mediastream/media_stream_request.h"
26
27 namespace content {
28
29 namespace {
30
GetPhotoStateOnIOThread(const std::string & source_id,MediaStreamManager * media_stream_manager,ImageCaptureImpl::GetPhotoStateCallback callback)31 void GetPhotoStateOnIOThread(const std::string& source_id,
32 MediaStreamManager* media_stream_manager,
33 ImageCaptureImpl::GetPhotoStateCallback callback) {
34 DCHECK_CURRENTLY_ON(BrowserThread::IO);
35
36 const base::UnguessableToken session_id =
37 media_stream_manager->VideoDeviceIdToSessionId(source_id);
38 if (session_id.is_empty())
39 return;
40
41 media_stream_manager->video_capture_manager()->GetPhotoState(
42 session_id, std::move(callback));
43 }
44
SetOptionsOnIOThread(const std::string & source_id,MediaStreamManager * media_stream_manager,media::mojom::PhotoSettingsPtr settings,ImageCaptureImpl::SetOptionsCallback callback)45 void SetOptionsOnIOThread(const std::string& source_id,
46 MediaStreamManager* media_stream_manager,
47 media::mojom::PhotoSettingsPtr settings,
48 ImageCaptureImpl::SetOptionsCallback callback) {
49 DCHECK_CURRENTLY_ON(BrowserThread::IO);
50
51 const base::UnguessableToken session_id =
52 media_stream_manager->VideoDeviceIdToSessionId(source_id);
53 if (session_id.is_empty())
54 return;
55 media_stream_manager->video_capture_manager()->SetPhotoOptions(
56 session_id, std::move(settings), std::move(callback));
57 }
58
TakePhotoOnIOThread(const std::string & source_id,MediaStreamManager * media_stream_manager,ImageCaptureImpl::TakePhotoCallback callback)59 void TakePhotoOnIOThread(const std::string& source_id,
60 MediaStreamManager* media_stream_manager,
61 ImageCaptureImpl::TakePhotoCallback callback) {
62 DCHECK_CURRENTLY_ON(BrowserThread::IO);
63 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
64 "image_capture_impl.cc::TakePhotoOnIOThread",
65 TRACE_EVENT_SCOPE_PROCESS);
66
67 const base::UnguessableToken session_id =
68 media_stream_manager->VideoDeviceIdToSessionId(source_id);
69 if (session_id.is_empty())
70 return;
71
72 media_stream_manager->video_capture_manager()->TakePhoto(session_id,
73 std::move(callback));
74 }
75
76 } // anonymous namespace
77
78 // static
Create(RenderFrameHost * render_frame_host,mojo::PendingReceiver<media::mojom::ImageCapture> receiver)79 void ImageCaptureImpl::Create(
80 RenderFrameHost* render_frame_host,
81 mojo::PendingReceiver<media::mojom::ImageCapture> receiver) {
82 DCHECK(render_frame_host);
83 // ImageCaptureImpl owns itself. It will self-destruct when a Mojo interface
84 // error occurs, the render frame host is deleted, or the render frame host
85 // navigates to a new document.
86 new ImageCaptureImpl(render_frame_host, std::move(receiver));
87 }
88
GetPhotoState(const std::string & source_id,GetPhotoStateCallback callback)89 void ImageCaptureImpl::GetPhotoState(const std::string& source_id,
90 GetPhotoStateCallback callback) {
91 DCHECK_CURRENTLY_ON(BrowserThread::UI);
92 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
93 "ImageCaptureImpl::GetPhotoState",
94 TRACE_EVENT_SCOPE_PROCESS);
95
96 GetPhotoStateCallback scoped_callback =
97 mojo::WrapCallbackWithDefaultInvokeIfNotRun(
98 media::BindToCurrentLoop(
99 base::BindOnce(&ImageCaptureImpl::OnGetPhotoState,
100 weak_factory_.GetWeakPtr(), std::move(callback))),
101 mojo::CreateEmptyPhotoState());
102 GetIOThreadTaskRunner({})->PostTask(
103 FROM_HERE,
104 base::BindOnce(&GetPhotoStateOnIOThread, source_id,
105 BrowserMainLoop::GetInstance()->media_stream_manager(),
106 std::move(scoped_callback)));
107 }
108
SetOptions(const std::string & source_id,media::mojom::PhotoSettingsPtr settings,SetOptionsCallback callback)109 void ImageCaptureImpl::SetOptions(const std::string& source_id,
110 media::mojom::PhotoSettingsPtr settings,
111 SetOptionsCallback callback) {
112 DCHECK_CURRENTLY_ON(BrowserThread::UI);
113 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
114 "ImageCaptureImpl::SetOptions",
115 TRACE_EVENT_SCOPE_PROCESS);
116
117 if ((settings->has_pan || settings->has_tilt || settings->has_zoom) &&
118 !HasPanTiltZoomPermissionGranted()) {
119 std::move(callback).Run(false);
120 return;
121 }
122
123 SetOptionsCallback scoped_callback =
124 mojo::WrapCallbackWithDefaultInvokeIfNotRun(
125 media::BindToCurrentLoop(std::move(callback)), false);
126 GetIOThreadTaskRunner({})->PostTask(
127 FROM_HERE,
128 base::BindOnce(&SetOptionsOnIOThread, source_id,
129 BrowserMainLoop::GetInstance()->media_stream_manager(),
130 std::move(settings), std::move(scoped_callback)));
131 }
132
TakePhoto(const std::string & source_id,TakePhotoCallback callback)133 void ImageCaptureImpl::TakePhoto(const std::string& source_id,
134 TakePhotoCallback callback) {
135 DCHECK_CURRENTLY_ON(BrowserThread::UI);
136 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
137 "ImageCaptureImpl::TakePhoto",
138 TRACE_EVENT_SCOPE_PROCESS);
139
140 TakePhotoCallback scoped_callback =
141 mojo::WrapCallbackWithDefaultInvokeIfNotRun(
142 media::BindToCurrentLoop(std::move(callback)),
143 media::mojom::Blob::New());
144 GetIOThreadTaskRunner({})->PostTask(
145 FROM_HERE,
146 base::BindOnce(&TakePhotoOnIOThread, source_id,
147 BrowserMainLoop::GetInstance()->media_stream_manager(),
148 std::move(scoped_callback)));
149 }
150
ImageCaptureImpl(RenderFrameHost * render_frame_host,mojo::PendingReceiver<media::mojom::ImageCapture> receiver)151 ImageCaptureImpl::ImageCaptureImpl(
152 RenderFrameHost* render_frame_host,
153 mojo::PendingReceiver<media::mojom::ImageCapture> receiver)
154 : FrameServiceBase(render_frame_host, std::move(receiver)) {}
155
156 ImageCaptureImpl::~ImageCaptureImpl() = default;
157
OnGetPhotoState(GetPhotoStateCallback callback,media::mojom::PhotoStatePtr state)158 void ImageCaptureImpl::OnGetPhotoState(GetPhotoStateCallback callback,
159 media::mojom::PhotoStatePtr state) {
160 DCHECK_CURRENTLY_ON(BrowserThread::UI);
161 if (!HasPanTiltZoomPermissionGranted()) {
162 state->pan = media::mojom::Range::New();
163 state->tilt = media::mojom::Range::New();
164 state->zoom = media::mojom::Range::New();
165 }
166 std::move(callback).Run(std::move(state));
167 }
168
HasPanTiltZoomPermissionGranted()169 bool ImageCaptureImpl::HasPanTiltZoomPermissionGranted() {
170 DCHECK_CURRENTLY_ON(BrowserThread::UI);
171
172 return MediaDevicesPermissionChecker::
173 HasPanTiltZoomPermissionGrantedOnUIThread(
174 render_frame_host()->GetProcess()->GetID(),
175 render_frame_host()->GetRoutingID());
176 }
177 } // namespace content
178