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