media_stream_manager.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
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#include "content/browser/renderer_host/media/media_stream_manager.h"
6
7#include <list>
8#include <vector>
9
10#include "base/bind.h"
11#include "base/command_line.h"
12#include "base/compiler_specific.h"
13#include "base/logging.h"
14#include "base/power_monitor/power_monitor.h"
15#include "base/rand_util.h"
16#include "base/run_loop.h"
17#include "base/strings/stringprintf.h"
18#include "base/threading/thread.h"
19#include "content/browser/browser_main_loop.h"
20#include "content/browser/media/capture/web_contents_capture_util.h"
21#include "content/browser/renderer_host/media/audio_input_device_manager.h"
22#include "content/browser/renderer_host/media/device_request_message_filter.h"
23#include "content/browser/renderer_host/media/media_capture_devices_impl.h"
24#include "content/browser/renderer_host/media/media_stream_requester.h"
25#include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
26#include "content/browser/renderer_host/media/video_capture_manager.h"
27#include "content/browser/renderer_host/render_process_host_impl.h"
28#include "content/public/browser/browser_thread.h"
29#include "content/public/browser/content_browser_client.h"
30#include "content/public/browser/media_device_id.h"
31#include "content/public/browser/media_observer.h"
32#include "content/public/browser/media_request_state.h"
33#include "content/public/browser/render_process_host.h"
34#include "content/public/common/content_switches.h"
35#include "content/public/common/media_stream_request.h"
36#include "media/audio/audio_manager_base.h"
37#include "media/audio/audio_parameters.h"
38#include "media/base/channel_layout.h"
39#include "url/gurl.h"
40
41#if defined(OS_WIN)
42#include "base/win/scoped_com_initializer.h"
43#endif
44
45namespace content {
46
47// Forward declaration of DeviceMonitorMac and its only useable method.
48class DeviceMonitorMac {
49 public:
50  void StartMonitoring();
51};
52
53namespace {
54// Creates a random label used to identify requests.
55std::string RandomLabel() {
56  // An earlier PeerConnection spec,
57  // http://dev.w3.org/2011/webrtc/editor/webrtc.html, specified the
58  // MediaStream::label alphabet as containing 36 characters from
59  // range: U+0021, U+0023 to U+0027, U+002A to U+002B, U+002D to U+002E,
60  // U+0030 to U+0039, U+0041 to U+005A, U+005E to U+007E.
61  // Here we use a safe subset.
62  static const char kAlphabet[] = "0123456789"
63      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
64
65  std::string label(36, ' ');
66  for (size_t i = 0; i < label.size(); ++i) {
67    int random_char = base::RandGenerator(sizeof(kAlphabet) - 1);
68    label[i] = kAlphabet[random_char];
69  }
70  return label;
71}
72
73void ParseStreamType(const StreamOptions& options,
74                     MediaStreamType* audio_type,
75                     MediaStreamType* video_type) {
76  *audio_type = MEDIA_NO_SERVICE;
77  *video_type = MEDIA_NO_SERVICE;
78  if (options.audio_requested) {
79     std::string audio_stream_source;
80     bool mandatory = false;
81     if (options.GetFirstAudioConstraintByName(kMediaStreamSource,
82                                               &audio_stream_source,
83                                               &mandatory)) {
84       DCHECK(mandatory);
85       // This is tab or screen capture.
86       if (audio_stream_source == kMediaStreamSourceTab) {
87         *audio_type = content::MEDIA_TAB_AUDIO_CAPTURE;
88       } else if (audio_stream_source == kMediaStreamSourceSystem) {
89         *audio_type = content::MEDIA_LOOPBACK_AUDIO_CAPTURE;
90       }
91     } else {
92       // This is normal audio device capture.
93       *audio_type = MEDIA_DEVICE_AUDIO_CAPTURE;
94     }
95  }
96  if (options.video_requested) {
97     std::string video_stream_source;
98     bool mandatory = false;
99     if (options.GetFirstVideoConstraintByName(kMediaStreamSource,
100                                               &video_stream_source,
101                                               &mandatory)) {
102       DCHECK(mandatory);
103       // This is tab or screen capture.
104       if (video_stream_source == kMediaStreamSourceTab) {
105         *video_type = content::MEDIA_TAB_VIDEO_CAPTURE;
106       } else if (video_stream_source == kMediaStreamSourceScreen) {
107         *video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
108       } else if (video_stream_source == kMediaStreamSourceDesktop) {
109         *video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
110       }
111     } else {
112       // This is normal video device capture.
113       *video_type = MEDIA_DEVICE_VIDEO_CAPTURE;
114     }
115  }
116}
117
118// Private helper method for SendMessageToNativeLog() that obtains the global
119// MediaStreamManager instance on the UI thread before sending |message| to the
120// webrtcLoggingPrivate API.
121void DoAddLogMessage(const std::string& message) {
122  // Must be on the UI thread to access BrowserMainLoop.
123  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
124  // May be null in tests.
125  // TODO(vrk): Handle this more elegantly by having native log messages become
126  // no-ops until MediaStreamManager is aware that a renderer process has
127  // started logging. crbug.com/333894
128  if (content::BrowserMainLoop::GetInstance()) {
129    BrowserThread::PostTask(
130        BrowserThread::IO,
131        FROM_HERE,
132        base::Bind(&MediaStreamManager::AddLogMessageOnIOThread,
133                   base::Unretained(content::BrowserMainLoop::GetInstance()
134                                        ->media_stream_manager()),
135                   message));
136  }
137}
138
139// Private helper method to generate a string for the log message that lists the
140// human readable names of |devices|.
141std::string GetLogMessageString(MediaStreamType stream_type,
142                                const StreamDeviceInfoArray& devices) {
143  std::string output_string =
144      base::StringPrintf("Getting devices for stream type %d:\n", stream_type);
145  if (devices.empty()) {
146    output_string += "No devices found.";
147  } else {
148    for (StreamDeviceInfoArray::const_iterator it = devices.begin();
149         it != devices.end(); ++it) {
150      output_string += "  " + it->device.name + "\n";
151    }
152  }
153  return output_string;
154}
155
156// Needed for MediaStreamManager::GenerateStream below.
157std::string ReturnEmptySalt() {
158  return std::string();
159}
160
161}  // namespace
162
163
164// MediaStreamManager::DeviceRequest represents a request to either enumerate
165// available devices or open one or more devices.
166// TODO(perkj): MediaStreamManager still needs refactoring. I propose we create
167// several subclasses of DeviceRequest and move some of the responsibility of
168// the MediaStreamManager to the subclasses to get rid of the way too many if
169// statements in MediaStreamManager.
170class MediaStreamManager::DeviceRequest {
171 public:
172  DeviceRequest(MediaStreamRequester* requester,
173                int requesting_process_id,
174                int requesting_view_id,
175                int page_request_id,
176                const GURL& security_origin,
177                bool user_gesture,
178                MediaStreamRequestType request_type,
179                const StreamOptions& options,
180                const ResourceContext::SaltCallback& salt_callback)
181      : requester(requester),
182        requesting_process_id(requesting_process_id),
183        requesting_view_id(requesting_view_id),
184        page_request_id(page_request_id),
185        security_origin(security_origin),
186        user_gesture(user_gesture),
187        request_type(request_type),
188        options(options),
189        salt_callback(salt_callback),
190        state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED),
191        audio_type_(MEDIA_NO_SERVICE),
192        video_type_(MEDIA_NO_SERVICE) {
193  }
194
195  ~DeviceRequest() {}
196
197  void SetAudioType(MediaStreamType audio_type) {
198    DCHECK(IsAudioMediaType(audio_type) || audio_type == MEDIA_NO_SERVICE);
199    audio_type_ = audio_type;
200  }
201
202  MediaStreamType audio_type() const { return audio_type_; }
203
204  void SetVideoType(MediaStreamType video_type) {
205    DCHECK(IsVideoMediaType(video_type) || video_type == MEDIA_NO_SERVICE);
206    video_type_ = video_type;
207  }
208
209  MediaStreamType video_type() const { return video_type_; }
210
211  // Creates a MediaStreamRequest object that is used by this request when UI
212  // is asked for permission and device selection.
213  void CreateUIRequest(const std::string& requested_audio_device_id,
214                       const std::string& requested_video_device_id) {
215    DCHECK(!ui_request_);
216    ui_request_.reset(new MediaStreamRequest(requesting_process_id,
217                                             requesting_view_id,
218                                             page_request_id,
219                                             security_origin,
220                                             user_gesture,
221                                             request_type,
222                                             requested_audio_device_id,
223                                             requested_video_device_id,
224                                             audio_type_,
225                                             video_type_));
226  }
227
228  // Creates a tab capture specific MediaStreamRequest object that is used by
229  // this request when UI is asked for permission and device selection.
230  void CreateTabCatureUIRequest(int target_render_process_id,
231                                int target_render_view_id,
232                                const std::string& tab_capture_id) {
233    DCHECK(!ui_request_);
234    ui_request_.reset(new MediaStreamRequest(target_render_process_id,
235                                             target_render_view_id,
236                                             page_request_id,
237                                             security_origin,
238                                             user_gesture,
239                                             request_type,
240                                             "",
241                                             "",
242                                             audio_type_,
243                                             video_type_));
244    ui_request_->tab_capture_device_id = tab_capture_id;
245  }
246
247  const MediaStreamRequest* UIRequest() const { return ui_request_.get(); }
248
249  // Update the request state and notify observers.
250  void SetState(MediaStreamType stream_type, MediaRequestState new_state) {
251    if (stream_type == NUM_MEDIA_TYPES) {
252      for (int i = MEDIA_NO_SERVICE + 1; i < NUM_MEDIA_TYPES; ++i) {
253        const MediaStreamType stream_type = static_cast<MediaStreamType>(i);
254        state_[stream_type] = new_state;
255      }
256    } else {
257      state_[stream_type] = new_state;
258    }
259
260    MediaObserver* media_observer =
261        GetContentClient()->browser()->GetMediaObserver();
262    if (!media_observer)
263      return;
264
265    // If |ui_request_| doesn't exist, it means that the request has not yet
266    // been setup fully and there are no valid observers.
267    if (!ui_request_)
268      return;
269
270    // If we appended a device_id scheme, we want to remove it when notifying
271    // observers which may be in different modules since this scheme is only
272    // used internally within the content module.
273    std::string device_id =
274        WebContentsCaptureUtil::StripWebContentsDeviceScheme(
275            ui_request_->tab_capture_device_id);
276
277    media_observer->OnMediaRequestStateChanged(
278        ui_request_->render_process_id, ui_request_->render_view_id,
279        ui_request_->page_request_id, ui_request_->security_origin,
280        MediaStreamDevice(stream_type, device_id, device_id), new_state);
281  }
282
283  MediaRequestState state(MediaStreamType stream_type) const {
284    return state_[stream_type];
285  }
286
287  MediaStreamRequester* const requester;  // Can be NULL.
288
289
290  // The render process id that requested this stream to be generated and that
291  // will receive a handle to the MediaStream. This may be different from
292  // MediaStreamRequest::render_process_id which in the tab capture case
293  // specifies the target renderer from which audio and video is captured.
294  const int requesting_process_id;
295
296  // The render view id that requested this stream to be generated and that
297  // will receive a handle to the MediaStream. This may be different from
298  // MediaStreamRequest::render_view_id which in the tab capture case
299  // specifies the target renderer from which audio and video is captured.
300  const int requesting_view_id;
301
302  // An ID the render view provided to identify this request.
303  const int page_request_id;
304
305  const GURL security_origin;
306
307  const bool user_gesture;
308
309  const MediaStreamRequestType request_type;
310
311  const StreamOptions options;
312
313  ResourceContext::SaltCallback salt_callback;
314
315  StreamDeviceInfoArray devices;
316
317  // Callback to the requester which audio/video devices have been selected.
318  // It can be null if the requester has no interest to know the result.
319  // Currently it is only used by |DEVICE_ACCESS| type.
320  MediaStreamManager::MediaRequestResponseCallback callback;
321
322  scoped_ptr<MediaStreamUIProxy> ui_proxy;
323
324 private:
325  std::vector<MediaRequestState> state_;
326  scoped_ptr<MediaStreamRequest> ui_request_;
327  MediaStreamType audio_type_;
328  MediaStreamType video_type_;
329};
330
331MediaStreamManager::EnumerationCache::EnumerationCache()
332    : valid(false) {
333}
334
335MediaStreamManager::EnumerationCache::~EnumerationCache() {
336}
337
338MediaStreamManager::MediaStreamManager()
339    : audio_manager_(NULL),
340      monitoring_started_(false),
341      io_loop_(NULL),
342      use_fake_ui_(false) {}
343
344MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager)
345    : audio_manager_(audio_manager),
346      monitoring_started_(false),
347      io_loop_(NULL),
348      use_fake_ui_(false) {
349  DCHECK(audio_manager_);
350  memset(active_enumeration_ref_count_, 0,
351         sizeof(active_enumeration_ref_count_));
352
353  // Some unit tests create the MSM in the IO thread and assumes the
354  // initialization is done synchronously.
355  if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
356    InitializeDeviceManagersOnIOThread();
357  } else {
358    BrowserThread::PostTask(
359        BrowserThread::IO, FROM_HERE,
360        base::Bind(&MediaStreamManager::InitializeDeviceManagersOnIOThread,
361                   base::Unretained(this)));
362  }
363
364  base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
365  // BrowserMainLoop always creates the PowerMonitor instance before creating
366  // MediaStreamManager, but power_monitor may be NULL in unit tests.
367  if (power_monitor)
368    power_monitor->AddObserver(this);
369}
370
371MediaStreamManager::~MediaStreamManager() {
372  DVLOG(1) << "~MediaStreamManager";
373  DCHECK(requests_.empty());
374  DCHECK(!device_task_runner_);
375
376  base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
377  // The PowerMonitor instance owned by BrowserMainLoops always outlives the
378  // MediaStreamManager, but it may be NULL in unit tests.
379  if (power_monitor)
380    power_monitor->RemoveObserver(this);
381}
382
383VideoCaptureManager* MediaStreamManager::video_capture_manager() {
384  DCHECK_CURRENTLY_ON(BrowserThread::IO);
385  DCHECK(video_capture_manager_.get());
386  return video_capture_manager_.get();
387}
388
389AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() {
390  DCHECK_CURRENTLY_ON(BrowserThread::IO);
391  DCHECK(audio_input_device_manager_.get());
392  return audio_input_device_manager_.get();
393}
394
395std::string MediaStreamManager::MakeMediaAccessRequest(
396    int render_process_id,
397    int render_view_id,
398    int page_request_id,
399    const StreamOptions& options,
400    const GURL& security_origin,
401    const MediaRequestResponseCallback& callback) {
402  DCHECK_CURRENTLY_ON(BrowserThread::IO);
403
404  // TODO(perkj): The argument list with NULL parameters to DeviceRequest
405  // suggests that this is the wrong design. Can this be refactored?
406  DeviceRequest* request = new DeviceRequest(NULL,
407                                             render_process_id,
408                                             render_view_id,
409                                             page_request_id,
410                                             security_origin,
411                                             false,  // user gesture
412                                             MEDIA_DEVICE_ACCESS,
413                                             options,
414                                             base::Bind(&ReturnEmptySalt));
415
416  const std::string& label = AddRequest(request);
417
418  request->callback = callback;
419  // Post a task and handle the request asynchronously. The reason is that the
420  // requester won't have a label for the request until this function returns
421  // and thus can not handle a response. Using base::Unretained is safe since
422  // MediaStreamManager is deleted on the UI thread, after the IO thread has
423  // been stopped.
424  BrowserThread::PostTask(
425      BrowserThread::IO, FROM_HERE,
426      base::Bind(&MediaStreamManager::SetupRequest,
427                 base::Unretained(this), label));
428  return label;
429}
430
431void MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
432                                        int render_process_id,
433                                        int render_view_id,
434                                        const ResourceContext::SaltCallback& sc,
435                                        int page_request_id,
436                                        const StreamOptions& options,
437                                        const GURL& security_origin,
438                                        bool user_gesture) {
439  DCHECK_CURRENTLY_ON(BrowserThread::IO);
440  DVLOG(1) << "GenerateStream()";
441  if (CommandLine::ForCurrentProcess()->HasSwitch(
442          switches::kUseFakeUIForMediaStream)) {
443    UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy>());
444  }
445
446  DeviceRequest* request = new DeviceRequest(requester,
447                                             render_process_id,
448                                             render_view_id,
449                                             page_request_id,
450                                             security_origin,
451                                             user_gesture,
452                                             MEDIA_GENERATE_STREAM,
453                                             options,
454                                             sc);
455
456  const std::string& label = AddRequest(request);
457
458  // Post a task and handle the request asynchronously. The reason is that the
459  // requester won't have a label for the request until this function returns
460  // and thus can not handle a response. Using base::Unretained is safe since
461  // MediaStreamManager is deleted on the UI thread, after the IO thread has
462  // been stopped.
463  BrowserThread::PostTask(
464      BrowserThread::IO, FROM_HERE,
465      base::Bind(&MediaStreamManager::SetupRequest,
466                 base::Unretained(this), label));
467}
468
469void MediaStreamManager::CancelRequest(int render_process_id,
470                                       int render_view_id,
471                                       int page_request_id) {
472  for (DeviceRequests::const_iterator request_it = requests_.begin();
473       request_it != requests_.end(); ++request_it) {
474    const DeviceRequest* request = request_it->second;
475    if (request->requesting_process_id == render_process_id &&
476        request->requesting_view_id == render_view_id &&
477        request->page_request_id == page_request_id) {
478      CancelRequest(request_it->first);
479      return;
480    }
481  }
482  NOTREACHED();
483}
484
485void MediaStreamManager::CancelRequest(const std::string& label) {
486  DCHECK_CURRENTLY_ON(BrowserThread::IO);
487  DVLOG(1) << "CancelRequest({label = " << label <<  "})";
488  DeviceRequest* request = FindRequest(label);
489  if (!request) {
490    // The request does not exist.
491    LOG(ERROR) << "The request with label = " << label  << " does not exist.";
492    return;
493  }
494
495  if (request->request_type == MEDIA_ENUMERATE_DEVICES) {
496    // It isn't an ideal use of "CancelRequest" to make it a requirement
497    // for enumeration requests to be deleted via "CancelRequest" _after_
498    // the request has been successfully fulfilled.
499    // See note in FinalizeEnumerateDevices for a recommendation on how
500    // we should refactor this.
501    DeleteRequest(label);
502    return;
503  }
504
505  // This is a request for opening one or more devices.
506  for (StreamDeviceInfoArray::iterator device_it = request->devices.begin();
507       device_it != request->devices.end(); ++device_it) {
508    MediaRequestState state = request->state(device_it->device.type);
509    // If we have not yet requested the device to be opened - just ignore it.
510    if (state != MEDIA_REQUEST_STATE_OPENING &&
511        state != MEDIA_REQUEST_STATE_DONE) {
512      continue;
513    }
514    // Stop the opening/opened devices of the requests.
515    CloseDevice(device_it->device.type, device_it->session_id);
516  }
517
518  // Cancel the request if still pending at UI side.
519  request->SetState(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_CLOSING);
520  DeleteRequest(label);
521}
522
523void MediaStreamManager::CancelAllRequests(int render_process_id) {
524  DeviceRequests::iterator request_it = requests_.begin();
525  while (request_it != requests_.end()) {
526    if (request_it->second->requesting_process_id != render_process_id) {
527      ++request_it;
528      continue;
529    }
530
531    std::string label = request_it->first;
532    ++request_it;
533    CancelRequest(label);
534  }
535}
536
537void MediaStreamManager::StopStreamDevice(int render_process_id,
538                                          int render_view_id,
539                                          const std::string& device_id) {
540  DCHECK_CURRENTLY_ON(BrowserThread::IO);
541  DVLOG(1) << "StopStreamDevice({render_view_id = " << render_view_id <<  "} "
542           << ", {device_id = " << device_id << "})";
543  // Find the first request for this |render_process_id| and |render_view_id|
544  // of type MEDIA_GENERATE_STREAM that has requested to use |device_id| and
545  // stop it.
546  for (DeviceRequests::iterator request_it = requests_.begin();
547       request_it  != requests_.end(); ++request_it) {
548    DeviceRequest* request = request_it->second;
549    if (request->requesting_process_id != render_process_id ||
550        request->requesting_view_id != render_view_id ||
551        request->request_type != MEDIA_GENERATE_STREAM) {
552      continue;
553    }
554
555    StreamDeviceInfoArray& devices = request->devices;
556    for (StreamDeviceInfoArray::iterator device_it = devices.begin();
557         device_it != devices.end(); ++device_it) {
558      if (device_it->device.id == device_id) {
559        StopDevice(device_it->device.type, device_it->session_id);
560        return;
561      }
562    }
563  }
564}
565
566void MediaStreamManager::StopDevice(MediaStreamType type, int session_id) {
567  DVLOG(1) << "StopDevice"
568           << "{type = " << type << "}"
569           << "{session_id = " << session_id << "}";
570  DeviceRequests::iterator request_it = requests_.begin();
571  while (request_it != requests_.end()) {
572    DeviceRequest* request = request_it->second;
573    StreamDeviceInfoArray* devices = &request->devices;
574    if (devices->empty()) {
575      // There is no device in use yet by this request.
576      ++request_it;
577      continue;
578    }
579    StreamDeviceInfoArray::iterator device_it = devices->begin();
580    while (device_it != devices->end()) {
581      if (device_it->device.type != type ||
582          device_it->session_id != session_id) {
583        ++device_it;
584        continue;
585      }
586
587      if (request->state(type) == MEDIA_REQUEST_STATE_DONE)
588        CloseDevice(type, session_id);
589      device_it = devices->erase(device_it);
590    }
591
592    // If this request doesn't have any active devices after a device
593    // has been stopped above, remove the request. Note that the request is
594    // only deleted if a device as been removed from |devices|.
595    if (devices->empty()) {
596      std::string label = request_it->first;
597      ++request_it;
598      DeleteRequest(label);
599    } else {
600      ++request_it;
601    }
602  }
603}
604
605void MediaStreamManager::CloseDevice(MediaStreamType type, int session_id) {
606  DVLOG(1) << "CloseDevice("
607           << "{type = " << type <<  "} "
608           << "{session_id = " << session_id << "})";
609  GetDeviceManager(type)->Close(session_id);
610
611  for (DeviceRequests::iterator request_it = requests_.begin();
612       request_it != requests_.end() ; ++request_it) {
613    StreamDeviceInfoArray* devices = &request_it->second->devices;
614    for (StreamDeviceInfoArray::iterator device_it = devices->begin();
615         device_it != devices->end(); ++device_it) {
616      if (device_it->session_id == session_id &&
617          device_it->device.type == type) {
618        // Notify observers that this device is being closed.
619        // Note that only one device per type can be opened.
620        request_it->second->SetState(type, MEDIA_REQUEST_STATE_CLOSING);
621      }
622    }
623  }
624}
625
626std::string MediaStreamManager::EnumerateDevices(
627    MediaStreamRequester* requester,
628    int render_process_id,
629    int render_view_id,
630    const ResourceContext::SaltCallback& sc,
631    int page_request_id,
632    MediaStreamType type,
633    const GURL& security_origin) {
634  DCHECK_CURRENTLY_ON(BrowserThread::IO);
635  DCHECK(requester);
636  DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
637         type == MEDIA_DEVICE_VIDEO_CAPTURE);
638
639  DeviceRequest* request = new DeviceRequest(requester,
640                                             render_process_id,
641                                             render_view_id,
642                                             page_request_id,
643                                             security_origin,
644                                             false,  // user gesture
645                                             MEDIA_ENUMERATE_DEVICES,
646                                             StreamOptions(),
647                                             sc);
648  if (IsAudioMediaType(type))
649    request->SetAudioType(type);
650  else if (IsVideoMediaType(type))
651    request->SetVideoType(type);
652
653  const std::string& label = AddRequest(request);
654  // Post a task and handle the request asynchronously. The reason is that the
655  // requester won't have a label for the request until this function returns
656  // and thus can not handle a response. Using base::Unretained is safe since
657  // MediaStreamManager is deleted on the UI thread, after the IO thread has
658  // been stopped.
659  BrowserThread::PostTask(
660      BrowserThread::IO, FROM_HERE,
661      base::Bind(&MediaStreamManager::DoEnumerateDevices,
662                 base::Unretained(this), label));
663  return label;
664}
665
666void MediaStreamManager::DoEnumerateDevices(const std::string& label) {
667  DCHECK_CURRENTLY_ON(BrowserThread::IO);
668  DeviceRequest* request = FindRequest(label);
669  if (!request)
670    return;  // This can happen if the request has been canceled.
671
672  MediaStreamType type;
673  EnumerationCache* cache;
674  if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE) {
675    DCHECK_EQ(MEDIA_NO_SERVICE, request->video_type());
676    type = MEDIA_DEVICE_AUDIO_CAPTURE;
677    cache = &audio_enumeration_cache_;
678  } else {
679    DCHECK_EQ(MEDIA_DEVICE_VIDEO_CAPTURE, request->video_type());
680    type = MEDIA_DEVICE_VIDEO_CAPTURE;
681    cache = &video_enumeration_cache_;
682  }
683
684  if (!EnumerationRequired(cache, type)) {
685    // Cached device list of this type exists. Just send it out.
686    request->SetState(type, MEDIA_REQUEST_STATE_REQUESTED);
687    request->devices = cache->devices;
688    FinalizeEnumerateDevices(label, request);
689  } else {
690    StartEnumeration(request);
691  }
692  DVLOG(1) << "Enumerate Devices ({label = " << label <<  "})";
693}
694
695void MediaStreamManager::OpenDevice(MediaStreamRequester* requester,
696                                    int render_process_id,
697                                    int render_view_id,
698                                    const ResourceContext::SaltCallback& sc,
699                                    int page_request_id,
700                                    const std::string& device_id,
701                                    MediaStreamType type,
702                                    const GURL& security_origin) {
703  DCHECK_CURRENTLY_ON(BrowserThread::IO);
704  DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
705         type == MEDIA_DEVICE_VIDEO_CAPTURE);
706  DVLOG(1) << "OpenDevice ({page_request_id = " << page_request_id <<  "})";
707  StreamOptions options;
708  if (IsAudioMediaType(type)) {
709    options.audio_requested = true;
710    options.mandatory_audio.push_back(
711        StreamOptions::Constraint(kMediaStreamSourceInfoId, device_id));
712  } else if (IsVideoMediaType(type)) {
713    options.video_requested = true;
714    options.mandatory_video.push_back(
715        StreamOptions::Constraint(kMediaStreamSourceInfoId, device_id));
716  } else {
717    NOTREACHED();
718  }
719  DeviceRequest* request = new DeviceRequest(requester,
720                                             render_process_id,
721                                             render_view_id,
722                                             page_request_id,
723                                             security_origin,
724                                             false,  // user gesture
725                                             MEDIA_OPEN_DEVICE,
726                                             options,
727                                             sc);
728
729  const std::string& label = AddRequest(request);
730  // Post a task and handle the request asynchronously. The reason is that the
731  // requester won't have a label for the request until this function returns
732  // and thus can not handle a response. Using base::Unretained is safe since
733  // MediaStreamManager is deleted on the UI thread, after the IO thread has
734  // been stopped.
735  BrowserThread::PostTask(
736      BrowserThread::IO, FROM_HERE,
737      base::Bind(&MediaStreamManager::SetupRequest,
738                 base::Unretained(this), label));
739}
740
741void MediaStreamManager::EnsureDeviceMonitorStarted() {
742  DCHECK_CURRENTLY_ON(BrowserThread::IO);
743  StartMonitoring();
744}
745
746void MediaStreamManager::StopRemovedDevices(
747    const StreamDeviceInfoArray& old_devices,
748    const StreamDeviceInfoArray& new_devices) {
749  DVLOG(1) << "StopRemovedDevices("
750           << "{#old_devices = " << old_devices.size() <<  "} "
751           << "{#new_devices = " << new_devices.size() << "})";
752  for (StreamDeviceInfoArray::const_iterator old_dev_it = old_devices.begin();
753       old_dev_it != old_devices.end(); ++old_dev_it) {
754    bool device_found = false;
755    StreamDeviceInfoArray::const_iterator new_dev_it = new_devices.begin();
756    for (; new_dev_it != new_devices.end(); ++new_dev_it) {
757      if (old_dev_it->device.id == new_dev_it->device.id) {
758        device_found = true;
759        break;
760      }
761    }
762
763    if (!device_found) {
764      // A device has been removed. We need to check if it is used by a
765      // MediaStream and in that case cleanup and notify the render process.
766      StopRemovedDevice(old_dev_it->device);
767    }
768  }
769}
770
771void MediaStreamManager::StopRemovedDevice(const MediaStreamDevice& device) {
772  std::vector<int> session_ids;
773  for (DeviceRequests::const_iterator it = requests_.begin();
774       it != requests_.end() ; ++it) {
775    const DeviceRequest* request = it->second;
776    for (StreamDeviceInfoArray::const_iterator device_it =
777             request->devices.begin();
778         device_it != request->devices.end(); ++device_it) {
779      std::string source_id = content::GetHMACForMediaDeviceID(
780          request->salt_callback,
781          request->security_origin,
782          device.id);
783      if (device_it->device.id == source_id &&
784          device_it->device.type == device.type) {
785        session_ids.push_back(device_it->session_id);
786        if (it->second->requester) {
787          it->second->requester->DeviceStopped(
788              it->second->requesting_view_id,
789              it->first,
790              *device_it);
791        }
792      }
793    }
794  }
795  for (std::vector<int>::const_iterator it = session_ids.begin();
796       it != session_ids.end(); ++it) {
797    StopDevice(device.type, *it);
798  }
799
800  std::ostringstream oss;
801  oss << "Media input device removed: type = " <<
802    (device.type == MEDIA_DEVICE_AUDIO_CAPTURE ? "audio" : "video") <<
803    ", id = " << device.id << ", name = " << device.name;
804  AddLogMessageOnIOThread(oss.str());
805}
806
807void MediaStreamManager::StartMonitoring() {
808  DCHECK_CURRENTLY_ON(BrowserThread::IO);
809  if (monitoring_started_)
810    return;
811
812  if (!base::SystemMonitor::Get())
813    return;
814
815  monitoring_started_ = true;
816  base::SystemMonitor::Get()->AddDevicesChangedObserver(this);
817
818  // Enumerate both the audio and video devices to cache the device lists
819  // and send them to media observer.
820  ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_CAPTURE];
821  audio_input_device_manager_->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE);
822  ++active_enumeration_ref_count_[MEDIA_DEVICE_VIDEO_CAPTURE];
823  video_capture_manager_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
824
825#if defined(OS_MACOSX)
826  BrowserThread::PostTask(
827      BrowserThread::UI, FROM_HERE,
828      base::Bind(&MediaStreamManager::StartMonitoringOnUIThread,
829                 base::Unretained(this)));
830#endif
831}
832
833#if defined(OS_MACOSX)
834void MediaStreamManager::StartMonitoringOnUIThread() {
835  DCHECK_CURRENTLY_ON(BrowserThread::UI);
836  BrowserMainLoop* browser_main_loop = content::BrowserMainLoop::GetInstance();
837  if (browser_main_loop)
838    browser_main_loop->device_monitor_mac()->StartMonitoring();
839}
840#endif
841
842void MediaStreamManager::StopMonitoring() {
843  DCHECK_EQ(base::MessageLoop::current(), io_loop_);
844  if (monitoring_started_) {
845    base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this);
846    monitoring_started_ = false;
847    ClearEnumerationCache(&audio_enumeration_cache_);
848    ClearEnumerationCache(&video_enumeration_cache_);
849  }
850}
851
852bool MediaStreamManager::GetRequestedDeviceCaptureId(
853    const DeviceRequest* request,
854    MediaStreamType type,
855    std::string* device_id) const {
856  DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
857         type == MEDIA_DEVICE_VIDEO_CAPTURE);
858  const StreamOptions::Constraints* mandatory =
859      (type == MEDIA_DEVICE_AUDIO_CAPTURE) ?
860          &request->options.mandatory_audio : &request->options.mandatory_video;
861  const StreamOptions::Constraints* optional =
862      (type == MEDIA_DEVICE_AUDIO_CAPTURE) ?
863          &request->options.optional_audio : &request->options.optional_video;
864
865  std::vector<std::string> source_ids;
866  StreamOptions::GetConstraintsByName(*mandatory,
867                                      kMediaStreamSourceInfoId, &source_ids);
868  if (source_ids.size() > 1) {
869    LOG(ERROR) << "Only one mandatory " << kMediaStreamSourceInfoId
870        << " is supported.";
871    return false;
872  }
873  // If a specific device has been requested we need to find the real device
874  // id.
875  if (source_ids.size() == 1 &&
876      !TranslateSourceIdToDeviceId(type,
877                                   request->salt_callback,
878                                   request->security_origin,
879                                   source_ids[0], device_id)) {
880    LOG(WARNING) << "Invalid mandatory " << kMediaStreamSourceInfoId
881                 << " = " << source_ids[0] << ".";
882    return false;
883  }
884  // Check for optional audio sourceIDs.
885  if (device_id->empty()) {
886    StreamOptions::GetConstraintsByName(*optional,
887                                        kMediaStreamSourceInfoId,
888                                        &source_ids);
889    // Find the first sourceID that translates to device. Note that only one
890    // device per type can call to GenerateStream is ever opened.
891    for (std::vector<std::string>::const_iterator it = source_ids.begin();
892         it != source_ids.end(); ++it) {
893      if (TranslateSourceIdToDeviceId(type,
894                                      request->salt_callback,
895                                      request->security_origin,
896                                      *it,
897                                      device_id)) {
898        break;
899      }
900    }
901  }
902  return true;
903}
904
905void MediaStreamManager::TranslateDeviceIdToSourceId(
906    DeviceRequest* request,
907    MediaStreamDevice* device) {
908  if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
909      request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE) {
910    device->id = content::GetHMACForMediaDeviceID(
911        request->salt_callback,
912        request->security_origin,
913        device->id);
914  }
915}
916
917bool MediaStreamManager::TranslateSourceIdToDeviceId(
918    MediaStreamType stream_type,
919    const ResourceContext::SaltCallback& sc,
920    const GURL& security_origin,
921    const std::string& source_id,
922    std::string* device_id) const {
923  DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ||
924         stream_type == MEDIA_DEVICE_VIDEO_CAPTURE);
925  // The source_id can be empty if the constraint is set but empty.
926  if (source_id.empty())
927    return false;
928
929  const EnumerationCache* cache =
930      stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
931      &audio_enumeration_cache_ : &video_enumeration_cache_;
932
933  // If device monitoring hasn't started, the |device_guid| is not valid.
934  if (!cache->valid)
935    return false;
936
937  for (StreamDeviceInfoArray::const_iterator it = cache->devices.begin();
938       it != cache->devices.end();
939       ++it) {
940    if (content::DoesMediaDeviceIDMatchHMAC(sc, security_origin, source_id,
941                                            it->device.id)) {
942      *device_id = it->device.id;
943      return true;
944    }
945  }
946  return false;
947}
948
949void MediaStreamManager::ClearEnumerationCache(EnumerationCache* cache) {
950  DCHECK_EQ(base::MessageLoop::current(), io_loop_);
951  cache->valid = false;
952}
953
954bool MediaStreamManager::EnumerationRequired(EnumerationCache* cache,
955                                             MediaStreamType stream_type) {
956  DCHECK_EQ(base::MessageLoop::current(), io_loop_);
957  if (stream_type == MEDIA_NO_SERVICE)
958    return false;
959
960  DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ||
961         stream_type == MEDIA_DEVICE_VIDEO_CAPTURE);
962
963#if defined(OS_ANDROID)
964  // There's no SystemMonitor on Android that notifies us when devices are
965  // added or removed, so we need to populate the cache on every request.
966  // Fortunately, there is an already up-to-date cache in the browser side
967  // audio manager that we can rely on, so the performance impact of
968  // invalidating the cache like this, is minimal.
969  if (stream_type == MEDIA_DEVICE_AUDIO_CAPTURE) {
970    // Make sure the cache is marked as invalid so that FinalizeEnumerateDevices
971    // will be called at the end of the enumeration.
972    ClearEnumerationCache(cache);
973  }
974#endif
975  // If the cache isn't valid, we need to start a full enumeration.
976  return !cache->valid;
977}
978
979void MediaStreamManager::StartEnumeration(DeviceRequest* request) {
980  DCHECK_CURRENTLY_ON(BrowserThread::IO);
981
982  // Start monitoring the devices when doing the first enumeration.
983  StartMonitoring();
984
985  // Start enumeration for devices of all requested device types.
986  const MediaStreamType streams[] = { request->audio_type(),
987                                      request->video_type() };
988  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(streams); ++i) {
989    if (streams[i] == MEDIA_NO_SERVICE)
990      continue;
991    request->SetState(streams[i], MEDIA_REQUEST_STATE_REQUESTED);
992    DCHECK_GE(active_enumeration_ref_count_[streams[i]], 0);
993    if (active_enumeration_ref_count_[streams[i]] == 0) {
994      ++active_enumeration_ref_count_[streams[i]];
995      GetDeviceManager(streams[i])->EnumerateDevices(streams[i]);
996    }
997  }
998}
999
1000std::string MediaStreamManager::AddRequest(DeviceRequest* request) {
1001  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1002
1003  // Create a label for this request and verify it is unique.
1004  std::string unique_label;
1005  do {
1006    unique_label = RandomLabel();
1007  } while (requests_.find(unique_label) != requests_.end());
1008
1009  requests_.insert(std::make_pair(unique_label, request));
1010
1011  return unique_label;
1012}
1013
1014MediaStreamManager::DeviceRequest*
1015MediaStreamManager::FindRequest(const std::string& label) const {
1016  DeviceRequests::const_iterator request_it = requests_.find(label);
1017  return request_it == requests_.end() ? NULL : request_it->second;
1018}
1019
1020void MediaStreamManager::DeleteRequest(const std::string& label) {
1021  DVLOG(1) << "DeleteRequest({label= " << label << "})";
1022  DeviceRequests::iterator it = requests_.find(label);
1023  scoped_ptr<DeviceRequest> request(it->second);
1024  requests_.erase(it);
1025}
1026
1027void MediaStreamManager::PostRequestToUI(const std::string& label,
1028                                         DeviceRequest* request) {
1029  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1030  DCHECK(request->UIRequest());
1031  DVLOG(1) << "PostRequestToUI({label= " << label << "})";
1032
1033  const MediaStreamType audio_type = request->audio_type();
1034  const MediaStreamType video_type = request->video_type();
1035
1036  // Post the request to UI and set the state.
1037  if (IsAudioMediaType(audio_type))
1038    request->SetState(audio_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
1039  if (IsVideoMediaType(video_type))
1040    request->SetState(video_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
1041
1042  if (use_fake_ui_) {
1043    if (!fake_ui_)
1044      fake_ui_.reset(new FakeMediaStreamUIProxy());
1045
1046    MediaStreamDevices devices;
1047    if (audio_enumeration_cache_.valid) {
1048      for (StreamDeviceInfoArray::const_iterator it =
1049               audio_enumeration_cache_.devices.begin();
1050           it != audio_enumeration_cache_.devices.end(); ++it) {
1051        devices.push_back(it->device);
1052      }
1053    }
1054    if (video_enumeration_cache_.valid) {
1055      for (StreamDeviceInfoArray::const_iterator it =
1056               video_enumeration_cache_.devices.begin();
1057           it != video_enumeration_cache_.devices.end(); ++it) {
1058        devices.push_back(it->device);
1059      }
1060    }
1061
1062    fake_ui_->SetAvailableDevices(devices);
1063
1064    request->ui_proxy = fake_ui_.Pass();
1065  } else {
1066    request->ui_proxy = MediaStreamUIProxy::Create();
1067  }
1068
1069  request->ui_proxy->RequestAccess(
1070      *request->UIRequest(),
1071      base::Bind(&MediaStreamManager::HandleAccessRequestResponse,
1072                 base::Unretained(this), label));
1073}
1074
1075void MediaStreamManager::SetupRequest(const std::string& label) {
1076  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1077  DeviceRequest* request = FindRequest(label);
1078  if (!request) {
1079    DVLOG(1) << "SetupRequest label " << label << " doesn't exist!!";
1080    return;  // This can happen if the request has been canceled.
1081  }
1082
1083  if (!request->security_origin.is_valid()) {
1084    LOG(ERROR) << "Invalid security origin. "
1085               << request->security_origin;
1086    FinalizeRequestFailed(label,
1087                          request,
1088                          MEDIA_DEVICE_INVALID_SECURITY_ORIGIN);
1089    return;
1090  }
1091
1092  MediaStreamType audio_type = MEDIA_NO_SERVICE;
1093  MediaStreamType video_type = MEDIA_NO_SERVICE;
1094  ParseStreamType(request->options, &audio_type, &video_type);
1095  request->SetAudioType(audio_type);
1096  request->SetVideoType(video_type);
1097
1098  bool is_web_contents_capture =
1099      audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
1100      video_type == MEDIA_TAB_VIDEO_CAPTURE;
1101  if (is_web_contents_capture && !SetupTabCaptureRequest(request)) {
1102    FinalizeRequestFailed(label,
1103                          request,
1104                          MEDIA_DEVICE_TAB_CAPTURE_FAILURE);
1105    return;
1106  }
1107
1108  bool is_screen_capture =
1109      video_type == MEDIA_DESKTOP_VIDEO_CAPTURE;
1110  if (is_screen_capture && !SetupScreenCaptureRequest(request)) {
1111    FinalizeRequestFailed(label,
1112                          request,
1113                          MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE);
1114    return;
1115  }
1116
1117  if (!is_web_contents_capture && !is_screen_capture) {
1118    if (EnumerationRequired(&audio_enumeration_cache_, audio_type) ||
1119        EnumerationRequired(&video_enumeration_cache_, video_type)) {
1120      // Enumerate the devices if there is no valid device lists to be used.
1121      StartEnumeration(request);
1122      return;
1123    } else {
1124        // Cache is valid, so log the cached devices for MediaStream requests.
1125      if (request->request_type == MEDIA_GENERATE_STREAM) {
1126        std::string log_message("Using cached devices for request.\n");
1127        if (audio_type != MEDIA_NO_SERVICE) {
1128          log_message +=
1129              GetLogMessageString(audio_type, audio_enumeration_cache_.devices);
1130        }
1131        if (video_type != MEDIA_NO_SERVICE) {
1132          log_message +=
1133              GetLogMessageString(video_type, video_enumeration_cache_.devices);
1134        }
1135        SendMessageToNativeLog(log_message);
1136      }
1137    }
1138
1139    if (!SetupDeviceCaptureRequest(request)) {
1140      FinalizeRequestFailed(label, request, MEDIA_DEVICE_NO_HARDWARE);
1141      return;
1142    }
1143  }
1144  PostRequestToUI(label, request);
1145}
1146
1147bool MediaStreamManager::SetupDeviceCaptureRequest(DeviceRequest* request) {
1148  DCHECK((request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
1149          request->audio_type() == MEDIA_NO_SERVICE) &&
1150         (request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE ||
1151          request->video_type() == MEDIA_NO_SERVICE));
1152  std::string audio_device_id;
1153  if (request->options.audio_requested &&
1154      !GetRequestedDeviceCaptureId(request, request->audio_type(),
1155                                     &audio_device_id)) {
1156    return false;
1157  }
1158
1159  std::string video_device_id;
1160  if (request->options.video_requested &&
1161      !GetRequestedDeviceCaptureId(request, request->video_type(),
1162                                   &video_device_id)) {
1163    return false;
1164  }
1165  request->CreateUIRequest(audio_device_id, video_device_id);
1166  DVLOG(3) << "Audio requested " << request->options.audio_requested
1167           << " device id = " << audio_device_id
1168           << "Video requested " << request->options.video_requested
1169           << " device id = " << video_device_id;
1170  return true;
1171}
1172
1173bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
1174  DCHECK(request->audio_type() == MEDIA_TAB_AUDIO_CAPTURE ||
1175         request->video_type() == MEDIA_TAB_VIDEO_CAPTURE);
1176
1177  std::string capture_device_id;
1178  bool mandatory_audio = false;
1179  bool mandatory_video = false;
1180  if (!request->options.GetFirstAudioConstraintByName(kMediaStreamSourceId,
1181                                                      &capture_device_id,
1182                                                      &mandatory_audio) &&
1183      !request->options.GetFirstVideoConstraintByName(kMediaStreamSourceId,
1184                                                      &capture_device_id,
1185                                                      &mandatory_video)) {
1186    return false;
1187  }
1188  DCHECK(mandatory_audio || mandatory_video);
1189
1190  // Customize options for a WebContents based capture.
1191  int target_render_process_id = 0;
1192  int target_render_view_id = 0;
1193
1194  // TODO(justinlin): Can't plumb audio mirroring using stream type right
1195  // now, so plumbing by device_id. Will revisit once it's refactored.
1196  // http://crbug.com/163100
1197  std::string tab_capture_device_id =
1198      WebContentsCaptureUtil::AppendWebContentsDeviceScheme(capture_device_id);
1199
1200  bool has_valid_device_id = WebContentsCaptureUtil::ExtractTabCaptureTarget(
1201      tab_capture_device_id, &target_render_process_id,
1202      &target_render_view_id);
1203  if (!has_valid_device_id ||
1204      (request->audio_type() != MEDIA_TAB_AUDIO_CAPTURE &&
1205       request->audio_type() != MEDIA_NO_SERVICE) ||
1206      (request->video_type() != MEDIA_TAB_VIDEO_CAPTURE &&
1207       request->video_type() != MEDIA_NO_SERVICE)) {
1208    return false;
1209  }
1210
1211  request->CreateTabCatureUIRequest(target_render_process_id,
1212                                    target_render_view_id,
1213                                    tab_capture_device_id);
1214
1215  DVLOG(3) << "SetupTabCaptureRequest "
1216           << ", {tab_capture_device_id = " << tab_capture_device_id <<  "}"
1217           << ", {target_render_process_id = " << target_render_process_id
1218           << "}"
1219           << ", {target_render_view_id = " << target_render_view_id << "}";
1220  return true;
1221}
1222
1223bool MediaStreamManager::SetupScreenCaptureRequest(DeviceRequest* request) {
1224  DCHECK(request->audio_type() == MEDIA_LOOPBACK_AUDIO_CAPTURE ||
1225         request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE);
1226
1227  // For screen capture we only support two valid combinations:
1228  // (1) screen video capture only, or
1229  // (2) screen video capture with loopback audio capture.
1230  if (request->video_type() != MEDIA_DESKTOP_VIDEO_CAPTURE ||
1231      (request->audio_type() != MEDIA_NO_SERVICE &&
1232       request->audio_type() != MEDIA_LOOPBACK_AUDIO_CAPTURE)) {
1233    LOG(ERROR) << "Invalid screen capture request.";
1234    return false;
1235  }
1236
1237  std::string video_device_id;
1238  if (request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE) {
1239    std::string video_stream_source;
1240    bool mandatory = false;
1241    if (!request->options.GetFirstVideoConstraintByName(
1242        kMediaStreamSource,
1243        &video_stream_source,
1244        &mandatory)) {
1245      LOG(ERROR) << kMediaStreamSource << " not found.";
1246      return false;
1247    }
1248    DCHECK(mandatory);
1249
1250    if (video_stream_source == kMediaStreamSourceDesktop) {
1251      if (!request->options.GetFirstVideoConstraintByName(
1252          kMediaStreamSourceId,
1253          &video_device_id,
1254          &mandatory)) {
1255        LOG(ERROR) << kMediaStreamSourceId << " not found.";
1256        return false;
1257      }
1258      DCHECK(mandatory);
1259    }
1260  }
1261
1262  request->CreateUIRequest("", video_device_id);
1263  return true;
1264}
1265
1266StreamDeviceInfoArray MediaStreamManager::GetDevicesOpenedByRequest(
1267    const std::string& label) const {
1268  DeviceRequest* request = FindRequest(label);
1269  if (!request)
1270    return StreamDeviceInfoArray();
1271  return request->devices;
1272}
1273
1274bool MediaStreamManager::FindExistingRequestedDeviceInfo(
1275    const DeviceRequest& new_request,
1276    const MediaStreamDevice& new_device_info,
1277    StreamDeviceInfo* existing_device_info,
1278    MediaRequestState* existing_request_state) const {
1279  DCHECK(existing_device_info);
1280  DCHECK(existing_request_state);
1281
1282  std::string source_id = content::GetHMACForMediaDeviceID(
1283      new_request.salt_callback,
1284      new_request.security_origin,
1285      new_device_info.id);
1286
1287  for (DeviceRequests::const_iterator it = requests_.begin();
1288       it != requests_.end() ; ++it) {
1289    const DeviceRequest* request = it->second;
1290    if (request->requesting_process_id == new_request.requesting_process_id &&
1291        request->requesting_view_id == new_request.requesting_view_id &&
1292        request->request_type == new_request.request_type) {
1293      for (StreamDeviceInfoArray::const_iterator device_it =
1294               request->devices.begin();
1295           device_it != request->devices.end(); ++device_it) {
1296        if (device_it->device.id == source_id &&
1297            device_it->device.type == new_device_info.type) {
1298            *existing_device_info = *device_it;
1299            *existing_request_state = request->state(device_it->device.type);
1300          return true;
1301        }
1302      }
1303    }
1304  }
1305  return false;
1306}
1307
1308void MediaStreamManager::FinalizeGenerateStream(const std::string& label,
1309                                                DeviceRequest* request) {
1310  DVLOG(1) << "FinalizeGenerateStream label " << label;
1311  const StreamDeviceInfoArray& requested_devices = request->devices;
1312
1313  // Partition the array of devices into audio vs video.
1314  StreamDeviceInfoArray audio_devices, video_devices;
1315  for (StreamDeviceInfoArray::const_iterator device_it =
1316           requested_devices.begin();
1317       device_it != requested_devices.end(); ++device_it) {
1318    if (IsAudioMediaType(device_it->device.type)) {
1319      audio_devices.push_back(*device_it);
1320    } else if (IsVideoMediaType(device_it->device.type)) {
1321      video_devices.push_back(*device_it);
1322    } else {
1323      NOTREACHED();
1324    }
1325  }
1326
1327  request->requester->StreamGenerated(
1328      request->requesting_view_id,
1329      request->page_request_id,
1330      label, audio_devices, video_devices);
1331}
1332
1333void MediaStreamManager::FinalizeRequestFailed(
1334    const std::string& label,
1335    DeviceRequest* request,
1336    content::MediaStreamRequestResult result) {
1337  if (request->requester)
1338    request->requester->StreamGenerationFailed(
1339        request->requesting_view_id,
1340        request->page_request_id,
1341        result);
1342
1343  if (request->request_type == MEDIA_DEVICE_ACCESS &&
1344      !request->callback.is_null()) {
1345    request->callback.Run(MediaStreamDevices(), request->ui_proxy.Pass());
1346  }
1347
1348  DeleteRequest(label);
1349}
1350
1351void MediaStreamManager::FinalizeOpenDevice(const std::string& label,
1352                                            DeviceRequest* request) {
1353  const StreamDeviceInfoArray& requested_devices = request->devices;
1354  request->requester->DeviceOpened(request->requesting_view_id,
1355                                   request->page_request_id,
1356                                   label, requested_devices.front());
1357}
1358
1359void MediaStreamManager::FinalizeEnumerateDevices(const std::string& label,
1360                                                  DeviceRequest* request) {
1361  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1362  DCHECK_EQ(request->request_type, MEDIA_ENUMERATE_DEVICES);
1363
1364  if (request->security_origin.is_valid()) {
1365    for (StreamDeviceInfoArray::iterator it = request->devices.begin();
1366         it != request->devices.end(); ++it) {
1367      TranslateDeviceIdToSourceId(request, &it->device);
1368    }
1369  } else {
1370    request->devices.clear();
1371  }
1372
1373  request->requester->DevicesEnumerated(
1374      request->requesting_view_id,
1375      request->page_request_id,
1376      label,
1377      request->devices);
1378
1379  // TODO(tommi):
1380  // Ideally enumeration requests should be deleted once they have been served
1381  // (as any request).  However, this implementation mixes requests and
1382  // notifications together so enumeration requests are kept open by some
1383  // implementations (only Pepper?) and enumerations are done again when
1384  // device notifications are fired.
1385  // Implementations that just want to request the device list and be done
1386  // (e.g. DeviceRequestMessageFilter), they must (confusingly) call
1387  // CancelRequest() after the request has been fulfilled.  This is not
1388  // obvious, not consistent in this class (see e.g. FinalizeMediaAccessRequest)
1389  // and can lead to subtle bugs (requests not deleted at all deleted too
1390  // early).
1391  //
1392  // Basically, it is not clear that using requests as an additional layer on
1393  // top of device notifications is necessary or good.
1394  //
1395  // To add to this, MediaStreamManager currently relies on the external
1396  // implementations of MediaStreamRequester to delete enumeration requests via
1397  // CancelRequest and e.g. DeviceRequestMessageFilter does this.  However the
1398  // Pepper implementation does not seem to to this at all (and from what I can
1399  // see, it is the only implementation that uses an enumeration request as a
1400  // notification mechanism).
1401  //
1402  // We should decouple notifications from enumeration requests and once that
1403  // has been done, remove the requirement to call CancelRequest() to delete
1404  // enumeration requests and uncomment the following line:
1405  //
1406  // DeleteRequest(label);
1407}
1408
1409void MediaStreamManager::FinalizeMediaAccessRequest(
1410    const std::string& label,
1411    DeviceRequest* request,
1412    const MediaStreamDevices& devices) {
1413  if (!request->callback.is_null())
1414    request->callback.Run(devices, request->ui_proxy.Pass());
1415
1416  // Delete the request since it is done.
1417  DeleteRequest(label);
1418}
1419
1420void MediaStreamManager::InitializeDeviceManagersOnIOThread() {
1421  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1422  if (device_task_runner_)
1423    return;
1424
1425  device_task_runner_ = audio_manager_->GetWorkerTaskRunner();
1426
1427  audio_input_device_manager_ = new AudioInputDeviceManager(audio_manager_);
1428  audio_input_device_manager_->Register(this, device_task_runner_);
1429
1430  video_capture_manager_ = new VideoCaptureManager();
1431  video_capture_manager_->Register(this, device_task_runner_);
1432
1433  // We want to be notified of IO message loop destruction to delete the thread
1434  // and the device managers.
1435  io_loop_ = base::MessageLoop::current();
1436  io_loop_->AddDestructionObserver(this);
1437
1438  if (CommandLine::ForCurrentProcess()->HasSwitch(
1439          switches::kUseFakeDeviceForMediaStream)) {
1440    DVLOG(1) << "Using fake device";
1441    UseFakeDevice();
1442  }
1443}
1444
1445void MediaStreamManager::Opened(MediaStreamType stream_type,
1446                                int capture_session_id) {
1447  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1448  DVLOG(1) << "Opened({stream_type = " << stream_type <<  "} "
1449           << "{capture_session_id = " << capture_session_id << "})";
1450  // Find the request(s) containing this device and mark it as used.
1451  // It can be used in several requests since the same device can be
1452  // requested from the same web page.
1453  for (DeviceRequests::iterator request_it = requests_.begin();
1454       request_it != requests_.end(); ++request_it) {
1455    const std::string& label = request_it->first;
1456    DeviceRequest* request = request_it->second;
1457    StreamDeviceInfoArray* devices = &(request->devices);
1458    for (StreamDeviceInfoArray::iterator device_it = devices->begin();
1459         device_it != devices->end(); ++device_it) {
1460      if (device_it->device.type == stream_type &&
1461          device_it->session_id == capture_session_id) {
1462        CHECK(request->state(device_it->device.type) ==
1463            MEDIA_REQUEST_STATE_OPENING);
1464        // We've found a matching request.
1465        request->SetState(device_it->device.type, MEDIA_REQUEST_STATE_DONE);
1466
1467        if (IsAudioMediaType(device_it->device.type)) {
1468          // Store the native audio parameters in the device struct.
1469          // TODO(xians): Handle the tab capture sample rate/channel layout
1470          // in AudioInputDeviceManager::Open().
1471          if (device_it->device.type != content::MEDIA_TAB_AUDIO_CAPTURE) {
1472            const StreamDeviceInfo* info =
1473                audio_input_device_manager_->GetOpenedDeviceInfoById(
1474                    device_it->session_id);
1475            device_it->device.input = info->device.input;
1476            device_it->device.matched_output = info->device.matched_output;
1477          }
1478        }
1479        if (RequestDone(*request))
1480          HandleRequestDone(label, request);
1481        break;
1482      }
1483    }
1484  }
1485}
1486
1487void MediaStreamManager::HandleRequestDone(const std::string& label,
1488                                           DeviceRequest* request) {
1489  DCHECK(RequestDone(*request));
1490  DVLOG(1) << "HandleRequestDone("
1491           << ", {label = " << label <<  "})";
1492
1493  switch (request->request_type) {
1494    case MEDIA_OPEN_DEVICE:
1495      FinalizeOpenDevice(label, request);
1496      break;
1497    case MEDIA_GENERATE_STREAM: {
1498      FinalizeGenerateStream(label, request);
1499      break;
1500    }
1501    default:
1502      NOTREACHED();
1503      break;
1504  }
1505
1506  if (request->ui_proxy.get()) {
1507    request->ui_proxy->OnStarted(
1508        base::Bind(&MediaStreamManager::StopMediaStreamFromBrowser,
1509                   base::Unretained(this),
1510                   label),
1511        base::Bind(&MediaStreamManager::OnMediaStreamUIWindowId,
1512                   base::Unretained(this),
1513                   request->video_type(),
1514                   request->devices));
1515  }
1516}
1517
1518void MediaStreamManager::Closed(MediaStreamType stream_type,
1519                                int capture_session_id) {
1520  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1521}
1522
1523void MediaStreamManager::DevicesEnumerated(
1524    MediaStreamType stream_type, const StreamDeviceInfoArray& devices) {
1525  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1526  DVLOG(1) << "DevicesEnumerated("
1527           << "{stream_type = " << stream_type << "})" << std::endl;
1528
1529  std::string log_message = "New device enumeration result:\n" +
1530                            GetLogMessageString(stream_type, devices);
1531  SendMessageToNativeLog(log_message);
1532
1533  // Only cache the device list when the device list has been changed.
1534  bool need_update_clients = false;
1535  EnumerationCache* cache =
1536      stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
1537      &audio_enumeration_cache_ : &video_enumeration_cache_;
1538  if (!cache->valid ||
1539      devices.size() != cache->devices.size() ||
1540      !std::equal(devices.begin(), devices.end(), cache->devices.begin(),
1541                  StreamDeviceInfo::IsEqual)) {
1542    StopRemovedDevices(cache->devices, devices);
1543    cache->devices = devices;
1544    need_update_clients = true;
1545
1546    // The device might not be able to be enumerated when it is not warmed up,
1547    // for example, when the machine just wakes up from sleep. We set the cache
1548    // to be invalid so that the next media request will trigger the
1549    // enumeration again. See issue/317673.
1550    cache->valid = !devices.empty();
1551 }
1552
1553  if (need_update_clients && monitoring_started_)
1554    NotifyDevicesChanged(stream_type, devices);
1555
1556  // Publish the result for all requests waiting for device list(s).
1557  // Find the requests waiting for this device list, store their labels and
1558  // release the iterator before calling device settings. We might get a call
1559  // back from device_settings that will need to iterate through devices.
1560  std::list<std::string> label_list;
1561  for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
1562       ++it) {
1563    if (it->second->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED &&
1564        (it->second->audio_type() == stream_type ||
1565         it->second->video_type() == stream_type)) {
1566      if (it->second->request_type != MEDIA_ENUMERATE_DEVICES)
1567        it->second->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
1568      label_list.push_back(it->first);
1569    }
1570  }
1571
1572  for (std::list<std::string>::iterator it = label_list.begin();
1573       it != label_list.end(); ++it) {
1574    DeviceRequest* request = FindRequest(*it);
1575    switch (request->request_type) {
1576      case MEDIA_ENUMERATE_DEVICES:
1577        if (need_update_clients && request->requester) {
1578          request->devices = devices;
1579          FinalizeEnumerateDevices(*it, request);
1580        }
1581        break;
1582      default:
1583        if (request->state(request->audio_type()) ==
1584                MEDIA_REQUEST_STATE_REQUESTED ||
1585            request->state(request->video_type()) ==
1586                MEDIA_REQUEST_STATE_REQUESTED) {
1587          // We are doing enumeration for other type of media, wait until it is
1588          // all done before posting the request to UI because UI needs
1589          // the device lists to handle the request.
1590          break;
1591        }
1592        if (!SetupDeviceCaptureRequest(request)) {
1593          FinalizeRequestFailed(*it,
1594                                request,
1595                                MEDIA_DEVICE_NO_HARDWARE);
1596        } else {
1597          PostRequestToUI(*it, request);
1598        }
1599        break;
1600    }
1601  }
1602  label_list.clear();
1603  --active_enumeration_ref_count_[stream_type];
1604  DCHECK_GE(active_enumeration_ref_count_[stream_type], 0);
1605}
1606
1607// static
1608void MediaStreamManager::SendMessageToNativeLog(const std::string& message) {
1609  BrowserThread::PostTask(
1610      BrowserThread::UI, FROM_HERE,
1611      base::Bind(DoAddLogMessage, message));
1612}
1613
1614void MediaStreamManager::OnSuspend() {
1615  SendMessageToNativeLog("Power state suspended.");
1616}
1617
1618void MediaStreamManager::OnResume() {
1619  SendMessageToNativeLog("Power state resumed.");
1620}
1621
1622void MediaStreamManager::AddLogMessageOnIOThread(const std::string& message) {
1623  // Get render process ids on the IO thread.
1624  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1625
1626  // Grab all unique process ids that request a MediaStream or have a
1627  // MediaStream running.
1628  std::set<int> requesting_process_ids;
1629  for (DeviceRequests::const_iterator it = requests_.begin();
1630       it != requests_.end(); ++it) {
1631    DeviceRequest* request = it->second;
1632    if (request->request_type == MEDIA_GENERATE_STREAM)
1633      requesting_process_ids.insert(request->requesting_process_id);
1634  }
1635
1636  // MediaStreamManager is a singleton in BrowserMainLoop, which owns the UI
1637  // thread. MediaStreamManager has the same lifetime as the UI thread, so it is
1638  // safe to use base::Unretained.
1639  BrowserThread::PostTask(
1640      BrowserThread::UI,
1641      FROM_HERE,
1642      base::Bind(&MediaStreamManager::AddLogMessageOnUIThread,
1643                 base::Unretained(this),
1644                 requesting_process_ids,
1645                 message));
1646}
1647
1648void MediaStreamManager::AddLogMessageOnUIThread(
1649    const std::set<int>& requesting_process_ids,
1650    const std::string& message) {
1651#if defined(ENABLE_WEBRTC)
1652  // Must be on the UI thread to access RenderProcessHost from process ID.
1653  DCHECK_CURRENTLY_ON(BrowserThread::UI);
1654
1655  for (std::set<int>::const_iterator it = requesting_process_ids.begin();
1656       it != requesting_process_ids.end(); ++it) {
1657    // Log the message to all renderers that are requesting a MediaStream or
1658    // have a MediaStream running.
1659    content::RenderProcessHostImpl* render_process_host_impl =
1660        static_cast<content::RenderProcessHostImpl*>(
1661            content::RenderProcessHost::FromID(*it));
1662    if (render_process_host_impl)
1663      render_process_host_impl->WebRtcLogMessage(message);
1664  }
1665#endif
1666}
1667
1668void MediaStreamManager::HandleAccessRequestResponse(
1669    const std::string& label,
1670    const MediaStreamDevices& devices,
1671    content::MediaStreamRequestResult result) {
1672  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1673  DVLOG(1) << "HandleAccessRequestResponse("
1674           << ", {label = " << label <<  "})";
1675
1676  DeviceRequest* request = FindRequest(label);
1677  if (!request) {
1678    // The request has been canceled before the UI returned.
1679    return;
1680  }
1681
1682  if (request->request_type == MEDIA_DEVICE_ACCESS) {
1683    FinalizeMediaAccessRequest(label, request, devices);
1684    return;
1685  }
1686
1687  // Handle the case when the request was denied.
1688  if (result != MEDIA_DEVICE_OK) {
1689    FinalizeRequestFailed(label, request, result);
1690    return;
1691  }
1692  DCHECK(!devices.empty());
1693
1694  // Process all newly-accepted devices for this request.
1695  bool found_audio = false;
1696  bool found_video = false;
1697  for (MediaStreamDevices::const_iterator device_it = devices.begin();
1698       device_it != devices.end(); ++device_it) {
1699    StreamDeviceInfo device_info;
1700    device_info.device = *device_it;
1701
1702    // TODO(justinlin): Nicer way to do this?
1703    // Re-append the device's id since we lost it when posting request to UI.
1704    if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE ||
1705        device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
1706      device_info.device.id = request->UIRequest()->tab_capture_device_id;
1707
1708      // Initialize the sample_rate and channel_layout here since for audio
1709      // mirroring, we don't go through EnumerateDevices where these are usually
1710      // initialized.
1711      if (device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
1712        const media::AudioParameters parameters =
1713            audio_manager_->GetDefaultOutputStreamParameters();
1714        int sample_rate = parameters.sample_rate();
1715        // If we weren't able to get the native sampling rate or the sample_rate
1716        // is outside the valid range for input devices set reasonable defaults.
1717        if (sample_rate <= 0 || sample_rate > 96000)
1718          sample_rate = 44100;
1719
1720        device_info.device.input.sample_rate = sample_rate;
1721        device_info.device.input.channel_layout = media::CHANNEL_LAYOUT_STEREO;
1722      }
1723    }
1724
1725    if (device_info.device.type == request->audio_type()) {
1726      found_audio = true;
1727    } else if (device_info.device.type == request->video_type()) {
1728      found_video = true;
1729    }
1730
1731    // If this is request for a new MediaStream, a device is only opened once
1732    // per render view. This is so that the permission to use a device can be
1733    // revoked by a single call to StopStreamDevice regardless of how many
1734    // MediaStreams it is being used in.
1735    if (request->request_type == MEDIA_GENERATE_STREAM) {
1736      MediaRequestState state;
1737      if (FindExistingRequestedDeviceInfo(*request,
1738                                          device_info.device,
1739                                          &device_info,
1740                                          &state)) {
1741        request->devices.push_back(device_info);
1742        request->SetState(device_info.device.type, state);
1743        DVLOG(1) << "HandleAccessRequestResponse - device already opened "
1744                 << ", {label = " << label <<  "}"
1745                 << ", device_id = " << device_it->id << "}";
1746        continue;
1747      }
1748    }
1749    device_info.session_id =
1750        GetDeviceManager(device_info.device.type)->Open(device_info);
1751    TranslateDeviceIdToSourceId(request, &device_info.device);
1752    request->devices.push_back(device_info);
1753
1754    request->SetState(device_info.device.type, MEDIA_REQUEST_STATE_OPENING);
1755    DVLOG(1) << "HandleAccessRequestResponse - opening device "
1756             << ", {label = " << label <<  "}"
1757             << ", {device_id = " << device_info.device.id << "}"
1758             << ", {session_id = " << device_info.session_id << "}";
1759  }
1760
1761  // Check whether we've received all stream types requested.
1762  if (!found_audio && IsAudioMediaType(request->audio_type())) {
1763    request->SetState(request->audio_type(), MEDIA_REQUEST_STATE_ERROR);
1764    DVLOG(1) << "Set no audio found label " << label;
1765  }
1766
1767  if (!found_video && IsVideoMediaType(request->video_type()))
1768    request->SetState(request->video_type(), MEDIA_REQUEST_STATE_ERROR);
1769
1770  if (RequestDone(*request))
1771    HandleRequestDone(label, request);
1772}
1773
1774void MediaStreamManager::StopMediaStreamFromBrowser(const std::string& label) {
1775  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1776
1777  DeviceRequest* request = FindRequest(label);
1778  if (!request)
1779    return;
1780
1781  // Notify renderers that the devices in the stream will be stopped.
1782  if (request->requester) {
1783    for (StreamDeviceInfoArray::iterator device_it = request->devices.begin();
1784         device_it != request->devices.end(); ++device_it) {
1785      request->requester->DeviceStopped(request->requesting_view_id,
1786                                        label,
1787                                        *device_it);
1788    }
1789  }
1790
1791  CancelRequest(label);
1792}
1793
1794void MediaStreamManager::UseFakeDevice() {
1795  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1796  video_capture_manager()->UseFakeDevice();
1797  audio_input_device_manager()->UseFakeDevice();
1798}
1799
1800void MediaStreamManager::UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy> fake_ui) {
1801  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1802  use_fake_ui_ = true;
1803  fake_ui_ = fake_ui.Pass();
1804}
1805
1806void MediaStreamManager::WillDestroyCurrentMessageLoop() {
1807  DVLOG(3) << "MediaStreamManager::WillDestroyCurrentMessageLoop()";
1808  DCHECK_EQ(base::MessageLoop::current(), io_loop_);
1809  DCHECK(requests_.empty());
1810  if (device_task_runner_) {
1811    StopMonitoring();
1812
1813    video_capture_manager_->Unregister();
1814    audio_input_device_manager_->Unregister();
1815    device_task_runner_ = NULL;
1816  }
1817
1818  audio_input_device_manager_ = NULL;
1819  video_capture_manager_ = NULL;
1820}
1821
1822void MediaStreamManager::NotifyDevicesChanged(
1823    MediaStreamType stream_type,
1824    const StreamDeviceInfoArray& devices) {
1825  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1826  MediaObserver* media_observer =
1827      GetContentClient()->browser()->GetMediaObserver();
1828  if (media_observer == NULL)
1829    return;
1830
1831  // Map the devices to MediaStreamDevices.
1832  MediaStreamDevices new_devices;
1833  for (StreamDeviceInfoArray::const_iterator it = devices.begin();
1834       it != devices.end(); ++it) {
1835    new_devices.push_back(it->device);
1836  }
1837
1838  if (IsAudioMediaType(stream_type)) {
1839    MediaCaptureDevicesImpl::GetInstance()->OnAudioCaptureDevicesChanged(
1840        new_devices);
1841    media_observer->OnAudioCaptureDevicesChanged();
1842  } else if (IsVideoMediaType(stream_type)) {
1843    MediaCaptureDevicesImpl::GetInstance()->OnVideoCaptureDevicesChanged(
1844        new_devices);
1845    media_observer->OnVideoCaptureDevicesChanged();
1846  } else {
1847    NOTREACHED();
1848  }
1849}
1850
1851bool MediaStreamManager::RequestDone(const DeviceRequest& request) const {
1852  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1853
1854  const bool requested_audio = IsAudioMediaType(request.audio_type());
1855  const bool requested_video = IsVideoMediaType(request.video_type());
1856
1857  const bool audio_done =
1858      !requested_audio ||
1859      request.state(request.audio_type()) == MEDIA_REQUEST_STATE_DONE ||
1860      request.state(request.audio_type()) == MEDIA_REQUEST_STATE_ERROR;
1861  if (!audio_done)
1862    return false;
1863
1864  const bool video_done =
1865      !requested_video ||
1866      request.state(request.video_type()) == MEDIA_REQUEST_STATE_DONE ||
1867      request.state(request.video_type()) == MEDIA_REQUEST_STATE_ERROR;
1868  if (!video_done)
1869    return false;
1870
1871  return true;
1872}
1873
1874MediaStreamProvider* MediaStreamManager::GetDeviceManager(
1875    MediaStreamType stream_type) {
1876  if (IsVideoMediaType(stream_type)) {
1877    return video_capture_manager();
1878  } else if (IsAudioMediaType(stream_type)) {
1879    return audio_input_device_manager();
1880  }
1881  NOTREACHED();
1882  return NULL;
1883}
1884
1885void MediaStreamManager::OnDevicesChanged(
1886    base::SystemMonitor::DeviceType device_type) {
1887  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1888
1889  // NOTE: This method is only called in response to physical audio/video device
1890  // changes (from the operating system).
1891
1892  MediaStreamType stream_type;
1893  if (device_type == base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE) {
1894    stream_type = MEDIA_DEVICE_AUDIO_CAPTURE;
1895  } else if (device_type == base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE) {
1896    stream_type = MEDIA_DEVICE_VIDEO_CAPTURE;
1897  } else {
1898    return;  // Uninteresting device change.
1899  }
1900
1901  // Always do enumeration even though some enumeration is in progress,
1902  // because those enumeration commands could be sent before these devices
1903  // change.
1904  ++active_enumeration_ref_count_[stream_type];
1905  GetDeviceManager(stream_type)->EnumerateDevices(stream_type);
1906}
1907
1908void MediaStreamManager::OnMediaStreamUIWindowId(MediaStreamType video_type,
1909                                                 StreamDeviceInfoArray devices,
1910                                                 gfx::NativeViewId window_id) {
1911  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1912  if (!window_id)
1913    return;
1914
1915  // Pass along for desktop capturing. Ignored for other stream types.
1916  if (video_type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
1917    for (StreamDeviceInfoArray::iterator it = devices.begin();
1918         it != devices.end();
1919         ++it) {
1920      if (it->device.type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
1921        video_capture_manager_->SetDesktopCaptureWindowId(it->session_id,
1922                                                          window_id);
1923        break;
1924      }
1925    }
1926  }
1927}
1928
1929}  // namespace content
1930