Index: content/browser/renderer_host/media/video_capture_manager.cc |
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc |
index e8664c14d0942fce2c45e74683563379256e1dc3..e1830eed9fa09a7704246e7d7ac534ed97e5d574 100644 |
--- a/content/browser/renderer_host/media/video_capture_manager.cc |
+++ b/content/browser/renderer_host/media/video_capture_manager.cc |
@@ -47,6 +47,27 @@ |
namespace { |
+class VideoFrameConsumerFeedbackObserverOnTaskRunner |
+ : public media::VideoFrameConsumerFeedbackObserver { |
+ public: |
+ VideoFrameConsumerFeedbackObserverOnTaskRunner( |
+ media::VideoFrameConsumerFeedbackObserver* observer, |
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) |
+ : observer_(observer), task_runner_(std::move(task_runner)) {} |
+ |
+ void OnUtilizationReport(int frame_feedback_id, double utilization) override { |
+ task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind( |
+ &media::VideoFrameConsumerFeedbackObserver::OnUtilizationReport, |
+ base::Unretained(observer_), frame_feedback_id, utilization)); |
+ } |
+ |
+ private: |
+ media::VideoFrameConsumerFeedbackObserver* const observer_; |
+ const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
+}; |
+ |
// Compares two VideoCaptureFormat by checking smallest frame_size area, then |
// by _largest_ frame_rate. Used to order a VideoCaptureFormats vector so that |
// the first entry for a given resolution has the largest frame rate, as needed |
@@ -126,9 +147,17 @@ const media::VideoCaptureSessionId kFakeSessionId = -1; |
namespace content { |
-// This class owns a pair VideoCaptureDevice - VideoCaptureController. |
-// VideoCaptureManager owns all such pairs and is responsible for deleting the |
-// instances when they are not used any longer. |
+// Instances of this struct go through 3 different phases during their lifetime. |
+// Phase 1: When first created (in GetOrCreateDeviceEntry()), this consists of |
+// only a controller. Clients can already connect to the controller, but there |
+// is no device present. |
+// Phase 2: When a request to "start" the entry comes in (via |
+// HandleQueuedStartRequest()), a VideoCaptureDevice::Client is created |
+// via video_capture_controller()->NewDeviceClient() and is used to schedule the |
+// creation and start of a VideoCaptureDevice on the Device Thread. |
+// Phase 3: As soon as the creation of the VideoCaptureDevice is complete, this |
+// newly created VideoCaptureDevice instance is connected to the |
+// VideoCaptureController via SetConsumerFeedbackObserver(). |
class VideoCaptureManager::DeviceEntry { |
public: |
DeviceEntry(MediaStreamType stream_type, |
@@ -406,9 +435,11 @@ void VideoCaptureManager::DoStopDevice(DeviceEntry* entry) { |
<< " serial_id = " << entry->serial_id << "."; |
entry->video_capture_controller()->OnLog( |
base::StringPrintf("Stopping device: id: %s", entry->id.c_str())); |
+ entry->video_capture_controller()->SetConsumerFeedbackObserver(nullptr); |
+ // |entry->video_capture_device| can be null if creating the device has |
+ // failed. |
if (entry->video_capture_device()) { |
- // |entry->video_capture_device| can be null if creating the device fails. |
device_task_runner_->PostTask( |
FROM_HERE, |
base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this, |
@@ -504,9 +535,9 @@ void VideoCaptureManager::OnDeviceStarted( |
DVLOG(3) << __func__; |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
DCHECK_EQ(serial_id, device_start_queue_.begin()->serial_id()); |
+ // |device| can be null if creation failed in |
+ // DoStartDeviceCaptureOnDeviceThread. |
if (device_start_queue_.front().abort_start()) { |
- // |device| can be null if creation failed in |
- // DoStartDeviceCaptureOnDeviceThread. |
// The device is no longer wanted. Stop the device again. |
DVLOG(3) << "OnDeviceStarted but start request have been aborted."; |
media::VideoCaptureDevice* device_ptr = device.get(); |
@@ -521,6 +552,13 @@ void VideoCaptureManager::OnDeviceStarted( |
DeviceEntry* const entry = GetDeviceEntryBySerialId(serial_id); |
DCHECK(entry); |
DCHECK(!entry->video_capture_device()); |
+ // Passing raw pointer |device.get()| to the controller is safe, |
+ // because we transfer ownership of it to |entry|. We are calling |
+ // SetConsumerFeedbackObserver(nullptr) before releasing |
+ // |entry->video_capture_device_| on the |device_task_runner_|. |
+ entry->video_capture_controller()->SetConsumerFeedbackObserver( |
+ base::MakeUnique<VideoFrameConsumerFeedbackObserverOnTaskRunner>( |
+ device.get(), device_task_runner_)); |
entry->SetVideoCaptureDevice(std::move(device)); |
if (entry->stream_type == MEDIA_DESKTOP_VIDEO_CAPTURE) { |