Upstream version 7.35.139.0
[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/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
45 namespace content {
46
47 // Forward declaration of DeviceMonitorMac and its only useable method.
48 class DeviceMonitorMac {
49  public:
50   void StartMonitoring();
51 };
52
53 namespace {
54 // Creates a random label used to identify requests.
55 std::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
73 void 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.
121 void DoAddLogMessage(const std::string& message) {
122   // Must be on the UI thread to access BrowserMainLoop.
123   DCHECK(content::BrowserThread::CurrentlyOn(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|.
141 std::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.
157 std::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.
170 class 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
331 MediaStreamManager::EnumerationCache::EnumerationCache()
332     : valid(false) {
333 }
334
335 MediaStreamManager::EnumerationCache::~EnumerationCache() {
336 }
337
338 MediaStreamManager::MediaStreamManager()
339     : audio_manager_(NULL),
340       monitoring_started_(false),
341       io_loop_(NULL),
342       use_fake_ui_(false) {}
343
344 MediaStreamManager::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
371 MediaStreamManager::~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
383 VideoCaptureManager* MediaStreamManager::video_capture_manager() {
384   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
385   DCHECK(video_capture_manager_.get());
386   return video_capture_manager_.get();
387 }
388
389 AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() {
390   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
391   DCHECK(audio_input_device_manager_.get());
392   return audio_input_device_manager_.get();
393 }
394
395 std::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(BrowserThread::CurrentlyOn(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
431 void 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(BrowserThread::CurrentlyOn(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
469 void 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
485 void MediaStreamManager::CancelRequest(const std::string& label) {
486   DCHECK(BrowserThread::CurrentlyOn(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
523 void 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
537 void MediaStreamManager::StopStreamDevice(int render_process_id,
538                                           int render_view_id,
539                                           const std::string& device_id) {
540   DCHECK(BrowserThread::CurrentlyOn(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
566 void 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
605 void 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
626 std::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(BrowserThread::CurrentlyOn(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
666 void MediaStreamManager::DoEnumerateDevices(const std::string& label) {
667   DCHECK(BrowserThread::CurrentlyOn(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
695 void 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(BrowserThread::CurrentlyOn(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
741 void MediaStreamManager::EnsureDeviceMonitorStarted() {
742   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
743   StartMonitoring();
744 }
745
746 void 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
771 void 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
801 void MediaStreamManager::StartMonitoring() {
802   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
803   if (monitoring_started_)
804     return;
805
806   if (!base::SystemMonitor::Get())
807     return;
808
809   monitoring_started_ = true;
810   base::SystemMonitor::Get()->AddDevicesChangedObserver(this);
811
812   // Enumerate both the audio and video devices to cache the device lists
813   // and send them to media observer.
814   ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_CAPTURE];
815   audio_input_device_manager_->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE);
816   ++active_enumeration_ref_count_[MEDIA_DEVICE_VIDEO_CAPTURE];
817   video_capture_manager_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
818
819 #if defined(OS_MACOSX)
820   BrowserThread::PostTask(
821       BrowserThread::UI, FROM_HERE,
822       base::Bind(&MediaStreamManager::StartMonitoringOnUIThread,
823                  base::Unretained(this)));
824 #endif
825 }
826
827 #if defined(OS_MACOSX)
828 void MediaStreamManager::StartMonitoringOnUIThread() {
829   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
830   BrowserMainLoop* browser_main_loop = content::BrowserMainLoop::GetInstance();
831   if (browser_main_loop)
832     browser_main_loop->device_monitor_mac()->StartMonitoring();
833 }
834 #endif
835
836 void MediaStreamManager::StopMonitoring() {
837   DCHECK_EQ(base::MessageLoop::current(), io_loop_);
838   if (monitoring_started_) {
839     base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this);
840     monitoring_started_ = false;
841     ClearEnumerationCache(&audio_enumeration_cache_);
842     ClearEnumerationCache(&video_enumeration_cache_);
843   }
844 }
845
846 bool MediaStreamManager::GetRequestedDeviceCaptureId(
847     const DeviceRequest* request,
848     MediaStreamType type,
849     std::string* device_id) const {
850   DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
851          type == MEDIA_DEVICE_VIDEO_CAPTURE);
852   const StreamOptions::Constraints* mandatory =
853       (type == MEDIA_DEVICE_AUDIO_CAPTURE) ?
854           &request->options.mandatory_audio : &request->options.mandatory_video;
855   const StreamOptions::Constraints* optional =
856       (type == MEDIA_DEVICE_AUDIO_CAPTURE) ?
857           &request->options.optional_audio : &request->options.optional_video;
858
859   std::vector<std::string> source_ids;
860   StreamOptions::GetConstraintsByName(*mandatory,
861                                       kMediaStreamSourceInfoId, &source_ids);
862   if (source_ids.size() > 1) {
863     LOG(ERROR) << "Only one mandatory " << kMediaStreamSourceInfoId
864         << " is supported.";
865     return false;
866   }
867   // If a specific device has been requested we need to find the real device
868   // id.
869   if (source_ids.size() == 1 &&
870       !TranslateSourceIdToDeviceId(type,
871                                    request->salt_callback,
872                                    request->security_origin,
873                                    source_ids[0], device_id)) {
874     LOG(WARNING) << "Invalid mandatory " << kMediaStreamSourceInfoId
875                  << " = " << source_ids[0] << ".";
876     return false;
877   }
878   // Check for optional audio sourceIDs.
879   if (device_id->empty()) {
880     StreamOptions::GetConstraintsByName(*optional,
881                                         kMediaStreamSourceInfoId,
882                                         &source_ids);
883     // Find the first sourceID that translates to device. Note that only one
884     // device per type can call to GenerateStream is ever opened.
885     for (std::vector<std::string>::const_iterator it = source_ids.begin();
886          it != source_ids.end(); ++it) {
887       if (TranslateSourceIdToDeviceId(type,
888                                       request->salt_callback,
889                                       request->security_origin,
890                                       *it,
891                                       device_id)) {
892         break;
893       }
894     }
895   }
896   return true;
897 }
898
899 void MediaStreamManager::TranslateDeviceIdToSourceId(
900     DeviceRequest* request,
901     MediaStreamDevice* device) {
902   if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
903       request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE) {
904     device->id = content::GetHMACForMediaDeviceID(
905         request->salt_callback,
906         request->security_origin,
907         device->id);
908   }
909 }
910
911 bool MediaStreamManager::TranslateSourceIdToDeviceId(
912     MediaStreamType stream_type,
913     const ResourceContext::SaltCallback& sc,
914     const GURL& security_origin,
915     const std::string& source_id,
916     std::string* device_id) const {
917   DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ||
918          stream_type == MEDIA_DEVICE_VIDEO_CAPTURE);
919   // The source_id can be empty if the constraint is set but empty.
920   if (source_id.empty())
921     return false;
922
923   const EnumerationCache* cache =
924       stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
925       &audio_enumeration_cache_ : &video_enumeration_cache_;
926
927   // If device monitoring hasn't started, the |device_guid| is not valid.
928   if (!cache->valid)
929     return false;
930
931   for (StreamDeviceInfoArray::const_iterator it = cache->devices.begin();
932        it != cache->devices.end();
933        ++it) {
934     if (content::DoesMediaDeviceIDMatchHMAC(sc, security_origin, source_id,
935                                             it->device.id)) {
936       *device_id = it->device.id;
937       return true;
938     }
939   }
940   return false;
941 }
942
943 void MediaStreamManager::ClearEnumerationCache(EnumerationCache* cache) {
944   DCHECK_EQ(base::MessageLoop::current(), io_loop_);
945   cache->valid = false;
946 }
947
948 bool MediaStreamManager::EnumerationRequired(EnumerationCache* cache,
949                                              MediaStreamType stream_type) {
950   DCHECK_EQ(base::MessageLoop::current(), io_loop_);
951   if (stream_type == MEDIA_NO_SERVICE)
952     return false;
953
954   DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ||
955          stream_type == MEDIA_DEVICE_VIDEO_CAPTURE);
956
957 #if defined(OS_ANDROID)
958   // There's no SystemMonitor on Android that notifies us when devices are
959   // added or removed, so we need to populate the cache on every request.
960   // Fortunately, there is an already up-to-date cache in the browser side
961   // audio manager that we can rely on, so the performance impact of
962   // invalidating the cache like this, is minimal.
963   if (stream_type == MEDIA_DEVICE_AUDIO_CAPTURE) {
964     // Make sure the cache is marked as invalid so that FinalizeEnumerateDevices
965     // will be called at the end of the enumeration.
966     ClearEnumerationCache(cache);
967   }
968 #endif
969   // If the cache isn't valid, we need to start a full enumeration.
970   return !cache->valid;
971 }
972
973 void MediaStreamManager::StartEnumeration(DeviceRequest* request) {
974   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
975
976   // Start monitoring the devices when doing the first enumeration.
977   StartMonitoring();
978
979   // Start enumeration for devices of all requested device types.
980   const MediaStreamType streams[] = { request->audio_type(),
981                                       request->video_type() };
982   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(streams); ++i) {
983     if (streams[i] == MEDIA_NO_SERVICE)
984       continue;
985     request->SetState(streams[i], MEDIA_REQUEST_STATE_REQUESTED);
986     DCHECK_GE(active_enumeration_ref_count_[streams[i]], 0);
987     if (active_enumeration_ref_count_[streams[i]] == 0) {
988       ++active_enumeration_ref_count_[streams[i]];
989       GetDeviceManager(streams[i])->EnumerateDevices(streams[i]);
990     }
991   }
992 }
993
994 std::string MediaStreamManager::AddRequest(DeviceRequest* request) {
995   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
996
997   // Create a label for this request and verify it is unique.
998   std::string unique_label;
999   do {
1000     unique_label = RandomLabel();
1001   } while (requests_.find(unique_label) != requests_.end());
1002
1003   requests_.insert(std::make_pair(unique_label, request));
1004
1005   return unique_label;
1006 }
1007
1008 MediaStreamManager::DeviceRequest*
1009 MediaStreamManager::FindRequest(const std::string& label) const {
1010   DeviceRequests::const_iterator request_it = requests_.find(label);
1011   return request_it == requests_.end() ? NULL : request_it->second;
1012 }
1013
1014 void MediaStreamManager::DeleteRequest(const std::string& label) {
1015   DVLOG(1) << "DeleteRequest({label= " << label << "})";
1016   DeviceRequests::iterator it = requests_.find(label);
1017   scoped_ptr<DeviceRequest> request(it->second);
1018   requests_.erase(it);
1019 }
1020
1021 void MediaStreamManager::PostRequestToUI(const std::string& label,
1022                                          DeviceRequest* request) {
1023   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1024   DCHECK(request->UIRequest());
1025   DVLOG(1) << "PostRequestToUI({label= " << label << "})";
1026
1027   const MediaStreamType audio_type = request->audio_type();
1028   const MediaStreamType video_type = request->video_type();
1029
1030   // Post the request to UI and set the state.
1031   if (IsAudioMediaType(audio_type))
1032     request->SetState(audio_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
1033   if (IsVideoMediaType(video_type))
1034     request->SetState(video_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
1035
1036   if (use_fake_ui_) {
1037     if (!fake_ui_)
1038       fake_ui_.reset(new FakeMediaStreamUIProxy());
1039
1040     MediaStreamDevices devices;
1041     if (audio_enumeration_cache_.valid) {
1042       for (StreamDeviceInfoArray::const_iterator it =
1043                audio_enumeration_cache_.devices.begin();
1044            it != audio_enumeration_cache_.devices.end(); ++it) {
1045         devices.push_back(it->device);
1046       }
1047     }
1048     if (video_enumeration_cache_.valid) {
1049       for (StreamDeviceInfoArray::const_iterator it =
1050                video_enumeration_cache_.devices.begin();
1051            it != video_enumeration_cache_.devices.end(); ++it) {
1052         devices.push_back(it->device);
1053       }
1054     }
1055
1056     fake_ui_->SetAvailableDevices(devices);
1057
1058     request->ui_proxy = fake_ui_.Pass();
1059   } else {
1060     request->ui_proxy = MediaStreamUIProxy::Create();
1061   }
1062
1063   request->ui_proxy->RequestAccess(
1064       *request->UIRequest(),
1065       base::Bind(&MediaStreamManager::HandleAccessRequestResponse,
1066                  base::Unretained(this), label));
1067 }
1068
1069 void MediaStreamManager::SetupRequest(const std::string& label) {
1070   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1071   DeviceRequest* request = FindRequest(label);
1072   if (!request) {
1073     DVLOG(1) << "SetupRequest label " << label << " doesn't exist!!";
1074     return;  // This can happen if the request has been canceled.
1075   }
1076
1077   if (!request->security_origin.is_valid()) {
1078     LOG(ERROR) << "Invalid security origin. "
1079                << request->security_origin;
1080     FinalizeRequestFailed(label,
1081                           request,
1082                           MEDIA_DEVICE_INVALID_SECURITY_ORIGIN);
1083     return;
1084   }
1085
1086   MediaStreamType audio_type = MEDIA_NO_SERVICE;
1087   MediaStreamType video_type = MEDIA_NO_SERVICE;
1088   ParseStreamType(request->options, &audio_type, &video_type);
1089   request->SetAudioType(audio_type);
1090   request->SetVideoType(video_type);
1091
1092   bool is_web_contents_capture =
1093       audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
1094       video_type == MEDIA_TAB_VIDEO_CAPTURE;
1095   if (is_web_contents_capture && !SetupTabCaptureRequest(request)) {
1096     FinalizeRequestFailed(label,
1097                           request,
1098                           MEDIA_DEVICE_TAB_CAPTURE_FAILURE);
1099     return;
1100   }
1101
1102   bool is_screen_capture =
1103       video_type == MEDIA_DESKTOP_VIDEO_CAPTURE;
1104   if (is_screen_capture && !SetupScreenCaptureRequest(request)) {
1105     FinalizeRequestFailed(label,
1106                           request,
1107                           MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE);
1108     return;
1109   }
1110
1111   if (!is_web_contents_capture && !is_screen_capture) {
1112     if (EnumerationRequired(&audio_enumeration_cache_, audio_type) ||
1113         EnumerationRequired(&video_enumeration_cache_, video_type)) {
1114       // Enumerate the devices if there is no valid device lists to be used.
1115       StartEnumeration(request);
1116       return;
1117     } else {
1118         // Cache is valid, so log the cached devices for MediaStream requests.
1119       if (request->request_type == MEDIA_GENERATE_STREAM) {
1120         std::string log_message("Using cached devices for request.\n");
1121         if (audio_type != MEDIA_NO_SERVICE) {
1122           log_message +=
1123               GetLogMessageString(audio_type, audio_enumeration_cache_.devices);
1124         }
1125         if (video_type != MEDIA_NO_SERVICE) {
1126           log_message +=
1127               GetLogMessageString(video_type, video_enumeration_cache_.devices);
1128         }
1129         SendMessageToNativeLog(log_message);
1130       }
1131     }
1132
1133     if (!SetupDeviceCaptureRequest(request)) {
1134       FinalizeRequestFailed(label, request, MEDIA_DEVICE_NO_HARDWARE);
1135       return;
1136     }
1137   }
1138   PostRequestToUI(label, request);
1139 }
1140
1141 bool MediaStreamManager::SetupDeviceCaptureRequest(DeviceRequest* request) {
1142   DCHECK((request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
1143           request->audio_type() == MEDIA_NO_SERVICE) &&
1144          (request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE ||
1145           request->video_type() == MEDIA_NO_SERVICE));
1146   std::string audio_device_id;
1147   if (request->options.audio_requested &&
1148       !GetRequestedDeviceCaptureId(request, request->audio_type(),
1149                                      &audio_device_id)) {
1150     return false;
1151   }
1152
1153   std::string video_device_id;
1154   if (request->options.video_requested &&
1155       !GetRequestedDeviceCaptureId(request, request->video_type(),
1156                                    &video_device_id)) {
1157     return false;
1158   }
1159   request->CreateUIRequest(audio_device_id, video_device_id);
1160   DVLOG(3) << "Audio requested " << request->options.audio_requested
1161            << " device id = " << audio_device_id
1162            << "Video requested " << request->options.video_requested
1163            << " device id = " << video_device_id;
1164   return true;
1165 }
1166
1167 bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
1168   DCHECK(request->audio_type() == MEDIA_TAB_AUDIO_CAPTURE ||
1169          request->video_type() == MEDIA_TAB_VIDEO_CAPTURE);
1170
1171   std::string capture_device_id;
1172   bool mandatory_audio = false;
1173   bool mandatory_video = false;
1174   if (!request->options.GetFirstAudioConstraintByName(kMediaStreamSourceId,
1175                                                       &capture_device_id,
1176                                                       &mandatory_audio) &&
1177       !request->options.GetFirstVideoConstraintByName(kMediaStreamSourceId,
1178                                                       &capture_device_id,
1179                                                       &mandatory_video)) {
1180     return false;
1181   }
1182   DCHECK(mandatory_audio || mandatory_video);
1183
1184   // Customize options for a WebContents based capture.
1185   int target_render_process_id = 0;
1186   int target_render_view_id = 0;
1187
1188   // TODO(justinlin): Can't plumb audio mirroring using stream type right
1189   // now, so plumbing by device_id. Will revisit once it's refactored.
1190   // http://crbug.com/163100
1191   std::string tab_capture_device_id =
1192       WebContentsCaptureUtil::AppendWebContentsDeviceScheme(capture_device_id);
1193
1194   bool has_valid_device_id = WebContentsCaptureUtil::ExtractTabCaptureTarget(
1195       tab_capture_device_id, &target_render_process_id,
1196       &target_render_view_id);
1197   if (!has_valid_device_id ||
1198       (request->audio_type() != MEDIA_TAB_AUDIO_CAPTURE &&
1199        request->audio_type() != MEDIA_NO_SERVICE) ||
1200       (request->video_type() != MEDIA_TAB_VIDEO_CAPTURE &&
1201        request->video_type() != MEDIA_NO_SERVICE)) {
1202     return false;
1203   }
1204
1205   request->CreateTabCatureUIRequest(target_render_process_id,
1206                                     target_render_view_id,
1207                                     tab_capture_device_id);
1208
1209   DVLOG(3) << "SetupTabCaptureRequest "
1210            << ", {tab_capture_device_id = " << tab_capture_device_id <<  "}"
1211            << ", {target_render_process_id = " << target_render_process_id
1212            << "}"
1213            << ", {target_render_view_id = " << target_render_view_id << "}";
1214   return true;
1215 }
1216
1217 bool MediaStreamManager::SetupScreenCaptureRequest(DeviceRequest* request) {
1218   DCHECK(request->audio_type() == MEDIA_LOOPBACK_AUDIO_CAPTURE ||
1219          request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE);
1220
1221   // For screen capture we only support two valid combinations:
1222   // (1) screen video capture only, or
1223   // (2) screen video capture with loopback audio capture.
1224   if (request->video_type() != MEDIA_DESKTOP_VIDEO_CAPTURE ||
1225       (request->audio_type() != MEDIA_NO_SERVICE &&
1226        request->audio_type() != MEDIA_LOOPBACK_AUDIO_CAPTURE)) {
1227     LOG(ERROR) << "Invalid screen capture request.";
1228     return false;
1229   }
1230
1231   std::string video_device_id;
1232   if (request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE) {
1233     std::string video_stream_source;
1234     bool mandatory = false;
1235     if (!request->options.GetFirstVideoConstraintByName(
1236         kMediaStreamSource,
1237         &video_stream_source,
1238         &mandatory)) {
1239       LOG(ERROR) << kMediaStreamSource << " not found.";
1240       return false;
1241     }
1242     DCHECK(mandatory);
1243
1244     if (video_stream_source == kMediaStreamSourceDesktop) {
1245       if (!request->options.GetFirstVideoConstraintByName(
1246           kMediaStreamSourceId,
1247           &video_device_id,
1248           &mandatory)) {
1249         LOG(ERROR) << kMediaStreamSourceId << " not found.";
1250         return false;
1251       }
1252       DCHECK(mandatory);
1253     }
1254   }
1255
1256   request->CreateUIRequest("", video_device_id);
1257   return true;
1258 }
1259
1260 StreamDeviceInfoArray MediaStreamManager::GetDevicesOpenedByRequest(
1261     const std::string& label) const {
1262   DeviceRequest* request = FindRequest(label);
1263   if (!request)
1264     return StreamDeviceInfoArray();
1265   return request->devices;
1266 }
1267
1268 bool MediaStreamManager::FindExistingRequestedDeviceInfo(
1269     const DeviceRequest& new_request,
1270     const MediaStreamDevice& new_device_info,
1271     StreamDeviceInfo* existing_device_info,
1272     MediaRequestState* existing_request_state) const {
1273   DCHECK(existing_device_info);
1274   DCHECK(existing_request_state);
1275
1276   std::string source_id = content::GetHMACForMediaDeviceID(
1277       new_request.salt_callback,
1278       new_request.security_origin,
1279       new_device_info.id);
1280
1281   for (DeviceRequests::const_iterator it = requests_.begin();
1282        it != requests_.end() ; ++it) {
1283     const DeviceRequest* request = it->second;
1284     if (request->requesting_process_id == new_request.requesting_process_id &&
1285         request->requesting_view_id == new_request.requesting_view_id &&
1286         request->request_type == new_request.request_type) {
1287       for (StreamDeviceInfoArray::const_iterator device_it =
1288                request->devices.begin();
1289            device_it != request->devices.end(); ++device_it) {
1290         if (device_it->device.id == source_id &&
1291             device_it->device.type == new_device_info.type) {
1292             *existing_device_info = *device_it;
1293             *existing_request_state = request->state(device_it->device.type);
1294           return true;
1295         }
1296       }
1297     }
1298   }
1299   return false;
1300 }
1301
1302 void MediaStreamManager::FinalizeGenerateStream(const std::string& label,
1303                                                 DeviceRequest* request) {
1304   DVLOG(1) << "FinalizeGenerateStream label " << label;
1305   const StreamDeviceInfoArray& requested_devices = request->devices;
1306
1307   // Partition the array of devices into audio vs video.
1308   StreamDeviceInfoArray audio_devices, video_devices;
1309   for (StreamDeviceInfoArray::const_iterator device_it =
1310            requested_devices.begin();
1311        device_it != requested_devices.end(); ++device_it) {
1312     if (IsAudioMediaType(device_it->device.type)) {
1313       audio_devices.push_back(*device_it);
1314     } else if (IsVideoMediaType(device_it->device.type)) {
1315       video_devices.push_back(*device_it);
1316     } else {
1317       NOTREACHED();
1318     }
1319   }
1320
1321   request->requester->StreamGenerated(
1322       request->requesting_view_id,
1323       request->page_request_id,
1324       label, audio_devices, video_devices);
1325 }
1326
1327 void MediaStreamManager::FinalizeRequestFailed(
1328     const std::string& label,
1329     DeviceRequest* request,
1330     content::MediaStreamRequestResult result) {
1331   if (request->requester)
1332     request->requester->StreamGenerationFailed(
1333         request->requesting_view_id,
1334         request->page_request_id,
1335         result);
1336
1337   if (request->request_type == MEDIA_DEVICE_ACCESS &&
1338       !request->callback.is_null()) {
1339     request->callback.Run(MediaStreamDevices(), request->ui_proxy.Pass());
1340   }
1341
1342   DeleteRequest(label);
1343 }
1344
1345 void MediaStreamManager::FinalizeOpenDevice(const std::string& label,
1346                                             DeviceRequest* request) {
1347   const StreamDeviceInfoArray& requested_devices = request->devices;
1348   request->requester->DeviceOpened(request->requesting_view_id,
1349                                    request->page_request_id,
1350                                    label, requested_devices.front());
1351 }
1352
1353 void MediaStreamManager::FinalizeEnumerateDevices(const std::string& label,
1354                                                   DeviceRequest* request) {
1355   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1356   DCHECK_EQ(request->request_type, MEDIA_ENUMERATE_DEVICES);
1357
1358   if (request->security_origin.is_valid()) {
1359     for (StreamDeviceInfoArray::iterator it = request->devices.begin();
1360          it != request->devices.end(); ++it) {
1361       TranslateDeviceIdToSourceId(request, &it->device);
1362     }
1363   } else {
1364     request->devices.clear();
1365   }
1366
1367   request->requester->DevicesEnumerated(
1368       request->requesting_view_id,
1369       request->page_request_id,
1370       label,
1371       request->devices);
1372
1373   // TODO(tommi):
1374   // Ideally enumeration requests should be deleted once they have been served
1375   // (as any request).  However, this implementation mixes requests and
1376   // notifications together so enumeration requests are kept open by some
1377   // implementations (only Pepper?) and enumerations are done again when
1378   // device notifications are fired.
1379   // Implementations that just want to request the device list and be done
1380   // (e.g. DeviceRequestMessageFilter), they must (confusingly) call
1381   // CancelRequest() after the request has been fulfilled.  This is not
1382   // obvious, not consistent in this class (see e.g. FinalizeMediaAccessRequest)
1383   // and can lead to subtle bugs (requests not deleted at all deleted too
1384   // early).
1385   //
1386   // Basically, it is not clear that using requests as an additional layer on
1387   // top of device notifications is necessary or good.
1388   //
1389   // To add to this, MediaStreamManager currently relies on the external
1390   // implementations of MediaStreamRequester to delete enumeration requests via
1391   // CancelRequest and e.g. DeviceRequestMessageFilter does this.  However the
1392   // Pepper implementation does not seem to to this at all (and from what I can
1393   // see, it is the only implementation that uses an enumeration request as a
1394   // notification mechanism).
1395   //
1396   // We should decouple notifications from enumeration requests and once that
1397   // has been done, remove the requirement to call CancelRequest() to delete
1398   // enumeration requests and uncomment the following line:
1399   //
1400   // DeleteRequest(label);
1401 }
1402
1403 void MediaStreamManager::FinalizeMediaAccessRequest(
1404     const std::string& label,
1405     DeviceRequest* request,
1406     const MediaStreamDevices& devices) {
1407   if (!request->callback.is_null())
1408     request->callback.Run(devices, request->ui_proxy.Pass());
1409
1410   // Delete the request since it is done.
1411   DeleteRequest(label);
1412 }
1413
1414 void MediaStreamManager::InitializeDeviceManagersOnIOThread() {
1415   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1416   if (device_task_runner_)
1417     return;
1418
1419   device_task_runner_ = audio_manager_->GetWorkerTaskRunner();
1420
1421   audio_input_device_manager_ = new AudioInputDeviceManager(audio_manager_);
1422   audio_input_device_manager_->Register(this, device_task_runner_);
1423
1424   video_capture_manager_ = new VideoCaptureManager();
1425   video_capture_manager_->Register(this, device_task_runner_);
1426
1427   // We want to be notified of IO message loop destruction to delete the thread
1428   // and the device managers.
1429   io_loop_ = base::MessageLoop::current();
1430   io_loop_->AddDestructionObserver(this);
1431
1432   if (CommandLine::ForCurrentProcess()->HasSwitch(
1433           switches::kUseFakeDeviceForMediaStream)) {
1434     DVLOG(1) << "Using fake device";
1435     UseFakeDevice();
1436   }
1437 }
1438
1439 void MediaStreamManager::Opened(MediaStreamType stream_type,
1440                                 int capture_session_id) {
1441   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1442   DVLOG(1) << "Opened({stream_type = " << stream_type <<  "} "
1443            << "{capture_session_id = " << capture_session_id << "})";
1444   // Find the request(s) containing this device and mark it as used.
1445   // It can be used in several requests since the same device can be
1446   // requested from the same web page.
1447   for (DeviceRequests::iterator request_it = requests_.begin();
1448        request_it != requests_.end(); ++request_it) {
1449     const std::string& label = request_it->first;
1450     DeviceRequest* request = request_it->second;
1451     StreamDeviceInfoArray* devices = &(request->devices);
1452     for (StreamDeviceInfoArray::iterator device_it = devices->begin();
1453          device_it != devices->end(); ++device_it) {
1454       if (device_it->device.type == stream_type &&
1455           device_it->session_id == capture_session_id) {
1456         CHECK(request->state(device_it->device.type) ==
1457             MEDIA_REQUEST_STATE_OPENING);
1458         // We've found a matching request.
1459         request->SetState(device_it->device.type, MEDIA_REQUEST_STATE_DONE);
1460
1461         if (IsAudioMediaType(device_it->device.type)) {
1462           // Store the native audio parameters in the device struct.
1463           // TODO(xians): Handle the tab capture sample rate/channel layout
1464           // in AudioInputDeviceManager::Open().
1465           if (device_it->device.type != content::MEDIA_TAB_AUDIO_CAPTURE) {
1466             const StreamDeviceInfo* info =
1467                 audio_input_device_manager_->GetOpenedDeviceInfoById(
1468                     device_it->session_id);
1469             device_it->device.input = info->device.input;
1470             device_it->device.matched_output = info->device.matched_output;
1471           }
1472         }
1473         if (RequestDone(*request))
1474           HandleRequestDone(label, request);
1475         break;
1476       }
1477     }
1478   }
1479 }
1480
1481 void MediaStreamManager::HandleRequestDone(const std::string& label,
1482                                            DeviceRequest* request) {
1483   DCHECK(RequestDone(*request));
1484   DVLOG(1) << "HandleRequestDone("
1485            << ", {label = " << label <<  "})";
1486
1487   switch (request->request_type) {
1488     case MEDIA_OPEN_DEVICE:
1489       FinalizeOpenDevice(label, request);
1490       break;
1491     case MEDIA_GENERATE_STREAM: {
1492       FinalizeGenerateStream(label, request);
1493       break;
1494     }
1495     default:
1496       NOTREACHED();
1497       break;
1498   }
1499
1500   if (request->ui_proxy.get()) {
1501     request->ui_proxy->OnStarted(
1502         base::Bind(&MediaStreamManager::StopMediaStreamFromBrowser,
1503                    base::Unretained(this),
1504                    label),
1505         base::Bind(&MediaStreamManager::OnMediaStreamUIWindowId,
1506                    base::Unretained(this),
1507                    request->video_type(),
1508                    request->devices));
1509   }
1510 }
1511
1512 void MediaStreamManager::Closed(MediaStreamType stream_type,
1513                                 int capture_session_id) {
1514   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1515 }
1516
1517 void MediaStreamManager::DevicesEnumerated(
1518     MediaStreamType stream_type, const StreamDeviceInfoArray& devices) {
1519   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1520   DVLOG(1) << "DevicesEnumerated("
1521            << "{stream_type = " << stream_type << "})" << std::endl;
1522
1523   std::string log_message = "New device enumeration result:\n" +
1524                             GetLogMessageString(stream_type, devices);
1525   SendMessageToNativeLog(log_message);
1526
1527   // Only cache the device list when the device list has been changed.
1528   bool need_update_clients = false;
1529   EnumerationCache* cache =
1530       stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
1531       &audio_enumeration_cache_ : &video_enumeration_cache_;
1532   if (!cache->valid ||
1533       devices.size() != cache->devices.size() ||
1534       !std::equal(devices.begin(), devices.end(), cache->devices.begin(),
1535                   StreamDeviceInfo::IsEqual)) {
1536     StopRemovedDevices(cache->devices, devices);
1537     cache->devices = devices;
1538     need_update_clients = true;
1539
1540     // The device might not be able to be enumerated when it is not warmed up,
1541     // for example, when the machine just wakes up from sleep. We set the cache
1542     // to be invalid so that the next media request will trigger the
1543     // enumeration again. See issue/317673.
1544     cache->valid = !devices.empty();
1545  }
1546
1547   if (need_update_clients && monitoring_started_)
1548     NotifyDevicesChanged(stream_type, devices);
1549
1550   // Publish the result for all requests waiting for device list(s).
1551   // Find the requests waiting for this device list, store their labels and
1552   // release the iterator before calling device settings. We might get a call
1553   // back from device_settings that will need to iterate through devices.
1554   std::list<std::string> label_list;
1555   for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
1556        ++it) {
1557     if (it->second->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED &&
1558         (it->second->audio_type() == stream_type ||
1559          it->second->video_type() == stream_type)) {
1560       if (it->second->request_type != MEDIA_ENUMERATE_DEVICES)
1561         it->second->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
1562       label_list.push_back(it->first);
1563     }
1564   }
1565
1566   for (std::list<std::string>::iterator it = label_list.begin();
1567        it != label_list.end(); ++it) {
1568     DeviceRequest* request = FindRequest(*it);
1569     switch (request->request_type) {
1570       case MEDIA_ENUMERATE_DEVICES:
1571         if (need_update_clients && request->requester) {
1572           request->devices = devices;
1573           FinalizeEnumerateDevices(*it, request);
1574         }
1575         break;
1576       default:
1577         if (request->state(request->audio_type()) ==
1578                 MEDIA_REQUEST_STATE_REQUESTED ||
1579             request->state(request->video_type()) ==
1580                 MEDIA_REQUEST_STATE_REQUESTED) {
1581           // We are doing enumeration for other type of media, wait until it is
1582           // all done before posting the request to UI because UI needs
1583           // the device lists to handle the request.
1584           break;
1585         }
1586         if (!SetupDeviceCaptureRequest(request)) {
1587           FinalizeRequestFailed(*it,
1588                                 request,
1589                                 MEDIA_DEVICE_NO_HARDWARE);
1590         } else {
1591           PostRequestToUI(*it, request);
1592         }
1593         break;
1594     }
1595   }
1596   label_list.clear();
1597   --active_enumeration_ref_count_[stream_type];
1598   DCHECK_GE(active_enumeration_ref_count_[stream_type], 0);
1599 }
1600
1601 // static
1602 void MediaStreamManager::SendMessageToNativeLog(const std::string& message) {
1603   BrowserThread::PostTask(
1604       BrowserThread::UI, FROM_HERE,
1605       base::Bind(DoAddLogMessage, message));
1606 }
1607
1608 void MediaStreamManager::OnSuspend() {
1609   SendMessageToNativeLog("Power state suspended.");
1610 }
1611
1612 void MediaStreamManager::OnResume() {
1613   SendMessageToNativeLog("Power state resumed.");
1614 }
1615
1616 void MediaStreamManager::AddLogMessageOnIOThread(const std::string& message) {
1617   // Get render process ids on the IO thread.
1618   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1619
1620   // Grab all unique process ids that request a MediaStream or have a
1621   // MediaStream running.
1622   std::set<int> requesting_process_ids;
1623   for (DeviceRequests::const_iterator it = requests_.begin();
1624        it != requests_.end(); ++it) {
1625     DeviceRequest* request = it->second;
1626     if (request->request_type == MEDIA_GENERATE_STREAM)
1627       requesting_process_ids.insert(request->requesting_process_id);
1628   }
1629
1630   // MediaStreamManager is a singleton in BrowserMainLoop, which owns the UI
1631   // thread. MediaStreamManager has the same lifetime as the UI thread, so it is
1632   // safe to use base::Unretained.
1633   BrowserThread::PostTask(
1634       BrowserThread::UI,
1635       FROM_HERE,
1636       base::Bind(&MediaStreamManager::AddLogMessageOnUIThread,
1637                  base::Unretained(this),
1638                  requesting_process_ids,
1639                  message));
1640 }
1641
1642 void MediaStreamManager::AddLogMessageOnUIThread(
1643     const std::set<int>& requesting_process_ids,
1644     const std::string& message) {
1645 #if defined(ENABLE_WEBRTC)
1646   // Must be on the UI thread to access RenderProcessHost from process ID.
1647   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1648
1649   for (std::set<int>::const_iterator it = requesting_process_ids.begin();
1650        it != requesting_process_ids.end(); ++it) {
1651     // Log the message to all renderers that are requesting a MediaStream or
1652     // have a MediaStream running.
1653     content::RenderProcessHostImpl* render_process_host_impl =
1654         static_cast<content::RenderProcessHostImpl*>(
1655             content::RenderProcessHost::FromID(*it));
1656     if (render_process_host_impl)
1657       render_process_host_impl->WebRtcLogMessage(message);
1658   }
1659 #endif
1660 }
1661
1662 void MediaStreamManager::HandleAccessRequestResponse(
1663     const std::string& label,
1664     const MediaStreamDevices& devices,
1665     content::MediaStreamRequestResult result) {
1666   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1667   DVLOG(1) << "HandleAccessRequestResponse("
1668            << ", {label = " << label <<  "})";
1669
1670   DeviceRequest* request = FindRequest(label);
1671   if (!request) {
1672     // The request has been canceled before the UI returned.
1673     return;
1674   }
1675
1676   if (request->request_type == MEDIA_DEVICE_ACCESS) {
1677     FinalizeMediaAccessRequest(label, request, devices);
1678     return;
1679   }
1680
1681   // Handle the case when the request was denied.
1682   if (result != MEDIA_DEVICE_OK) {
1683     FinalizeRequestFailed(label, request, result);
1684     return;
1685   }
1686   DCHECK(!devices.empty());
1687
1688   // Process all newly-accepted devices for this request.
1689   bool found_audio = false;
1690   bool found_video = false;
1691   for (MediaStreamDevices::const_iterator device_it = devices.begin();
1692        device_it != devices.end(); ++device_it) {
1693     StreamDeviceInfo device_info;
1694     device_info.device = *device_it;
1695
1696     // TODO(justinlin): Nicer way to do this?
1697     // Re-append the device's id since we lost it when posting request to UI.
1698     if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE ||
1699         device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
1700       device_info.device.id = request->UIRequest()->tab_capture_device_id;
1701
1702       // Initialize the sample_rate and channel_layout here since for audio
1703       // mirroring, we don't go through EnumerateDevices where these are usually
1704       // initialized.
1705       if (device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
1706         const media::AudioParameters parameters =
1707             audio_manager_->GetDefaultOutputStreamParameters();
1708         int sample_rate = parameters.sample_rate();
1709         // If we weren't able to get the native sampling rate or the sample_rate
1710         // is outside the valid range for input devices set reasonable defaults.
1711         if (sample_rate <= 0 || sample_rate > 96000)
1712           sample_rate = 44100;
1713
1714         device_info.device.input.sample_rate = sample_rate;
1715         device_info.device.input.channel_layout = media::CHANNEL_LAYOUT_STEREO;
1716       }
1717     }
1718
1719     if (device_info.device.type == request->audio_type()) {
1720       found_audio = true;
1721     } else if (device_info.device.type == request->video_type()) {
1722       found_video = true;
1723     }
1724
1725     // If this is request for a new MediaStream, a device is only opened once
1726     // per render view. This is so that the permission to use a device can be
1727     // revoked by a single call to StopStreamDevice regardless of how many
1728     // MediaStreams it is being used in.
1729     if (request->request_type == MEDIA_GENERATE_STREAM) {
1730       MediaRequestState state;
1731       if (FindExistingRequestedDeviceInfo(*request,
1732                                           device_info.device,
1733                                           &device_info,
1734                                           &state)) {
1735         request->devices.push_back(device_info);
1736         request->SetState(device_info.device.type, state);
1737         DVLOG(1) << "HandleAccessRequestResponse - device already opened "
1738                  << ", {label = " << label <<  "}"
1739                  << ", device_id = " << device_it->id << "}";
1740         continue;
1741       }
1742     }
1743     device_info.session_id =
1744         GetDeviceManager(device_info.device.type)->Open(device_info);
1745     TranslateDeviceIdToSourceId(request, &device_info.device);
1746     request->devices.push_back(device_info);
1747
1748     request->SetState(device_info.device.type, MEDIA_REQUEST_STATE_OPENING);
1749     DVLOG(1) << "HandleAccessRequestResponse - opening device "
1750              << ", {label = " << label <<  "}"
1751              << ", {device_id = " << device_info.device.id << "}"
1752              << ", {session_id = " << device_info.session_id << "}";
1753   }
1754
1755   // Check whether we've received all stream types requested.
1756   if (!found_audio && IsAudioMediaType(request->audio_type())) {
1757     request->SetState(request->audio_type(), MEDIA_REQUEST_STATE_ERROR);
1758     DVLOG(1) << "Set no audio found label " << label;
1759   }
1760
1761   if (!found_video && IsVideoMediaType(request->video_type()))
1762     request->SetState(request->video_type(), MEDIA_REQUEST_STATE_ERROR);
1763
1764   if (RequestDone(*request))
1765     HandleRequestDone(label, request);
1766 }
1767
1768 void MediaStreamManager::StopMediaStreamFromBrowser(const std::string& label) {
1769   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1770
1771   DeviceRequest* request = FindRequest(label);
1772   if (!request)
1773     return;
1774
1775   // Notify renderers that the devices in the stream will be stopped.
1776   if (request->requester) {
1777     for (StreamDeviceInfoArray::iterator device_it = request->devices.begin();
1778          device_it != request->devices.end(); ++device_it) {
1779       request->requester->DeviceStopped(request->requesting_view_id,
1780                                         label,
1781                                         *device_it);
1782     }
1783   }
1784
1785   CancelRequest(label);
1786 }
1787
1788 void MediaStreamManager::UseFakeDevice() {
1789   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1790   video_capture_manager()->UseFakeDevice();
1791   audio_input_device_manager()->UseFakeDevice();
1792 }
1793
1794 void MediaStreamManager::UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy> fake_ui) {
1795   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1796   use_fake_ui_ = true;
1797   fake_ui_ = fake_ui.Pass();
1798 }
1799
1800 void MediaStreamManager::WillDestroyCurrentMessageLoop() {
1801   DVLOG(3) << "MediaStreamManager::WillDestroyCurrentMessageLoop()";
1802   DCHECK_EQ(base::MessageLoop::current(), io_loop_);
1803   DCHECK(requests_.empty());
1804   if (device_task_runner_) {
1805     StopMonitoring();
1806
1807     video_capture_manager_->Unregister();
1808     audio_input_device_manager_->Unregister();
1809     device_task_runner_ = NULL;
1810   }
1811
1812   audio_input_device_manager_ = NULL;
1813   video_capture_manager_ = NULL;
1814 }
1815
1816 void MediaStreamManager::NotifyDevicesChanged(
1817     MediaStreamType stream_type,
1818     const StreamDeviceInfoArray& devices) {
1819   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1820   MediaObserver* media_observer =
1821       GetContentClient()->browser()->GetMediaObserver();
1822   if (media_observer == NULL)
1823     return;
1824
1825   // Map the devices to MediaStreamDevices.
1826   MediaStreamDevices new_devices;
1827   for (StreamDeviceInfoArray::const_iterator it = devices.begin();
1828        it != devices.end(); ++it) {
1829     new_devices.push_back(it->device);
1830   }
1831
1832   if (IsAudioMediaType(stream_type)) {
1833     MediaCaptureDevicesImpl::GetInstance()->OnAudioCaptureDevicesChanged(
1834         new_devices);
1835     media_observer->OnAudioCaptureDevicesChanged();
1836   } else if (IsVideoMediaType(stream_type)) {
1837     MediaCaptureDevicesImpl::GetInstance()->OnVideoCaptureDevicesChanged(
1838         new_devices);
1839     media_observer->OnVideoCaptureDevicesChanged();
1840   } else {
1841     NOTREACHED();
1842   }
1843 }
1844
1845 bool MediaStreamManager::RequestDone(const DeviceRequest& request) const {
1846   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1847
1848   const bool requested_audio = IsAudioMediaType(request.audio_type());
1849   const bool requested_video = IsVideoMediaType(request.video_type());
1850
1851   const bool audio_done =
1852       !requested_audio ||
1853       request.state(request.audio_type()) == MEDIA_REQUEST_STATE_DONE ||
1854       request.state(request.audio_type()) == MEDIA_REQUEST_STATE_ERROR;
1855   if (!audio_done)
1856     return false;
1857
1858   const bool video_done =
1859       !requested_video ||
1860       request.state(request.video_type()) == MEDIA_REQUEST_STATE_DONE ||
1861       request.state(request.video_type()) == MEDIA_REQUEST_STATE_ERROR;
1862   if (!video_done)
1863     return false;
1864
1865   return true;
1866 }
1867
1868 MediaStreamProvider* MediaStreamManager::GetDeviceManager(
1869     MediaStreamType stream_type) {
1870   if (IsVideoMediaType(stream_type)) {
1871     return video_capture_manager();
1872   } else if (IsAudioMediaType(stream_type)) {
1873     return audio_input_device_manager();
1874   }
1875   NOTREACHED();
1876   return NULL;
1877 }
1878
1879 void MediaStreamManager::OnDevicesChanged(
1880     base::SystemMonitor::DeviceType device_type) {
1881   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1882
1883   // NOTE: This method is only called in response to physical audio/video device
1884   // changes (from the operating system).
1885
1886   MediaStreamType stream_type;
1887   if (device_type == base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE) {
1888     stream_type = MEDIA_DEVICE_AUDIO_CAPTURE;
1889   } else if (device_type == base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE) {
1890     stream_type = MEDIA_DEVICE_VIDEO_CAPTURE;
1891   } else {
1892     return;  // Uninteresting device change.
1893   }
1894
1895   // Always do enumeration even though some enumeration is in progress,
1896   // because those enumeration commands could be sent before these devices
1897   // change.
1898   ++active_enumeration_ref_count_[stream_type];
1899   GetDeviceManager(stream_type)->EnumerateDevices(stream_type);
1900 }
1901
1902 void MediaStreamManager::OnMediaStreamUIWindowId(MediaStreamType video_type,
1903                                                  StreamDeviceInfoArray devices,
1904                                                  gfx::NativeViewId window_id) {
1905   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1906   if (!window_id)
1907     return;
1908
1909   // Pass along for desktop capturing. Ignored for other stream types.
1910   if (video_type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
1911     for (StreamDeviceInfoArray::iterator it = devices.begin();
1912          it != devices.end();
1913          ++it) {
1914       if (it->device.type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
1915         video_capture_manager_->SetDesktopCaptureWindowId(it->session_id,
1916                                                           window_id);
1917         break;
1918       }
1919     }
1920   }
1921 }
1922
1923 }  // namespace content