Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / renderer / media / video_capture_impl_manager.cc
blobf72f3138e9768aed811af2116efef0784e17dd73
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // Implementation notes about interactions with VideoCaptureImpl.
6 //
7 // How is VideoCaptureImpl used:
8 //
9 // VideoCaptureImpl is an IO thread object while VideoCaptureImplManager
10 // lives only on the render thread. It is only possible to access an
11 // object of VideoCaptureImpl via a task on the IO thread.
13 // How is VideoCaptureImpl deleted:
15 // A task is posted to the IO thread to delete a VideoCaptureImpl.
16 // Immediately after that the pointer to it is dropped. This means no
17 // access to this VideoCaptureImpl object is possible on the render
18 // thread. Also note that VideoCaptureImpl does not post task to itself.
20 // The use of Unretained:
22 // We make sure deletion is the last task on the IO thread for a
23 // VideoCaptureImpl object. This allows the use of Unretained() binding.
25 #include "content/renderer/media/video_capture_impl_manager.h"
27 #include "base/bind.h"
28 #include "base/bind_helpers.h"
29 #include "content/child/child_process.h"
30 #include "content/renderer/media/video_capture_impl.h"
31 #include "content/renderer/media/video_capture_message_filter.h"
32 #include "media/base/bind_to_current_loop.h"
34 namespace content {
36 VideoCaptureImplManager::VideoCaptureImplManager()
37 : next_client_id_(0),
38 filter_(new VideoCaptureMessageFilter()),
39 render_main_message_loop_(base::MessageLoopProxy::current()),
40 weak_factory_(this) {
43 VideoCaptureImplManager::~VideoCaptureImplManager() {
44 DCHECK(render_main_message_loop_->BelongsToCurrentThread());
45 if (devices_.empty())
46 return;
47 // Forcibly release all video capture resources.
48 for (const auto& device : devices_) {
49 VideoCaptureImpl* const impl = device.second.second;
50 ChildProcess::current()->io_message_loop_proxy()->PostTask(
51 FROM_HERE,
52 base::Bind(&VideoCaptureImpl::DeInit,
53 base::Unretained(impl)));
54 ChildProcess::current()->io_message_loop_proxy()->DeleteSoon(FROM_HERE,
55 impl);
57 devices_.clear();
60 base::Closure VideoCaptureImplManager::UseDevice(
61 media::VideoCaptureSessionId id) {
62 DCHECK(render_main_message_loop_->BelongsToCurrentThread());
64 VideoCaptureImpl* impl = NULL;
65 const VideoCaptureDeviceMap::iterator it = devices_.find(id);
66 if (it == devices_.end()) {
67 impl = CreateVideoCaptureImplForTesting(id, filter_.get());
68 if (!impl)
69 impl = new VideoCaptureImpl(id, filter_.get());
70 devices_[id] = std::make_pair(1, impl);
71 ChildProcess::current()->io_message_loop_proxy()->PostTask(
72 FROM_HERE,
73 base::Bind(&VideoCaptureImpl::Init,
74 base::Unretained(impl)));
75 } else {
76 ++it->second.first;
78 return base::Bind(&VideoCaptureImplManager::UnrefDevice,
79 weak_factory_.GetWeakPtr(), id);
82 base::Closure VideoCaptureImplManager::StartCapture(
83 media::VideoCaptureSessionId id,
84 const media::VideoCaptureParams& params,
85 const VideoCaptureStateUpdateCB& state_update_cb,
86 const VideoCaptureDeliverFrameCB& deliver_frame_cb) {
87 DCHECK(render_main_message_loop_->BelongsToCurrentThread());
88 const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
89 DCHECK(it != devices_.end());
90 VideoCaptureImpl* const impl = it->second.second;
92 // This ID is used to identify a client of VideoCaptureImpl.
93 const int client_id = ++next_client_id_;
95 ChildProcess::current()->io_message_loop_proxy()->PostTask(
96 FROM_HERE,
97 base::Bind(&VideoCaptureImpl::StartCapture,
98 base::Unretained(impl),
99 client_id,
100 params,
101 state_update_cb,
102 deliver_frame_cb));
103 return base::Bind(&VideoCaptureImplManager::StopCapture,
104 weak_factory_.GetWeakPtr(),
105 client_id, id);
108 void VideoCaptureImplManager::GetDeviceSupportedFormats(
109 media::VideoCaptureSessionId id,
110 const VideoCaptureDeviceFormatsCB& callback) {
111 DCHECK(render_main_message_loop_->BelongsToCurrentThread());
112 const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
113 DCHECK(it != devices_.end());
114 VideoCaptureImpl* const impl = it->second.second;
115 ChildProcess::current()->io_message_loop_proxy()->PostTask(
116 FROM_HERE,
117 base::Bind(&VideoCaptureImpl::GetDeviceSupportedFormats,
118 base::Unretained(impl), callback));
121 void VideoCaptureImplManager::GetDeviceFormatsInUse(
122 media::VideoCaptureSessionId id,
123 const VideoCaptureDeviceFormatsCB& callback) {
124 DCHECK(render_main_message_loop_->BelongsToCurrentThread());
125 const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
126 DCHECK(it != devices_.end());
127 VideoCaptureImpl* const impl = it->second.second;
128 ChildProcess::current()->io_message_loop_proxy()->PostTask(
129 FROM_HERE,
130 base::Bind(&VideoCaptureImpl::GetDeviceFormatsInUse,
131 base::Unretained(impl), callback));
134 VideoCaptureImpl*
135 VideoCaptureImplManager::CreateVideoCaptureImplForTesting(
136 media::VideoCaptureSessionId id,
137 VideoCaptureMessageFilter* filter) const {
138 return NULL;
141 void VideoCaptureImplManager::StopCapture(int client_id,
142 media::VideoCaptureSessionId id) {
143 DCHECK(render_main_message_loop_->BelongsToCurrentThread());
144 const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
145 DCHECK(it != devices_.end());
146 VideoCaptureImpl* const impl = it->second.second;
147 ChildProcess::current()->io_message_loop_proxy()->PostTask(
148 FROM_HERE,
149 base::Bind(&VideoCaptureImpl::StopCapture,
150 base::Unretained(impl), client_id));
153 void VideoCaptureImplManager::UnrefDevice(
154 media::VideoCaptureSessionId id) {
155 DCHECK(render_main_message_loop_->BelongsToCurrentThread());
156 const VideoCaptureDeviceMap::iterator it = devices_.find(id);
157 DCHECK(it != devices_.end());
158 VideoCaptureImpl* const impl = it->second.second;
160 // Unref and destroy on the IO thread if there's no more client.
161 DCHECK(it->second.first);
162 --it->second.first;
163 if (!it->second.first) {
164 devices_.erase(id);
165 ChildProcess::current()->io_message_loop_proxy()->PostTask(
166 FROM_HERE,
167 base::Bind(&VideoCaptureImpl::DeInit,
168 base::Unretained(impl)));
169 ChildProcess::current()->io_message_loop_proxy()->DeleteSoon(FROM_HERE,
170 impl);
174 void VideoCaptureImplManager::SuspendDevices(bool suspend) {
175 DCHECK(render_main_message_loop_->BelongsToCurrentThread());
176 for (const auto& device : devices_) {
177 VideoCaptureImpl* const impl = device.second.second;
178 ChildProcess::current()->io_message_loop_proxy()->PostTask(
179 FROM_HERE, base::Bind(&VideoCaptureImpl::SuspendCapture,
180 base::Unretained(impl), suspend));
184 } // namespace content