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