15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_manager.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
1046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/bind_helpers.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
12d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/message_loop/message_loop.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/task_runner_util.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/sequenced_worker_pool.h"
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/media/capture/web_contents_video_capture_device.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_controller.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/desktop_media_id.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/common/content_switches.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/media_stream_request.h"
2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "media/base/bind_to_current_loop.h"
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "media/base/scoped_histogram_timer.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/video/capture/video_capture_device.h"
265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "media/video/capture/video_capture_device_factory.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#if defined(ENABLE_SCREEN_CAPTURE)
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/media/capture/desktop_capture_device.h"
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(USE_AURA)
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/media/capture/desktop_capture_device_aura.h"
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
35effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochnamespace {
36effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
37effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Compares two VideoCaptureFormat by checking smallest frame_size area, then
38effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// by _largest_ frame_rate. Used to order a VideoCaptureFormats vector so that
39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// the first entry for a given resolution has the largest frame rate, as needed
40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// by the ConsolidateCaptureFormats() method.
41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool IsCaptureFormatSmaller(const media::VideoCaptureFormat& format1,
42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            const media::VideoCaptureFormat& format2) {
43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (format1.frame_size.GetArea() == format2.frame_size.GetArea())
44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return format1.frame_rate > format2.frame_rate;
45effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return format1.frame_size.GetArea() < format2.frame_size.GetArea();
46effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
47effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
48effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool IsCaptureFormatSizeEqual(const media::VideoCaptureFormat& format1,
49effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                              const media::VideoCaptureFormat& format2) {
50effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return format1.frame_size.GetArea() == format2.frame_size.GetArea();
51effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
52effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
53effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// This function receives a list of capture formats, removes duplicated
54effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// resolutions while keeping the highest frame rate for each, and forcing I420
55effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// pixel format.
56effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid ConsolidateCaptureFormats(media::VideoCaptureFormats* formats) {
57effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (formats->empty())
58effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
59effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::sort(formats->begin(), formats->end(), IsCaptureFormatSmaller);
60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Due to the ordering imposed, the largest frame_rate is kept while removing
61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // duplicated resolutions.
62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  media::VideoCaptureFormats::iterator last =
63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      std::unique(formats->begin(), formats->end(), IsCaptureFormatSizeEqual);
64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  formats->erase(last, formats->end());
65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Mark all formats as I420, since this is what the renderer side will get
66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // anyhow: the actual pixel format is decided at the device level.
67effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (media::VideoCaptureFormats::iterator it = formats->begin();
68effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       it != formats->end(); ++it) {
69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    it->pixel_format = media::PIXEL_FORMAT_I420;
70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
71effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// The maximum number of buffers in the capture pipeline.  See
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// VideoCaptureController ctor comments for more details.
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const int kMaxNumberOfBuffers = 3;
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const int kMaxNumberOfBuffersForTabCapture = 5;
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Used for logging capture events.
796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Elements in this enum should not be deleted or rearranged; the only
806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// permitted operation is to add new elements before NUM_VIDEO_CAPTURE_EVENT.
816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)enum VideoCaptureEvent {
826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  VIDEO_CAPTURE_EVENT_START_CAPTURE = 0,
836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  VIDEO_CAPTURE_EVENT_STOP_CAPTURE_NORMAL = 1,
846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  VIDEO_CAPTURE_EVENT_STOP_CAPTURE_DUE_TO_ERROR = 2,
856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  NUM_VIDEO_CAPTURE_EVENT
866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)};
876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void LogVideoCaptureEvent(VideoCaptureEvent event) {
896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Media.VideoCaptureManager.Event",
906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                            event,
916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                            NUM_VIDEO_CAPTURE_EVENT);
926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
94effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}  // namespace
95effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
98d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)VideoCaptureManager::DeviceEntry::DeviceEntry(
99d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    MediaStreamType stream_type,
100d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::string& id,
101d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    scoped_ptr<VideoCaptureController> controller)
102d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    : stream_type(stream_type),
103d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      id(id),
104d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      video_capture_controller(controller.Pass()) {}
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
106d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)VideoCaptureManager::DeviceEntry::~DeviceEntry() {}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VideoCaptureManager::DeviceInfo::DeviceInfo() {}
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VideoCaptureManager::DeviceInfo::DeviceInfo(
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const media::VideoCaptureDevice::Name& name,
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const media::VideoCaptureFormats& supported_formats)
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : name(name),
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      supported_formats(supported_formats) {}
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VideoCaptureManager::DeviceInfo::~DeviceInfo() {}
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuVideoCaptureManager::VideoCaptureManager(
1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    scoped_ptr<media::VideoCaptureDeviceFactory> factory)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : listener_(NULL),
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      new_capture_session_id_(1),
1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      video_capture_device_factory_(factory.Pass()) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VideoCaptureManager::~VideoCaptureManager() {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(devices_.empty());
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void VideoCaptureManager::Register(
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MediaStreamProviderListener* listener,
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) {
132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!listener_);
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!device_task_runner_.get());
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listener_ = listener;
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_task_runner_ = device_task_runner;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void VideoCaptureManager::Unregister() {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(listener_);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listener_ = NULL;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VideoCaptureManager::EnumerateDevices(MediaStreamType stream_type) {
145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
146d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DVLOG(1) << "VideoCaptureManager::EnumerateDevices, type " << stream_type;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(listener_);
14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK_EQ(stream_type, MEDIA_DEVICE_VIDEO_CAPTURE);
14946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
15046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Bind a callback to ConsolidateDevicesInfoOnDeviceThread() with an argument
15146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // for another callback to OnDevicesInfoEnumerated() to be run in the current
15246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // loop, i.e. IO loop. Pass a timer for UMA histogram collection.
15346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::Callback<void(scoped_ptr<media::VideoCaptureDevice::Names>)>
15446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      devices_enumerated_callback =
15546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          base::Bind(&VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread,
15646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                     this,
15746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                     media::BindToCurrentLoop(base::Bind(
15846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                         &VideoCaptureManager::OnDevicesInfoEnumerated,
15946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                         this,
16046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                         stream_type,
16146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                         base::Owned(new base::ElapsedTimer()))),
16246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                     stream_type,
16346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                     devices_info_cache_);
16446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // OK to use base::Unretained() since we own the VCDFactory and |this| is
16546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // bound in |devices_enumerated_callback|.
16646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  device_task_runner_->PostTask(FROM_HERE,
16746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Bind(&media::VideoCaptureDeviceFactory::EnumerateDeviceNames,
16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 base::Unretained(video_capture_device_factory_.get()),
16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 devices_enumerated_callback));
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
172d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)int VideoCaptureManager::Open(const StreamDeviceInfo& device_info) {
173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(listener_);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
176d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Generate a new id for the session being opened.
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const media::VideoCaptureSessionId capture_session_id =
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new_capture_session_id_++;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
180d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(sessions_.find(capture_session_id) == sessions_.end());
181d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DVLOG(1) << "VideoCaptureManager::Open, id " << capture_session_id;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
183d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // We just save the stream info for processing later.
184d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  sessions_[capture_session_id] = device_info.device;
185d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
186d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Notify our listener asynchronously; this ensures that we return
187d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // |capture_session_id| to the caller of this function before using that same
188d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // id in a listener event.
189d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::MessageLoop::current()->PostTask(FROM_HERE,
190d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(&VideoCaptureManager::OnOpened, this,
191d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                 device_info.device.type, capture_session_id));
192d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return capture_session_id;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void VideoCaptureManager::Close(int capture_session_id) {
196effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(listener_);
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DVLOG(1) << "VideoCaptureManager::Close, id " << capture_session_id;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  SessionMap::iterator session_it = sessions_.find(capture_session_id);
201d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (session_it == sessions_.end()) {
202d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    NOTREACHED();
203d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return;
204d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
206d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DeviceEntry* const existing_device = GetDeviceEntryForMediaStreamDevice(
207d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      session_it->second);
208d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (existing_device) {
209d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Remove any client that is still using the session. This is safe to call
210d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // even if there are no clients using the session.
211d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    existing_device->video_capture_controller->StopSession(capture_session_id);
212d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
213d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // StopSession() may have removed the last client, so we might need to
214d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // close the device.
215d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DestroyDeviceEntryIfNoClients(existing_device);
216d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
217d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
218d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Notify listeners asynchronously, and forget the session.
219d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::MessageLoop::current()->PostTask(FROM_HERE,
220d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(&VideoCaptureManager::OnClosed, this, session_it->second.type,
221d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                 capture_session_id));
222d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  sessions_.erase(session_it);
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void VideoCaptureManager::DoStartDeviceOnDeviceThread(
226effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    media::VideoCaptureSessionId session_id,
227d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DeviceEntry* entry,
228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const media::VideoCaptureParams& params,
22968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    scoped_ptr<media::VideoCaptureDevice::Client> device_client) {
230d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsOnDeviceThread());
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
233ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  scoped_ptr<media::VideoCaptureDevice> video_capture_device;
234d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  switch (entry->stream_type) {
235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case MEDIA_DEVICE_VIDEO_CAPTURE: {
236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // We look up the device id from the renderer in our local enumeration
237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // since the renderer does not have all the information that might be
238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // held in the browser-side VideoCaptureDevice::Name structure.
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DeviceInfo* found = FindDeviceInfoById(entry->id, devices_info_cache_);
240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (found) {
2415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        video_capture_device =
24246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            video_capture_device_factory_->Create(found->name);
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
244eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
246eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case MEDIA_TAB_VIDEO_CAPTURE: {
247ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      video_capture_device.reset(
248d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          WebContentsVideoCaptureDevice::Create(entry->id));
249eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
250eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
251ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    case MEDIA_DESKTOP_VIDEO_CAPTURE: {
2527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#if defined(ENABLE_SCREEN_CAPTURE)
253d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      DesktopMediaID id = DesktopMediaID::Parse(entry->id);
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(USE_AURA)
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (id.type == DesktopMediaID::TYPE_AURA_WINDOW) {
256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        video_capture_device.reset(DesktopCaptureDeviceAura::Create(id));
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      } else
258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (id.type != DesktopMediaID::TYPE_NONE &&
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          id.type != DesktopMediaID::TYPE_AURA_WINDOW) {
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        video_capture_device = DesktopCaptureDevice::Create(id);
262effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        if (notification_window_ids_.find(session_id) !=
263effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            notification_window_ids_.end()) {
264effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          static_cast<DesktopCaptureDevice*>(video_capture_device.get())
265effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch              ->SetNotificationWindowId(notification_window_ids_[session_id]);
2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          VLOG(2) << "Screen capture notification window passed for session "
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  << session_id;
268effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        }
269ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      }
2707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#endif  // defined(ENABLE_SCREEN_CAPTURE)
271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    default: {
274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      NOTIMPLEMENTED();
275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!video_capture_device) {
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    device_client->OnError("Could not create capture device");
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  video_capture_device->AllocateAndStart(params, device_client.Pass());
285d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  entry->video_capture_device = video_capture_device.Pass();
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
288d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void VideoCaptureManager::StartCaptureForClient(
289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    media::VideoCaptureSessionId session_id,
2901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const media::VideoCaptureParams& params,
291d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    base::ProcessHandle client_render_process,
292d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    VideoCaptureControllerID client_id,
293d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    VideoCaptureControllerEventHandler* client_handler,
294d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const DoneCB& done_cb) {
295effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DVLOG(1) << "VideoCaptureManager::StartCaptureForClient, "
297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)           << params.requested_format.frame_size.ToString() << ", "
298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)           << params.requested_format.frame_rate << ", #" << session_id << ")";
299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DeviceEntry* entry = GetOrCreateDeviceEntry(session_id);
301d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!entry) {
302d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    done_cb.Run(base::WeakPtr<VideoCaptureController>());
303d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
306d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(entry->video_capture_controller);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  LogVideoCaptureEvent(VIDEO_CAPTURE_EVENT_START_CAPTURE);
3096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
310d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // First client starts the device.
31134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  if (entry->video_capture_controller->GetActiveClientCount() == 0) {
312d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DVLOG(1) << "VideoCaptureManager starting device (type = "
313d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)             << entry->stream_type << ", id = " << entry->id << ")";
314d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    device_task_runner_->PostTask(
316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        FROM_HERE,
317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        base::Bind(
318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            &VideoCaptureManager::DoStartDeviceOnDeviceThread,
319f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            this,
320effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            session_id,
321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            entry,
322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            params,
323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            base::Passed(entry->video_capture_controller->NewDeviceClient())));
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
325d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Run the callback first, as AddClient() may trigger OnFrameInfo().
326d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  done_cb.Run(entry->video_capture_controller->GetWeakPtr());
327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  entry->video_capture_controller->AddClient(
328f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      client_id, client_handler, client_render_process, session_id, params);
329d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
330d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
331d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void VideoCaptureManager::StopCaptureForClient(
332d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    VideoCaptureController* controller,
333d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    VideoCaptureControllerID client_id,
3345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    VideoCaptureControllerEventHandler* client_handler,
3355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    bool aborted_due_to_error) {
336effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
337d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(controller);
338d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(client_handler);
339d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
3406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  LogVideoCaptureEvent(aborted_due_to_error ?
3416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      VIDEO_CAPTURE_EVENT_STOP_CAPTURE_DUE_TO_ERROR :
3426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      VIDEO_CAPTURE_EVENT_STOP_CAPTURE_NORMAL);
3436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
344d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DeviceEntry* entry = GetDeviceEntryForController(controller);
345d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!entry) {
346d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    NOTREACHED();
347a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
348a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
3495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (aborted_due_to_error) {
3505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    SessionMap::iterator it;
3515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    for (it = sessions_.begin(); it != sessions_.end(); ++it) {
3525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (it->second.type == entry->stream_type &&
3535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          it->second.id == entry->id) {
3545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        listener_->Aborted(it->second.type, it->first);
3555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        break;
3565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      }
3575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
3585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
360d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Detach client from controller.
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  media::VideoCaptureSessionId session_id =
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      controller->RemoveClient(client_id, client_handler);
363d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DVLOG(1) << "VideoCaptureManager::StopCaptureForClient, session_id = "
364d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)           << session_id;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
366d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // If controller has no more clients, delete controller and device.
367d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DestroyDeviceEntryIfNoClients(entry);
368d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)void VideoCaptureManager::PauseCaptureForClient(
37134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    VideoCaptureController* controller,
37234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    VideoCaptureControllerID client_id,
37334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    VideoCaptureControllerEventHandler* client_handler) {
37434680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::IO);
37534680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  DCHECK(controller);
37634680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  DCHECK(client_handler);
37734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  DeviceEntry* entry = GetDeviceEntryForController(controller);
37834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  if (!entry) {
37934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    NOTREACHED();
38034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    return;
38134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  }
38234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
38334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  // We only pause the MEDIA_DEVICE_VIDEO_CAPTURE entry to release camera to
38434680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  // system.
38534680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE)
38634680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    return;
38734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
38834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  controller->PauseOrResumeClient(client_id, client_handler, true);
38934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  if (controller->GetActiveClientCount() != 0)
39034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    return;
39134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
39234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  // There is no more client, release the camera.
39334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  device_task_runner_->PostTask(
39434680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)      FROM_HERE,
39534680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)      base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
39634680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)                 base::Unretained(entry)));
39734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)}
39834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
39934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)void VideoCaptureManager::ResumeCaptureForClient(
40034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    media::VideoCaptureSessionId session_id,
40134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    const media::VideoCaptureParams& params,
40234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    VideoCaptureController* controller,
40334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    VideoCaptureControllerID client_id,
40434680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    VideoCaptureControllerEventHandler* client_handler) {
40534680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::IO);
40634680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  DCHECK(controller);
40734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  DCHECK(client_handler);
40834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
40934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  DeviceEntry* entry = GetDeviceEntryForController(controller);
41034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  if (!entry) {
41134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    NOTREACHED();
41234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    return;
41334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  }
41434680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
41534680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  // We only pause/resume the MEDIA_DEVICE_VIDEO_CAPTURE entry.
41634680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE)
41734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    return;
41834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
41934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  controller->PauseOrResumeClient(client_id, client_handler, false);
42034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  if (controller->GetActiveClientCount() != 1)
42134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    return;
42234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
42334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  // This is first active client, allocate the camera.
42434680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  device_task_runner_->PostTask(
42534680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)      FROM_HERE,
42634680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)      base::Bind(
42734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)          &VideoCaptureManager::DoStartDeviceOnDeviceThread,
42834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)          this,
42934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)          session_id,
43034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)          entry,
43134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)          params,
43234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)          base::Passed(entry->video_capture_controller->NewDeviceClient())));
43334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)}
43434680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool VideoCaptureManager::GetDeviceSupportedFormats(
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    media::VideoCaptureSessionId capture_session_id,
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    media::VideoCaptureFormats* supported_formats) {
438effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(supported_formats->empty());
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  SessionMap::iterator it = sessions_.find(capture_session_id);
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (it == sessions_.end())
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "GetDeviceSupportedFormats for device: " << it->second.name;
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Return all available formats of the device, regardless its started state.
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DeviceInfo* existing_device =
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FindDeviceInfoById(it->second.id, devices_info_cache_);
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (existing_device)
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *supported_formats = existing_device->supported_formats;
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool VideoCaptureManager::GetDeviceFormatsInUse(
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    media::VideoCaptureSessionId capture_session_id,
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    media::VideoCaptureFormats* formats_in_use) {
457effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(formats_in_use->empty());
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  SessionMap::iterator it = sessions_.find(capture_session_id);
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (it == sessions_.end())
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "GetDeviceFormatsInUse for device: " << it->second.name;
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Return the currently in-use format(s) of the device, if it's started.
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DeviceEntry* device_in_use =
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GetDeviceEntryForMediaStreamDevice(it->second);
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (device_in_use) {
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Currently only one format-in-use is supported at the VCC level.
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    formats_in_use->push_back(
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        device_in_use->video_capture_controller->GetVideoCaptureFormat());
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
476effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid VideoCaptureManager::SetDesktopCaptureWindowId(
477effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    media::VideoCaptureSessionId session_id,
478effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    gfx::NativeViewId window_id) {
479effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
4801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  VLOG(2) << "SetDesktopCaptureWindowId called for session " << session_id;
4811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  SessionMap::iterator session_it = sessions_.find(session_id);
483effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (session_it == sessions_.end()) {
4841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    VLOG(2) << "Session not found, will save the notification window.";
485effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    device_task_runner_->PostTask(
486effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        FROM_HERE,
487effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        base::Bind(
488effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            &VideoCaptureManager::SaveDesktopCaptureWindowIdOnDeviceThread,
489effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            this,
490effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            session_id,
491effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            window_id));
492effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
493effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
494effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
495effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DeviceEntry* const existing_device =
496effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      GetDeviceEntryForMediaStreamDevice(session_it->second);
4971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!existing_device) {
4981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    VLOG(2) << "Failed to find an existing device.";
499effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
5001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
501effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
502effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_EQ(MEDIA_DESKTOP_VIDEO_CAPTURE, existing_device->stream_type);
503effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DesktopMediaID id = DesktopMediaID::Parse(existing_device->id);
504effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (id.type == DesktopMediaID::TYPE_NONE ||
505effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      id.type == DesktopMediaID::TYPE_AURA_WINDOW) {
5061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    VLOG(2) << "Video capture device type mismatch.";
507effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
508effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
509effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
510effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  device_task_runner_->PostTask(
511effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FROM_HERE,
512effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread,
513effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 this,
514effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 existing_device,
515effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 window_id));
516effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
517effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
518d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void VideoCaptureManager::DoStopDeviceOnDeviceThread(DeviceEntry* entry) {
519d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StopDeviceTime");
520d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(IsOnDeviceThread());
521d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (entry->video_capture_device) {
522d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    entry->video_capture_device->StopAndDeAllocate();
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
524d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  entry->video_capture_device.reset();
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void VideoCaptureManager::OnOpened(
5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MediaStreamType stream_type,
5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    media::VideoCaptureSessionId capture_session_id) {
530effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!listener_) {
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Listener has been removed.
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listener_->Opened(stream_type, capture_session_id);
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void VideoCaptureManager::OnClosed(
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MediaStreamType stream_type,
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    media::VideoCaptureSessionId capture_session_id) {
541effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!listener_) {
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Listener has been removed.
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listener_->Closed(stream_type, capture_session_id);
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void VideoCaptureManager::OnDevicesInfoEnumerated(
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MediaStreamType stream_type,
55146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    base::ElapsedTimer* timer,
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const DeviceInfos& new_devices_info_cache) {
553effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
55446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  UMA_HISTOGRAM_TIMES(
55546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      "Media.VideoCaptureManager.GetAvailableDevicesInfoOnDeviceThreadTime",
55646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      timer->Elapsed());
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!listener_) {
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Listener has been removed.
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  devices_info_cache_ = new_devices_info_cache;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Walk the |devices_info_cache_| and transform from VCD::Name to
5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // StreamDeviceInfo for return purposes.
565d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  StreamDeviceInfoArray devices;
5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (DeviceInfos::const_iterator it = devices_info_cache_.begin();
5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != devices_info_cache_.end(); ++it) {
568d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    devices.push_back(StreamDeviceInfo(
5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        stream_type, it->name.GetNameAndModel(), it->name.id()));
570d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
571d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  listener_->DevicesEnumerated(stream_type, devices);
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VideoCaptureManager::IsOnDeviceThread() const {
5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return device_task_runner_->BelongsToCurrentThread();
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread(
57946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    base::Callback<void(const DeviceInfos&)> on_devices_enumerated_callback,
5805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MediaStreamType stream_type,
58146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const DeviceInfos& old_device_info_cache,
58246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    scoped_ptr<media::VideoCaptureDevice::Names> names_snapshot) {
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsOnDeviceThread());
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Construct |new_devices_info_cache| with the cached devices that are still
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // present in the system, and remove their names from |names_snapshot|, so we
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // keep there the truly new devices.
5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DeviceInfos new_devices_info_cache;
5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (DeviceInfos::const_iterator it_device_info =
5895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           old_device_info_cache.begin();
5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it_device_info != old_device_info_cache.end(); ++it_device_info) {
5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     for (media::VideoCaptureDevice::Names::iterator it =
59246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)         names_snapshot->begin();
59346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          it != names_snapshot->end(); ++it) {
5945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (it_device_info->name.id() == it->id()) {
5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        new_devices_info_cache.push_back(*it_device_info);
59646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        names_snapshot->erase(it);
5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        break;
5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get the supported capture formats for the new devices in |names_snapshot|.
6035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (media::VideoCaptureDevice::Names::const_iterator it =
60446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      names_snapshot->begin();
60546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       it != names_snapshot->end(); ++it) {
6065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    media::VideoCaptureFormats supported_formats;
6075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DeviceInfo device_info(*it, media::VideoCaptureFormats());
6085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    video_capture_device_factory_->GetDeviceSupportedFormats(
6095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        *it, &(device_info.supported_formats));
610effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ConsolidateCaptureFormats(&device_info.supported_formats);
6115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    new_devices_info_cache.push_back(device_info);
6125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
61346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
61446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  on_devices_enumerated_callback.Run(new_devices_info_cache);
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
617d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)VideoCaptureManager::DeviceEntry*
618d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)VideoCaptureManager::GetDeviceEntryForMediaStreamDevice(
619d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const MediaStreamDevice& device_info) {
620effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
622d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (DeviceEntries::iterator it = devices_.begin();
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != devices_.end(); ++it) {
624d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DeviceEntry* device = *it;
625d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (device_info.type == device->stream_type &&
626d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        device_info.id == device->id) {
627d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return device;
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
633d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)VideoCaptureManager::DeviceEntry*
634d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)VideoCaptureManager::GetDeviceEntryForController(
6355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const VideoCaptureController* controller) const {
636d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Look up |controller| in |devices_|.
6375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (DeviceEntries::const_iterator it = devices_.begin();
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != devices_.end(); ++it) {
639d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if ((*it)->video_capture_controller.get() == controller) {
640d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return *it;
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
643d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return NULL;
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
646d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) {
647effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
648d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Removal of the last client stops the device.
649d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (entry->video_capture_controller->GetClientCount() == 0) {
650d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DVLOG(1) << "VideoCaptureManager stopping device (type = "
651d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)             << entry->stream_type << ", id = " << entry->id << ")";
652d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
653d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // The DeviceEntry is removed from |devices_| immediately. The controller is
654d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // deleted immediately, and the device is freed asynchronously. After this
655d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // point, subsequent requests to open this same device ID will create a new
656d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // DeviceEntry, VideoCaptureController, and VideoCaptureDevice.
657d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    devices_.erase(entry);
658d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    entry->video_capture_controller.reset();
6595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    device_task_runner_->PostTask(
660d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        FROM_HERE,
661d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
662d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                   base::Owned(entry)));
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
664d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
666d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry(
6675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    media::VideoCaptureSessionId capture_session_id) {
668effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  SessionMap::iterator session_it = sessions_.find(capture_session_id);
671d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (session_it == sessions_.end()) {
672d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return NULL;
673d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
674d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const MediaStreamDevice& device_info = session_it->second;
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
676d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Check if another session has already opened this device. If so, just
677d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // use that opened device.
678d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DeviceEntry* const existing_device =
6795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GetDeviceEntryForMediaStreamDevice(device_info);
680d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (existing_device) {
681d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DCHECK_EQ(device_info.type, existing_device->stream_type);
682d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return existing_device;
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
684d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int max_buffers = device_info.type == MEDIA_TAB_VIDEO_CAPTURE ?
6865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      kMaxNumberOfBuffersForTabCapture : kMaxNumberOfBuffers;
687d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  scoped_ptr<VideoCaptureController> video_capture_controller(
6885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new VideoCaptureController(max_buffers));
689d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DeviceEntry* new_device = new DeviceEntry(device_info.type,
690d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                            device_info.id,
691d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                            video_capture_controller.Pass());
692d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  devices_.insert(new_device);
693d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return new_device;
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VideoCaptureManager::DeviceInfo* VideoCaptureManager::FindDeviceInfoById(
6975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& id,
6985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DeviceInfos& device_vector) {
6995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (DeviceInfos::iterator it = device_vector.begin();
7005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != device_vector.end(); ++it) {
7015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (it->name.id() == id)
7025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return &(*it);
7035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
7045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return NULL;
7055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
707effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread(
708effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DeviceEntry* entry,
709effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    gfx::NativeViewId window_id) {
710effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(IsOnDeviceThread());
711effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(entry->stream_type == MEDIA_DESKTOP_VIDEO_CAPTURE);
712effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#if defined(ENABLE_SCREEN_CAPTURE)
713effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DesktopCaptureDevice* device =
714effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      static_cast<DesktopCaptureDevice*>(entry->video_capture_device.get());
715effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  device->SetNotificationWindowId(window_id);
7161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  VLOG(2) << "Screen capture notification window passed on device thread.";
717effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#endif
718effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
719effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
720effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid VideoCaptureManager::SaveDesktopCaptureWindowIdOnDeviceThread(
721effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    media::VideoCaptureSessionId session_id,
722effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    gfx::NativeViewId window_id) {
723effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(IsOnDeviceThread());
724effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(notification_window_ids_.find(session_id) ==
725effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         notification_window_ids_.end());
726effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  notification_window_ids_[session_id] = window_id;
7271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  VLOG(2) << "Screen capture notification window saved for session "
7281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          << session_id << " on device thread.";
729effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
730effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
732