| 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; |
| 105 } | 68 std::move(done_cb).Run(); |
| 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 } | 69 } |
| 127 | 70 |
| 128 // The maximum number of video frame buffers in-flight at any one time. This | 71 // 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 | 72 // 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 | 73 // not on hardware performance. For example, tab capture requires more buffers |
| 131 // than webcam capture because the pipeline is longer (it includes read-backs | 74 // than webcam capture because the pipeline is longer (it includes read-backs |
| 132 // pending in the GPU pipeline). | 75 // pending in the GPU pipeline). |
| 133 const int kMaxNumberOfBuffers = 3; | 76 const int kMaxNumberOfBuffers = 3; |
| 134 // TODO(miu): The value for tab capture should be determined programmatically. | 77 // TODO(miu): The value for tab capture should be determined programmatically. |
| 135 // http://crbug.com/460318 | 78 // http://crbug.com/460318 |
| 136 const int kMaxNumberOfBuffersForTabCapture = 10; | 79 const int kMaxNumberOfBuffersForTabCapture = 10; |
| 137 | 80 |
| 138 // Used for logging capture events. | 81 } // 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 | 82 |
| 168 namespace content { | 83 namespace content { |
| 169 | 84 |
| 170 // Instances of this struct go through several different phases during their | 85 InProcessBuildableVideoCaptureDevice::InProcessBuildableVideoCaptureDevice( |
| 171 // lifetime. | 86 scoped_refptr<base::SingleThreadTaskRunner> device_task_runner, |
| 172 // Phase 1: When first created (in GetOrCreateDeviceEntry()), this consists of | 87 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)), | 88 : device_task_runner_(std::move(device_task_runner)), |
| 304 new_capture_session_id_(1), | 89 device_factory_(device_factory) {} |
| 305 video_capture_device_factory_(std::move(factory)) {} | 90 |
| 306 | 91 InProcessBuildableVideoCaptureDevice::~InProcessBuildableVideoCaptureDevice() { |
| 307 VideoCaptureManager::~VideoCaptureManager() { | 92 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 308 DCHECK(devices_.empty()); | 93 DCHECK(!device_); |
| 309 DCHECK(device_start_queue_.empty()); | 94 } |
| 310 } | 95 |
| 311 | 96 void InProcessBuildableVideoCaptureDevice::CreateAndStartDeviceAsync( |
| 312 void VideoCaptureManager::AddVideoCaptureObserver( | 97 VideoCaptureController* controller, |
| 313 media::VideoCaptureObserver* observer) { | 98 const media::VideoCaptureParams& params, |
| 314 DCHECK(observer); | 99 BuildableDeviceCallbacks* callbacks, |
| 315 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 100 base::OnceClosure done_cb) { |
| 316 capture_observers_.AddObserver(observer); | 101 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 317 } | 102 |
| 318 | 103 const int max_buffers = (controller->stream_type() == MEDIA_TAB_VIDEO_CAPTURE |
| 319 void VideoCaptureManager::RemoveAllVideoCaptureObservers() { | 104 ? kMaxNumberOfBuffersForTabCapture |
| 320 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 105 : kMaxNumberOfBuffers); |
| 321 capture_observers_.Clear(); | 106 |
| 322 } | 107 auto device_client = |
| 323 | 108 CreateDeviceClient(max_buffers, controller->GetWeakPtrForIOThread()); |
| 324 void VideoCaptureManager::RegisterListener( | 109 |
| 325 MediaStreamProviderListener* listener) { | 110 base::Closure start_capture_closure; |
| 326 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 111 switch (controller->stream_type()) { |
| 327 DCHECK(listener); | |
| 328 DCHECK(device_task_runner_); | |
| 329 listeners_.AddObserver(listener); | |
| 330 #if defined(OS_ANDROID) | |
| 331 application_state_has_running_activities_ = true; | |
| 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: { | 112 case MEDIA_DEVICE_VIDEO_CAPTURE: { |
| 499 // We look up the device id from the renderer in our local enumeration | 113 const media::VideoCaptureDeviceDescriptor* descriptor = |
| 500 // since the renderer does not have all the information that might be | 114 callbacks->LookupDeviceDescriptor(controller->device_id()); |
| 501 // held in the browser-side VideoCaptureDevice::Name structure. | 115 if (descriptor) { |
| 502 const DeviceInfo* found = GetDeviceInfoById(entry->id); | 116 controller->OnLog( |
| 503 if (found) { | |
| 504 entry->video_capture_controller.OnLog( | |
| 505 base::StringPrintf("Starting device: id: %s, name: %s, api: %s", | 117 base::StringPrintf("Starting device: id: %s, name: %s, api: %s", |
| 506 found->descriptor.device_id.c_str(), | 118 descriptor->device_id.c_str(), |
| 507 found->descriptor.GetNameAndModel().c_str(), | 119 descriptor->GetNameAndModel().c_str(), |
| 508 found->descriptor.GetCaptureApiTypeString())); | 120 descriptor->GetCaptureApiTypeString())); |
| 509 | 121 |
| 510 for (auto& observer : capture_observers_) | 122 callbacks->WillStartDevice(descriptor->facing); |
| 511 observer.OnVideoCaptureStarted(found->descriptor.facing); | 123 |
| 512 | 124 // Use of Unretained() is safe, because |context_reference| guarantees |
| 513 start_capture_function = | 125 // that |this| stays alive. |
| 514 base::Bind(&VideoCaptureManager::DoStartDeviceCaptureOnDeviceThread, | 126 ReceiveDeviceCallback after_start_capture_callback = |
| 515 this, found->descriptor, request->params(), | 127 media::BindToCurrentLoop(base::Bind( |
| 516 base::Passed(std::move(device_client))); | 128 &InProcessBuildableVideoCaptureDevice::OnDeviceStarted, |
| 129 base::Unretained(this), controller, callbacks, |
| 130 base::Passed(&done_cb))); |
| 131 start_capture_closure = |
| 132 base::Bind(&InProcessBuildableVideoCaptureDevice:: |
| 133 DoStartDeviceCaptureOnDeviceThread, |
| 134 base::Unretained(this), *descriptor, params, |
| 135 base::Passed(std::move(device_client)), |
| 136 std::move(after_start_capture_callback)); |
| 517 } else { | 137 } else { |
| 518 // Errors from DoStartDeviceCaptureOnDeviceThread go via | 138 callbacks->OnDeviceStartFailed(controller); |
| 519 // VideoCaptureDeviceClient::OnError, which needs some thread | 139 std::move(done_cb).Run(); |
| 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; | 140 return; |
| 533 } | 141 } |
| 534 break; | 142 break; |
| 535 } | 143 } |
| 536 case MEDIA_TAB_VIDEO_CAPTURE: | 144 case MEDIA_TAB_VIDEO_CAPTURE: { |
| 537 start_capture_function = base::Bind( | 145 // Use of Unretained() is safe, because |context_reference| guarantees |
| 538 &VideoCaptureManager::DoStartTabCaptureOnDeviceThread, this, | 146 // that |this| stays alive. |
| 539 entry->id, request->params(), base::Passed(std::move(device_client))); | 147 ReceiveDeviceCallback after_start_capture_callback = |
| 148 media::BindToCurrentLoop( |
| 149 base::Bind(&InProcessBuildableVideoCaptureDevice::OnDeviceStarted, |
| 150 base::Unretained(this), controller, callbacks, |
| 151 base::Passed(&done_cb))); |
| 152 start_capture_closure = |
| 153 base::Bind(&InProcessBuildableVideoCaptureDevice:: |
| 154 DoStartTabCaptureOnDeviceThread, |
| 155 base::Unretained(this), controller->device_id(), params, |
| 156 base::Passed(std::move(device_client)), |
| 157 std::move(after_start_capture_callback)); |
| 540 break; | 158 break; |
| 541 | 159 } |
| 542 case MEDIA_DESKTOP_VIDEO_CAPTURE: | 160 case MEDIA_DESKTOP_VIDEO_CAPTURE: { |
| 543 start_capture_function = base::Bind( | 161 // Use of Unretained() is safe, because |context_reference| guarantees |
| 544 &VideoCaptureManager::DoStartDesktopCaptureOnDeviceThread, this, | 162 // that |this| stays alive. |
| 545 entry->id, request->params(), base::Passed(std::move(device_client))); | 163 ReceiveDeviceCallback after_start_capture_callback = |
| 164 media::BindToCurrentLoop( |
| 165 base::Bind(&InProcessBuildableVideoCaptureDevice::OnDeviceStarted, |
| 166 base::Unretained(this), controller, callbacks, |
| 167 base::Passed(&done_cb))); |
| 168 start_capture_closure = |
| 169 base::Bind(&InProcessBuildableVideoCaptureDevice:: |
| 170 DoStartDesktopCaptureOnDeviceThread, |
| 171 base::Unretained(this), controller->device_id(), params, |
| 172 base::Passed(std::move(device_client)), |
| 173 std::move(after_start_capture_callback)); |
| 546 break; | 174 break; |
| 547 | 175 } |
| 548 default: { | 176 default: { |
| 549 NOTIMPLEMENTED(); | 177 NOTIMPLEMENTED(); |
| 550 return; | 178 return; |
| 551 } | 179 } |
| 552 } | 180 } |
| 553 base::PostTaskAndReplyWithResult( | 181 |
| 554 device_task_runner_.get(), FROM_HERE, start_capture_function, | 182 device_task_runner_->PostTask(FROM_HERE, start_capture_closure); |
| 555 base::Bind(&VideoCaptureManager::OnDeviceStarted, this, | 183 } |
| 556 request->serial_id())); | 184 |
| 557 } | 185 void InProcessBuildableVideoCaptureDevice::ReleaseDeviceAsync( |
| 558 | 186 VideoCaptureController* controller, |
| 559 void VideoCaptureManager::OnDeviceStarted( | 187 base::OnceClosure done_cb) { |
| 560 int serial_id, | 188 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 561 std::unique_ptr<VideoCaptureDevice> device) { | 189 controller->SetConsumerFeedbackObserver(nullptr); |
| 562 DVLOG(3) << __func__; | 190 if (!device_) |
| 563 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 191 return; |
| 564 DCHECK_EQ(serial_id, device_start_queue_.begin()->serial_id()); | 192 media::VideoCaptureDevice* device_ptr = device_.release(); |
| 565 // |device| can be null if creation failed in | 193 |
| 566 // DoStartDeviceCaptureOnDeviceThread. | 194 bool posting_task_succeeded = device_task_runner_->PostTask( |
| 567 if (device_start_queue_.front().abort_start()) { | 195 FROM_HERE, |
| 568 // The device is no longer wanted. Stop the device again. | 196 base::Bind(&StopAndReleaseDeviceOnDeviceThread, device_ptr, |
| 569 DVLOG(3) << "OnDeviceStarted but start request have been aborted."; | 197 base::Bind([](scoped_refptr<base::SingleThreadTaskRunner>) {}, |
| 570 media::VideoCaptureDevice* device_ptr = device.get(); | 198 device_task_runner_))); |
| 571 base::Closure closure = | 199 if (posting_task_succeeded == false) { |
| 572 base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this, | 200 // Since posting to the task runner has failed, we attempt doing it on |
| 573 base::Passed(&device)); | 201 // the calling thread instead. |
| 574 if (device_ptr && !device_task_runner_->PostTask(FROM_HERE, closure)) { | 202 StopAndReleaseDeviceOnDeviceThread(device_ptr, base::Bind([]() {})); |
| 575 // PostTask failed. The device must be stopped anyway. | 203 } |
| 576 device_ptr->StopAndDeAllocate(); | 204 std::move(done_cb).Run(); |
| 577 } | 205 } |
| 578 } else { | 206 |
| 579 DeviceEntry* const entry = GetDeviceEntryBySerialId(serial_id); | 207 bool InProcessBuildableVideoCaptureDevice::IsDeviceAlive() const { |
| 580 DCHECK(entry); | 208 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 581 DCHECK(!entry->video_capture_device); | 209 return device_ != nullptr; |
| 582 if (device) { | 210 } |
| 583 // Passing raw pointer |device.get()| to the controller is safe, | 211 |
| 584 // because we transfer ownership of it to |entry|. We are calling | 212 void InProcessBuildableVideoCaptureDevice::GetPhotoCapabilities( |
| 585 // SetConsumerFeedbackObserver(nullptr) before releasing | 213 media::VideoCaptureDevice::GetPhotoCapabilitiesCallback callback) const { |
| 586 // |entry->video_capture_device_| on the |device_task_runner_|. | 214 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 587 entry->video_capture_controller.SetConsumerFeedbackObserver( | 215 // Unretained() is safe to use here because |device| would be null if it |
| 588 base::MakeUnique<VideoFrameConsumerFeedbackObserverOnTaskRunner>( | 216 // was scheduled for shutdown and destruction, and because this task is |
| 589 device.get(), device_task_runner_)); | 217 // guaranteed to run before the task that destroys the |device|. |
| 590 } | 218 device_task_runner_->PostTask( |
| 591 entry->video_capture_device = std::move(device); | 219 FROM_HERE, |
| 592 | 220 base::Bind(&media::VideoCaptureDevice::GetPhotoCapabilities, |
| 593 if (entry->stream_type == MEDIA_DESKTOP_VIDEO_CAPTURE) { | 221 base::Unretained(device_.get()), base::Passed(&callback))); |
| 594 const media::VideoCaptureSessionId session_id = | 222 } |
| 595 device_start_queue_.front().session_id(); | 223 |
| 596 DCHECK(session_id != kFakeSessionId); | 224 void InProcessBuildableVideoCaptureDevice::SetPhotoOptions( |
| 597 MaybePostDesktopCaptureWindowId(session_id); | 225 media::mojom::PhotoSettingsPtr settings, |
| 598 } | 226 media::VideoCaptureDevice::SetPhotoOptionsCallback callback) { |
| 599 | 227 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 600 auto it = photo_request_queue_.begin(); | 228 // Unretained() is safe to use here because |device| would be null if it |
| 601 while (it != photo_request_queue_.end()) { | 229 // was scheduled for shutdown and destruction, and because this task is |
| 602 auto request = it++; | 230 // guaranteed to run before the task that destroys the |device|. |
| 603 DeviceEntry* maybe_entry = GetDeviceEntryBySessionId(request->first); | 231 device_task_runner_->PostTask( |
| 604 if (maybe_entry && maybe_entry->video_capture_device) { | 232 FROM_HERE, base::Bind(&media::VideoCaptureDevice::SetPhotoOptions, |
| 605 request->second.Run(maybe_entry->video_capture_device.get()); | 233 base::Unretained(device_.get()), |
| 606 photo_request_queue_.erase(request); | 234 base::Passed(&settings), base::Passed(&callback))); |
| 607 } | 235 } |
| 608 } | 236 |
| 609 } | 237 void InProcessBuildableVideoCaptureDevice::TakePhoto( |
| 610 | 238 media::VideoCaptureDevice::TakePhotoCallback callback) { |
| 611 device_start_queue_.pop_front(); | 239 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 612 HandleQueuedStartRequest(); | 240 // Unretained() is safe to use here because |device| would be null if it |
| 613 } | 241 // was scheduled for shutdown and destruction, and because this task is |
| 614 | 242 // guaranteed to run before the task that destroys the |device|. |
| 615 std::unique_ptr<media::VideoCaptureDevice> | 243 device_task_runner_->PostTask( |
| 616 VideoCaptureManager::DoStartDeviceCaptureOnDeviceThread( | 244 FROM_HERE, |
| 617 const VideoCaptureDeviceDescriptor& descriptor, | 245 base::Bind(&media::VideoCaptureDevice::TakePhoto, |
| 246 base::Unretained(device_.get()), base::Passed(&callback))); |
| 247 } |
| 248 |
| 249 void InProcessBuildableVideoCaptureDevice::MaybeSuspendDevice() { |
| 250 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 251 // Unretained() is safe to use here because |device| would be null if it |
| 252 // was scheduled for shutdown and destruction, and because this task is |
| 253 // guaranteed to run before the task that destroys the |device|. |
| 254 device_task_runner_->PostTask( |
| 255 FROM_HERE, base::Bind(&media::VideoCaptureDevice::MaybeSuspend, |
| 256 base::Unretained(device_.get()))); |
| 257 } |
| 258 |
| 259 void InProcessBuildableVideoCaptureDevice::ResumeDevice() { |
| 260 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 261 // Unretained() is safe to use here because |device| would be null if it |
| 262 // was scheduled for shutdown and destruction, and because this task is |
| 263 // guaranteed to run before the task that destroys the |device|. |
| 264 device_task_runner_->PostTask(FROM_HERE, |
| 265 base::Bind(&media::VideoCaptureDevice::Resume, |
| 266 base::Unretained(device_.get()))); |
| 267 } |
| 268 |
| 269 void InProcessBuildableVideoCaptureDevice::RequestRefreshFrame() { |
| 270 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 271 // Unretained() is safe to use here because |device| would be null if it |
| 272 // was scheduled for shutdown and destruction, and because this task is |
| 273 // guaranteed to run before the task that destroys the |device|. |
| 274 device_task_runner_->PostTask( |
| 275 FROM_HERE, base::Bind(&media::VideoCaptureDevice::RequestRefreshFrame, |
| 276 base::Unretained(device_.get()))); |
| 277 } |
| 278 |
| 279 void InProcessBuildableVideoCaptureDevice::SetDesktopCaptureWindowIdAsync( |
| 280 gfx::NativeViewId window_id, |
| 281 base::OnceClosure done_cb) { |
| 282 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 283 // Post |device_| to the the device_task_runner_. This is safe since the |
| 284 // device is destroyed on the device_task_runner_ and |context_reference| |
| 285 // guarantees that |this| stays alive. |
| 286 device_task_runner_->PostTask( |
| 287 FROM_HERE, base::Bind(&InProcessBuildableVideoCaptureDevice:: |
| 288 SetDesktopCaptureWindowIdOnDeviceThread, |
| 289 base::Unretained(this), device_.get(), window_id, |
| 290 base::Passed(&done_cb))); |
| 291 } |
| 292 |
| 293 std::unique_ptr<media::VideoCaptureDeviceClient> |
| 294 InProcessBuildableVideoCaptureDevice::CreateDeviceClient( |
| 295 int buffer_pool_max_buffer_count, |
| 296 base::WeakPtr<media::VideoFrameReceiver> receiver) { |
| 297 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 298 |
| 299 scoped_refptr<media::VideoCaptureBufferPool> buffer_pool_ = |
| 300 new media::VideoCaptureBufferPoolImpl( |
| 301 base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(), |
| 302 buffer_pool_max_buffer_count); |
| 303 |
| 304 return base::MakeUnique<media::VideoCaptureDeviceClient>( |
| 305 base::MakeUnique<VideoFrameReceiverOnIOThread>(receiver), buffer_pool_, |
| 306 base::Bind(&CreateGpuJpegDecoder, |
| 307 base::Bind(&media::VideoFrameReceiver::OnFrameReadyInBuffer, |
| 308 receiver))); |
| 309 } |
| 310 |
| 311 void InProcessBuildableVideoCaptureDevice::OnDeviceStarted( |
| 312 VideoCaptureController* controller, |
| 313 BuildableDeviceCallbacks* callbacks, |
| 314 base::OnceClosure done_cb, |
| 315 std::unique_ptr<media::VideoCaptureDevice> device) { |
| 316 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 317 if (!device) { |
| 318 callbacks->OnDeviceStartFailed(controller); |
| 319 std::move(done_cb).Run(); |
| 320 return; |
| 321 } |
| 322 // Passing raw pointer |device.get()| to the controller is safe, |
| 323 // because we take ownership of |device| and we call |
| 324 // controller->SetConsumerFeedbackObserver(nullptr) before releasing |device|. |
| 325 controller->SetConsumerFeedbackObserver( |
| 326 base::MakeUnique<VideoFrameConsumerFeedbackObserverOnTaskRunner>( |
| 327 device.get(), device_task_runner_)); |
| 328 device_ = std::move(device); |
| 329 callbacks->DidStartDevice(controller); |
| 330 std::move(done_cb).Run(); |
| 331 } |
| 332 |
| 333 void InProcessBuildableVideoCaptureDevice::DoStartDeviceCaptureOnDeviceThread( |
| 334 const media::VideoCaptureDeviceDescriptor& descriptor, |
| 618 const media::VideoCaptureParams& params, | 335 const media::VideoCaptureParams& params, |
| 619 std::unique_ptr<VideoCaptureDevice::Client> device_client) { | 336 std::unique_ptr<media::VideoCaptureDeviceClient> device_client, |
| 337 ReceiveDeviceCallback result_callback) { |
| 620 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); | 338 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); |
| 621 DCHECK(IsOnDeviceThread()); | 339 DCHECK(device_task_runner_->BelongsToCurrentThread()); |
| 622 | 340 |
| 623 std::unique_ptr<VideoCaptureDevice> video_capture_device; | 341 std::unique_ptr<media::VideoCaptureDevice> video_capture_device = |
| 624 video_capture_device = | 342 device_factory_->CreateDevice(descriptor); |
| 625 video_capture_device_factory_->CreateDevice(descriptor); | |
| 626 | 343 |
| 627 if (!video_capture_device) { | 344 if (!video_capture_device) { |
| 628 device_client->OnError(FROM_HERE, "Could not create capture device"); | 345 result_callback.Run(nullptr); |
| 629 return nullptr; | 346 return; |
| 630 } | 347 } |
| 631 | 348 |
| 632 video_capture_device->AllocateAndStart(params, std::move(device_client)); | 349 video_capture_device->AllocateAndStart(params, std::move(device_client)); |
| 633 return video_capture_device; | 350 result_callback.Run(std::move(video_capture_device)); |
| 634 } | 351 } |
| 635 | 352 |
| 636 std::unique_ptr<media::VideoCaptureDevice> | 353 void InProcessBuildableVideoCaptureDevice::DoStartTabCaptureOnDeviceThread( |
| 637 VideoCaptureManager::DoStartTabCaptureOnDeviceThread( | |
| 638 const std::string& id, | 354 const std::string& id, |
| 639 const media::VideoCaptureParams& params, | 355 const media::VideoCaptureParams& params, |
| 640 std::unique_ptr<VideoCaptureDevice::Client> device_client) { | 356 std::unique_ptr<media::VideoCaptureDeviceClient> device_client, |
| 357 ReceiveDeviceCallback result_callback) { |
| 641 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); | 358 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); |
| 642 DCHECK(IsOnDeviceThread()); | 359 DCHECK(device_task_runner_->BelongsToCurrentThread()); |
| 643 | 360 |
| 644 std::unique_ptr<VideoCaptureDevice> video_capture_device; | 361 std::unique_ptr<media::VideoCaptureDevice> video_capture_device; |
| 645 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) | 362 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) |
| 646 video_capture_device = WebContentsVideoCaptureDevice::Create(id); | 363 video_capture_device = WebContentsVideoCaptureDevice::Create(id); |
| 647 #endif | 364 #endif |
| 648 | 365 |
| 649 if (!video_capture_device) { | 366 if (!video_capture_device) { |
| 650 device_client->OnError(FROM_HERE, "Could not create capture device"); | 367 result_callback.Run(nullptr); |
| 651 return nullptr; | 368 return; |
| 652 } | 369 } |
| 653 | 370 |
| 654 video_capture_device->AllocateAndStart(params, std::move(device_client)); | 371 video_capture_device->AllocateAndStart(params, std::move(device_client)); |
| 655 return video_capture_device; | 372 result_callback.Run(std::move(video_capture_device)); |
| 656 } | 373 } |
| 657 | 374 |
| 658 std::unique_ptr<media::VideoCaptureDevice> | 375 void InProcessBuildableVideoCaptureDevice::DoStartDesktopCaptureOnDeviceThread( |
| 659 VideoCaptureManager::DoStartDesktopCaptureOnDeviceThread( | |
| 660 const std::string& id, | 376 const std::string& id, |
| 661 const media::VideoCaptureParams& params, | 377 const media::VideoCaptureParams& params, |
| 662 std::unique_ptr<VideoCaptureDevice::Client> device_client) { | 378 std::unique_ptr<media::VideoCaptureDeviceClient> device_client, |
| 379 ReceiveDeviceCallback result_callback) { |
| 663 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); | 380 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); |
| 664 DCHECK(IsOnDeviceThread()); | 381 DCHECK(device_task_runner_->BelongsToCurrentThread()); |
| 665 | 382 |
| 666 std::unique_ptr<VideoCaptureDevice> video_capture_device; | 383 std::unique_ptr<media::VideoCaptureDevice> video_capture_device; |
| 667 #if defined(ENABLE_SCREEN_CAPTURE) | 384 #if defined(ENABLE_SCREEN_CAPTURE) |
| 668 DesktopMediaID desktop_id = DesktopMediaID::Parse(id); | 385 DesktopMediaID desktop_id = DesktopMediaID::Parse(id); |
| 669 if (desktop_id.is_null()) { | 386 if (desktop_id.is_null()) { |
| 670 device_client->OnError(FROM_HERE, "Desktop media ID is null"); | 387 DLOG(ERROR) << "Desktop media ID is null"; |
| 671 return nullptr; | 388 result_callback.Run(nullptr); |
| 389 return; |
| 672 } | 390 } |
| 673 | 391 |
| 674 if (desktop_id.type == DesktopMediaID::TYPE_WEB_CONTENTS) { | 392 if (desktop_id.type == DesktopMediaID::TYPE_WEB_CONTENTS) { |
| 675 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) | 393 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) |
| 676 video_capture_device = WebContentsVideoCaptureDevice::Create(id); | 394 video_capture_device = WebContentsVideoCaptureDevice::Create(id); |
| 677 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED); | 395 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED); |
| 678 if (desktop_id.audio_share) { | 396 if (desktop_id.audio_share) { |
| 679 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED_WITH_AUDIO); | 397 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED_WITH_AUDIO); |
| 680 } else { | 398 } else { |
| 681 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED_WITHOUT_AUDIO); | 399 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED_WITHOUT_AUDIO); |
| 682 } | 400 } |
| 683 #endif | 401 #endif |
| 684 } else { | 402 } else { |
| 685 #if defined(OS_ANDROID) | 403 #if defined(OS_ANDROID) |
| 686 video_capture_device = base::MakeUnique<ScreenCaptureDeviceAndroid>(); | 404 video_capture_device = base::MakeUnique<ScreenCaptureDeviceAndroid>(); |
| 687 #else | 405 #else |
| 688 #if defined(USE_AURA) | 406 #if defined(USE_AURA) |
| 689 video_capture_device = DesktopCaptureDeviceAura::Create(desktop_id); | 407 video_capture_device = DesktopCaptureDeviceAura::Create(desktop_id); |
| 690 #endif // defined(USE_AURA) | 408 #endif // defined(USE_AURA) |
| 691 #if BUILDFLAG(ENABLE_WEBRTC) | 409 #if BUILDFLAG(ENABLE_WEBRTC) |
| 692 if (!video_capture_device) | 410 if (!video_capture_device) |
| 693 video_capture_device = DesktopCaptureDevice::Create(desktop_id); | 411 video_capture_device = DesktopCaptureDevice::Create(desktop_id); |
| 694 #endif // BUILDFLAG(ENABLE_WEBRTC) | 412 #endif // BUILDFLAG(ENABLE_WEBRTC) |
| 695 #endif // defined (OS_ANDROID) | 413 #endif // defined (OS_ANDROID) |
| 696 } | 414 } |
| 697 #endif // defined(ENABLE_SCREEN_CAPTURE) | 415 #endif // defined(ENABLE_SCREEN_CAPTURE) |
| 698 | 416 |
| 699 if (!video_capture_device) { | 417 if (!video_capture_device) { |
| 700 device_client->OnError(FROM_HERE, "Could not create capture device"); | 418 result_callback.Run(nullptr); |
| 701 return nullptr; | 419 return; |
| 702 } | 420 } |
| 703 | 421 |
| 704 video_capture_device->AllocateAndStart(params, std::move(device_client)); | 422 video_capture_device->AllocateAndStart(params, std::move(device_client)); |
| 705 return video_capture_device; | 423 result_callback.Run(std::move(video_capture_device)); |
| 706 } | 424 } |
| 707 | 425 |
| 708 void VideoCaptureManager::StartCaptureForClient( | 426 void InProcessBuildableVideoCaptureDevice:: |
| 709 media::VideoCaptureSessionId session_id, | 427 SetDesktopCaptureWindowIdOnDeviceThread(media::VideoCaptureDevice* device, |
| 710 const media::VideoCaptureParams& params, | 428 gfx::NativeViewId window_id, |
| 711 VideoCaptureControllerID client_id, | 429 base::OnceClosure done_cb) { |
| 712 VideoCaptureControllerEventHandler* client_handler, | 430 DCHECK(device_task_runner_->BelongsToCurrentThread()); |
| 713 const DoneCB& done_cb) { | 431 #if defined(ENABLE_SCREEN_CAPTURE) && BUILDFLAG(ENABLE_WEBRTC) && \ |
| 714 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 432 !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 = | 433 DesktopCaptureDevice* desktop_device = |
| 1231 static_cast<DesktopCaptureDevice*>(device); | 434 static_cast<DesktopCaptureDevice*>(device); |
| 1232 desktop_device->SetNotificationWindowId(window_id); | 435 desktop_device->SetNotificationWindowId(window_id); |
| 1233 VLOG(2) << "Screen capture notification window passed on device thread."; | 436 VLOG(2) << "Screen capture notification window passed on device thread."; |
| 1234 #endif | 437 #endif |
| 438 std::move(done_cb).Run(); |
| 1235 } | 439 } |
| 1236 | 440 |
| 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 | 441 } // namespace content |
| OLD | NEW |