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