12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_host.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/browser_main_loop.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/renderer_host/media/media_stream_manager.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_manager.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/common/media/video_capture_messages.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content {
1503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)VideoCaptureHost::VideoCaptureHost(MediaStreamManager* media_stream_manager)
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : BrowserMessageFilter(VideoCaptureMsgStart),
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      media_stream_manager_(media_stream_manager) {
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)VideoCaptureHost::~VideoCaptureHost() {}
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VideoCaptureHost::OnChannelClosing() {
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Since the IPC sender is gone, close all requested VideoCaptureDevices.
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (EntryMap::iterator it = entries_.begin(); it != entries_.end(); ) {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::WeakPtr<VideoCaptureController>& controller = it->second;
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (controller) {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      VideoCaptureControllerID controller_id(it->first);
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      media_stream_manager_->video_capture_manager()->StopCaptureForClient(
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          controller.get(), controller_id, this, false);
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ++it;
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Remove the entry for this controller_id so that when the controller
3403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // is added, the controller will be notified to stop for this client
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // in DoControllerAddedOnIOThread.
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      entries_.erase(it++);
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VideoCaptureHost::OnDestruct() const {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::DeleteOnIOThread::Destruct(this);
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
46
47// Implements VideoCaptureControllerEventHandler.
48void VideoCaptureHost::OnError(const VideoCaptureControllerID& controller_id) {
49  DVLOG(1) << "VideoCaptureHost::OnError";
50  BrowserThread::PostTask(
51      BrowserThread::IO, FROM_HERE,
52      base::Bind(&VideoCaptureHost::DoHandleErrorOnIOThread,
53                 this, controller_id));
54}
55
56void VideoCaptureHost::OnBufferCreated(
57    const VideoCaptureControllerID& controller_id,
58    base::SharedMemoryHandle handle,
59    int length,
60    int buffer_id) {
61  BrowserThread::PostTask(
62      BrowserThread::IO, FROM_HERE,
63      base::Bind(&VideoCaptureHost::DoSendNewBufferOnIOThread,
64                 this, controller_id, handle, length, buffer_id));
65}
66
67void VideoCaptureHost::OnBufferDestroyed(
68    const VideoCaptureControllerID& controller_id,
69    int buffer_id) {
70  BrowserThread::PostTask(
71      BrowserThread::IO, FROM_HERE,
72      base::Bind(&VideoCaptureHost::DoSendFreeBufferOnIOThread,
73                 this, controller_id, buffer_id));
74}
75
76void VideoCaptureHost::OnBufferReady(
77    const VideoCaptureControllerID& controller_id,
78    int buffer_id,
79    const media::VideoCaptureFormat& frame_format,
80    const gfx::Rect& visible_rect,
81    base::TimeTicks timestamp) {
82  BrowserThread::PostTask(
83      BrowserThread::IO,
84      FROM_HERE,
85      base::Bind(&VideoCaptureHost::DoSendFilledBufferOnIOThread,
86                 this,
87                 controller_id,
88                 buffer_id,
89                 frame_format,
90                 visible_rect,
91                 timestamp));
92}
93
94void VideoCaptureHost::OnMailboxBufferReady(
95    const VideoCaptureControllerID& controller_id,
96    int buffer_id,
97    const gpu::MailboxHolder& mailbox_holder,
98    const media::VideoCaptureFormat& frame_format,
99    base::TimeTicks timestamp) {
100  BrowserThread::PostTask(
101      BrowserThread::IO,
102      FROM_HERE,
103      base::Bind(&VideoCaptureHost::DoSendFilledMailboxBufferOnIOThread,
104                 this,
105                 controller_id,
106                 buffer_id,
107                 mailbox_holder,
108                 frame_format,
109                 timestamp));
110}
111
112void VideoCaptureHost::OnEnded(const VideoCaptureControllerID& controller_id) {
113  DVLOG(1) << "VideoCaptureHost::OnEnded";
114  BrowserThread::PostTask(
115      BrowserThread::IO, FROM_HERE,
116      base::Bind(&VideoCaptureHost::DoEndedOnIOThread, this, controller_id));
117}
118
119void VideoCaptureHost::DoSendNewBufferOnIOThread(
120    const VideoCaptureControllerID& controller_id,
121    base::SharedMemoryHandle handle,
122    int length,
123    int buffer_id) {
124  DCHECK_CURRENTLY_ON(BrowserThread::IO);
125
126  if (entries_.find(controller_id) == entries_.end())
127    return;
128
129  Send(new VideoCaptureMsg_NewBuffer(controller_id.device_id, handle,
130                                     length, buffer_id));
131}
132
133void VideoCaptureHost::DoSendFreeBufferOnIOThread(
134    const VideoCaptureControllerID& controller_id,
135    int buffer_id) {
136  DCHECK_CURRENTLY_ON(BrowserThread::IO);
137
138  if (entries_.find(controller_id) == entries_.end())
139    return;
140
141  Send(new VideoCaptureMsg_FreeBuffer(controller_id.device_id, buffer_id));
142}
143
144void VideoCaptureHost::DoSendFilledBufferOnIOThread(
145    const VideoCaptureControllerID& controller_id,
146    int buffer_id,
147    const media::VideoCaptureFormat& format,
148    const gfx::Rect& visible_rect,
149    base::TimeTicks timestamp) {
150  DCHECK_CURRENTLY_ON(BrowserThread::IO);
151
152  if (entries_.find(controller_id) == entries_.end())
153    return;
154
155  Send(new VideoCaptureMsg_BufferReady(
156      controller_id.device_id, buffer_id, format, visible_rect, timestamp));
157}
158
159void VideoCaptureHost::DoSendFilledMailboxBufferOnIOThread(
160    const VideoCaptureControllerID& controller_id,
161    int buffer_id,
162    const gpu::MailboxHolder& mailbox_holder,
163    const media::VideoCaptureFormat& format,
164    base::TimeTicks timestamp) {
165  DCHECK_CURRENTLY_ON(BrowserThread::IO);
166
167  if (entries_.find(controller_id) == entries_.end())
168    return;
169
170  Send(new VideoCaptureMsg_MailboxBufferReady(
171      controller_id.device_id, buffer_id, mailbox_holder, format, timestamp));
172}
173
174void VideoCaptureHost::DoHandleErrorOnIOThread(
175    const VideoCaptureControllerID& controller_id) {
176  DCHECK_CURRENTLY_ON(BrowserThread::IO);
177
178  if (entries_.find(controller_id) == entries_.end())
179    return;
180
181  Send(new VideoCaptureMsg_StateChanged(controller_id.device_id,
182                                        VIDEO_CAPTURE_STATE_ERROR));
183  DeleteVideoCaptureControllerOnIOThread(controller_id, true);
184}
185
186void VideoCaptureHost::DoEndedOnIOThread(
187    const VideoCaptureControllerID& controller_id) {
188  DCHECK_CURRENTLY_ON(BrowserThread::IO);
189  DVLOG(1) << "VideoCaptureHost::DoEndedOnIOThread";
190  if (entries_.find(controller_id) == entries_.end())
191    return;
192
193  Send(new VideoCaptureMsg_StateChanged(controller_id.device_id,
194                                        VIDEO_CAPTURE_STATE_ENDED));
195  DeleteVideoCaptureControllerOnIOThread(controller_id, false);
196}
197
198///////////////////////////////////////////////////////////////////////////////
199// IPC Messages handler.
200bool VideoCaptureHost::OnMessageReceived(const IPC::Message& message) {
201  bool handled = true;
202  IPC_BEGIN_MESSAGE_MAP(VideoCaptureHost, message)
203    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Start, OnStartCapture)
204    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Pause, OnPauseCapture)
205    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Resume, OnResumeCapture)
206    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Stop, OnStopCapture)
207    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_BufferReady, OnReceiveEmptyBuffer)
208    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_GetDeviceSupportedFormats,
209                        OnGetDeviceSupportedFormats)
210    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_GetDeviceFormatsInUse,
211                        OnGetDeviceFormatsInUse)
212    IPC_MESSAGE_UNHANDLED(handled = false)
213  IPC_END_MESSAGE_MAP()
214
215  return handled;
216}
217
218void VideoCaptureHost::OnStartCapture(int device_id,
219                                      media::VideoCaptureSessionId session_id,
220                                      const media::VideoCaptureParams& params) {
221  DCHECK_CURRENTLY_ON(BrowserThread::IO);
222  DVLOG(1) << "VideoCaptureHost::OnStartCapture:"
223           << " session_id=" << session_id
224           << ", device_id=" << device_id
225           << ", format=" << params.requested_format.ToString()
226           << "@" << params.requested_format.frame_rate
227           << " (" << (params.resolution_change_policy ==
228                           media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT ?
229                           "variable" : "constant")
230           << ")";
231  VideoCaptureControllerID controller_id(device_id);
232  if (entries_.find(controller_id) != entries_.end()) {
233    Send(new VideoCaptureMsg_StateChanged(device_id,
234                                          VIDEO_CAPTURE_STATE_ERROR));
235    return;
236  }
237
238  entries_[controller_id] = base::WeakPtr<VideoCaptureController>();
239  media_stream_manager_->video_capture_manager()->StartCaptureForClient(
240      session_id,
241      params,
242      PeerHandle(),
243      controller_id,
244      this,
245      base::Bind(&VideoCaptureHost::OnControllerAdded, this, device_id));
246}
247
248void VideoCaptureHost::OnControllerAdded(
249    int device_id,
250    const base::WeakPtr<VideoCaptureController>& controller) {
251  BrowserThread::PostTask(
252      BrowserThread::IO,
253      FROM_HERE,
254      base::Bind(&VideoCaptureHost::DoControllerAddedOnIOThread,
255                 this,
256                 device_id,
257                 controller));
258}
259
260void VideoCaptureHost::DoControllerAddedOnIOThread(
261    int device_id,
262    const base::WeakPtr<VideoCaptureController>& controller) {
263  DCHECK_CURRENTLY_ON(BrowserThread::IO);
264  VideoCaptureControllerID controller_id(device_id);
265  EntryMap::iterator it = entries_.find(controller_id);
266  if (it == entries_.end()) {
267    if (controller) {
268      media_stream_manager_->video_capture_manager()->StopCaptureForClient(
269          controller.get(), controller_id, this, false);
270    }
271    return;
272  }
273
274  if (!controller) {
275    Send(new VideoCaptureMsg_StateChanged(device_id,
276                                          VIDEO_CAPTURE_STATE_ERROR));
277    entries_.erase(controller_id);
278    return;
279  }
280
281  DCHECK(!it->second);
282  it->second = controller;
283}
284
285void VideoCaptureHost::OnStopCapture(int device_id) {
286  DCHECK_CURRENTLY_ON(BrowserThread::IO);
287  DVLOG(1) << "VideoCaptureHost::OnStopCapture, device_id " << device_id;
288
289  VideoCaptureControllerID controller_id(device_id);
290
291  Send(new VideoCaptureMsg_StateChanged(device_id,
292                                        VIDEO_CAPTURE_STATE_STOPPED));
293  DeleteVideoCaptureControllerOnIOThread(controller_id, false);
294}
295
296void VideoCaptureHost::OnPauseCapture(int device_id) {
297  DCHECK_CURRENTLY_ON(BrowserThread::IO);
298  DVLOG(1) << "VideoCaptureHost::OnPauseCapture, device_id " << device_id;
299
300  VideoCaptureControllerID controller_id(device_id);
301  EntryMap::iterator it = entries_.find(controller_id);
302  if (it == entries_.end())
303    return;
304
305  if (it->second) {
306    media_stream_manager_->video_capture_manager()->PauseCaptureForClient(
307        it->second.get(), controller_id, this);
308  }
309}
310
311void VideoCaptureHost::OnResumeCapture(
312    int device_id,
313    media::VideoCaptureSessionId session_id,
314    const media::VideoCaptureParams& params) {
315  DCHECK_CURRENTLY_ON(BrowserThread::IO);
316  DVLOG(1) << "VideoCaptureHost::OnResumeCapture, device_id " << device_id;
317
318  VideoCaptureControllerID controller_id(device_id);
319  EntryMap::iterator it = entries_.find(controller_id);
320  if (it == entries_.end())
321    return;
322
323  if (it->second) {
324    media_stream_manager_->video_capture_manager()->ResumeCaptureForClient(
325        session_id, params, it->second.get(), controller_id, this);
326  }
327}
328
329void VideoCaptureHost::OnReceiveEmptyBuffer(int device_id,
330                                            int buffer_id,
331                                            uint32 sync_point) {
332  DCHECK_CURRENTLY_ON(BrowserThread::IO);
333
334  VideoCaptureControllerID controller_id(device_id);
335  EntryMap::iterator it = entries_.find(controller_id);
336  if (it != entries_.end()) {
337    const base::WeakPtr<VideoCaptureController>& controller = it->second;
338    if (controller)
339      controller->ReturnBuffer(controller_id, this, buffer_id, sync_point);
340  }
341}
342
343void VideoCaptureHost::OnGetDeviceSupportedFormats(
344    int device_id,
345    media::VideoCaptureSessionId capture_session_id) {
346  DCHECK_CURRENTLY_ON(BrowserThread::IO);
347  DVLOG(1) << "VideoCaptureHost::OnGetDeviceFormats, capture_session_id "
348           << capture_session_id;
349  media::VideoCaptureFormats device_supported_formats;
350  if (!media_stream_manager_->video_capture_manager()
351           ->GetDeviceSupportedFormats(capture_session_id,
352                                       &device_supported_formats)) {
353    DLOG(WARNING)
354        << "Could not retrieve device supported formats for device_id="
355        << device_id << " capture_session_id=" << capture_session_id;
356  }
357  Send(new VideoCaptureMsg_DeviceSupportedFormatsEnumerated(
358      device_id, device_supported_formats));
359}
360
361void VideoCaptureHost::OnGetDeviceFormatsInUse(
362    int device_id,
363    media::VideoCaptureSessionId capture_session_id) {
364  DCHECK_CURRENTLY_ON(BrowserThread::IO);
365  DVLOG(1) << "VideoCaptureHost::OnGetDeviceFormatsInUse, capture_session_id "
366           << capture_session_id;
367  media::VideoCaptureFormats formats_in_use;
368  if (!media_stream_manager_->video_capture_manager()->GetDeviceFormatsInUse(
369           capture_session_id, &formats_in_use)) {
370    DVLOG(1) << "Could not retrieve device format(s) in use for device_id="
371             << device_id << " capture_session_id=" << capture_session_id;
372  }
373  Send(new VideoCaptureMsg_DeviceFormatsInUseReceived(device_id,
374                                                      formats_in_use));
375}
376
377void VideoCaptureHost::DeleteVideoCaptureControllerOnIOThread(
378    const VideoCaptureControllerID& controller_id, bool on_error) {
379  DCHECK_CURRENTLY_ON(BrowserThread::IO);
380
381  EntryMap::iterator it = entries_.find(controller_id);
382  if (it == entries_.end())
383    return;
384
385  if (it->second) {
386    media_stream_manager_->video_capture_manager()->StopCaptureForClient(
387        it->second.get(), controller_id, this, on_error);
388  }
389  entries_.erase(it);
390}
391
392}  // namespace content
393