OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/media/video_capture_manager.h" | 5 #include "content/browser/renderer_host/media/in_process_buildable_video_capture _device.h" |
6 | 6 |
7 #include <algorithm> | |
8 #include <set> | |
9 #include <utility> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/bind_helpers.h" | |
13 #include "base/command_line.h" | |
14 #include "base/location.h" | |
15 #include "base/logging.h" | |
16 #include "base/memory/ptr_util.h" | |
17 #include "base/metrics/histogram_macros.h" | 7 #include "base/metrics/histogram_macros.h" |
18 #include "base/single_thread_task_runner.h" | |
19 #include "base/stl_util.h" | |
20 #include "base/strings/stringprintf.h" | 8 #include "base/strings/stringprintf.h" |
21 #include "base/task_runner_util.h" | |
22 #include "base/threading/sequenced_worker_pool.h" | |
23 #include "base/threading/thread_task_runner_handle.h" | |
24 #include "build/build_config.h" | |
25 #include "content/browser/media/capture/desktop_capture_device_uma_types.h" | 9 #include "content/browser/media/capture/desktop_capture_device_uma_types.h" |
26 #include "content/browser/media/capture/web_contents_video_capture_device.h" | 10 #include "content/browser/media/capture/web_contents_video_capture_device.h" |
27 #include "content/browser/media/media_internals.h" | |
28 #include "content/browser/renderer_host/media/video_capture_controller.h" | 11 #include "content/browser/renderer_host/media/video_capture_controller.h" |
29 #include "content/browser/renderer_host/media/video_capture_controller_event_han dler.h" | |
30 #include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h" | 12 #include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h" |
31 #include "content/browser/renderer_host/media/video_frame_receiver_on_io_thread. h" | 13 #include "content/browser/renderer_host/media/video_frame_receiver_on_io_thread. h" |
32 #include "content/public/browser/browser_thread.h" | 14 #include "content/public/browser/browser_thread.h" |
33 #include "content/public/browser/desktop_media_id.h" | 15 #include "content/public/browser/desktop_media_id.h" |
34 #include "content/public/common/media_stream_request.h" | 16 #include "content/public/common/media_stream_request.h" |
35 #include "media/base/bind_to_current_loop.h" | 17 #include "media/base/bind_to_current_loop.h" |
36 #include "media/base/media_switches.h" | |
37 #include "media/base/video_facing.h" | |
38 #include "media/capture/video/video_capture_buffer_pool_impl.h" | 18 #include "media/capture/video/video_capture_buffer_pool_impl.h" |
39 #include "media/capture/video/video_capture_buffer_tracker_factory_impl.h" | 19 #include "media/capture/video/video_capture_buffer_tracker_factory_impl.h" |
40 #include "media/capture/video/video_capture_device.h" | |
41 #include "media/capture/video/video_capture_device_client.h" | 20 #include "media/capture/video/video_capture_device_client.h" |
42 #include "media/capture/video/video_capture_device_factory.h" | 21 #include "media/capture/video/video_frame_receiver.h" |
43 | 22 |
44 #if defined(ENABLE_SCREEN_CAPTURE) | 23 #if defined(ENABLE_SCREEN_CAPTURE) && !defined(OS_ANDROID) |
45 | |
46 #if BUILDFLAG(ENABLE_WEBRTC) && !defined(OS_ANDROID) | |
47 #include "content/browser/media/capture/desktop_capture_device.h" | 24 #include "content/browser/media/capture/desktop_capture_device.h" |
48 #endif | |
49 | |
50 #if defined(USE_AURA) | 25 #if defined(USE_AURA) |
51 #include "content/browser/media/capture/desktop_capture_device_aura.h" | 26 #include "content/browser/media/capture/desktop_capture_device_aura.h" |
52 #endif | 27 #endif |
28 #endif | |
53 | 29 |
54 #if defined(OS_ANDROID) | 30 #if defined(ENABLE_SCREEN_CAPTURE) && defined(OS_ANDROID) |
55 #include "content/browser/media/capture/screen_capture_device_android.h" | 31 #include "content/browser/media/capture/screen_capture_device_android.h" |
56 #endif | 32 #endif |
57 | 33 |
58 #endif // defined(ENABLE_SCREEN_CAPTURE) | |
59 | |
60 namespace { | 34 namespace { |
61 | 35 |
62 class VideoFrameConsumerFeedbackObserverOnTaskRunner | 36 class VideoFrameConsumerFeedbackObserverOnTaskRunner |
63 : public media::VideoFrameConsumerFeedbackObserver { | 37 : public media::VideoFrameConsumerFeedbackObserver { |
64 public: | 38 public: |
65 VideoFrameConsumerFeedbackObserverOnTaskRunner( | 39 VideoFrameConsumerFeedbackObserverOnTaskRunner( |
66 media::VideoFrameConsumerFeedbackObserver* observer, | 40 media::VideoFrameConsumerFeedbackObserver* observer, |
67 scoped_refptr<base::SingleThreadTaskRunner> task_runner) | 41 scoped_refptr<base::SingleThreadTaskRunner> task_runner) |
68 : observer_(observer), task_runner_(std::move(task_runner)) {} | 42 : observer_(observer), task_runner_(std::move(task_runner)) {} |
69 | 43 |
70 void OnUtilizationReport(int frame_feedback_id, double utilization) override { | 44 void OnUtilizationReport(int frame_feedback_id, double utilization) override { |
71 task_runner_->PostTask( | 45 task_runner_->PostTask( |
72 FROM_HERE, | 46 FROM_HERE, |
73 base::Bind( | 47 base::Bind( |
74 &media::VideoFrameConsumerFeedbackObserver::OnUtilizationReport, | 48 &media::VideoFrameConsumerFeedbackObserver::OnUtilizationReport, |
75 base::Unretained(observer_), frame_feedback_id, utilization)); | 49 base::Unretained(observer_), frame_feedback_id, utilization)); |
76 } | 50 } |
77 | 51 |
78 private: | 52 private: |
79 media::VideoFrameConsumerFeedbackObserver* const observer_; | 53 media::VideoFrameConsumerFeedbackObserver* const observer_; |
80 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 54 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
81 }; | 55 }; |
82 | 56 |
83 // Compares two VideoCaptureFormat by checking smallest frame_size area, then | 57 std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder( |
84 // by _largest_ frame_rate. Used to order a VideoCaptureFormats vector so that | 58 const media::VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) { |
85 // the first entry for a given resolution has the largest frame rate, as needed | 59 return base::MakeUnique<content::VideoCaptureGpuJpegDecoder>(decode_done_cb); |
86 // by the ConsolidateCaptureFormats() method. | |
87 bool IsCaptureFormatSmaller(const media::VideoCaptureFormat& format1, | |
88 const media::VideoCaptureFormat& format2) { | |
89 DCHECK(format1.frame_size.GetCheckedArea().IsValid()); | |
90 DCHECK(format2.frame_size.GetCheckedArea().IsValid()); | |
91 if (format1.frame_size.GetCheckedArea().ValueOrDefault(0) == | |
92 format2.frame_size.GetCheckedArea().ValueOrDefault(0)) { | |
93 return format1.frame_rate > format2.frame_rate; | |
94 } | |
95 return format1.frame_size.GetCheckedArea().ValueOrDefault(0) < | |
96 format2.frame_size.GetCheckedArea().ValueOrDefault(0); | |
97 } | 60 } |
98 | 61 |
99 bool IsCaptureFormatSizeEqual(const media::VideoCaptureFormat& format1, | 62 void StopAndReleaseDeviceOnDeviceThread(media::VideoCaptureDevice* device, |
100 const media::VideoCaptureFormat& format2) { | 63 base::OnceClosure done_cb) { |
101 DCHECK(format1.frame_size.GetCheckedArea().IsValid()); | 64 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StopDeviceTime"); |
102 DCHECK(format2.frame_size.GetCheckedArea().IsValid()); | 65 device->StopAndDeAllocate(); |
103 return format1.frame_size.GetCheckedArea().ValueOrDefault(0) == | 66 DVLOG(3) << "StopAndReleaseDeviceOnDeviceThread"; |
104 format2.frame_size.GetCheckedArea().ValueOrDefault(0); | 67 delete device; |
miu
2017/03/20 23:02:16
After this line:
done_cb.Run();
Even though yo
chfremer
2017/03/20 23:58:26
Done.
| |
105 } | |
106 | |
107 // This function receives a list of capture formats, removes duplicated | |
108 // resolutions while keeping the highest frame rate for each, and forcing I420 | |
109 // pixel format. | |
110 void ConsolidateCaptureFormats(media::VideoCaptureFormats* formats) { | |
111 if (formats->empty()) | |
112 return; | |
113 std::sort(formats->begin(), formats->end(), IsCaptureFormatSmaller); | |
114 // Due to the ordering imposed, the largest frame_rate is kept while removing | |
115 // duplicated resolutions. | |
116 media::VideoCaptureFormats::iterator last = | |
117 std::unique(formats->begin(), formats->end(), IsCaptureFormatSizeEqual); | |
118 formats->erase(last, formats->end()); | |
119 // Mark all formats as I420, since this is what the renderer side will get | |
120 // anyhow: the actual pixel format is decided at the device level. | |
121 // Don't do this for Y16 format as it is handled separatelly. | |
122 for (auto& format : *formats) { | |
123 if (format.pixel_format != media::PIXEL_FORMAT_Y16) | |
124 format.pixel_format = media::PIXEL_FORMAT_I420; | |
125 } | |
126 } | 68 } |
127 | 69 |
128 // The maximum number of video frame buffers in-flight at any one time. This | 70 // The maximum number of video frame buffers in-flight at any one time. This |
129 // value should be based on the logical capacity of the capture pipeline, and | 71 // value should be based on the logical capacity of the capture pipeline, and |
130 // not on hardware performance. For example, tab capture requires more buffers | 72 // not on hardware performance. For example, tab capture requires more buffers |
131 // than webcam capture because the pipeline is longer (it includes read-backs | 73 // than webcam capture because the pipeline is longer (it includes read-backs |
132 // pending in the GPU pipeline). | 74 // pending in the GPU pipeline). |
133 const int kMaxNumberOfBuffers = 3; | 75 const int kMaxNumberOfBuffers = 3; |
134 // TODO(miu): The value for tab capture should be determined programmatically. | 76 // TODO(miu): The value for tab capture should be determined programmatically. |
135 // http://crbug.com/460318 | 77 // http://crbug.com/460318 |
136 const int kMaxNumberOfBuffersForTabCapture = 10; | 78 const int kMaxNumberOfBuffersForTabCapture = 10; |
137 | 79 |
138 // Used for logging capture events. | 80 } // anonymous namespace |
139 // Elements in this enum should not be deleted or rearranged; the only | |
140 // permitted operation is to add new elements before NUM_VIDEO_CAPTURE_EVENT. | |
141 enum VideoCaptureEvent { | |
142 VIDEO_CAPTURE_START_CAPTURE = 0, | |
143 VIDEO_CAPTURE_STOP_CAPTURE_OK = 1, | |
144 VIDEO_CAPTURE_STOP_CAPTURE_DUE_TO_ERROR = 2, | |
145 VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DEVICE = 3, | |
146 VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DESKTOP_OR_TAB = 4, | |
147 NUM_VIDEO_CAPTURE_EVENT | |
148 }; | |
149 | |
150 void LogVideoCaptureEvent(VideoCaptureEvent event) { | |
151 UMA_HISTOGRAM_ENUMERATION("Media.VideoCaptureManager.Event", | |
152 event, | |
153 NUM_VIDEO_CAPTURE_EVENT); | |
154 } | |
155 | |
156 // Counter used for identifying a DeviceRequest to start a capture device. | |
157 static int g_device_start_id = 0; | |
158 | |
159 const media::VideoCaptureSessionId kFakeSessionId = -1; | |
160 | |
161 std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder( | |
162 const media::VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) { | |
163 return base::MakeUnique<content::VideoCaptureGpuJpegDecoder>(decode_done_cb); | |
164 } | |
165 | |
166 } // namespace | |
167 | 81 |
168 namespace content { | 82 namespace content { |
169 | 83 |
170 // Instances of this struct go through several different phases during their | 84 InProcessBuildableVideoCaptureDevice::InProcessBuildableVideoCaptureDevice( |
171 // lifetime. | 85 scoped_refptr<base::SingleThreadTaskRunner> device_task_runner, |
172 // Phase 1: When first created (in GetOrCreateDeviceEntry()), this consists of | 86 media::VideoCaptureDeviceFactory* device_factory) |
173 // only the |video_capture_controller|. Clients can already connect to the | |
174 // controller, but there is no |video_capture_device| present. | |
175 // Phase 2: When a request to "start" the entry comes in (via | |
176 // HandleQueuedStartRequest()), creation of |video_capture_device| is scheduled | |
177 // to run asynchronously on the Device Thread. | |
178 // Phase 3: As soon as the creation of the VideoCaptureDevice is complete, this | |
179 // newly created VideoCaptureDevice instance is connected to the | |
180 // VideoCaptureController via SetConsumerFeedbackObserver(). | |
181 // Phase 4: This phase can only be reached on Android. When the application goes | |
182 // to the background, the |video_capture_device| is asynchronously stopped and | |
183 // released on the Device Thread. When the application is resumed, we | |
184 // transition to Phase 2. | |
185 struct VideoCaptureManager::DeviceEntry { | |
186 public: | |
187 DeviceEntry(MediaStreamType stream_type, | |
188 const std::string& id, | |
189 const media::VideoCaptureParams& params); | |
190 ~DeviceEntry(); | |
191 std::unique_ptr<media::VideoCaptureDevice::Client> CreateDeviceClient(); | |
192 | |
193 const int serial_id; | |
194 const MediaStreamType stream_type; | |
195 const std::string id; | |
196 const media::VideoCaptureParams parameters; | |
197 VideoCaptureController video_capture_controller; | |
198 std::unique_ptr<media::VideoCaptureDevice> video_capture_device; | |
199 }; | |
200 | |
201 // Bundles a media::VideoCaptureDeviceDescriptor with corresponding supported | |
202 // video formats. | |
203 struct VideoCaptureManager::DeviceInfo { | |
204 DeviceInfo(); | |
205 DeviceInfo(media::VideoCaptureDeviceDescriptor descriptor); | |
206 DeviceInfo(const DeviceInfo& other); | |
207 ~DeviceInfo(); | |
208 DeviceInfo& operator=(const DeviceInfo& other); | |
209 | |
210 media::VideoCaptureDeviceDescriptor descriptor; | |
211 media::VideoCaptureFormats supported_formats; | |
212 }; | |
213 | |
214 // Class used for queuing request for starting a device. | |
215 class VideoCaptureManager::CaptureDeviceStartRequest { | |
216 public: | |
217 CaptureDeviceStartRequest(int serial_id, | |
218 media::VideoCaptureSessionId session_id, | |
219 const media::VideoCaptureParams& params); | |
220 int serial_id() const { return serial_id_; } | |
221 media::VideoCaptureSessionId session_id() const { return session_id_; } | |
222 media::VideoCaptureParams params() const { return params_; } | |
223 | |
224 // Set to true if the device should be stopped before it has successfully | |
225 // been started. | |
226 bool abort_start() const { return abort_start_; } | |
227 void set_abort_start() { abort_start_ = true; } | |
228 | |
229 private: | |
230 const int serial_id_; | |
231 const media::VideoCaptureSessionId session_id_; | |
232 const media::VideoCaptureParams params_; | |
233 // Set to true if the device should be stopped before it has successfully | |
234 // been started. | |
235 bool abort_start_; | |
236 }; | |
237 | |
238 VideoCaptureManager::DeviceEntry::DeviceEntry( | |
239 MediaStreamType stream_type, | |
240 const std::string& id, | |
241 const media::VideoCaptureParams& params) | |
242 : serial_id(g_device_start_id++), | |
243 stream_type(stream_type), | |
244 id(id), | |
245 parameters(params) {} | |
246 | |
247 VideoCaptureManager::DeviceEntry::~DeviceEntry() { | |
248 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
249 // DCHECK that this DeviceEntry does not still own a | |
250 // media::VideoCaptureDevice. media::VideoCaptureDevice must be deleted on | |
251 // the device thread. | |
252 DCHECK(video_capture_device == nullptr); | |
253 } | |
254 | |
255 std::unique_ptr<media::VideoCaptureDevice::Client> | |
256 VideoCaptureManager::DeviceEntry::CreateDeviceClient() { | |
257 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
258 | |
259 const int max_buffers = stream_type == MEDIA_TAB_VIDEO_CAPTURE | |
260 ? kMaxNumberOfBuffersForTabCapture | |
261 : kMaxNumberOfBuffers; | |
262 scoped_refptr<media::VideoCaptureBufferPool> buffer_pool = | |
263 new media::VideoCaptureBufferPoolImpl( | |
264 base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(), | |
265 max_buffers); | |
266 | |
267 return base::MakeUnique<media::VideoCaptureDeviceClient>( | |
268 base::MakeUnique<VideoFrameReceiverOnIOThread>( | |
269 video_capture_controller.GetWeakPtrForIOThread()), | |
270 std::move(buffer_pool), | |
271 base::Bind(&CreateGpuJpegDecoder, | |
272 base::Bind(&media::VideoFrameReceiver::OnFrameReadyInBuffer, | |
273 video_capture_controller.GetWeakPtrForIOThread()))); | |
274 } | |
275 | |
276 VideoCaptureManager::DeviceInfo::DeviceInfo() = default; | |
277 | |
278 VideoCaptureManager::DeviceInfo::DeviceInfo( | |
279 media::VideoCaptureDeviceDescriptor descriptor) | |
280 : descriptor(descriptor) {} | |
281 | |
282 VideoCaptureManager::DeviceInfo::DeviceInfo( | |
283 const VideoCaptureManager::DeviceInfo& other) = default; | |
284 | |
285 VideoCaptureManager::DeviceInfo::~DeviceInfo() = default; | |
286 | |
287 VideoCaptureManager::DeviceInfo& VideoCaptureManager::DeviceInfo::operator=( | |
288 const VideoCaptureManager::DeviceInfo& other) = default; | |
289 | |
290 VideoCaptureManager::CaptureDeviceStartRequest::CaptureDeviceStartRequest( | |
291 int serial_id, | |
292 media::VideoCaptureSessionId session_id, | |
293 const media::VideoCaptureParams& params) | |
294 : serial_id_(serial_id), | |
295 session_id_(session_id), | |
296 params_(params), | |
297 abort_start_(false) { | |
298 } | |
299 | |
300 VideoCaptureManager::VideoCaptureManager( | |
301 std::unique_ptr<media::VideoCaptureDeviceFactory> factory, | |
302 scoped_refptr<base::SingleThreadTaskRunner> device_task_runner) | |
303 : device_task_runner_(std::move(device_task_runner)), | 87 : device_task_runner_(std::move(device_task_runner)), |
304 new_capture_session_id_(1), | 88 device_factory_(device_factory) {} |
305 video_capture_device_factory_(std::move(factory)) {} | 89 |
306 | 90 InProcessBuildableVideoCaptureDevice::~InProcessBuildableVideoCaptureDevice() { |
307 VideoCaptureManager::~VideoCaptureManager() { | 91 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
308 DCHECK(devices_.empty()); | 92 DCHECK(!device_); |
309 DCHECK(device_start_queue_.empty()); | 93 } |
310 } | 94 |
311 | 95 void InProcessBuildableVideoCaptureDevice::CreateAndStartDeviceAsync( |
312 void VideoCaptureManager::AddVideoCaptureObserver( | 96 VideoCaptureController* controller, |
313 media::VideoCaptureObserver* observer) { | 97 const media::VideoCaptureParams& params, |
314 DCHECK(observer); | 98 DeviceBuildContext context) { |
315 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 99 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
316 capture_observers_.AddObserver(observer); | 100 |
317 } | 101 const int max_buffers = (controller->stream_type() == MEDIA_TAB_VIDEO_CAPTURE |
318 | 102 ? kMaxNumberOfBuffersForTabCapture |
319 void VideoCaptureManager::RemoveAllVideoCaptureObservers() { | 103 : kMaxNumberOfBuffers); |
320 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 104 |
321 capture_observers_.Clear(); | 105 auto device_client = |
322 } | 106 CreateDeviceClient(max_buffers, controller->GetWeakPtrForIOThread()); |
323 | 107 |
324 void VideoCaptureManager::RegisterListener( | 108 base::Closure start_capture_closure; |
325 MediaStreamProviderListener* listener) { | 109 // Use of Unretained() is safe, because |context_reference| guarantees that |
326 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 110 // |this| stays alive. |
327 DCHECK(listener); | 111 ReceiveDeviceCallback after_start_capture_callback = media::BindToCurrentLoop( |
328 DCHECK(device_task_runner_); | 112 base::Bind(&InProcessBuildableVideoCaptureDevice::OnDeviceStarted, |
329 listeners_.AddObserver(listener); | 113 base::Unretained(this), controller, base::Passed(&context))); |
330 #if defined(OS_ANDROID) | 114 |
331 application_state_has_running_activities_ = true; | 115 switch (controller->stream_type()) { |
332 app_status_listener_.reset(new base::android::ApplicationStatusListener( | |
333 base::Bind(&VideoCaptureManager::OnApplicationStateChange, | |
334 base::Unretained(this)))); | |
335 #endif | |
336 } | |
337 | |
338 void VideoCaptureManager::UnregisterListener( | |
339 MediaStreamProviderListener* listener) { | |
340 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
341 listeners_.RemoveObserver(listener); | |
342 } | |
343 | |
344 void VideoCaptureManager::EnumerateDevices( | |
345 const EnumerationCallback& client_callback) { | |
346 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
347 DVLOG(1) << "VideoCaptureManager::EnumerateDevices"; | |
348 | |
349 // Bind a callback to ConsolidateDevicesInfoOnDeviceThread() with an argument | |
350 // for another callback to OnDevicesInfoEnumerated() to be run in the current | |
351 // loop, i.e. IO loop. Pass a timer for UMA histogram collection. | |
352 base::Callback<void(std::unique_ptr<VideoCaptureDeviceDescriptors>)> | |
353 devices_enumerated_callback = base::Bind( | |
354 &VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread, this, | |
355 media::BindToCurrentLoop(base::Bind( | |
356 &VideoCaptureManager::OnDevicesInfoEnumerated, this, | |
357 base::Owned(new base::ElapsedTimer()), client_callback)), | |
358 devices_info_cache_); | |
359 // OK to use base::Unretained() since we own the VCDFactory and |this| is | |
360 // bound in |devices_enumerated_callback|. | |
361 device_task_runner_->PostTask( | |
362 FROM_HERE, | |
363 base::Bind(&media::VideoCaptureDeviceFactory::EnumerateDeviceDescriptors, | |
364 base::Unretained(video_capture_device_factory_.get()), | |
365 devices_enumerated_callback)); | |
366 } | |
367 | |
368 int VideoCaptureManager::Open(const MediaStreamDevice& device) { | |
369 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
370 | |
371 // Generate a new id for the session being opened. | |
372 const media::VideoCaptureSessionId capture_session_id = | |
373 new_capture_session_id_++; | |
374 | |
375 DCHECK(sessions_.find(capture_session_id) == sessions_.end()); | |
376 DVLOG(1) << "VideoCaptureManager::Open, id " << capture_session_id; | |
377 | |
378 // We just save the stream info for processing later. | |
379 sessions_[capture_session_id] = device; | |
380 | |
381 // Notify our listener asynchronously; this ensures that we return | |
382 // |capture_session_id| to the caller of this function before using that same | |
383 // id in a listener event. | |
384 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
385 FROM_HERE, base::Bind(&VideoCaptureManager::OnOpened, this, device.type, | |
386 capture_session_id)); | |
387 return capture_session_id; | |
388 } | |
389 | |
390 void VideoCaptureManager::Close(int capture_session_id) { | |
391 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
392 DVLOG(1) << "VideoCaptureManager::Close, id " << capture_session_id; | |
393 | |
394 SessionMap::iterator session_it = sessions_.find(capture_session_id); | |
395 if (session_it == sessions_.end()) { | |
396 NOTREACHED(); | |
397 return; | |
398 } | |
399 | |
400 DeviceEntry* const existing_device = | |
401 GetDeviceEntryByTypeAndId(session_it->second.type, session_it->second.id); | |
402 if (existing_device) { | |
403 // Remove any client that is still using the session. This is safe to call | |
404 // even if there are no clients using the session. | |
405 existing_device->video_capture_controller.StopSession(capture_session_id); | |
406 | |
407 // StopSession() may have removed the last client, so we might need to | |
408 // close the device. | |
409 DestroyDeviceEntryIfNoClients(existing_device); | |
410 } | |
411 | |
412 // Notify listeners asynchronously, and forget the session. | |
413 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
414 FROM_HERE, base::Bind(&VideoCaptureManager::OnClosed, this, | |
415 session_it->second.type, capture_session_id)); | |
416 sessions_.erase(session_it); | |
417 } | |
418 | |
419 void VideoCaptureManager::QueueStartDevice( | |
420 media::VideoCaptureSessionId session_id, | |
421 DeviceEntry* entry, | |
422 const media::VideoCaptureParams& params) { | |
423 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
424 device_start_queue_.push_back( | |
425 CaptureDeviceStartRequest(entry->serial_id, session_id, params)); | |
426 if (device_start_queue_.size() == 1) | |
427 HandleQueuedStartRequest(); | |
428 } | |
429 | |
430 void VideoCaptureManager::DoStopDevice(DeviceEntry* entry) { | |
431 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
432 // TODO(mcasas): use a helper function https://crbug.com/624854. | |
433 DCHECK( | |
434 std::find_if(devices_.begin(), devices_.end(), | |
435 [entry](const std::unique_ptr<DeviceEntry>& device_entry) { | |
436 return device_entry.get() == entry; | |
437 }) != devices_.end()); | |
438 | |
439 // Find the matching start request. | |
440 for (DeviceStartQueue::reverse_iterator request = | |
441 device_start_queue_.rbegin(); | |
442 request != device_start_queue_.rend(); ++request) { | |
443 if (request->serial_id() == entry->serial_id) { | |
444 request->set_abort_start(); | |
445 DVLOG(3) << "DoStopDevice, aborting start request for device " | |
446 << entry->id << " serial_id = " << entry->serial_id; | |
447 return; | |
448 } | |
449 } | |
450 | |
451 const DeviceInfo* device_info = GetDeviceInfoById(entry->id); | |
452 if (device_info != nullptr) { | |
453 for (auto& observer : capture_observers_) | |
454 observer.OnVideoCaptureStopped(device_info->descriptor.facing); | |
455 } | |
456 | |
457 DVLOG(3) << "DoStopDevice. Send stop request for device = " << entry->id | |
458 << " serial_id = " << entry->serial_id << "."; | |
459 entry->video_capture_controller.OnLog( | |
460 base::StringPrintf("Stopping device: id: %s", entry->id.c_str())); | |
461 entry->video_capture_controller.SetConsumerFeedbackObserver(nullptr); | |
462 | |
463 // |entry->video_capture_device| can be null if creating the device has | |
464 // failed. | |
465 if (entry->video_capture_device) { | |
466 device_task_runner_->PostTask( | |
467 FROM_HERE, | |
468 base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this, | |
469 base::Passed(&entry->video_capture_device))); | |
470 } | |
471 } | |
472 | |
473 void VideoCaptureManager::HandleQueuedStartRequest() { | |
474 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
475 // Remove all start requests that have been aborted. | |
476 while (device_start_queue_.begin() != device_start_queue_.end() && | |
477 device_start_queue_.begin()->abort_start()) { | |
478 device_start_queue_.pop_front(); | |
479 } | |
480 DeviceStartQueue::iterator request = device_start_queue_.begin(); | |
481 if (request == device_start_queue_.end()) | |
482 return; | |
483 | |
484 const int serial_id = request->serial_id(); | |
485 DeviceEntry* const entry = GetDeviceEntryBySerialId(serial_id); | |
486 DCHECK(entry); | |
487 | |
488 DVLOG(3) << "HandleQueuedStartRequest, Post start to device thread, device = " | |
489 << entry->id << " start id = " << entry->serial_id; | |
490 | |
491 std::unique_ptr<media::VideoCaptureDevice::Client> device_client = | |
492 entry->CreateDeviceClient(); | |
493 | |
494 base::Callback<std::unique_ptr<VideoCaptureDevice>(void)> | |
495 start_capture_function; | |
496 | |
497 switch (entry->stream_type) { | |
498 case MEDIA_DEVICE_VIDEO_CAPTURE: { | 116 case MEDIA_DEVICE_VIDEO_CAPTURE: { |
499 // We look up the device id from the renderer in our local enumeration | 117 const media::VideoCaptureDeviceDescriptor* descriptor = |
500 // since the renderer does not have all the information that might be | 118 context.LookupDeviceDescriptor(controller->device_id()); |
miu
2017/03/20 23:02:15
|context| is invalid at this point (because you've
chfremer
2017/03/20 23:58:26
Ouch! Thanks for catching that.
What I don't under
miu
2017/03/22 22:09:50
I'm guessing nothing stomped on the memory of the
| |
501 // held in the browser-side VideoCaptureDevice::Name structure. | 119 if (descriptor) { |
502 const DeviceInfo* found = GetDeviceInfoById(entry->id); | 120 controller->OnLog( |
503 if (found) { | |
504 entry->video_capture_controller.OnLog( | |
505 base::StringPrintf("Starting device: id: %s, name: %s, api: %s", | 121 base::StringPrintf("Starting device: id: %s, name: %s, api: %s", |
506 found->descriptor.device_id.c_str(), | 122 descriptor->device_id.c_str(), |
507 found->descriptor.GetNameAndModel().c_str(), | 123 descriptor->GetNameAndModel().c_str(), |
508 found->descriptor.GetCaptureApiTypeString())); | 124 descriptor->GetCaptureApiTypeString())); |
509 | 125 |
510 for (auto& observer : capture_observers_) | 126 context.WillStartDevice(descriptor->facing); |
511 observer.OnVideoCaptureStarted(found->descriptor.facing); | 127 |
512 | 128 start_capture_closure = |
513 start_capture_function = | 129 base::Bind(&InProcessBuildableVideoCaptureDevice:: |
514 base::Bind(&VideoCaptureManager::DoStartDeviceCaptureOnDeviceThread, | 130 DoStartDeviceCaptureOnDeviceThread, |
515 this, found->descriptor, request->params(), | 131 base::Unretained(this), *descriptor, params, |
516 base::Passed(std::move(device_client))); | 132 base::Passed(std::move(device_client)), |
133 std::move(after_start_capture_callback)); | |
517 } else { | 134 } else { |
518 // Errors from DoStartDeviceCaptureOnDeviceThread go via | 135 std::move(context).OnDeviceStartFailed(controller); |
519 // VideoCaptureDeviceClient::OnError, which needs some thread | |
520 // dancing to get errors processed on the IO thread. But since | |
521 // we're on that thread, we call VideoCaptureController | |
522 // methods directly. | |
523 const std::string log_message = base::StringPrintf( | |
524 "Error on %s:%d: device %s unknown. Maybe recently disconnected?", | |
525 __FILE__, __LINE__, entry->id.c_str()); | |
526 DLOG(ERROR) << log_message; | |
527 entry->video_capture_controller.OnLog(log_message); | |
528 entry->video_capture_controller.OnError(); | |
529 // Drop the failed start request. | |
530 device_start_queue_.pop_front(); | |
531 | |
532 return; | 136 return; |
533 } | 137 } |
534 break; | 138 break; |
535 } | 139 } |
536 case MEDIA_TAB_VIDEO_CAPTURE: | 140 case MEDIA_TAB_VIDEO_CAPTURE: |
537 start_capture_function = base::Bind( | 141 start_capture_closure = |
538 &VideoCaptureManager::DoStartTabCaptureOnDeviceThread, this, | 142 base::Bind(&InProcessBuildableVideoCaptureDevice:: |
539 entry->id, request->params(), base::Passed(std::move(device_client))); | 143 DoStartTabCaptureOnDeviceThread, |
144 base::Unretained(this), controller->device_id(), params, | |
145 base::Passed(std::move(device_client)), | |
146 std::move(after_start_capture_callback)); | |
540 break; | 147 break; |
541 | 148 |
542 case MEDIA_DESKTOP_VIDEO_CAPTURE: | 149 case MEDIA_DESKTOP_VIDEO_CAPTURE: |
543 start_capture_function = base::Bind( | 150 start_capture_closure = |
544 &VideoCaptureManager::DoStartDesktopCaptureOnDeviceThread, this, | 151 base::Bind(&InProcessBuildableVideoCaptureDevice:: |
545 entry->id, request->params(), base::Passed(std::move(device_client))); | 152 DoStartDesktopCaptureOnDeviceThread, |
153 base::Unretained(this), controller->device_id(), params, | |
154 base::Passed(std::move(device_client)), | |
155 std::move(after_start_capture_callback)); | |
546 break; | 156 break; |
547 | 157 |
548 default: { | 158 default: { |
549 NOTIMPLEMENTED(); | 159 NOTIMPLEMENTED(); |
550 return; | 160 return; |
551 } | 161 } |
552 } | 162 } |
553 base::PostTaskAndReplyWithResult( | 163 |
554 device_task_runner_.get(), FROM_HERE, start_capture_function, | 164 device_task_runner_->PostTask(FROM_HERE, start_capture_closure); |
555 base::Bind(&VideoCaptureManager::OnDeviceStarted, this, | 165 } |
556 request->serial_id())); | 166 |
557 } | 167 void InProcessBuildableVideoCaptureDevice::ReleaseDeviceAsync( |
558 | 168 VideoCaptureController* controller, |
559 void VideoCaptureManager::OnDeviceStarted( | 169 base::OnceClosure done_cb) { |
miu
2017/03/20 23:02:16
Need to ensure |done_cb| is Run().
chfremer
2017/03/20 23:58:26
Done.
| |
560 int serial_id, | 170 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
561 std::unique_ptr<VideoCaptureDevice> device) { | 171 controller->SetConsumerFeedbackObserver(nullptr); |
562 DVLOG(3) << __func__; | 172 if (!device_) |
563 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 173 return; |
564 DCHECK_EQ(serial_id, device_start_queue_.begin()->serial_id()); | 174 media::VideoCaptureDevice* device_ptr = device_.release(); |
565 // |device| can be null if creation failed in | 175 |
566 // DoStartDeviceCaptureOnDeviceThread. | 176 bool posting_task_succeeded = device_task_runner_->PostTask( |
567 if (device_start_queue_.front().abort_start()) { | 177 FROM_HERE, |
568 // The device is no longer wanted. Stop the device again. | 178 base::Bind(&StopAndReleaseDeviceOnDeviceThread, device_ptr, |
569 DVLOG(3) << "OnDeviceStarted but start request have been aborted."; | 179 base::Bind([](scoped_refptr<base::SingleThreadTaskRunner>) {}, |
570 media::VideoCaptureDevice* device_ptr = device.get(); | 180 device_task_runner_))); |
571 base::Closure closure = | 181 if (posting_task_succeeded == false) { |
572 base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this, | 182 // Since posting to the task runner has failed, we attempt doing it on |
573 base::Passed(&device)); | 183 // the calling thread instead. |
574 if (device_ptr && !device_task_runner_->PostTask(FROM_HERE, closure)) { | 184 StopAndReleaseDeviceOnDeviceThread(device_ptr, base::Bind([]() {})); |
575 // PostTask failed. The device must be stopped anyway. | 185 } |
576 device_ptr->StopAndDeAllocate(); | 186 } |
577 } | 187 |
578 } else { | 188 bool InProcessBuildableVideoCaptureDevice::IsDeviceAlive() const { |
579 DeviceEntry* const entry = GetDeviceEntryBySerialId(serial_id); | 189 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
580 DCHECK(entry); | 190 return device_ != nullptr; |
581 DCHECK(!entry->video_capture_device); | 191 } |
582 if (device) { | 192 |
583 // Passing raw pointer |device.get()| to the controller is safe, | 193 void InProcessBuildableVideoCaptureDevice::GetPhotoCapabilities( |
584 // because we transfer ownership of it to |entry|. We are calling | 194 media::VideoCaptureDevice::GetPhotoCapabilitiesCallback callback) const { |
585 // SetConsumerFeedbackObserver(nullptr) before releasing | 195 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
586 // |entry->video_capture_device_| on the |device_task_runner_|. | 196 // Unretained() is safe to use here because |device| would be null if it |
587 entry->video_capture_controller.SetConsumerFeedbackObserver( | 197 // was scheduled for shutdown and destruction, and because this task is |
588 base::MakeUnique<VideoFrameConsumerFeedbackObserverOnTaskRunner>( | 198 // guaranteed to run before the task that destroys the |device|. |
589 device.get(), device_task_runner_)); | 199 device_task_runner_->PostTask( |
590 } | 200 FROM_HERE, |
591 entry->video_capture_device = std::move(device); | 201 base::Bind(&media::VideoCaptureDevice::GetPhotoCapabilities, |
592 | 202 base::Unretained(device_.get()), base::Passed(&callback))); |
593 if (entry->stream_type == MEDIA_DESKTOP_VIDEO_CAPTURE) { | 203 } |
594 const media::VideoCaptureSessionId session_id = | 204 |
595 device_start_queue_.front().session_id(); | 205 void InProcessBuildableVideoCaptureDevice::SetPhotoOptions( |
596 DCHECK(session_id != kFakeSessionId); | 206 media::mojom::PhotoSettingsPtr settings, |
597 MaybePostDesktopCaptureWindowId(session_id); | 207 media::VideoCaptureDevice::SetPhotoOptionsCallback callback) { |
598 } | 208 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
599 | 209 // Unretained() is safe to use here because |device| would be null if it |
600 auto it = photo_request_queue_.begin(); | 210 // was scheduled for shutdown and destruction, and because this task is |
601 while (it != photo_request_queue_.end()) { | 211 // guaranteed to run before the task that destroys the |device|. |
602 auto request = it++; | 212 device_task_runner_->PostTask( |
603 DeviceEntry* maybe_entry = GetDeviceEntryBySessionId(request->first); | 213 FROM_HERE, base::Bind(&media::VideoCaptureDevice::SetPhotoOptions, |
604 if (maybe_entry && maybe_entry->video_capture_device) { | 214 base::Unretained(device_.get()), |
605 request->second.Run(maybe_entry->video_capture_device.get()); | 215 base::Passed(&settings), base::Passed(&callback))); |
606 photo_request_queue_.erase(request); | 216 } |
607 } | 217 |
608 } | 218 void InProcessBuildableVideoCaptureDevice::TakePhoto( |
609 } | 219 media::VideoCaptureDevice::TakePhotoCallback callback) { |
610 | 220 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
611 device_start_queue_.pop_front(); | 221 // Unretained() is safe to use here because |device| would be null if it |
612 HandleQueuedStartRequest(); | 222 // was scheduled for shutdown and destruction, and because this task is |
613 } | 223 // guaranteed to run before the task that destroys the |device|. |
614 | 224 device_task_runner_->PostTask( |
615 std::unique_ptr<media::VideoCaptureDevice> | 225 FROM_HERE, |
616 VideoCaptureManager::DoStartDeviceCaptureOnDeviceThread( | 226 base::Bind(&media::VideoCaptureDevice::TakePhoto, |
617 const VideoCaptureDeviceDescriptor& descriptor, | 227 base::Unretained(device_.get()), base::Passed(&callback))); |
618 const media::VideoCaptureParams& params, | 228 } |
619 std::unique_ptr<VideoCaptureDevice::Client> device_client) { | 229 |
230 void InProcessBuildableVideoCaptureDevice::MaybeSuspendDevice() { | |
231 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
232 // Unretained() is safe to use here because |device| would be null if it | |
233 // was scheduled for shutdown and destruction, and because this task is | |
234 // guaranteed to run before the task that destroys the |device|. | |
235 device_task_runner_->PostTask( | |
236 FROM_HERE, base::Bind(&media::VideoCaptureDevice::MaybeSuspend, | |
237 base::Unretained(device_.get()))); | |
238 } | |
239 | |
240 void InProcessBuildableVideoCaptureDevice::ResumeDevice() { | |
241 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
242 // Unretained() is safe to use here because |device| would be null if it | |
243 // was scheduled for shutdown and destruction, and because this task is | |
244 // guaranteed to run before the task that destroys the |device|. | |
245 device_task_runner_->PostTask(FROM_HERE, | |
246 base::Bind(&media::VideoCaptureDevice::Resume, | |
247 base::Unretained(device_.get()))); | |
248 } | |
249 | |
250 void InProcessBuildableVideoCaptureDevice::RequestRefreshFrame() { | |
251 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
252 // Unretained() is safe to use here because |device| would be null if it | |
253 // was scheduled for shutdown and destruction, and because this task is | |
254 // guaranteed to run before the task that destroys the |device|. | |
255 device_task_runner_->PostTask( | |
256 FROM_HERE, base::Bind(&media::VideoCaptureDevice::RequestRefreshFrame, | |
257 base::Unretained(device_.get()))); | |
258 } | |
259 | |
260 void InProcessBuildableVideoCaptureDevice::SetDesktopCaptureWindowIdAsync( | |
261 gfx::NativeViewId window_id, | |
262 base::OnceClosure done_cb) { | |
263 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
264 // Post |device_| to the the device_task_runner_. This is safe since the | |
265 // device is destroyed on the device_task_runner_ and |context_reference| | |
266 // guarantees that |this| stays alive. | |
267 device_task_runner_->PostTask( | |
268 FROM_HERE, base::Bind(&InProcessBuildableVideoCaptureDevice:: | |
269 SetDesktopCaptureWindowIdOnDeviceThread, | |
270 base::Unretained(this), device_.get(), window_id, | |
271 base::Passed(&done_cb))); | |
272 } | |
273 | |
274 std::unique_ptr<media::VideoCaptureDeviceClient> | |
275 InProcessBuildableVideoCaptureDevice::CreateDeviceClient( | |
276 int buffer_pool_max_buffer_count, | |
277 base::WeakPtr<media::VideoFrameReceiver> receiver) { | |
278 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
279 | |
280 scoped_refptr<media::VideoCaptureBufferPool> buffer_pool_ = | |
281 new media::VideoCaptureBufferPoolImpl( | |
282 base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(), | |
283 buffer_pool_max_buffer_count); | |
284 | |
285 return base::MakeUnique<media::VideoCaptureDeviceClient>( | |
286 base::MakeUnique<VideoFrameReceiverOnIOThread>(receiver), buffer_pool_, | |
287 base::Bind(&CreateGpuJpegDecoder, | |
288 base::Bind(&media::VideoFrameReceiver::OnFrameReadyInBuffer, | |
289 receiver))); | |
290 } | |
291 | |
292 void InProcessBuildableVideoCaptureDevice::OnDeviceStarted( | |
293 VideoCaptureController* controller, | |
294 DeviceBuildContext context, | |
295 std::unique_ptr<media::VideoCaptureDevice> device) { | |
296 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
297 if (!device) { | |
298 std::move(context).OnDeviceStartFailed(controller); | |
299 return; | |
300 } | |
301 // Passing raw pointer |device.get()| to the controller is safe, | |
302 // because we take ownership of |device| and we call | |
303 // controller->SetConsumerFeedbackObserver(nullptr) before releasing |device|. | |
304 controller->SetConsumerFeedbackObserver( | |
305 base::MakeUnique<VideoFrameConsumerFeedbackObserverOnTaskRunner>( | |
306 device.get(), device_task_runner_)); | |
307 device_ = std::move(device); | |
308 std::move(context).DidStartDevice(controller); | |
309 } | |
310 | |
311 void InProcessBuildableVideoCaptureDevice::DoStartDeviceCaptureOnDeviceThread( | |
312 const media::VideoCaptureDeviceDescriptor& descriptor, | |
313 const media::VideoCaptureParams& params, | |
314 std::unique_ptr<media::VideoCaptureDeviceClient> device_client, | |
315 ReceiveDeviceCallback result_callback) { | |
620 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); | 316 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); |
621 DCHECK(IsOnDeviceThread()); | 317 DCHECK(device_task_runner_->BelongsToCurrentThread()); |
622 | 318 |
623 std::unique_ptr<VideoCaptureDevice> video_capture_device; | 319 std::unique_ptr<media::VideoCaptureDevice> video_capture_device = |
624 video_capture_device = | 320 device_factory_->CreateDevice(descriptor); |
625 video_capture_device_factory_->CreateDevice(descriptor); | |
626 | 321 |
627 if (!video_capture_device) { | 322 if (!video_capture_device) { |
628 device_client->OnError(FROM_HERE, "Could not create capture device"); | 323 result_callback.Run(nullptr); |
629 return nullptr; | 324 return; |
630 } | 325 } |
631 | 326 |
632 video_capture_device->AllocateAndStart(params, std::move(device_client)); | 327 video_capture_device->AllocateAndStart(params, std::move(device_client)); |
633 return video_capture_device; | 328 result_callback.Run(std::move(video_capture_device)); |
634 } | 329 } |
635 | 330 |
636 std::unique_ptr<media::VideoCaptureDevice> | 331 void InProcessBuildableVideoCaptureDevice::DoStartTabCaptureOnDeviceThread( |
637 VideoCaptureManager::DoStartTabCaptureOnDeviceThread( | |
638 const std::string& id, | 332 const std::string& id, |
639 const media::VideoCaptureParams& params, | 333 const media::VideoCaptureParams& params, |
640 std::unique_ptr<VideoCaptureDevice::Client> device_client) { | 334 std::unique_ptr<media::VideoCaptureDeviceClient> device_client, |
335 ReceiveDeviceCallback result_callback) { | |
641 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); | 336 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); |
642 DCHECK(IsOnDeviceThread()); | 337 DCHECK(device_task_runner_->BelongsToCurrentThread()); |
643 | 338 |
644 std::unique_ptr<VideoCaptureDevice> video_capture_device; | 339 std::unique_ptr<media::VideoCaptureDevice> video_capture_device; |
645 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) | 340 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) |
646 video_capture_device = WebContentsVideoCaptureDevice::Create(id); | 341 video_capture_device = WebContentsVideoCaptureDevice::Create(id); |
647 #endif | 342 #endif |
648 | 343 |
649 if (!video_capture_device) { | 344 if (!video_capture_device) { |
650 device_client->OnError(FROM_HERE, "Could not create capture device"); | 345 result_callback.Run(nullptr); |
651 return nullptr; | 346 return; |
652 } | 347 } |
653 | 348 |
654 video_capture_device->AllocateAndStart(params, std::move(device_client)); | 349 video_capture_device->AllocateAndStart(params, std::move(device_client)); |
655 return video_capture_device; | 350 result_callback.Run(std::move(video_capture_device)); |
656 } | 351 } |
657 | 352 |
658 std::unique_ptr<media::VideoCaptureDevice> | 353 void InProcessBuildableVideoCaptureDevice::DoStartDesktopCaptureOnDeviceThread( |
659 VideoCaptureManager::DoStartDesktopCaptureOnDeviceThread( | |
660 const std::string& id, | 354 const std::string& id, |
661 const media::VideoCaptureParams& params, | 355 const media::VideoCaptureParams& params, |
662 std::unique_ptr<VideoCaptureDevice::Client> device_client) { | 356 std::unique_ptr<media::VideoCaptureDeviceClient> device_client, |
357 ReceiveDeviceCallback result_callback) { | |
663 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); | 358 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); |
664 DCHECK(IsOnDeviceThread()); | 359 DCHECK(device_task_runner_->BelongsToCurrentThread()); |
665 | 360 |
666 std::unique_ptr<VideoCaptureDevice> video_capture_device; | 361 std::unique_ptr<media::VideoCaptureDevice> video_capture_device; |
667 #if defined(ENABLE_SCREEN_CAPTURE) | 362 #if defined(ENABLE_SCREEN_CAPTURE) |
668 DesktopMediaID desktop_id = DesktopMediaID::Parse(id); | 363 DesktopMediaID desktop_id = DesktopMediaID::Parse(id); |
669 if (desktop_id.is_null()) { | 364 if (desktop_id.is_null()) { |
670 device_client->OnError(FROM_HERE, "Desktop media ID is null"); | 365 DLOG(ERROR) << "Desktop media ID is null"; |
671 return nullptr; | 366 result_callback.Run(nullptr); |
367 return; | |
672 } | 368 } |
673 | 369 |
674 if (desktop_id.type == DesktopMediaID::TYPE_WEB_CONTENTS) { | 370 if (desktop_id.type == DesktopMediaID::TYPE_WEB_CONTENTS) { |
675 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) | 371 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) |
676 video_capture_device = WebContentsVideoCaptureDevice::Create(id); | 372 video_capture_device = WebContentsVideoCaptureDevice::Create(id); |
677 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED); | 373 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED); |
678 if (desktop_id.audio_share) { | 374 if (desktop_id.audio_share) { |
679 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED_WITH_AUDIO); | 375 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED_WITH_AUDIO); |
680 } else { | 376 } else { |
681 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED_WITHOUT_AUDIO); | 377 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED_WITHOUT_AUDIO); |
682 } | 378 } |
683 #endif | 379 #endif |
684 } else { | 380 } else { |
685 #if defined(OS_ANDROID) | 381 #if defined(OS_ANDROID) |
686 video_capture_device = base::MakeUnique<ScreenCaptureDeviceAndroid>(); | 382 video_capture_device = base::MakeUnique<ScreenCaptureDeviceAndroid>(); |
687 #else | 383 #else |
688 #if defined(USE_AURA) | 384 #if defined(USE_AURA) |
689 video_capture_device = DesktopCaptureDeviceAura::Create(desktop_id); | 385 video_capture_device = DesktopCaptureDeviceAura::Create(desktop_id); |
690 #endif // defined(USE_AURA) | 386 #endif // defined(USE_AURA) |
691 #if BUILDFLAG(ENABLE_WEBRTC) | 387 #if BUILDFLAG(ENABLE_WEBRTC) |
692 if (!video_capture_device) | 388 if (!video_capture_device) |
693 video_capture_device = DesktopCaptureDevice::Create(desktop_id); | 389 video_capture_device = DesktopCaptureDevice::Create(desktop_id); |
694 #endif // BUILDFLAG(ENABLE_WEBRTC) | 390 #endif // BUILDFLAG(ENABLE_WEBRTC) |
695 #endif // defined (OS_ANDROID) | 391 #endif // defined (OS_ANDROID) |
696 } | 392 } |
697 #endif // defined(ENABLE_SCREEN_CAPTURE) | 393 #endif // defined(ENABLE_SCREEN_CAPTURE) |
698 | 394 |
699 if (!video_capture_device) { | 395 if (!video_capture_device) { |
700 device_client->OnError(FROM_HERE, "Could not create capture device"); | 396 result_callback.Run(nullptr); |
701 return nullptr; | 397 return; |
702 } | 398 } |
703 | 399 |
704 video_capture_device->AllocateAndStart(params, std::move(device_client)); | 400 video_capture_device->AllocateAndStart(params, std::move(device_client)); |
705 return video_capture_device; | 401 result_callback.Run(std::move(video_capture_device)); |
706 } | 402 } |
707 | 403 |
708 void VideoCaptureManager::StartCaptureForClient( | 404 void InProcessBuildableVideoCaptureDevice:: |
709 media::VideoCaptureSessionId session_id, | 405 SetDesktopCaptureWindowIdOnDeviceThread(media::VideoCaptureDevice* device, |
710 const media::VideoCaptureParams& params, | 406 gfx::NativeViewId window_id, |
711 VideoCaptureControllerID client_id, | 407 base::OnceClosure done_cb) { |
miu
2017/03/20 23:02:16
Run |done_cb| here too.
chfremer
2017/03/20 23:58:26
Done.
| |
712 VideoCaptureControllerEventHandler* client_handler, | 408 DCHECK(device_task_runner_->BelongsToCurrentThread()); |
713 const DoneCB& done_cb) { | 409 #if defined(ENABLE_SCREEN_CAPTURE) && BUILDFLAG(ENABLE_WEBRTC) && \ |
714 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 410 !defined(OS_ANDROID) |
715 DVLOG(1) << __func__ << ", session_id = " << session_id << ", request: " | |
716 << media::VideoCaptureFormat::ToString(params.requested_format); | |
717 | |
718 DeviceEntry* entry = GetOrCreateDeviceEntry(session_id, params); | |
719 if (!entry) { | |
720 done_cb.Run(base::WeakPtr<VideoCaptureController>()); | |
721 return; | |
722 } | |
723 | |
724 LogVideoCaptureEvent(VIDEO_CAPTURE_START_CAPTURE); | |
725 | |
726 // First client starts the device. | |
727 if (!entry->video_capture_controller.HasActiveClient() && | |
728 !entry->video_capture_controller.HasPausedClient()) { | |
729 DVLOG(1) << "VideoCaptureManager starting device (type = " | |
730 << entry->stream_type << ", id = " << entry->id << ")"; | |
731 QueueStartDevice(session_id, entry, params); | |
732 } | |
733 // Run the callback first, as AddClient() may trigger OnFrameInfo(). | |
734 done_cb.Run(entry->video_capture_controller.GetWeakPtrForIOThread()); | |
735 entry->video_capture_controller.AddClient(client_id, client_handler, | |
736 session_id, params); | |
737 } | |
738 | |
739 void VideoCaptureManager::StopCaptureForClient( | |
740 VideoCaptureController* controller, | |
741 VideoCaptureControllerID client_id, | |
742 VideoCaptureControllerEventHandler* client_handler, | |
743 bool aborted_due_to_error) { | |
744 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
745 DCHECK(controller); | |
746 DCHECK(client_handler); | |
747 | |
748 DeviceEntry* entry = GetDeviceEntryByController(controller); | |
749 if (!entry) { | |
750 NOTREACHED(); | |
751 return; | |
752 } | |
753 if (!aborted_due_to_error) { | |
754 if (controller->has_received_frames()) { | |
755 LogVideoCaptureEvent(VIDEO_CAPTURE_STOP_CAPTURE_OK); | |
756 } else if (entry->stream_type == MEDIA_DEVICE_VIDEO_CAPTURE) { | |
757 LogVideoCaptureEvent( | |
758 VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DEVICE); | |
759 } else { | |
760 LogVideoCaptureEvent( | |
761 VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DESKTOP_OR_TAB); | |
762 } | |
763 } else { | |
764 LogVideoCaptureEvent(VIDEO_CAPTURE_STOP_CAPTURE_DUE_TO_ERROR); | |
765 for (auto it : sessions_) { | |
766 if (it.second.type == entry->stream_type && it.second.id == entry->id) { | |
767 for (auto& listener : listeners_) | |
768 listener.Aborted(it.second.type, it.first); | |
769 // Aborted() call might synchronously destroy |entry|, recheck. | |
770 entry = GetDeviceEntryByController(controller); | |
771 if (!entry) | |
772 return; | |
773 break; | |
774 } | |
775 } | |
776 } | |
777 | |
778 // Detach client from controller. | |
779 const media::VideoCaptureSessionId session_id = | |
780 controller->RemoveClient(client_id, client_handler); | |
781 DVLOG(1) << __func__ << ", session_id = " << session_id; | |
782 | |
783 // If controller has no more clients, delete controller and device. | |
784 DestroyDeviceEntryIfNoClients(entry); | |
785 } | |
786 | |
787 void VideoCaptureManager::PauseCaptureForClient( | |
788 VideoCaptureController* controller, | |
789 VideoCaptureControllerID client_id, | |
790 VideoCaptureControllerEventHandler* client_handler) { | |
791 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
792 DCHECK(controller); | |
793 DCHECK(client_handler); | |
794 DeviceEntry* entry = GetDeviceEntryByController(controller); | |
795 if (!entry) | |
796 NOTREACHED() << "Got Null entry while pausing capture"; | |
797 | |
798 const bool had_active_client = controller->HasActiveClient(); | |
799 controller->PauseClient(client_id, client_handler); | |
800 if (!had_active_client || controller->HasActiveClient()) | |
801 return; | |
802 if (media::VideoCaptureDevice* device = entry->video_capture_device.get()) { | |
803 device_task_runner_->PostTask( | |
804 FROM_HERE, | |
805 base::Bind(&VideoCaptureDevice::MaybeSuspend, | |
806 // Unretained is safe to use here because |device| would be | |
807 // null if it was scheduled for shutdown and destruction, and | |
808 // because this task is guaranteed to run before the task | |
809 // that destroys the |device|. | |
810 base::Unretained(device))); | |
811 } | |
812 } | |
813 | |
814 void VideoCaptureManager::ResumeCaptureForClient( | |
815 media::VideoCaptureSessionId session_id, | |
816 const media::VideoCaptureParams& params, | |
817 VideoCaptureController* controller, | |
818 VideoCaptureControllerID client_id, | |
819 VideoCaptureControllerEventHandler* client_handler) { | |
820 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
821 DCHECK(controller); | |
822 DCHECK(client_handler); | |
823 | |
824 DeviceEntry* entry = GetDeviceEntryByController(controller); | |
825 if (!entry) | |
826 NOTREACHED() << "Got Null entry while resuming capture"; | |
827 | |
828 const bool had_active_client = controller->HasActiveClient(); | |
829 controller->ResumeClient(client_id, client_handler); | |
830 if (had_active_client || !controller->HasActiveClient()) | |
831 return; | |
832 if (media::VideoCaptureDevice* device = entry->video_capture_device.get()) { | |
833 device_task_runner_->PostTask( | |
834 FROM_HERE, | |
835 base::Bind(&VideoCaptureDevice::Resume, | |
836 // Unretained is safe to use here because |device| would be | |
837 // null if it was scheduled for shutdown and destruction, and | |
838 // because this task is guaranteed to run before the task | |
839 // that destroys the |device|. | |
840 base::Unretained(device))); | |
841 } | |
842 } | |
843 | |
844 void VideoCaptureManager::RequestRefreshFrameForClient( | |
845 VideoCaptureController* controller) { | |
846 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
847 | |
848 if (DeviceEntry* entry = GetDeviceEntryByController(controller)) { | |
849 if (media::VideoCaptureDevice* device = entry->video_capture_device.get()) { | |
850 device_task_runner_->PostTask( | |
851 FROM_HERE, | |
852 base::Bind(&VideoCaptureDevice::RequestRefreshFrame, | |
853 // Unretained is safe to use here because |device| would be | |
854 // null if it was scheduled for shutdown and destruction, | |
855 // and because this task is guaranteed to run before the | |
856 // task that destroys the |device|. | |
857 base::Unretained(device))); | |
858 } | |
859 } | |
860 } | |
861 | |
862 bool VideoCaptureManager::GetDeviceSupportedFormats( | |
863 media::VideoCaptureSessionId capture_session_id, | |
864 media::VideoCaptureFormats* supported_formats) { | |
865 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
866 DCHECK(supported_formats->empty()); | |
867 | |
868 SessionMap::iterator it = sessions_.find(capture_session_id); | |
869 if (it == sessions_.end()) | |
870 return false; | |
871 DVLOG(1) << "GetDeviceSupportedFormats for device: " << it->second.name; | |
872 | |
873 return GetDeviceSupportedFormats(it->second.id, supported_formats); | |
874 } | |
875 | |
876 bool VideoCaptureManager::GetDeviceSupportedFormats( | |
877 const std::string& device_id, | |
878 media::VideoCaptureFormats* supported_formats) { | |
879 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
880 DCHECK(supported_formats->empty()); | |
881 | |
882 // Return all available formats of the device, regardless its started state. | |
883 DeviceInfo* existing_device = GetDeviceInfoById(device_id); | |
884 if (existing_device) | |
885 *supported_formats = existing_device->supported_formats; | |
886 return true; | |
887 } | |
888 | |
889 bool VideoCaptureManager::GetDeviceFormatsInUse( | |
890 media::VideoCaptureSessionId capture_session_id, | |
891 media::VideoCaptureFormats* formats_in_use) { | |
892 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
893 DCHECK(formats_in_use->empty()); | |
894 | |
895 SessionMap::iterator it = sessions_.find(capture_session_id); | |
896 if (it == sessions_.end()) | |
897 return false; | |
898 DVLOG(1) << "GetDeviceFormatsInUse for device: " << it->second.name; | |
899 | |
900 return GetDeviceFormatsInUse(it->second.type, it->second.id, formats_in_use); | |
901 } | |
902 | |
903 bool VideoCaptureManager::GetDeviceFormatsInUse( | |
904 MediaStreamType stream_type, | |
905 const std::string& device_id, | |
906 media::VideoCaptureFormats* formats_in_use) { | |
907 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
908 DCHECK(formats_in_use->empty()); | |
909 // Return the currently in-use format(s) of the device, if it's started. | |
910 DeviceEntry* device_in_use = | |
911 GetDeviceEntryByTypeAndId(stream_type, device_id); | |
912 if (device_in_use) { | |
913 // Currently only one format-in-use is supported at the VCC level. | |
914 formats_in_use->push_back( | |
915 device_in_use->video_capture_controller.GetVideoCaptureFormat()); | |
916 } | |
917 return true; | |
918 } | |
919 | |
920 void VideoCaptureManager::SetDesktopCaptureWindowId( | |
921 media::VideoCaptureSessionId session_id, | |
922 gfx::NativeViewId window_id) { | |
923 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
924 VLOG(2) << "SetDesktopCaptureWindowId called for session " << session_id; | |
925 | |
926 notification_window_ids_[session_id] = window_id; | |
927 MaybePostDesktopCaptureWindowId(session_id); | |
928 } | |
929 | |
930 void VideoCaptureManager::MaybePostDesktopCaptureWindowId( | |
931 media::VideoCaptureSessionId session_id) { | |
932 SessionMap::iterator session_it = sessions_.find(session_id); | |
933 if (session_it == sessions_.end()) | |
934 return; | |
935 | |
936 DeviceEntry* const existing_device = | |
937 GetDeviceEntryByTypeAndId(session_it->second.type, session_it->second.id); | |
938 if (!existing_device) { | |
939 DVLOG(2) << "Failed to find an existing screen capture device."; | |
940 return; | |
941 } | |
942 | |
943 if (!existing_device->video_capture_device) { | |
944 DVLOG(2) << "Screen capture device not yet started."; | |
945 return; | |
946 } | |
947 | |
948 DCHECK_EQ(MEDIA_DESKTOP_VIDEO_CAPTURE, existing_device->stream_type); | |
949 DesktopMediaID id = DesktopMediaID::Parse(existing_device->id); | |
950 if (id.is_null()) | |
951 return; | |
952 | |
953 auto window_id_it = notification_window_ids_.find(session_id); | |
954 if (window_id_it == notification_window_ids_.end()) { | |
955 DVLOG(2) << "Notification window id not set for screen capture."; | |
956 return; | |
957 } | |
958 | |
959 // Post |existing_device->video_capture_device| to the VideoCaptureDevice to | |
960 // the device_task_runner_. This is safe since the device is destroyed on the | |
961 // device_task_runner_. | |
962 device_task_runner_->PostTask( | |
963 FROM_HERE, | |
964 base::Bind(&VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread, | |
965 this, existing_device->video_capture_device.get(), | |
966 window_id_it->second)); | |
967 | |
968 notification_window_ids_.erase(window_id_it); | |
969 } | |
970 | |
971 void VideoCaptureManager::GetPhotoCapabilities( | |
972 int session_id, | |
973 VideoCaptureDevice::GetPhotoCapabilitiesCallback callback) { | |
974 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
975 | |
976 const DeviceEntry* entry = GetDeviceEntryBySessionId(session_id); | |
977 if (!entry) | |
978 return; | |
979 VideoCaptureDevice* device = entry->video_capture_device.get(); | |
980 if (device) { | |
981 VideoCaptureManager::DoGetPhotoCapabilities(std::move(callback), device); | |
982 return; | |
983 } | |
984 // |entry| is known but |device| is nullptr, queue up a request for later. | |
985 photo_request_queue_.emplace_back( | |
986 session_id, base::Bind(&VideoCaptureManager::DoGetPhotoCapabilities, this, | |
987 base::Passed(&callback))); | |
988 } | |
989 | |
990 void VideoCaptureManager::SetPhotoOptions( | |
991 int session_id, | |
992 media::mojom::PhotoSettingsPtr settings, | |
993 VideoCaptureDevice::SetPhotoOptionsCallback callback) { | |
994 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
995 | |
996 const DeviceEntry* entry = GetDeviceEntryBySessionId(session_id); | |
997 if (!entry) | |
998 return; | |
999 VideoCaptureDevice* device = entry->video_capture_device.get(); | |
1000 if (device) { | |
1001 VideoCaptureManager::DoSetPhotoOptions(std::move(callback), | |
1002 std::move(settings), device); | |
1003 return; | |
1004 } | |
1005 // |entry| is known but |device| is nullptr, queue up a request for later. | |
1006 photo_request_queue_.emplace_back( | |
1007 session_id, base::Bind(&VideoCaptureManager::DoSetPhotoOptions, this, | |
1008 base::Passed(&callback), base::Passed(&settings))); | |
1009 } | |
1010 | |
1011 void VideoCaptureManager::TakePhoto( | |
1012 int session_id, | |
1013 VideoCaptureDevice::TakePhotoCallback callback) { | |
1014 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1015 | |
1016 const DeviceEntry* entry = GetDeviceEntryBySessionId(session_id); | |
1017 if (!entry) | |
1018 return; | |
1019 VideoCaptureDevice* device = entry->video_capture_device.get(); | |
1020 if (device) { | |
1021 VideoCaptureManager::DoTakePhoto(std::move(callback), device); | |
1022 return; | |
1023 } | |
1024 // |entry| is known but |device| is nullptr, queue up a request for later. | |
1025 photo_request_queue_.emplace_back( | |
1026 session_id, base::Bind(&VideoCaptureManager::DoTakePhoto, this, | |
1027 base::Passed(&callback))); | |
1028 } | |
1029 | |
1030 void VideoCaptureManager::DoStopDeviceOnDeviceThread( | |
1031 std::unique_ptr<VideoCaptureDevice> device) { | |
1032 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StopDeviceTime"); | |
1033 DCHECK(IsOnDeviceThread()); | |
1034 device->StopAndDeAllocate(); | |
1035 DVLOG(3) << "DoStopDeviceOnDeviceThread"; | |
1036 } | |
1037 | |
1038 void VideoCaptureManager::OnOpened( | |
1039 MediaStreamType stream_type, | |
1040 media::VideoCaptureSessionId capture_session_id) { | |
1041 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1042 for (auto& listener : listeners_) | |
1043 listener.Opened(stream_type, capture_session_id); | |
1044 } | |
1045 | |
1046 void VideoCaptureManager::OnClosed( | |
1047 MediaStreamType stream_type, | |
1048 media::VideoCaptureSessionId capture_session_id) { | |
1049 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1050 for (auto& listener : listeners_) | |
1051 listener.Closed(stream_type, capture_session_id); | |
1052 } | |
1053 | |
1054 void VideoCaptureManager::OnDevicesInfoEnumerated( | |
1055 base::ElapsedTimer* timer, | |
1056 const EnumerationCallback& client_callback, | |
1057 const VideoCaptureManager::DeviceInfos& new_devices_info_cache) { | |
1058 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1059 UMA_HISTOGRAM_TIMES( | |
1060 "Media.VideoCaptureManager.GetAvailableDevicesInfoOnDeviceThreadTime", | |
1061 timer->Elapsed()); | |
1062 devices_info_cache_ = new_devices_info_cache; | |
1063 | |
1064 // Walk the |devices_info_cache_| and produce a | |
1065 // media::VideoCaptureDeviceDescriptors for return purposes. | |
1066 media::VideoCaptureDeviceDescriptors devices; | |
1067 std::vector<std::tuple<media::VideoCaptureDeviceDescriptor, | |
1068 media::VideoCaptureFormats>> | |
1069 descriptors_and_formats; | |
1070 for (const auto& it : devices_info_cache_) { | |
1071 devices.emplace_back(it.descriptor); | |
1072 descriptors_and_formats.emplace_back(it.descriptor, it.supported_formats); | |
1073 } | |
1074 | |
1075 if (!descriptors_and_formats.empty()) { | |
1076 MediaInternals::GetInstance()->UpdateVideoCaptureDeviceCapabilities( | |
1077 descriptors_and_formats); | |
1078 } | |
1079 | |
1080 client_callback.Run(devices); | |
1081 } | |
1082 | |
1083 bool VideoCaptureManager::IsOnDeviceThread() const { | |
1084 return device_task_runner_->BelongsToCurrentThread(); | |
1085 } | |
1086 | |
1087 void VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread( | |
1088 base::Callback<void(const VideoCaptureManager::DeviceInfos&)> | |
1089 on_devices_enumerated_callback, | |
1090 const VideoCaptureManager::DeviceInfos& old_device_info_cache, | |
1091 std::unique_ptr<VideoCaptureDeviceDescriptors> descriptors_snapshot) { | |
1092 DCHECK(IsOnDeviceThread()); | |
1093 // Construct |new_devices_info_cache| with the cached devices that are still | |
1094 // present in the system, and remove their names from |names_snapshot|, so we | |
1095 // keep there the truly new devices. | |
1096 VideoCaptureManager::DeviceInfos new_devices_info_cache; | |
1097 for (const auto& device_info : old_device_info_cache) { | |
1098 for (VideoCaptureDeviceDescriptors::iterator it = | |
1099 descriptors_snapshot->begin(); | |
1100 it != descriptors_snapshot->end(); ++it) { | |
1101 if (device_info.descriptor.device_id == it->device_id) { | |
1102 new_devices_info_cache.push_back(device_info); | |
1103 descriptors_snapshot->erase(it); | |
1104 break; | |
1105 } | |
1106 } | |
1107 } | |
1108 | |
1109 // Get the device info for the new devices in |names_snapshot|. | |
1110 for (const auto& it : *descriptors_snapshot) { | |
1111 DeviceInfo device_info(it); | |
1112 video_capture_device_factory_->GetSupportedFormats( | |
1113 it, &device_info.supported_formats); | |
1114 ConsolidateCaptureFormats(&device_info.supported_formats); | |
1115 new_devices_info_cache.push_back(device_info); | |
1116 } | |
1117 | |
1118 on_devices_enumerated_callback.Run(new_devices_info_cache); | |
1119 } | |
1120 | |
1121 void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) { | |
1122 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1123 // Removal of the last client stops the device. | |
1124 if (!entry->video_capture_controller.HasActiveClient() && | |
1125 !entry->video_capture_controller.HasPausedClient()) { | |
1126 DVLOG(1) << "VideoCaptureManager stopping device (type = " | |
1127 << entry->stream_type << ", id = " << entry->id << ")"; | |
1128 | |
1129 // The DeviceEntry is removed from |devices_| immediately. The controller is | |
1130 // deleted immediately, and the device is freed asynchronously. After this | |
1131 // point, subsequent requests to open this same device ID will create a new | |
1132 // DeviceEntry, VideoCaptureController, and VideoCaptureDevice. | |
1133 DoStopDevice(entry); | |
1134 // TODO(mcasas): use a helper function https://crbug.com/624854. | |
1135 DeviceEntries::iterator device_it = | |
1136 std::find_if(devices_.begin(), devices_.end(), | |
1137 [entry](const std::unique_ptr<DeviceEntry>& device_entry) { | |
1138 return device_entry.get() == entry; | |
1139 }); | |
1140 devices_.erase(device_it); | |
1141 } | |
1142 } | |
1143 | |
1144 VideoCaptureManager::DeviceEntry* | |
1145 VideoCaptureManager::GetDeviceEntryBySessionId(int session_id) { | |
1146 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1147 SessionMap::const_iterator session_it = sessions_.find(session_id); | |
1148 if (session_it == sessions_.end()) | |
1149 return nullptr; | |
1150 | |
1151 return GetDeviceEntryByTypeAndId(session_it->second.type, | |
1152 session_it->second.id); | |
1153 } | |
1154 | |
1155 VideoCaptureManager::DeviceEntry* | |
1156 VideoCaptureManager::GetDeviceEntryByTypeAndId( | |
1157 MediaStreamType type, | |
1158 const std::string& device_id) const { | |
1159 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1160 | |
1161 for (const std::unique_ptr<DeviceEntry>& device : devices_) { | |
1162 if (type == device->stream_type && device_id == device->id) | |
1163 return device.get(); | |
1164 } | |
1165 return nullptr; | |
1166 } | |
1167 | |
1168 VideoCaptureManager::DeviceEntry* | |
1169 VideoCaptureManager::GetDeviceEntryByController( | |
1170 const VideoCaptureController* controller) const { | |
1171 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1172 | |
1173 // Look up |controller| in |devices_|. | |
1174 for (const std::unique_ptr<DeviceEntry>& device : devices_) { | |
1175 if (&device->video_capture_controller == controller) | |
1176 return device.get(); | |
1177 } | |
1178 return nullptr; | |
1179 } | |
1180 | |
1181 VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetDeviceEntryBySerialId( | |
1182 int serial_id) const { | |
1183 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1184 | |
1185 for (const std::unique_ptr<DeviceEntry>& device : devices_) { | |
1186 if (device->serial_id == serial_id) | |
1187 return device.get(); | |
1188 } | |
1189 return nullptr; | |
1190 } | |
1191 | |
1192 VideoCaptureManager::DeviceInfo* VideoCaptureManager::GetDeviceInfoById( | |
1193 const std::string& id) { | |
1194 for (auto& it : devices_info_cache_) { | |
1195 if (it.descriptor.device_id == id) | |
1196 return ⁢ | |
1197 } | |
1198 return nullptr; | |
1199 } | |
1200 | |
1201 VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry( | |
1202 media::VideoCaptureSessionId capture_session_id, | |
1203 const media::VideoCaptureParams& params) { | |
1204 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1205 | |
1206 SessionMap::iterator session_it = sessions_.find(capture_session_id); | |
1207 if (session_it == sessions_.end()) | |
1208 return nullptr; | |
1209 const MediaStreamDevice& device_info = session_it->second; | |
1210 | |
1211 // Check if another session has already opened this device. If so, just | |
1212 // use that opened device. | |
1213 DeviceEntry* const existing_device = | |
1214 GetDeviceEntryByTypeAndId(device_info.type, device_info.id); | |
1215 if (existing_device) { | |
1216 DCHECK_EQ(device_info.type, existing_device->stream_type); | |
1217 return existing_device; | |
1218 } | |
1219 | |
1220 devices_.emplace_back( | |
1221 new DeviceEntry(device_info.type, device_info.id, params)); | |
1222 return devices_.back().get(); | |
1223 } | |
1224 | |
1225 void VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread( | |
1226 media::VideoCaptureDevice* device, | |
1227 gfx::NativeViewId window_id) { | |
1228 DCHECK(IsOnDeviceThread()); | |
1229 #if defined(ENABLE_SCREEN_CAPTURE) && BUILDFLAG(ENABLE_WEBRTC) && !defined(OS_AN DROID) | |
1230 DesktopCaptureDevice* desktop_device = | 411 DesktopCaptureDevice* desktop_device = |
1231 static_cast<DesktopCaptureDevice*>(device); | 412 static_cast<DesktopCaptureDevice*>(device); |
1232 desktop_device->SetNotificationWindowId(window_id); | 413 desktop_device->SetNotificationWindowId(window_id); |
1233 VLOG(2) << "Screen capture notification window passed on device thread."; | 414 VLOG(2) << "Screen capture notification window passed on device thread."; |
1234 #endif | 415 #endif |
1235 } | 416 } |
1236 | 417 |
1237 void VideoCaptureManager::DoGetPhotoCapabilities( | |
1238 VideoCaptureDevice::GetPhotoCapabilitiesCallback callback, | |
1239 VideoCaptureDevice* device) { | |
1240 // Unretained() is safe to use here because |device| would be null if it | |
1241 // was scheduled for shutdown and destruction, and because this task is | |
1242 // guaranteed to run before the task that destroys the |device|. | |
1243 device_task_runner_->PostTask( | |
1244 FROM_HERE, base::Bind(&VideoCaptureDevice::GetPhotoCapabilities, | |
1245 base::Unretained(device), base::Passed(&callback))); | |
1246 } | |
1247 | |
1248 void VideoCaptureManager::DoSetPhotoOptions( | |
1249 VideoCaptureDevice::SetPhotoOptionsCallback callback, | |
1250 media::mojom::PhotoSettingsPtr settings, | |
1251 VideoCaptureDevice* device) { | |
1252 // Unretained() is safe to use here because |device| would be null if it | |
1253 // was scheduled for shutdown and destruction, and because this task is | |
1254 // guaranteed to run before the task that destroys the |device|. | |
1255 device_task_runner_->PostTask( | |
1256 FROM_HERE, | |
1257 base::Bind(&VideoCaptureDevice::SetPhotoOptions, base::Unretained(device), | |
1258 base::Passed(&settings), base::Passed(&callback))); | |
1259 } | |
1260 | |
1261 void VideoCaptureManager::DoTakePhoto( | |
1262 VideoCaptureDevice::TakePhotoCallback callback, | |
1263 VideoCaptureDevice* device) { | |
1264 // Unretained() is safe to use here because |device| would be null if it | |
1265 // was scheduled for shutdown and destruction, and because this task is | |
1266 // guaranteed to run before the task that destroys the |device|. | |
1267 device_task_runner_->PostTask( | |
1268 FROM_HERE, base::Bind(&VideoCaptureDevice::TakePhoto, | |
1269 base::Unretained(device), base::Passed(&callback))); | |
1270 } | |
1271 | |
1272 base::Optional<CameraCalibration> VideoCaptureManager::GetCameraCalibration( | |
1273 const std::string& device_id) { | |
1274 VideoCaptureManager::DeviceInfo* info = GetDeviceInfoById(device_id); | |
1275 if (!info) | |
1276 return base::Optional<CameraCalibration>(); | |
1277 return info->descriptor.camera_calibration; | |
1278 } | |
1279 | |
1280 #if defined(OS_ANDROID) | |
1281 void VideoCaptureManager::OnApplicationStateChange( | |
1282 base::android::ApplicationState state) { | |
1283 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1284 | |
1285 // Only release/resume devices when the Application state changes from | |
1286 // RUNNING->STOPPED->RUNNING. | |
1287 if (state == base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES && | |
1288 !application_state_has_running_activities_) { | |
1289 ResumeDevices(); | |
1290 application_state_has_running_activities_ = true; | |
1291 } else if (state == base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES) { | |
1292 ReleaseDevices(); | |
1293 application_state_has_running_activities_ = false; | |
1294 } | |
1295 } | |
1296 | |
1297 void VideoCaptureManager::ReleaseDevices() { | |
1298 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1299 | |
1300 for (auto& entry : devices_) { | |
1301 // Do not stop Content Video Capture devices, e.g. Tab or Screen capture. | |
1302 if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE) | |
1303 continue; | |
1304 | |
1305 DoStopDevice(entry.get()); | |
1306 } | |
1307 } | |
1308 | |
1309 void VideoCaptureManager::ResumeDevices() { | |
1310 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1311 | |
1312 for (auto& entry : devices_) { | |
1313 // Do not resume Content Video Capture devices, e.g. Tab or Screen capture. | |
1314 // Do not try to restart already running devices. | |
1315 if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE || | |
1316 entry->video_capture_device) | |
1317 continue; | |
1318 | |
1319 // Check if the device is already in the start queue. | |
1320 bool device_in_queue = false; | |
1321 for (auto& request : device_start_queue_) { | |
1322 if (request.serial_id() == entry->serial_id) { | |
1323 device_in_queue = true; | |
1324 break; | |
1325 } | |
1326 } | |
1327 | |
1328 if (!device_in_queue) { | |
1329 // Session ID is only valid for Screen capture. So we can fake it to | |
1330 // resume video capture devices here. | |
1331 QueueStartDevice(kFakeSessionId, entry.get(), entry->parameters); | |
1332 } | |
1333 } | |
1334 } | |
1335 #endif // defined(OS_ANDROID) | |
1336 | |
1337 } // namespace content | 418 } // namespace content |
OLD | NEW |