- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / media / media_stream_manager.cc
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/rand_util.h"
15 #include "base/threading/thread.h"
16 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
17 #include "content/browser/renderer_host/media/device_request_message_filter.h"
18 #include "content/browser/renderer_host/media/media_stream_requester.h"
19 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
20 #include "content/browser/renderer_host/media/video_capture_manager.h"
21 #include "content/browser/renderer_host/media/web_contents_capture_util.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/content_browser_client.h"
24 #include "content/public/browser/media_device_id.h"
25 #include "content/public/browser/media_observer.h"
26 #include "content/public/browser/media_request_state.h"
27 #include "content/public/common/content_switches.h"
28 #include "content/public/common/media_stream_request.h"
29 #include "media/audio/audio_manager_base.h"
30 #include "media/audio/audio_parameters.h"
31 #include "media/base/channel_layout.h"
32 #include "url/gurl.h"
33
34 #if defined(OS_WIN)
35 #include "base/win/scoped_com_initializer.h"
36 #endif
37
38 namespace content {
39
40 // Creates a random label used to identify requests.
41 static std::string RandomLabel() {
42   // An earlier PeerConnection spec,
43   // http://dev.w3.org/2011/webrtc/editor/webrtc.html, specified the
44   // MediaStream::label alphabet as containing 36 characters from
45   // range: U+0021, U+0023 to U+0027, U+002A to U+002B, U+002D to U+002E,
46   // U+0030 to U+0039, U+0041 to U+005A, U+005E to U+007E.
47   // Here we use a safe subset.
48   static const char kAlphabet[] = "0123456789"
49       "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
50
51   std::string label(36, ' ');
52   for (size_t i = 0; i < label.size(); ++i) {
53     int random_char = base::RandGenerator(sizeof(kAlphabet) - 1);
54     label[i] = kAlphabet[random_char];
55   }
56   return label;
57 }
58
59 // Helper to verify if a media stream type is part of options or not.
60 static bool Requested(const MediaStreamRequest& request,
61                       MediaStreamType stream_type) {
62   return (request.audio_type == stream_type ||
63           request.video_type == stream_type);
64 }
65
66 // TODO(xians): Merge DeviceRequest with MediaStreamRequest.
67 class MediaStreamManager::DeviceRequest {
68  public:
69   DeviceRequest(MediaStreamRequester* requester,
70                 const MediaStreamRequest& request,
71                 int requesting_process_id,
72                 int requesting_view_id)
73       : requester(requester),
74         request(request),
75         requesting_process_id(requesting_process_id),
76         requesting_view_id(requesting_view_id),
77         state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED) {
78   }
79
80   ~DeviceRequest() {}
81
82   // Update the request state and notify observers.
83   void SetState(MediaStreamType stream_type, MediaRequestState new_state) {
84     if (stream_type == NUM_MEDIA_TYPES) {
85       for (int i = MEDIA_NO_SERVICE + 1; i < NUM_MEDIA_TYPES; ++i) {
86         const MediaStreamType stream_type = static_cast<MediaStreamType>(i);
87         state_[stream_type] = new_state;
88       }
89     } else {
90       state_[stream_type] = new_state;
91     }
92
93     if (request.video_type != MEDIA_TAB_VIDEO_CAPTURE &&
94         request.audio_type != MEDIA_TAB_AUDIO_CAPTURE &&
95         new_state != MEDIA_REQUEST_STATE_CLOSING) {
96       return;
97     }
98
99     MediaObserver* media_observer =
100         GetContentClient()->browser()->GetMediaObserver();
101     if (media_observer == NULL)
102       return;
103
104     // If we appended a device_id scheme, we want to remove it when notifying
105     // observers which may be in different modules since this scheme is only
106     // used internally within the content module.
107     std::string device_id =
108         WebContentsCaptureUtil::StripWebContentsDeviceScheme(
109             request.tab_capture_device_id);
110
111     media_observer->OnMediaRequestStateChanged(
112         request.render_process_id, request.render_view_id,
113         request.page_request_id,
114         MediaStreamDevice(stream_type, device_id, device_id), new_state);
115   }
116
117   MediaRequestState state(MediaStreamType stream_type) const {
118     return state_[stream_type];
119   }
120
121   MediaStreamRequester* const requester;  // Can be NULL.
122   MediaStreamRequest request;
123
124   // The render process id that requested this stream to be generated and that
125   // will receive a handle to the MediaStream. This may be different from
126   // MediaStreamRequest::render_process_id which in the tab capture case
127   // specifies the target renderer from which audio and video is captured.
128   const int requesting_process_id;
129
130   // The render view id that requested this stream to be generated and that
131   // will receive a handle to the MediaStream. This may be different from
132   // MediaStreamRequest::render_view_id which in the tab capture case
133   // specifies the target renderer from which audio and video is captured.
134   const int requesting_view_id;
135
136   StreamDeviceInfoArray devices;
137
138   // Callback to the requester which audio/video devices have been selected.
139   // It can be null if the requester has no interest to know the result.
140   // Currently it is only used by |DEVICE_ACCESS| type.
141   MediaStreamManager::MediaRequestResponseCallback callback;
142
143   scoped_ptr<MediaStreamUIProxy> ui_proxy;
144
145  private:
146   std::vector<MediaRequestState> state_;
147 };
148
149 MediaStreamManager::EnumerationCache::EnumerationCache()
150     : valid(false) {
151 }
152
153 MediaStreamManager::EnumerationCache::~EnumerationCache() {
154 }
155
156 MediaStreamManager::MediaStreamManager()
157     : audio_manager_(NULL),
158       monitoring_started_(false),
159       io_loop_(NULL),
160       use_fake_ui_(false) {}
161
162 MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager)
163     : audio_manager_(audio_manager),
164       monitoring_started_(false),
165       io_loop_(NULL),
166       use_fake_ui_(false) {
167   DCHECK(audio_manager_);
168   memset(active_enumeration_ref_count_, 0,
169          sizeof(active_enumeration_ref_count_));
170
171   // Some unit tests create the MSM in the IO thread and assumes the
172   // initialization is done synchronously.
173   if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
174     InitializeDeviceManagersOnIOThread();
175   } else {
176     BrowserThread::PostTask(
177         BrowserThread::IO, FROM_HERE,
178         base::Bind(&MediaStreamManager::InitializeDeviceManagersOnIOThread,
179                    base::Unretained(this)));
180   }
181 }
182
183 MediaStreamManager::~MediaStreamManager() {
184   DCHECK(requests_.empty());
185   DCHECK(!device_thread_.get());
186 }
187
188 VideoCaptureManager* MediaStreamManager::video_capture_manager() {
189   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
190   DCHECK(video_capture_manager_.get());
191   return video_capture_manager_.get();
192 }
193
194 AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() {
195   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
196   DCHECK(audio_input_device_manager_.get());
197   return audio_input_device_manager_.get();
198 }
199
200 std::string MediaStreamManager::MakeMediaAccessRequest(
201     int render_process_id,
202     int render_view_id,
203     int page_request_id,
204     const StreamOptions& options,
205     const GURL& security_origin,
206     const MediaRequestResponseCallback& callback) {
207   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
208   // Create a new request based on options.
209   MediaStreamRequest stream_request(
210       render_process_id, render_view_id, page_request_id, std::string(),
211       security_origin, MEDIA_DEVICE_ACCESS, std::string(), std::string(),
212       options.audio_type, options.video_type);
213   DeviceRequest* request = new DeviceRequest(NULL, stream_request,
214                                              render_process_id, render_view_id);
215   const std::string& label = AddRequest(request);
216
217   request->callback = callback;
218
219   HandleRequest(label);
220
221   return label;
222 }
223
224 std::string MediaStreamManager::GenerateStream(
225     MediaStreamRequester* requester,
226     int render_process_id,
227     int render_view_id,
228     int page_request_id,
229     const StreamOptions& options,
230     const GURL& security_origin) {
231   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
232   if (CommandLine::ForCurrentProcess()->HasSwitch(
233           switches::kUseFakeDeviceForMediaStream)) {
234     UseFakeDevice();
235   }
236   if (CommandLine::ForCurrentProcess()->HasSwitch(
237       switches::kUseFakeUIForMediaStream)) {
238     UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy>());
239   }
240
241   int target_render_process_id = render_process_id;
242   int target_render_view_id = render_view_id;
243   std::string tab_capture_device_id;
244
245   // Customize options for a WebContents based capture.
246   if (options.audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
247       options.video_type == MEDIA_TAB_VIDEO_CAPTURE) {
248     // TODO(justinlin): Can't plumb audio mirroring using stream type right
249     // now, so plumbing by device_id. Will revisit once it's refactored.
250     // http://crbug.com/163100
251     tab_capture_device_id =
252         WebContentsCaptureUtil::AppendWebContentsDeviceScheme(
253             !options.video_device_id.empty() ?
254             options.video_device_id : options.audio_device_id);
255
256     bool has_valid_device_id = WebContentsCaptureUtil::ExtractTabCaptureTarget(
257         tab_capture_device_id, &target_render_process_id,
258         &target_render_view_id);
259     if (!has_valid_device_id ||
260         (options.audio_type != MEDIA_TAB_AUDIO_CAPTURE &&
261          options.audio_type != MEDIA_NO_SERVICE) ||
262         (options.video_type != MEDIA_TAB_VIDEO_CAPTURE &&
263          options.video_type != MEDIA_NO_SERVICE)) {
264       LOG(ERROR) << "Invalid request.";
265       return std::string();
266     }
267   }
268
269   std::string translated_audio_device_id;
270   std::string translated_video_device_id;
271   if (options.audio_type == MEDIA_DEVICE_AUDIO_CAPTURE) {
272     bool found_match = TranslateGUIDToRawId(
273         MEDIA_DEVICE_AUDIO_CAPTURE, security_origin, options.audio_device_id,
274         &translated_audio_device_id);
275     DCHECK(found_match || translated_audio_device_id.empty());
276   }
277
278   if (options.video_type == MEDIA_DEVICE_VIDEO_CAPTURE) {
279     bool found_match = TranslateGUIDToRawId(
280         MEDIA_DEVICE_VIDEO_CAPTURE, security_origin, options.video_device_id,
281         &translated_video_device_id);
282     DCHECK(found_match || translated_video_device_id.empty());
283   }
284
285   if (options.video_type == MEDIA_DESKTOP_VIDEO_CAPTURE ||
286       options.audio_type == MEDIA_LOOPBACK_AUDIO_CAPTURE) {
287     // For screen capture we only support two valid combinations:
288     // (1) screen video capture only, or
289     // (2) screen video capture with loopback audio capture.
290     if (options.video_type != MEDIA_DESKTOP_VIDEO_CAPTURE ||
291         (options.audio_type != MEDIA_NO_SERVICE &&
292          options.audio_type != MEDIA_LOOPBACK_AUDIO_CAPTURE)) {
293       // TODO(sergeyu): Surface error message to the calling JS code.
294       LOG(ERROR) << "Invalid screen capture request.";
295       return std::string();
296     }
297     translated_video_device_id = options.video_device_id;
298   }
299
300   // Create a new request based on options.
301   MediaStreamRequest stream_request(
302       target_render_process_id, target_render_view_id, page_request_id,
303       tab_capture_device_id, security_origin, MEDIA_GENERATE_STREAM,
304       translated_audio_device_id, translated_video_device_id,
305       options.audio_type, options.video_type);
306   DeviceRequest* request = new DeviceRequest(requester, stream_request,
307                                              render_process_id,
308                                              render_view_id);
309   const std::string& label = AddRequest(request);
310   HandleRequest(label);
311   return label;
312 }
313
314 void MediaStreamManager::CancelRequest(const std::string& label) {
315   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
316
317   DeviceRequests::iterator request_it = requests_.find(label);
318   if (request_it == requests_.end()) {
319     NOTREACHED();
320     return;
321   }
322   scoped_ptr<DeviceRequest> request(request_it->second);
323   RemoveRequest(request_it);
324
325   if (request->request.request_type == MEDIA_ENUMERATE_DEVICES) {
326     return;
327   }
328
329   // This is a request for opening one or more devices.
330   for (StreamDeviceInfoArray::iterator device_it = request->devices.begin();
331       device_it != request->devices.end(); ++device_it) {
332     // If we have not yet requested the device to be opened - just ignore it.
333     if (request->state(device_it->device.type) != MEDIA_REQUEST_STATE_OPENING
334         &&
335         request->state(device_it->device.type) != MEDIA_REQUEST_STATE_DONE) {
336       continue;
337     }
338     // Stop the opening/opened devices of the requests.
339     StopDevice(*device_it);
340   }
341
342   // Cancel the request if still pending at UI side.
343   request->SetState(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_CLOSING);
344 }
345
346 void MediaStreamManager::CancelAllRequests(int render_process_id) {
347   DeviceRequests::iterator request_it = requests_.begin();
348   while (request_it != requests_.end()) {
349     if (request_it->second->requesting_process_id != render_process_id) {
350       ++request_it;
351       continue;
352     }
353
354     std::string label = request_it->first;
355     ++request_it;
356     CancelRequest(label);
357   }
358 }
359
360 void MediaStreamManager::StopStreamDevice(int render_process_id,
361                                           int render_view_id,
362                                           const std::string& device_id) {
363   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
364   DVLOG(1) << "StopStreamDevice({render_view_id = " << render_view_id <<  "} "
365            << ", {device_id = " << device_id << "})";
366
367   // Find all requests for this |render_process_id| and |render_view_id| of type
368   // MEDIA_GENERATE_STREAM that has requested to use |device_id|.
369   DeviceRequests::iterator request_it = requests_.begin();
370   while (request_it  != requests_.end()) {
371     DeviceRequest* request = request_it->second;
372     const MediaStreamRequest& ms_request = request->request;
373     if (request->requesting_process_id != render_process_id ||
374         request->requesting_view_id != render_view_id ||
375         ms_request.request_type != MEDIA_GENERATE_STREAM) {
376       ++request_it;
377       continue;
378     }
379
380     StreamDeviceInfoArray* devices = &request->devices;
381     StreamDeviceInfoArray::iterator device_it = devices->begin();
382     while (device_it != devices->end()) {
383       MediaStreamType device_type = device_it->device.type;
384       if (device_it->device.id == device_id) {
385         if (request->state(device_type) == MEDIA_REQUEST_STATE_DONE) {
386           StopDevice(*device_it);
387         }
388         device_it = devices->erase(device_it);
389       } else {
390         ++device_it;
391       }
392     }
393
394     // If this request doesn't have any active devices, remove the request.
395     if (devices->empty()) {
396       DeviceRequests::iterator del_itor(request_it);
397       ++request_it;
398       scoped_ptr<DeviceRequest> request(del_itor->second);
399       RemoveRequest(del_itor);
400     } else {
401       ++request_it;
402     }
403   }
404 }
405
406 void MediaStreamManager::StopDevice(const StreamDeviceInfo& device_info) {
407   DVLOG(1) << "StopDevice("
408            << "{device_info.session_id = " << device_info.session_id <<  "} "
409            << "{device_id = " << device_info.device.id << "})";
410   GetDeviceManager(device_info.device.type)->Close(device_info.session_id);
411
412   for (DeviceRequests::iterator request_it = requests_.begin();
413        request_it != requests_.end() ; ++request_it) {
414     StreamDeviceInfoArray* devices = &request_it->second->devices;
415     for (StreamDeviceInfoArray::iterator device_it = devices->begin();
416          device_it != devices->end(); ++device_it) {
417       if (device_it->session_id == device_info.session_id &&
418           device_it->device.type == device_info.device.type) {
419         // Notify observers that this device is being closed.
420         // Note that only one device per type can be opened.
421         request_it->second->SetState(device_it->device.type,
422                                      MEDIA_REQUEST_STATE_CLOSING);
423       }
424     }
425   }
426 }
427
428 std::string MediaStreamManager::EnumerateDevices(
429     MediaStreamRequester* requester,
430     int render_process_id,
431     int render_view_id,
432     int page_request_id,
433     MediaStreamType type,
434     const GURL& security_origin) {
435   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
436   DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
437          type == MEDIA_DEVICE_VIDEO_CAPTURE);
438
439   // When the requester is NULL, the request is made by the UI to ensure MSM
440   // starts monitoring devices.
441   if (!requester) {
442     if (!monitoring_started_)
443       StartMonitoring();
444
445     return std::string();
446   }
447
448   // Create a new request.
449   StreamOptions options;
450   EnumerationCache* cache = NULL;
451   if (type == MEDIA_DEVICE_AUDIO_CAPTURE) {
452     options.audio_type = type;
453     cache = &audio_enumeration_cache_;
454   } else if (type == MEDIA_DEVICE_VIDEO_CAPTURE) {
455     options.video_type = type;
456     cache = &video_enumeration_cache_;
457   } else {
458     NOTREACHED();
459     return std::string();
460   }
461
462   MediaStreamRequest stream_request(
463       render_process_id, render_view_id, page_request_id, std::string(),
464       security_origin, MEDIA_ENUMERATE_DEVICES, std::string(), std::string(),
465       options.audio_type, options.video_type);
466   DeviceRequest* request = new DeviceRequest(requester, stream_request,
467                                              render_process_id,
468                                              render_view_id);
469   const std::string& label = AddRequest(request);
470
471   if (cache->valid) {
472     // Cached device list of this type exists. Just send it out.
473     request->SetState(type, MEDIA_REQUEST_STATE_REQUESTED);
474
475     // Need to post a task since the requester won't have label till
476     // this function returns.
477     BrowserThread::PostTask(
478         BrowserThread::IO, FROM_HERE,
479         base::Bind(&MediaStreamManager::SendCachedDeviceList,
480                    base::Unretained(this), cache, label));
481   } else {
482     StartEnumeration(request);
483   }
484
485   return label;
486 }
487
488 std::string MediaStreamManager::OpenDevice(
489     MediaStreamRequester* requester,
490     int render_process_id,
491     int render_view_id,
492     int page_request_id,
493     const std::string& device_id,
494     MediaStreamType type,
495     const GURL& security_origin) {
496   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
497   DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
498          type == MEDIA_DEVICE_VIDEO_CAPTURE);
499
500   // Create a new request.
501   StreamOptions options;
502   if (IsAudioMediaType(type)) {
503     options.audio_type = type;
504     options.audio_device_id = device_id;
505   } else if (IsVideoMediaType(type)) {
506     options.video_type = type;
507     options.video_device_id = device_id;
508   } else {
509     NOTREACHED();
510     return std::string();
511   }
512
513   MediaStreamRequest stream_request(
514       render_process_id, render_view_id, page_request_id, std::string(),
515       security_origin, MEDIA_OPEN_DEVICE, options.audio_device_id,
516       options.video_device_id, options.audio_type, options.video_type);
517   DeviceRequest* request = new DeviceRequest(requester, stream_request,
518                                              render_process_id,
519                                              render_view_id);
520   const std::string& label = AddRequest(request);
521   StartEnumeration(request);
522
523   return label;
524 }
525
526 void MediaStreamManager::SendCachedDeviceList(
527     EnumerationCache* cache,
528     const std::string& label) {
529   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
530   if (cache->valid) {
531     DeviceRequests::iterator it = requests_.find(label);
532     if (it != requests_.end()) {
533       it->second->requester->DevicesEnumerated(label, cache->devices);
534     }
535   }
536 }
537
538 void MediaStreamManager::StopRemovedDevices(
539     const StreamDeviceInfoArray& old_devices,
540     const StreamDeviceInfoArray& new_devices) {
541   DVLOG(1) << "StopRemovedDevices("
542            << "{#old_devices = " << old_devices.size() <<  "} "
543            << "{#new_devices = " << new_devices.size() << "})";
544   for (StreamDeviceInfoArray::const_iterator old_dev_it = old_devices.begin();
545        old_dev_it != old_devices.end(); ++old_dev_it) {
546     bool device_found = false;
547     for (StreamDeviceInfoArray::const_iterator new_dev_it = new_devices.begin();
548          new_dev_it != new_devices.end(); ++new_dev_it) {
549       if (old_dev_it->device.id == new_dev_it->device.id) {
550         device_found = true;
551         break;
552       }
553     }
554
555     if (!device_found) {
556       // A device has been removed. We need to check if it is used by a
557       // MediaStream and in that case cleanup and notify the render process.
558       do {
559         std::string label =
560             FindFirstMediaStreamRequestWithDevice(old_dev_it->device);
561         if (label.empty())
562           break;
563         // TODO(perkj): We would like to stop all tracks that use the removed
564         // device, not the MediaStream. But at the moment, there is no way of
565         // doing that from the browser process. crbug/315585
566         StopMediaStreamFromBrowser(label);
567       } while(true);
568     }
569   }
570 }
571
572 void MediaStreamManager::StartMonitoring() {
573   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
574   if (!base::SystemMonitor::Get())
575     return;
576
577   if (!monitoring_started_) {
578     monitoring_started_ = true;
579     base::SystemMonitor::Get()->AddDevicesChangedObserver(this);
580
581     // Enumerate both the audio and video devices to cache the device lists
582     // and send them to media observer.
583     ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_CAPTURE];
584     audio_input_device_manager_->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE);
585     ++active_enumeration_ref_count_[MEDIA_DEVICE_VIDEO_CAPTURE];
586     video_capture_manager_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
587   }
588 }
589
590 void MediaStreamManager::StopMonitoring() {
591   DCHECK_EQ(base::MessageLoop::current(), io_loop_);
592   if (monitoring_started_) {
593     base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this);
594     monitoring_started_ = false;
595     ClearEnumerationCache(&audio_enumeration_cache_);
596     ClearEnumerationCache(&video_enumeration_cache_);
597   }
598 }
599
600 bool MediaStreamManager::TranslateGUIDToRawId(MediaStreamType stream_type,
601                                               const GURL& security_origin,
602                                               const std::string& device_guid,
603                                               std::string* raw_device_id) {
604   DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ||
605          stream_type == MEDIA_DEVICE_VIDEO_CAPTURE);
606   if (device_guid.empty())
607     return false;
608
609   EnumerationCache* cache =
610       stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
611       &audio_enumeration_cache_ : &video_enumeration_cache_;
612
613   // If device monitoring hasn't started, the |device_guid| is not valid.
614   if (!cache->valid)
615     return false;
616
617   for (StreamDeviceInfoArray::const_iterator it = cache->devices.begin();
618        it != cache->devices.end();
619        ++it) {
620     if (content::DoesMediaDeviceIDMatchHMAC(
621             security_origin, device_guid, it->device.id)) {
622       *raw_device_id = it->device.id;
623       return true;
624     }
625   }
626   return false;
627 }
628
629 void MediaStreamManager::ClearEnumerationCache(EnumerationCache* cache) {
630   DCHECK_EQ(base::MessageLoop::current(), io_loop_);
631   cache->valid = false;
632 }
633
634 void MediaStreamManager::StartEnumeration(DeviceRequest* request) {
635   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
636
637   // Start monitoring the devices when doing the first enumeration.
638   if (!monitoring_started_ && base::SystemMonitor::Get()) {
639     StartMonitoring();
640   }
641
642   // Start enumeration for devices of all requested device types.
643   for (int i = MEDIA_NO_SERVICE + 1; i < NUM_MEDIA_TYPES; ++i) {
644     const MediaStreamType stream_type = static_cast<MediaStreamType>(i);
645     if (Requested(request->request, stream_type)) {
646       request->SetState(stream_type, MEDIA_REQUEST_STATE_REQUESTED);
647       DCHECK_GE(active_enumeration_ref_count_[stream_type], 0);
648       if (active_enumeration_ref_count_[stream_type] == 0) {
649         ++active_enumeration_ref_count_[stream_type];
650         GetDeviceManager(stream_type)->EnumerateDevices(stream_type);
651       }
652     }
653   }
654 }
655
656 std::string MediaStreamManager::AddRequest(DeviceRequest* request) {
657   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
658
659   // Create a label for this request and verify it is unique.
660   std::string unique_label;
661   do {
662     unique_label = RandomLabel();
663   } while (requests_.find(unique_label) != requests_.end());
664
665   requests_.insert(std::make_pair(unique_label, request));
666
667   return unique_label;
668 }
669
670 void MediaStreamManager::RemoveRequest(DeviceRequests::iterator it) {
671   requests_.erase(it);
672 }
673
674 void MediaStreamManager::PostRequestToUI(const std::string& label) {
675   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
676   DeviceRequest* request = requests_[label];
677
678   if (use_fake_ui_) {
679     if (!fake_ui_)
680       fake_ui_.reset(new FakeMediaStreamUIProxy());
681
682     MediaStreamDevices devices;
683     if (audio_enumeration_cache_.valid) {
684       for (StreamDeviceInfoArray::const_iterator it =
685                audio_enumeration_cache_.devices.begin();
686            it != audio_enumeration_cache_.devices.end(); ++it) {
687         devices.push_back(it->device);
688       }
689     }
690     if (video_enumeration_cache_.valid) {
691       for (StreamDeviceInfoArray::const_iterator it =
692                video_enumeration_cache_.devices.begin();
693            it != video_enumeration_cache_.devices.end(); ++it) {
694         devices.push_back(it->device);
695       }
696     }
697
698     fake_ui_->SetAvailableDevices(devices);
699
700     request->ui_proxy = fake_ui_.Pass();
701   } else {
702     request->ui_proxy = MediaStreamUIProxy::Create();
703   }
704
705   request->ui_proxy->RequestAccess(
706       request->request,
707       base::Bind(&MediaStreamManager::HandleAccessRequestResponse,
708                  base::Unretained(this), label));
709 }
710
711 void MediaStreamManager::HandleRequest(const std::string& label) {
712   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
713   DeviceRequest* request = requests_[label];
714
715   const MediaStreamType audio_type = request->request.audio_type;
716   const MediaStreamType video_type = request->request.video_type;
717
718   bool is_web_contents_capture =
719       audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
720       video_type == MEDIA_TAB_VIDEO_CAPTURE;
721
722   bool is_screen_capture =
723       video_type == MEDIA_DESKTOP_VIDEO_CAPTURE;
724
725   if (!is_web_contents_capture &&
726       !is_screen_capture &&
727       ((IsAudioMediaType(audio_type) && !audio_enumeration_cache_.valid) ||
728        (IsVideoMediaType(video_type) && !video_enumeration_cache_.valid))) {
729     // Enumerate the devices if there is no valid device lists to be used.
730     StartEnumeration(request);
731     return;
732   }
733
734   // No need to do new device enumerations, post the request to UI
735   // immediately.
736   if (IsAudioMediaType(audio_type))
737     request->SetState(audio_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
738   if (IsVideoMediaType(video_type))
739     request->SetState(video_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
740
741   PostRequestToUI(label);
742 }
743
744 bool MediaStreamManager::FindExistingRequestedDeviceInfo(
745     int render_process_id,
746     int render_view_id,
747     MediaStreamRequestType type,
748     const std::string& device_id,
749     StreamDeviceInfo* device_info,
750     MediaRequestState* request_state) const {
751   DCHECK(device_info);
752   DCHECK(request_state);
753   for (DeviceRequests::const_iterator it = requests_.begin();
754        it != requests_.end() ; ++it) {
755     const DeviceRequest* request = it->second;
756     if (request->requesting_process_id ==render_process_id &&
757         request->requesting_view_id == render_view_id &&
758         request->request.request_type == type) {
759       for (StreamDeviceInfoArray::const_iterator device_it =
760                request->devices.begin();
761            device_it != request->devices.end(); ++device_it) {
762         if (device_it->device.id == device_id) {
763             *device_info = *device_it;
764             *request_state = request->state(device_it->device.type);
765           return true;
766         }
767       }
768     }
769   }
770   return false;
771 }
772
773 std::string MediaStreamManager::FindFirstMediaStreamRequestWithDevice(
774     const MediaStreamDevice& device) const {
775   for (DeviceRequests::const_iterator it = requests_.begin();
776        it != requests_.end() ; ++it) {
777     const DeviceRequest* request = it->second;
778     if (request->request.request_type != MEDIA_GENERATE_STREAM)
779       continue;
780     for (StreamDeviceInfoArray::const_iterator device_it =
781              request->devices.begin();
782          device_it != request->devices.end(); ++device_it) {
783       if (device_it->device.id == device.id &&
784           device_it->device.type == device.type) {
785         return it->first;
786       }
787     }
788   }
789   return std::string();
790 }
791
792 void MediaStreamManager::InitializeDeviceManagersOnIOThread() {
793   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
794   if (device_thread_)
795     return;
796
797   device_thread_.reset(new base::Thread("MediaStreamDeviceThread"));
798 #if defined(OS_WIN)
799   device_thread_->init_com_with_mta(true);
800 #endif
801   CHECK(device_thread_->Start());
802
803   audio_input_device_manager_ = new AudioInputDeviceManager(audio_manager_);
804   audio_input_device_manager_->Register(
805       this, device_thread_->message_loop_proxy().get());
806
807   video_capture_manager_ = new VideoCaptureManager();
808   video_capture_manager_->Register(this,
809                                    device_thread_->message_loop_proxy().get());
810
811   // We want to be notified of IO message loop destruction to delete the thread
812   // and the device managers.
813   io_loop_ = base::MessageLoop::current();
814   io_loop_->AddDestructionObserver(this);
815 }
816
817 void MediaStreamManager::Opened(MediaStreamType stream_type,
818                                 int capture_session_id) {
819   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
820   DVLOG(1) << "Opened({stream_type = " << stream_type <<  "} "
821            << "{capture_session_id = " << capture_session_id << "})";
822   // Find the request(s) containing this device and mark it as used.
823   // It can be used in several requests since the same device can be
824   // requested from the same web page.
825   for (DeviceRequests::iterator request_it = requests_.begin();
826        request_it != requests_.end(); ++request_it) {
827     const std::string& label = request_it->first;
828     DeviceRequest* request = request_it->second;
829     StreamDeviceInfoArray* devices = &(request->devices);
830     for (StreamDeviceInfoArray::iterator device_it = devices->begin();
831          device_it != devices->end(); ++device_it) {
832       if (device_it->device.type == stream_type &&
833           device_it->session_id == capture_session_id &&
834           request->state(device_it->device.type) != MEDIA_REQUEST_STATE_DONE) {
835         // We've found a matching request.
836         request->SetState(device_it->device.type, MEDIA_REQUEST_STATE_DONE);
837
838         if (IsAudioMediaType(device_it->device.type)) {
839           // Store the native audio parameters in the device struct.
840           // TODO(xians): Handle the tab capture sample rate/channel layout
841           // in AudioInputDeviceManager::Open().
842           if (device_it->device.type != content::MEDIA_TAB_AUDIO_CAPTURE) {
843             const StreamDeviceInfo* info =
844                 audio_input_device_manager_->GetOpenedDeviceInfoById(
845                     device_it->session_id);
846             DCHECK_EQ(info->device.id, device_it->device.id);
847             device_it->device.input = info->device.input;
848             device_it->device.matched_output = info->device.matched_output;
849           }
850         }
851         if (RequestDone(*request))
852           HandleRequestDone(label, request);
853         break;
854       }
855     }
856   }
857 }
858
859 void MediaStreamManager::HandleRequestDone(const std::string& label,
860                                            DeviceRequest* request) {
861   DCHECK(RequestDone(*request));
862   DVLOG(1) << "HandleRequestDone("
863            << ", {label = " << label <<  "})";
864
865   const StreamDeviceInfoArray& requested_devices = request->devices;
866   switch (request->request.request_type) {
867     case MEDIA_OPEN_DEVICE:
868       request->requester->DeviceOpened(label, requested_devices.front());
869       break;
870     case MEDIA_GENERATE_STREAM: {
871       // Partition the array of devices into audio vs video.
872       StreamDeviceInfoArray audio_devices, video_devices;
873       for (StreamDeviceInfoArray::const_iterator device_it =
874                requested_devices.begin();
875            device_it != requested_devices.end(); ++device_it) {
876         if (IsAudioMediaType(device_it->device.type)) {
877           audio_devices.push_back(*device_it);
878         } else if (IsVideoMediaType(device_it->device.type)) {
879           video_devices.push_back(*device_it);
880         } else {
881           NOTREACHED();
882         }
883       }
884
885       request->requester->StreamGenerated(label, audio_devices, video_devices);
886       break;
887     }
888     default:
889       NOTREACHED();
890       break;
891   }
892
893   if (request->ui_proxy.get()) {
894     request->ui_proxy->OnStarted(
895         base::Bind(&MediaStreamManager::StopMediaStreamFromBrowser,
896                    base::Unretained(this), label));
897   }
898 }
899
900 void MediaStreamManager::Closed(MediaStreamType stream_type,
901                                 int capture_session_id) {
902   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
903 }
904
905 void MediaStreamManager::DevicesEnumerated(
906     MediaStreamType stream_type, const StreamDeviceInfoArray& devices) {
907   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
908   DVLOG(1) << "DevicesEnumerated("
909            << ", {stream_type = " << stream_type <<  "})";
910
911   // Only cache the device list when the device list has been changed.
912   bool need_update_clients = false;
913   EnumerationCache* cache =
914       stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
915       &audio_enumeration_cache_ : &video_enumeration_cache_;
916   if (!cache->valid ||
917       devices.size() != cache->devices.size() ||
918       !std::equal(devices.begin(), devices.end(), cache->devices.begin(),
919                   StreamDeviceInfo::IsEqual)) {
920     StopRemovedDevices(cache->devices, devices);
921     cache->valid = true;
922     cache->devices = devices;
923     need_update_clients = true;
924   }
925
926   if (need_update_clients && monitoring_started_)
927     NotifyDevicesChanged(stream_type, devices);
928
929   // Publish the result for all requests waiting for device list(s).
930   // Find the requests waiting for this device list, store their labels and
931   // release the iterator before calling device settings. We might get a call
932   // back from device_settings that will need to iterate through devices.
933   std::list<std::string> label_list;
934   for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
935        ++it) {
936     if (it->second->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED &&
937         Requested(it->second->request, stream_type)) {
938       if (it->second->request.request_type != MEDIA_ENUMERATE_DEVICES)
939         it->second->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
940       label_list.push_back(it->first);
941     }
942   }
943   for (std::list<std::string>::iterator it = label_list.begin();
944        it != label_list.end(); ++it) {
945     DeviceRequest* request = requests_[*it];
946     switch (request->request.request_type) {
947       case MEDIA_ENUMERATE_DEVICES:
948         if (need_update_clients && request->requester)
949           request->requester->DevicesEnumerated(*it, devices);
950         break;
951       default:
952         if (request->state(request->request.audio_type) ==
953                 MEDIA_REQUEST_STATE_REQUESTED ||
954             request->state(request->request.video_type) ==
955                 MEDIA_REQUEST_STATE_REQUESTED) {
956           // We are doing enumeration for other type of media, wait until it is
957           // all done before posting the request to UI because UI needs
958           // the device lists to handle the request.
959           break;
960         }
961
962         // Post the request to UI for permission approval.
963         PostRequestToUI(*it);
964         break;
965     }
966   }
967   label_list.clear();
968   --active_enumeration_ref_count_[stream_type];
969   DCHECK_GE(active_enumeration_ref_count_[stream_type], 0);
970 }
971
972 void MediaStreamManager::Error(MediaStreamType stream_type,
973                                int capture_session_id,
974                                MediaStreamProviderError error) {
975   // Find the device for the error call.
976   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
977   DVLOG(1) << "Error("
978            << "{stream_type = " << stream_type << "} ,"
979            << "{capture_session_id = " << capture_session_id <<  "})";
980
981
982   for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
983        ++it) {
984     StreamDeviceInfoArray& devices = it->second->devices;
985
986     // TODO(miu): BUG.  It's possible for the audio (or video) device array in
987     // the "requester" to become out-of-sync with the order of devices we have
988     // here.  See http://crbug.com/147650
989     int audio_device_idx = -1;
990     int video_device_idx = -1;
991     for (StreamDeviceInfoArray::iterator device_it = devices.begin();
992          device_it != devices.end(); ++device_it) {
993       if (IsAudioMediaType(device_it->device.type)) {
994         ++audio_device_idx;
995       } else if (IsVideoMediaType(device_it->device.type)) {
996         ++video_device_idx;
997       } else {
998         NOTREACHED();
999         continue;
1000       }
1001       if (device_it->device.type != stream_type ||
1002           device_it->session_id != capture_session_id) {
1003         continue;
1004       }
1005       // We've found the failing device. Find the error case:
1006       // An error should only be reported to the MediaStreamManager if
1007       // the request has not been fulfilled yet.
1008       DCHECK(it->second->state(stream_type) != MEDIA_REQUEST_STATE_DONE);
1009       if (it->second->state(stream_type) != MEDIA_REQUEST_STATE_DONE) {
1010         // Request is not done, devices are not opened in this case.
1011         if (devices.size() <= 1) {
1012           scoped_ptr<DeviceRequest> request(it->second);
1013           // 1. Device not opened and no other devices for this request ->
1014           //    signal stream error and remove the request.
1015           if (request->requester)
1016             request->requester->StreamGenerationFailed(it->first);
1017
1018           RemoveRequest(it);
1019         } else {
1020           // 2. Not opened but other devices exists for this request -> remove
1021           //    device from list, but don't signal an error.
1022           devices.erase(device_it);  // NOTE: This invalidates device_it!
1023           it->second->SetState(stream_type, MEDIA_REQUEST_STATE_ERROR);
1024           DVLOG(1) << "Error("
1025                    << ", {capture_session_id = " << capture_session_id <<  "})";
1026         }
1027       }
1028       if (RequestDone(*it->second))
1029         HandleRequestDone(it->first, it->second);
1030       break;
1031     }
1032   }
1033 }
1034
1035 void MediaStreamManager::HandleAccessRequestResponse(
1036     const std::string& label,
1037     const MediaStreamDevices& devices) {
1038   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1039   DVLOG(1) << "HandleAccessRequestResponse("
1040            << ", {label = " << label <<  "})";
1041
1042   DeviceRequests::iterator request_it = requests_.find(label);
1043   if (request_it == requests_.end()) {
1044     return;
1045   }
1046
1047   // Handle the case when the request was denied.
1048   if (devices.empty()) {
1049     // Notify the users about the request result.
1050     scoped_ptr<DeviceRequest> request(request_it->second);
1051     if (request->requester)
1052       request->requester->StreamGenerationFailed(label);
1053
1054     if (request->request.request_type == MEDIA_DEVICE_ACCESS &&
1055         !request->callback.is_null()) {
1056       request->callback.Run(MediaStreamDevices(), request->ui_proxy.Pass());
1057     }
1058
1059     RemoveRequest(request_it);
1060     return;
1061   }
1062
1063   if (request_it->second->request.request_type == MEDIA_DEVICE_ACCESS) {
1064     scoped_ptr<DeviceRequest> request(request_it->second);
1065     if (!request->callback.is_null())
1066       request->callback.Run(devices, request->ui_proxy.Pass());
1067
1068     // Delete the request since it is done.
1069     RemoveRequest(request_it);
1070     return;
1071   }
1072
1073   // Process all newly-accepted devices for this request.
1074   DeviceRequest* request = request_it->second;
1075   bool found_audio = false;
1076   bool found_video = false;
1077   for (MediaStreamDevices::const_iterator device_it = devices.begin();
1078        device_it != devices.end(); ++device_it) {
1079     StreamDeviceInfo device_info;
1080     device_info.device = *device_it;
1081
1082     // TODO(justinlin): Nicer way to do this?
1083     // Re-append the device's id since we lost it when posting request to UI.
1084     if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE ||
1085         device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
1086       device_info.device.id = request->request.tab_capture_device_id;
1087
1088       // Initialize the sample_rate and channel_layout here since for audio
1089       // mirroring, we don't go through EnumerateDevices where these are usually
1090       // initialized.
1091       if (device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
1092         const media::AudioParameters parameters =
1093             audio_manager_->GetDefaultOutputStreamParameters();
1094         int sample_rate = parameters.sample_rate();
1095         // If we weren't able to get the native sampling rate or the sample_rate
1096         // is outside the valid range for input devices set reasonable defaults.
1097         if (sample_rate <= 0 || sample_rate > 96000)
1098           sample_rate = 44100;
1099
1100         device_info.device.input.sample_rate = sample_rate;
1101         device_info.device.input.channel_layout = media::CHANNEL_LAYOUT_STEREO;
1102       }
1103     }
1104
1105     if (device_info.device.type == request->request.audio_type) {
1106       found_audio = true;
1107     } else if (device_info.device.type == request->request.video_type) {
1108       found_video = true;
1109     }
1110
1111     // If this is request for a new MediaStream, a device is only opened once
1112     // per render view. This is so that the permission to use a device can be
1113     // revoked by a single call to StopStreamDevice regardless of how many
1114     // MediaStreams it is being used in.
1115
1116     if (request->request.request_type == MEDIA_GENERATE_STREAM) {
1117       MediaRequestState state;
1118       if (FindExistingRequestedDeviceInfo(request->requesting_process_id,
1119                                           request->requesting_view_id,
1120                                           request->request.request_type,
1121                                           device_it->id,
1122                                           &device_info,
1123                                           &state)) {
1124         request->devices.push_back(device_info);
1125         request->SetState(device_info.device.type, state);
1126         DVLOG(1) << "HandleAccessRequestResponse - device already opened "
1127             << ", {label = " << label <<  "}"
1128             << ", device_id = " << device_it->id << "}";
1129         continue;
1130       }
1131     }
1132     device_info.session_id =
1133         GetDeviceManager(device_info.device.type)->Open(device_info);
1134     request->devices.push_back(device_info);
1135     request->SetState(device_info.device.type, MEDIA_REQUEST_STATE_OPENING);
1136     DVLOG(1) << "HandleAccessRequestResponse - opening device "
1137              << ", {label = " << label <<  "}"
1138              << ", {device_id = " << device_it->id << "}"
1139              << ", {session_id = " << device_info.session_id << "}";
1140   }
1141
1142   // Check whether we've received all stream types requested.
1143   if (!found_audio && IsAudioMediaType(request->request.audio_type)) {
1144     request->SetState(request->request.audio_type, MEDIA_REQUEST_STATE_ERROR);
1145     DVLOG(1) << "Set no audio found label " << label;
1146   }
1147
1148   if (!found_video && IsVideoMediaType(request->request.video_type))
1149     request->SetState(request->request.video_type, MEDIA_REQUEST_STATE_ERROR);
1150
1151   if (RequestDone(*request))
1152     HandleRequestDone(label, request);
1153 }
1154
1155 void MediaStreamManager::StopMediaStreamFromBrowser(const std::string& label) {
1156   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1157
1158   DeviceRequests::iterator it = requests_.find(label);
1159   if (it == requests_.end())
1160     return;
1161
1162   // Notify renderers that the stream has been stopped.
1163   if (it->second->requester)
1164     it->second->requester->StopGeneratedStream(
1165         it->second->request.render_view_id,
1166         label);
1167
1168   CancelRequest(label);
1169 }
1170
1171 void MediaStreamManager::UseFakeDevice() {
1172   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1173   video_capture_manager()->UseFakeDevice();
1174   audio_input_device_manager()->UseFakeDevice();
1175 }
1176
1177 void MediaStreamManager::UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy> fake_ui) {
1178   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1179   use_fake_ui_ = true;
1180   fake_ui_ = fake_ui.Pass();
1181 }
1182
1183 void MediaStreamManager::WillDestroyCurrentMessageLoop() {
1184   DCHECK_EQ(base::MessageLoop::current(), io_loop_);
1185   DCHECK(requests_.empty());
1186   if (device_thread_) {
1187     StopMonitoring();
1188
1189     video_capture_manager_->Unregister();
1190     audio_input_device_manager_->Unregister();
1191     device_thread_.reset();
1192   }
1193
1194   audio_input_device_manager_ = NULL;
1195   video_capture_manager_ = NULL;
1196 }
1197
1198 void MediaStreamManager::NotifyDevicesChanged(
1199     MediaStreamType stream_type,
1200     const StreamDeviceInfoArray& devices) {
1201   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1202   MediaObserver* media_observer =
1203       GetContentClient()->browser()->GetMediaObserver();
1204   if (media_observer == NULL)
1205     return;
1206
1207   // Map the devices to MediaStreamDevices.
1208   MediaStreamDevices new_devices;
1209   for (StreamDeviceInfoArray::const_iterator it = devices.begin();
1210        it != devices.end(); ++it) {
1211     new_devices.push_back(it->device);
1212   }
1213
1214   if (IsAudioMediaType(stream_type)) {
1215     media_observer->OnAudioCaptureDevicesChanged(new_devices);
1216   } else if (IsVideoMediaType(stream_type)) {
1217     media_observer->OnVideoCaptureDevicesChanged(new_devices);
1218   } else {
1219     NOTREACHED();
1220   }
1221 }
1222
1223 bool MediaStreamManager::RequestDone(const DeviceRequest& request) const {
1224   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1225
1226   const bool requested_audio = IsAudioMediaType(request.request.audio_type);
1227   const bool requested_video = IsVideoMediaType(request.request.video_type);
1228
1229   const bool audio_done =
1230       !requested_audio ||
1231       request.state(request.request.audio_type) ==
1232       MEDIA_REQUEST_STATE_DONE ||
1233       request.state(request.request.audio_type) ==
1234       MEDIA_REQUEST_STATE_ERROR;
1235   if (!audio_done)
1236     return false;
1237
1238   const bool video_done =
1239       !requested_video ||
1240       request.state(request.request.video_type) ==
1241       MEDIA_REQUEST_STATE_DONE ||
1242       request.state(request.request.video_type) ==
1243       MEDIA_REQUEST_STATE_ERROR;
1244   if (!video_done)
1245     return false;
1246
1247   return true;
1248 }
1249
1250 MediaStreamProvider* MediaStreamManager::GetDeviceManager(
1251     MediaStreamType stream_type) {
1252   if (IsVideoMediaType(stream_type)) {
1253     return video_capture_manager();
1254   } else if (IsAudioMediaType(stream_type)) {
1255     return audio_input_device_manager();
1256   }
1257   NOTREACHED();
1258   return NULL;
1259 }
1260
1261 void MediaStreamManager::OnDevicesChanged(
1262     base::SystemMonitor::DeviceType device_type) {
1263   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1264
1265   // NOTE: This method is only called in response to physical audio/video device
1266   // changes (from the operating system).
1267
1268   MediaStreamType stream_type;
1269   if (device_type == base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE) {
1270     stream_type = MEDIA_DEVICE_AUDIO_CAPTURE;
1271   } else if (device_type == base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE) {
1272     stream_type = MEDIA_DEVICE_VIDEO_CAPTURE;
1273   } else {
1274     return;  // Uninteresting device change.
1275   }
1276
1277   // Always do enumeration even though some enumeration is in progress,
1278   // because those enumeration commands could be sent before these devices
1279   // change.
1280   ++active_enumeration_ref_count_[stream_type];
1281   GetDeviceManager(stream_type)->EnumerateDevices(stream_type);
1282 }
1283
1284 }  // namespace content