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"
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"
42 #include "base/win/scoped_com_initializer.h"
47 // Forward declaration of DeviceMonitorMac and its only useable method.
48 class DeviceMonitorMac {
50 void StartMonitoring();
54 // Creates a random label used to identify requests.
55 std::string RandomLabel() {
56 // An earlier PeerConnection spec,
57 // http://dev.w3.org/2011/webrtc/editor/webrtc.html, specified the
58 // MediaStream::label alphabet as containing 36 characters from
59 // range: U+0021, U+0023 to U+0027, U+002A to U+002B, U+002D to U+002E,
60 // U+0030 to U+0039, U+0041 to U+005A, U+005E to U+007E.
61 // Here we use a safe subset.
62 static const char kAlphabet[] = "0123456789"
63 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
65 std::string label(36, ' ');
66 for (size_t i = 0; i < label.size(); ++i) {
67 int random_char = base::RandGenerator(sizeof(kAlphabet) - 1);
68 label[i] = kAlphabet[random_char];
73 void ParseStreamType(const StreamOptions& options,
74 MediaStreamType* audio_type,
75 MediaStreamType* video_type) {
76 *audio_type = MEDIA_NO_SERVICE;
77 *video_type = MEDIA_NO_SERVICE;
78 if (options.audio_requested) {
79 std::string audio_stream_source;
80 bool mandatory = false;
81 if (options.GetFirstAudioConstraintByName(kMediaStreamSource,
85 // This is tab or screen capture.
86 if (audio_stream_source == kMediaStreamSourceTab) {
87 *audio_type = content::MEDIA_TAB_AUDIO_CAPTURE;
88 } else if (audio_stream_source == kMediaStreamSourceSystem) {
89 *audio_type = content::MEDIA_LOOPBACK_AUDIO_CAPTURE;
92 // This is normal audio device capture.
93 *audio_type = MEDIA_DEVICE_AUDIO_CAPTURE;
96 if (options.video_requested) {
97 std::string video_stream_source;
98 bool mandatory = false;
99 if (options.GetFirstVideoConstraintByName(kMediaStreamSource,
100 &video_stream_source,
103 // This is tab or screen capture.
104 if (video_stream_source == kMediaStreamSourceTab) {
105 *video_type = content::MEDIA_TAB_VIDEO_CAPTURE;
106 } else if (video_stream_source == kMediaStreamSourceScreen) {
107 *video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
108 } else if (video_stream_source == kMediaStreamSourceDesktop) {
109 *video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
112 // This is normal video device capture.
113 *video_type = MEDIA_DEVICE_VIDEO_CAPTURE;
118 // Private helper method for SendMessageToNativeLog() that obtains the global
119 // MediaStreamManager instance on the UI thread before sending |message| to the
120 // webrtcLoggingPrivate API.
121 void DoAddLogMessage(const std::string& message) {
122 // Must be on the UI thread to access BrowserMainLoop.
123 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
124 // May be null in tests.
125 // TODO(vrk): Handle this more elegantly by having native log messages become
126 // no-ops until MediaStreamManager is aware that a renderer process has
127 // started logging. crbug.com/333894
128 if (content::BrowserMainLoop::GetInstance()) {
129 BrowserThread::PostTask(
132 base::Bind(&MediaStreamManager::AddLogMessageOnIOThread,
133 base::Unretained(content::BrowserMainLoop::GetInstance()
134 ->media_stream_manager()),
139 // Private helper method to generate a string for the log message that lists the
140 // human readable names of |devices|.
141 std::string GetLogMessageString(MediaStreamType stream_type,
142 const StreamDeviceInfoArray& devices) {
143 std::string output_string =
144 base::StringPrintf("Getting devices for stream type %d:\n", stream_type);
145 if (devices.empty()) {
146 output_string += "No devices found.";
148 for (StreamDeviceInfoArray::const_iterator it = devices.begin();
149 it != devices.end(); ++it) {
150 output_string += " " + it->device.name + "\n";
153 return output_string;
156 // Needed for MediaStreamManager::GenerateStream below.
157 std::string ReturnEmptySalt() {
158 return std::string();
164 // MediaStreamManager::DeviceRequest represents a request to either enumerate
165 // available devices or open one or more devices.
166 // TODO(perkj): MediaStreamManager still needs refactoring. I propose we create
167 // several subclasses of DeviceRequest and move some of the responsibility of
168 // the MediaStreamManager to the subclasses to get rid of the way too many if
169 // statements in MediaStreamManager.
170 class MediaStreamManager::DeviceRequest {
172 DeviceRequest(MediaStreamRequester* requester,
173 int requesting_process_id,
174 int requesting_view_id,
176 const GURL& security_origin,
178 MediaStreamRequestType request_type,
179 const StreamOptions& options,
180 const ResourceContext::SaltCallback& salt_callback)
181 : requester(requester),
182 requesting_process_id(requesting_process_id),
183 requesting_view_id(requesting_view_id),
184 page_request_id(page_request_id),
185 security_origin(security_origin),
186 user_gesture(user_gesture),
187 request_type(request_type),
189 salt_callback(salt_callback),
190 state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED),
191 audio_type_(MEDIA_NO_SERVICE),
192 video_type_(MEDIA_NO_SERVICE) {
197 void SetAudioType(MediaStreamType audio_type) {
198 DCHECK(IsAudioMediaType(audio_type) || audio_type == MEDIA_NO_SERVICE);
199 audio_type_ = audio_type;
202 MediaStreamType audio_type() const { return audio_type_; }
204 void SetVideoType(MediaStreamType video_type) {
205 DCHECK(IsVideoMediaType(video_type) || video_type == MEDIA_NO_SERVICE);
206 video_type_ = video_type;
209 MediaStreamType video_type() const { return video_type_; }
211 // Creates a MediaStreamRequest object that is used by this request when UI
212 // is asked for permission and device selection.
213 void CreateUIRequest(const std::string& requested_audio_device_id,
214 const std::string& requested_video_device_id) {
215 DCHECK(!ui_request_);
216 ui_request_.reset(new MediaStreamRequest(requesting_process_id,
222 requested_audio_device_id,
223 requested_video_device_id,
228 // Creates a tab capture specific MediaStreamRequest object that is used by
229 // this request when UI is asked for permission and device selection.
230 void CreateTabCatureUIRequest(int target_render_process_id,
231 int target_render_view_id,
232 const std::string& tab_capture_id) {
233 DCHECK(!ui_request_);
234 ui_request_.reset(new MediaStreamRequest(target_render_process_id,
235 target_render_view_id,
244 ui_request_->tab_capture_device_id = tab_capture_id;
247 const MediaStreamRequest* UIRequest() const { return ui_request_.get(); }
249 // Update the request state and notify observers.
250 void SetState(MediaStreamType stream_type, MediaRequestState new_state) {
251 if (stream_type == NUM_MEDIA_TYPES) {
252 for (int i = MEDIA_NO_SERVICE + 1; i < NUM_MEDIA_TYPES; ++i) {
253 const MediaStreamType stream_type = static_cast<MediaStreamType>(i);
254 state_[stream_type] = new_state;
257 state_[stream_type] = new_state;
260 MediaObserver* media_observer =
261 GetContentClient()->browser()->GetMediaObserver();
265 // If |ui_request_| doesn't exist, it means that the request has not yet
266 // been setup fully and there are no valid observers.
270 // If we appended a device_id scheme, we want to remove it when notifying
271 // observers which may be in different modules since this scheme is only
272 // used internally within the content module.
273 std::string device_id =
274 WebContentsCaptureUtil::StripWebContentsDeviceScheme(
275 ui_request_->tab_capture_device_id);
277 media_observer->OnMediaRequestStateChanged(
278 ui_request_->render_process_id, ui_request_->render_view_id,
279 ui_request_->page_request_id, ui_request_->security_origin,
280 MediaStreamDevice(stream_type, device_id, device_id), new_state);
283 MediaRequestState state(MediaStreamType stream_type) const {
284 return state_[stream_type];
287 MediaStreamRequester* const requester; // Can be NULL.
290 // The render process id that requested this stream to be generated and that
291 // will receive a handle to the MediaStream. This may be different from
292 // MediaStreamRequest::render_process_id which in the tab capture case
293 // specifies the target renderer from which audio and video is captured.
294 const int requesting_process_id;
296 // The render view id that requested this stream to be generated and that
297 // will receive a handle to the MediaStream. This may be different from
298 // MediaStreamRequest::render_view_id which in the tab capture case
299 // specifies the target renderer from which audio and video is captured.
300 const int requesting_view_id;
302 // An ID the render view provided to identify this request.
303 const int page_request_id;
305 const GURL security_origin;
307 const bool user_gesture;
309 const MediaStreamRequestType request_type;
311 const StreamOptions options;
313 ResourceContext::SaltCallback salt_callback;
315 StreamDeviceInfoArray devices;
317 // Callback to the requester which audio/video devices have been selected.
318 // It can be null if the requester has no interest to know the result.
319 // Currently it is only used by |DEVICE_ACCESS| type.
320 MediaStreamManager::MediaRequestResponseCallback callback;
322 scoped_ptr<MediaStreamUIProxy> ui_proxy;
325 std::vector<MediaRequestState> state_;
326 scoped_ptr<MediaStreamRequest> ui_request_;
327 MediaStreamType audio_type_;
328 MediaStreamType video_type_;
331 MediaStreamManager::EnumerationCache::EnumerationCache()
335 MediaStreamManager::EnumerationCache::~EnumerationCache() {
338 MediaStreamManager::MediaStreamManager()
339 : audio_manager_(NULL),
340 monitoring_started_(false),
342 use_fake_ui_(false) {}
344 MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager)
345 : audio_manager_(audio_manager),
346 monitoring_started_(false),
348 use_fake_ui_(false) {
349 DCHECK(audio_manager_);
350 memset(active_enumeration_ref_count_, 0,
351 sizeof(active_enumeration_ref_count_));
353 // Some unit tests create the MSM in the IO thread and assumes the
354 // initialization is done synchronously.
355 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
356 InitializeDeviceManagersOnIOThread();
358 BrowserThread::PostTask(
359 BrowserThread::IO, FROM_HERE,
360 base::Bind(&MediaStreamManager::InitializeDeviceManagersOnIOThread,
361 base::Unretained(this)));
364 base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
365 // BrowserMainLoop always creates the PowerMonitor instance before creating
366 // MediaStreamManager, but power_monitor may be NULL in unit tests.
368 power_monitor->AddObserver(this);
371 MediaStreamManager::~MediaStreamManager() {
372 DVLOG(1) << "~MediaStreamManager";
373 DCHECK(requests_.empty());
374 DCHECK(!device_task_runner_);
376 base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
377 // The PowerMonitor instance owned by BrowserMainLoops always outlives the
378 // MediaStreamManager, but it may be NULL in unit tests.
380 power_monitor->RemoveObserver(this);
383 VideoCaptureManager* MediaStreamManager::video_capture_manager() {
384 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
385 DCHECK(video_capture_manager_.get());
386 return video_capture_manager_.get();
389 AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() {
390 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
391 DCHECK(audio_input_device_manager_.get());
392 return audio_input_device_manager_.get();
395 std::string MediaStreamManager::MakeMediaAccessRequest(
396 int render_process_id,
399 const StreamOptions& options,
400 const GURL& security_origin,
401 const MediaRequestResponseCallback& callback) {
402 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
404 // TODO(perkj): The argument list with NULL parameters to DeviceRequest
405 // suggests that this is the wrong design. Can this be refactored?
406 DeviceRequest* request = new DeviceRequest(NULL,
411 false, // user gesture
414 base::Bind(&ReturnEmptySalt));
416 const std::string& label = AddRequest(request);
418 request->callback = callback;
419 // Post a task and handle the request asynchronously. The reason is that the
420 // requester won't have a label for the request until this function returns
421 // and thus can not handle a response. Using base::Unretained is safe since
422 // MediaStreamManager is deleted on the UI thread, after the IO thread has
424 BrowserThread::PostTask(
425 BrowserThread::IO, FROM_HERE,
426 base::Bind(&MediaStreamManager::SetupRequest,
427 base::Unretained(this), label));
431 void MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
432 int render_process_id,
434 const ResourceContext::SaltCallback& sc,
436 const StreamOptions& options,
437 const GURL& security_origin,
439 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
440 DVLOG(1) << "GenerateStream()";
441 if (CommandLine::ForCurrentProcess()->HasSwitch(
442 switches::kUseFakeUIForMediaStream)) {
443 UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy>());
446 DeviceRequest* request = new DeviceRequest(requester,
452 MEDIA_GENERATE_STREAM,
456 const std::string& label = AddRequest(request);
458 // Post a task and handle the request asynchronously. The reason is that the
459 // requester won't have a label for the request until this function returns
460 // and thus can not handle a response. Using base::Unretained is safe since
461 // MediaStreamManager is deleted on the UI thread, after the IO thread has
463 BrowserThread::PostTask(
464 BrowserThread::IO, FROM_HERE,
465 base::Bind(&MediaStreamManager::SetupRequest,
466 base::Unretained(this), label));
469 void MediaStreamManager::CancelRequest(int render_process_id,
471 int page_request_id) {
472 for (DeviceRequests::const_iterator request_it = requests_.begin();
473 request_it != requests_.end(); ++request_it) {
474 const DeviceRequest* request = request_it->second;
475 if (request->requesting_process_id == render_process_id &&
476 request->requesting_view_id == render_view_id &&
477 request->page_request_id == page_request_id) {
478 CancelRequest(request_it->first);
485 void MediaStreamManager::CancelRequest(const std::string& label) {
486 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
487 DVLOG(1) << "CancelRequest({label = " << label << "})";
488 DeviceRequest* request = FindRequest(label);
490 // The request does not exist.
491 LOG(ERROR) << "The request with label = " << label << " does not exist.";
495 if (request->request_type == MEDIA_ENUMERATE_DEVICES) {
496 // It isn't an ideal use of "CancelRequest" to make it a requirement
497 // for enumeration requests to be deleted via "CancelRequest" _after_
498 // the request has been successfully fulfilled.
499 // See note in FinalizeEnumerateDevices for a recommendation on how
500 // we should refactor this.
501 DeleteRequest(label);
505 // This is a request for opening one or more devices.
506 for (StreamDeviceInfoArray::iterator device_it = request->devices.begin();
507 device_it != request->devices.end(); ++device_it) {
508 MediaRequestState state = request->state(device_it->device.type);
509 // If we have not yet requested the device to be opened - just ignore it.
510 if (state != MEDIA_REQUEST_STATE_OPENING &&
511 state != MEDIA_REQUEST_STATE_DONE) {
514 // Stop the opening/opened devices of the requests.
515 CloseDevice(device_it->device.type, device_it->session_id);
518 // Cancel the request if still pending at UI side.
519 request->SetState(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_CLOSING);
520 DeleteRequest(label);
523 void MediaStreamManager::CancelAllRequests(int render_process_id) {
524 DeviceRequests::iterator request_it = requests_.begin();
525 while (request_it != requests_.end()) {
526 if (request_it->second->requesting_process_id != render_process_id) {
531 std::string label = request_it->first;
533 CancelRequest(label);
537 void MediaStreamManager::StopStreamDevice(int render_process_id,
539 const std::string& device_id) {
540 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
541 DVLOG(1) << "StopStreamDevice({render_view_id = " << render_view_id << "} "
542 << ", {device_id = " << device_id << "})";
543 // Find the first request for this |render_process_id| and |render_view_id|
544 // of type MEDIA_GENERATE_STREAM that has requested to use |device_id| and
546 for (DeviceRequests::iterator request_it = requests_.begin();
547 request_it != requests_.end(); ++request_it) {
548 DeviceRequest* request = request_it->second;
549 if (request->requesting_process_id != render_process_id ||
550 request->requesting_view_id != render_view_id ||
551 request->request_type != MEDIA_GENERATE_STREAM) {
555 StreamDeviceInfoArray& devices = request->devices;
556 for (StreamDeviceInfoArray::iterator device_it = devices.begin();
557 device_it != devices.end(); ++device_it) {
558 if (device_it->device.id == device_id) {
559 StopDevice(device_it->device.type, device_it->session_id);
566 void MediaStreamManager::StopDevice(MediaStreamType type, int session_id) {
567 DVLOG(1) << "StopDevice"
568 << "{type = " << type << "}"
569 << "{session_id = " << session_id << "}";
570 DeviceRequests::iterator request_it = requests_.begin();
571 while (request_it != requests_.end()) {
572 DeviceRequest* request = request_it->second;
573 StreamDeviceInfoArray* devices = &request->devices;
574 if (devices->empty()) {
575 // There is no device in use yet by this request.
579 StreamDeviceInfoArray::iterator device_it = devices->begin();
580 while (device_it != devices->end()) {
581 if (device_it->device.type != type ||
582 device_it->session_id != session_id) {
587 if (request->state(type) == MEDIA_REQUEST_STATE_DONE)
588 CloseDevice(type, session_id);
589 device_it = devices->erase(device_it);
592 // If this request doesn't have any active devices after a device
593 // has been stopped above, remove the request. Note that the request is
594 // only deleted if a device as been removed from |devices|.
595 if (devices->empty()) {
596 std::string label = request_it->first;
598 DeleteRequest(label);
605 void MediaStreamManager::CloseDevice(MediaStreamType type, int session_id) {
606 DVLOG(1) << "CloseDevice("
607 << "{type = " << type << "} "
608 << "{session_id = " << session_id << "})";
609 GetDeviceManager(type)->Close(session_id);
611 for (DeviceRequests::iterator request_it = requests_.begin();
612 request_it != requests_.end() ; ++request_it) {
613 StreamDeviceInfoArray* devices = &request_it->second->devices;
614 for (StreamDeviceInfoArray::iterator device_it = devices->begin();
615 device_it != devices->end(); ++device_it) {
616 if (device_it->session_id == session_id &&
617 device_it->device.type == type) {
618 // Notify observers that this device is being closed.
619 // Note that only one device per type can be opened.
620 request_it->second->SetState(type, MEDIA_REQUEST_STATE_CLOSING);
626 std::string MediaStreamManager::EnumerateDevices(
627 MediaStreamRequester* requester,
628 int render_process_id,
630 const ResourceContext::SaltCallback& sc,
632 MediaStreamType type,
633 const GURL& security_origin) {
634 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
636 DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
637 type == MEDIA_DEVICE_VIDEO_CAPTURE);
639 DeviceRequest* request = new DeviceRequest(requester,
644 false, // user gesture
645 MEDIA_ENUMERATE_DEVICES,
648 if (IsAudioMediaType(type))
649 request->SetAudioType(type);
650 else if (IsVideoMediaType(type))
651 request->SetVideoType(type);
653 const std::string& label = AddRequest(request);
654 // Post a task and handle the request asynchronously. The reason is that the
655 // requester won't have a label for the request until this function returns
656 // and thus can not handle a response. Using base::Unretained is safe since
657 // MediaStreamManager is deleted on the UI thread, after the IO thread has
659 BrowserThread::PostTask(
660 BrowserThread::IO, FROM_HERE,
661 base::Bind(&MediaStreamManager::DoEnumerateDevices,
662 base::Unretained(this), label));
666 void MediaStreamManager::DoEnumerateDevices(const std::string& label) {
667 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
668 DeviceRequest* request = FindRequest(label);
670 return; // This can happen if the request has been canceled.
672 MediaStreamType type;
673 EnumerationCache* cache;
674 if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE) {
675 DCHECK_EQ(MEDIA_NO_SERVICE, request->video_type());
676 type = MEDIA_DEVICE_AUDIO_CAPTURE;
677 cache = &audio_enumeration_cache_;
679 DCHECK_EQ(MEDIA_DEVICE_VIDEO_CAPTURE, request->video_type());
680 type = MEDIA_DEVICE_VIDEO_CAPTURE;
681 cache = &video_enumeration_cache_;
684 if (!EnumerationRequired(cache, type)) {
685 // Cached device list of this type exists. Just send it out.
686 request->SetState(type, MEDIA_REQUEST_STATE_REQUESTED);
687 request->devices = cache->devices;
688 FinalizeEnumerateDevices(label, request);
690 StartEnumeration(request);
692 DVLOG(1) << "Enumerate Devices ({label = " << label << "})";
695 void MediaStreamManager::OpenDevice(MediaStreamRequester* requester,
696 int render_process_id,
698 const ResourceContext::SaltCallback& sc,
700 const std::string& device_id,
701 MediaStreamType type,
702 const GURL& security_origin) {
703 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
704 DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
705 type == MEDIA_DEVICE_VIDEO_CAPTURE);
706 DVLOG(1) << "OpenDevice ({page_request_id = " << page_request_id << "})";
707 StreamOptions options;
708 if (IsAudioMediaType(type)) {
709 options.audio_requested = true;
710 options.mandatory_audio.push_back(
711 StreamOptions::Constraint(kMediaStreamSourceInfoId, device_id));
712 } else if (IsVideoMediaType(type)) {
713 options.video_requested = true;
714 options.mandatory_video.push_back(
715 StreamOptions::Constraint(kMediaStreamSourceInfoId, device_id));
719 DeviceRequest* request = new DeviceRequest(requester,
724 false, // user gesture
729 const std::string& label = AddRequest(request);
730 // Post a task and handle the request asynchronously. The reason is that the
731 // requester won't have a label for the request until this function returns
732 // and thus can not handle a response. Using base::Unretained is safe since
733 // MediaStreamManager is deleted on the UI thread, after the IO thread has
735 BrowserThread::PostTask(
736 BrowserThread::IO, FROM_HERE,
737 base::Bind(&MediaStreamManager::SetupRequest,
738 base::Unretained(this), label));
741 void MediaStreamManager::EnsureDeviceMonitorStarted() {
742 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
746 void MediaStreamManager::StopRemovedDevices(
747 const StreamDeviceInfoArray& old_devices,
748 const StreamDeviceInfoArray& new_devices) {
749 DVLOG(1) << "StopRemovedDevices("
750 << "{#old_devices = " << old_devices.size() << "} "
751 << "{#new_devices = " << new_devices.size() << "})";
752 for (StreamDeviceInfoArray::const_iterator old_dev_it = old_devices.begin();
753 old_dev_it != old_devices.end(); ++old_dev_it) {
754 bool device_found = false;
755 StreamDeviceInfoArray::const_iterator new_dev_it = new_devices.begin();
756 for (; new_dev_it != new_devices.end(); ++new_dev_it) {
757 if (old_dev_it->device.id == new_dev_it->device.id) {
764 // A device has been removed. We need to check if it is used by a
765 // MediaStream and in that case cleanup and notify the render process.
766 StopRemovedDevice(old_dev_it->device);
771 void MediaStreamManager::StopRemovedDevice(const MediaStreamDevice& device) {
772 std::vector<int> session_ids;
773 for (DeviceRequests::const_iterator it = requests_.begin();
774 it != requests_.end() ; ++it) {
775 const DeviceRequest* request = it->second;
776 for (StreamDeviceInfoArray::const_iterator device_it =
777 request->devices.begin();
778 device_it != request->devices.end(); ++device_it) {
779 std::string source_id = content::GetHMACForMediaDeviceID(
780 request->salt_callback,
781 request->security_origin,
783 if (device_it->device.id == source_id &&
784 device_it->device.type == device.type) {
785 session_ids.push_back(device_it->session_id);
786 if (it->second->requester) {
787 it->second->requester->DeviceStopped(
788 it->second->requesting_view_id,
795 for (std::vector<int>::const_iterator it = session_ids.begin();
796 it != session_ids.end(); ++it) {
797 StopDevice(device.type, *it);
801 void MediaStreamManager::StartMonitoring() {
802 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
803 if (monitoring_started_)
806 if (!base::SystemMonitor::Get())
809 monitoring_started_ = true;
810 base::SystemMonitor::Get()->AddDevicesChangedObserver(this);
812 // Enumerate both the audio and video devices to cache the device lists
813 // and send them to media observer.
814 ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_CAPTURE];
815 audio_input_device_manager_->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE);
816 ++active_enumeration_ref_count_[MEDIA_DEVICE_VIDEO_CAPTURE];
817 video_capture_manager_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
819 #if defined(OS_MACOSX)
820 BrowserThread::PostTask(
821 BrowserThread::UI, FROM_HERE,
822 base::Bind(&MediaStreamManager::StartMonitoringOnUIThread,
823 base::Unretained(this)));
827 #if defined(OS_MACOSX)
828 void MediaStreamManager::StartMonitoringOnUIThread() {
829 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
830 BrowserMainLoop* browser_main_loop = content::BrowserMainLoop::GetInstance();
831 if (browser_main_loop)
832 browser_main_loop->device_monitor_mac()->StartMonitoring();
836 void MediaStreamManager::StopMonitoring() {
837 DCHECK_EQ(base::MessageLoop::current(), io_loop_);
838 if (monitoring_started_) {
839 base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this);
840 monitoring_started_ = false;
841 ClearEnumerationCache(&audio_enumeration_cache_);
842 ClearEnumerationCache(&video_enumeration_cache_);
846 bool MediaStreamManager::GetRequestedDeviceCaptureId(
847 const DeviceRequest* request,
848 MediaStreamType type,
849 std::string* device_id) const {
850 DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
851 type == MEDIA_DEVICE_VIDEO_CAPTURE);
852 const StreamOptions::Constraints* mandatory =
853 (type == MEDIA_DEVICE_AUDIO_CAPTURE) ?
854 &request->options.mandatory_audio : &request->options.mandatory_video;
855 const StreamOptions::Constraints* optional =
856 (type == MEDIA_DEVICE_AUDIO_CAPTURE) ?
857 &request->options.optional_audio : &request->options.optional_video;
859 std::vector<std::string> source_ids;
860 StreamOptions::GetConstraintsByName(*mandatory,
861 kMediaStreamSourceInfoId, &source_ids);
862 if (source_ids.size() > 1) {
863 LOG(ERROR) << "Only one mandatory " << kMediaStreamSourceInfoId
867 // If a specific device has been requested we need to find the real device
869 if (source_ids.size() == 1 &&
870 !TranslateSourceIdToDeviceId(type,
871 request->salt_callback,
872 request->security_origin,
873 source_ids[0], device_id)) {
874 LOG(WARNING) << "Invalid mandatory " << kMediaStreamSourceInfoId
875 << " = " << source_ids[0] << ".";
878 // Check for optional audio sourceIDs.
879 if (device_id->empty()) {
880 StreamOptions::GetConstraintsByName(*optional,
881 kMediaStreamSourceInfoId,
883 // Find the first sourceID that translates to device. Note that only one
884 // device per type can call to GenerateStream is ever opened.
885 for (std::vector<std::string>::const_iterator it = source_ids.begin();
886 it != source_ids.end(); ++it) {
887 if (TranslateSourceIdToDeviceId(type,
888 request->salt_callback,
889 request->security_origin,
899 void MediaStreamManager::TranslateDeviceIdToSourceId(
900 DeviceRequest* request,
901 MediaStreamDevice* device) {
902 if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
903 request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE) {
904 device->id = content::GetHMACForMediaDeviceID(
905 request->salt_callback,
906 request->security_origin,
911 bool MediaStreamManager::TranslateSourceIdToDeviceId(
912 MediaStreamType stream_type,
913 const ResourceContext::SaltCallback& sc,
914 const GURL& security_origin,
915 const std::string& source_id,
916 std::string* device_id) const {
917 DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ||
918 stream_type == MEDIA_DEVICE_VIDEO_CAPTURE);
919 // The source_id can be empty if the constraint is set but empty.
920 if (source_id.empty())
923 const EnumerationCache* cache =
924 stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
925 &audio_enumeration_cache_ : &video_enumeration_cache_;
927 // If device monitoring hasn't started, the |device_guid| is not valid.
931 for (StreamDeviceInfoArray::const_iterator it = cache->devices.begin();
932 it != cache->devices.end();
934 if (content::DoesMediaDeviceIDMatchHMAC(sc, security_origin, source_id,
936 *device_id = it->device.id;
943 void MediaStreamManager::ClearEnumerationCache(EnumerationCache* cache) {
944 DCHECK_EQ(base::MessageLoop::current(), io_loop_);
945 cache->valid = false;
948 bool MediaStreamManager::EnumerationRequired(EnumerationCache* cache,
949 MediaStreamType stream_type) {
950 DCHECK_EQ(base::MessageLoop::current(), io_loop_);
951 if (stream_type == MEDIA_NO_SERVICE)
954 DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ||
955 stream_type == MEDIA_DEVICE_VIDEO_CAPTURE);
957 #if defined(OS_ANDROID)
958 // There's no SystemMonitor on Android that notifies us when devices are
959 // added or removed, so we need to populate the cache on every request.
960 // Fortunately, there is an already up-to-date cache in the browser side
961 // audio manager that we can rely on, so the performance impact of
962 // invalidating the cache like this, is minimal.
963 if (stream_type == MEDIA_DEVICE_AUDIO_CAPTURE) {
964 // Make sure the cache is marked as invalid so that FinalizeEnumerateDevices
965 // will be called at the end of the enumeration.
966 ClearEnumerationCache(cache);
969 // If the cache isn't valid, we need to start a full enumeration.
970 return !cache->valid;
973 void MediaStreamManager::StartEnumeration(DeviceRequest* request) {
974 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
976 // Start monitoring the devices when doing the first enumeration.
979 // Start enumeration for devices of all requested device types.
980 const MediaStreamType streams[] = { request->audio_type(),
981 request->video_type() };
982 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(streams); ++i) {
983 if (streams[i] == MEDIA_NO_SERVICE)
985 request->SetState(streams[i], MEDIA_REQUEST_STATE_REQUESTED);
986 DCHECK_GE(active_enumeration_ref_count_[streams[i]], 0);
987 if (active_enumeration_ref_count_[streams[i]] == 0) {
988 ++active_enumeration_ref_count_[streams[i]];
989 GetDeviceManager(streams[i])->EnumerateDevices(streams[i]);
994 std::string MediaStreamManager::AddRequest(DeviceRequest* request) {
995 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
997 // Create a label for this request and verify it is unique.
998 std::string unique_label;
1000 unique_label = RandomLabel();
1001 } while (requests_.find(unique_label) != requests_.end());
1003 requests_.insert(std::make_pair(unique_label, request));
1005 return unique_label;
1008 MediaStreamManager::DeviceRequest*
1009 MediaStreamManager::FindRequest(const std::string& label) const {
1010 DeviceRequests::const_iterator request_it = requests_.find(label);
1011 return request_it == requests_.end() ? NULL : request_it->second;
1014 void MediaStreamManager::DeleteRequest(const std::string& label) {
1015 DVLOG(1) << "DeleteRequest({label= " << label << "})";
1016 DeviceRequests::iterator it = requests_.find(label);
1017 scoped_ptr<DeviceRequest> request(it->second);
1018 requests_.erase(it);
1021 void MediaStreamManager::PostRequestToUI(const std::string& label,
1022 DeviceRequest* request) {
1023 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1024 DCHECK(request->UIRequest());
1025 DVLOG(1) << "PostRequestToUI({label= " << label << "})";
1027 const MediaStreamType audio_type = request->audio_type();
1028 const MediaStreamType video_type = request->video_type();
1030 // Post the request to UI and set the state.
1031 if (IsAudioMediaType(audio_type))
1032 request->SetState(audio_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
1033 if (IsVideoMediaType(video_type))
1034 request->SetState(video_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
1038 fake_ui_.reset(new FakeMediaStreamUIProxy());
1040 MediaStreamDevices devices;
1041 if (audio_enumeration_cache_.valid) {
1042 for (StreamDeviceInfoArray::const_iterator it =
1043 audio_enumeration_cache_.devices.begin();
1044 it != audio_enumeration_cache_.devices.end(); ++it) {
1045 devices.push_back(it->device);
1048 if (video_enumeration_cache_.valid) {
1049 for (StreamDeviceInfoArray::const_iterator it =
1050 video_enumeration_cache_.devices.begin();
1051 it != video_enumeration_cache_.devices.end(); ++it) {
1052 devices.push_back(it->device);
1056 fake_ui_->SetAvailableDevices(devices);
1058 request->ui_proxy = fake_ui_.Pass();
1060 request->ui_proxy = MediaStreamUIProxy::Create();
1063 request->ui_proxy->RequestAccess(
1064 *request->UIRequest(),
1065 base::Bind(&MediaStreamManager::HandleAccessRequestResponse,
1066 base::Unretained(this), label));
1069 void MediaStreamManager::SetupRequest(const std::string& label) {
1070 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1071 DeviceRequest* request = FindRequest(label);
1073 DVLOG(1) << "SetupRequest label " << label << " doesn't exist!!";
1074 return; // This can happen if the request has been canceled.
1077 if (!request->security_origin.is_valid()) {
1078 LOG(ERROR) << "Invalid security origin. "
1079 << request->security_origin;
1080 FinalizeRequestFailed(label,
1082 MEDIA_DEVICE_INVALID_SECURITY_ORIGIN);
1086 MediaStreamType audio_type = MEDIA_NO_SERVICE;
1087 MediaStreamType video_type = MEDIA_NO_SERVICE;
1088 ParseStreamType(request->options, &audio_type, &video_type);
1089 request->SetAudioType(audio_type);
1090 request->SetVideoType(video_type);
1092 bool is_web_contents_capture =
1093 audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
1094 video_type == MEDIA_TAB_VIDEO_CAPTURE;
1095 if (is_web_contents_capture && !SetupTabCaptureRequest(request)) {
1096 FinalizeRequestFailed(label,
1098 MEDIA_DEVICE_TAB_CAPTURE_FAILURE);
1102 bool is_screen_capture =
1103 video_type == MEDIA_DESKTOP_VIDEO_CAPTURE;
1104 if (is_screen_capture && !SetupScreenCaptureRequest(request)) {
1105 FinalizeRequestFailed(label,
1107 MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE);
1111 if (!is_web_contents_capture && !is_screen_capture) {
1112 if (EnumerationRequired(&audio_enumeration_cache_, audio_type) ||
1113 EnumerationRequired(&video_enumeration_cache_, video_type)) {
1114 // Enumerate the devices if there is no valid device lists to be used.
1115 StartEnumeration(request);
1118 // Cache is valid, so log the cached devices for MediaStream requests.
1119 if (request->request_type == MEDIA_GENERATE_STREAM) {
1120 std::string log_message("Using cached devices for request.\n");
1121 if (audio_type != MEDIA_NO_SERVICE) {
1123 GetLogMessageString(audio_type, audio_enumeration_cache_.devices);
1125 if (video_type != MEDIA_NO_SERVICE) {
1127 GetLogMessageString(video_type, video_enumeration_cache_.devices);
1129 SendMessageToNativeLog(log_message);
1133 if (!SetupDeviceCaptureRequest(request)) {
1134 FinalizeRequestFailed(label, request, MEDIA_DEVICE_NO_HARDWARE);
1138 PostRequestToUI(label, request);
1141 bool MediaStreamManager::SetupDeviceCaptureRequest(DeviceRequest* request) {
1142 DCHECK((request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
1143 request->audio_type() == MEDIA_NO_SERVICE) &&
1144 (request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE ||
1145 request->video_type() == MEDIA_NO_SERVICE));
1146 std::string audio_device_id;
1147 if (request->options.audio_requested &&
1148 !GetRequestedDeviceCaptureId(request, request->audio_type(),
1149 &audio_device_id)) {
1153 std::string video_device_id;
1154 if (request->options.video_requested &&
1155 !GetRequestedDeviceCaptureId(request, request->video_type(),
1156 &video_device_id)) {
1159 request->CreateUIRequest(audio_device_id, video_device_id);
1160 DVLOG(3) << "Audio requested " << request->options.audio_requested
1161 << " device id = " << audio_device_id
1162 << "Video requested " << request->options.video_requested
1163 << " device id = " << video_device_id;
1167 bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
1168 DCHECK(request->audio_type() == MEDIA_TAB_AUDIO_CAPTURE ||
1169 request->video_type() == MEDIA_TAB_VIDEO_CAPTURE);
1171 std::string capture_device_id;
1172 bool mandatory_audio = false;
1173 bool mandatory_video = false;
1174 if (!request->options.GetFirstAudioConstraintByName(kMediaStreamSourceId,
1176 &mandatory_audio) &&
1177 !request->options.GetFirstVideoConstraintByName(kMediaStreamSourceId,
1179 &mandatory_video)) {
1182 DCHECK(mandatory_audio || mandatory_video);
1184 // Customize options for a WebContents based capture.
1185 int target_render_process_id = 0;
1186 int target_render_view_id = 0;
1188 // TODO(justinlin): Can't plumb audio mirroring using stream type right
1189 // now, so plumbing by device_id. Will revisit once it's refactored.
1190 // http://crbug.com/163100
1191 std::string tab_capture_device_id =
1192 WebContentsCaptureUtil::AppendWebContentsDeviceScheme(capture_device_id);
1194 bool has_valid_device_id = WebContentsCaptureUtil::ExtractTabCaptureTarget(
1195 tab_capture_device_id, &target_render_process_id,
1196 &target_render_view_id);
1197 if (!has_valid_device_id ||
1198 (request->audio_type() != MEDIA_TAB_AUDIO_CAPTURE &&
1199 request->audio_type() != MEDIA_NO_SERVICE) ||
1200 (request->video_type() != MEDIA_TAB_VIDEO_CAPTURE &&
1201 request->video_type() != MEDIA_NO_SERVICE)) {
1205 request->CreateTabCatureUIRequest(target_render_process_id,
1206 target_render_view_id,
1207 tab_capture_device_id);
1209 DVLOG(3) << "SetupTabCaptureRequest "
1210 << ", {tab_capture_device_id = " << tab_capture_device_id << "}"
1211 << ", {target_render_process_id = " << target_render_process_id
1213 << ", {target_render_view_id = " << target_render_view_id << "}";
1217 bool MediaStreamManager::SetupScreenCaptureRequest(DeviceRequest* request) {
1218 DCHECK(request->audio_type() == MEDIA_LOOPBACK_AUDIO_CAPTURE ||
1219 request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE);
1221 // For screen capture we only support two valid combinations:
1222 // (1) screen video capture only, or
1223 // (2) screen video capture with loopback audio capture.
1224 if (request->video_type() != MEDIA_DESKTOP_VIDEO_CAPTURE ||
1225 (request->audio_type() != MEDIA_NO_SERVICE &&
1226 request->audio_type() != MEDIA_LOOPBACK_AUDIO_CAPTURE)) {
1227 LOG(ERROR) << "Invalid screen capture request.";
1231 std::string video_device_id;
1232 if (request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE) {
1233 std::string video_stream_source;
1234 bool mandatory = false;
1235 if (!request->options.GetFirstVideoConstraintByName(
1237 &video_stream_source,
1239 LOG(ERROR) << kMediaStreamSource << " not found.";
1244 if (video_stream_source == kMediaStreamSourceDesktop) {
1245 if (!request->options.GetFirstVideoConstraintByName(
1246 kMediaStreamSourceId,
1249 LOG(ERROR) << kMediaStreamSourceId << " not found.";
1256 request->CreateUIRequest("", video_device_id);
1260 StreamDeviceInfoArray MediaStreamManager::GetDevicesOpenedByRequest(
1261 const std::string& label) const {
1262 DeviceRequest* request = FindRequest(label);
1264 return StreamDeviceInfoArray();
1265 return request->devices;
1268 bool MediaStreamManager::FindExistingRequestedDeviceInfo(
1269 const DeviceRequest& new_request,
1270 const MediaStreamDevice& new_device_info,
1271 StreamDeviceInfo* existing_device_info,
1272 MediaRequestState* existing_request_state) const {
1273 DCHECK(existing_device_info);
1274 DCHECK(existing_request_state);
1276 std::string source_id = content::GetHMACForMediaDeviceID(
1277 new_request.salt_callback,
1278 new_request.security_origin,
1279 new_device_info.id);
1281 for (DeviceRequests::const_iterator it = requests_.begin();
1282 it != requests_.end() ; ++it) {
1283 const DeviceRequest* request = it->second;
1284 if (request->requesting_process_id == new_request.requesting_process_id &&
1285 request->requesting_view_id == new_request.requesting_view_id &&
1286 request->request_type == new_request.request_type) {
1287 for (StreamDeviceInfoArray::const_iterator device_it =
1288 request->devices.begin();
1289 device_it != request->devices.end(); ++device_it) {
1290 if (device_it->device.id == source_id &&
1291 device_it->device.type == new_device_info.type) {
1292 *existing_device_info = *device_it;
1293 *existing_request_state = request->state(device_it->device.type);
1302 void MediaStreamManager::FinalizeGenerateStream(const std::string& label,
1303 DeviceRequest* request) {
1304 DVLOG(1) << "FinalizeGenerateStream label " << label;
1305 const StreamDeviceInfoArray& requested_devices = request->devices;
1307 // Partition the array of devices into audio vs video.
1308 StreamDeviceInfoArray audio_devices, video_devices;
1309 for (StreamDeviceInfoArray::const_iterator device_it =
1310 requested_devices.begin();
1311 device_it != requested_devices.end(); ++device_it) {
1312 if (IsAudioMediaType(device_it->device.type)) {
1313 audio_devices.push_back(*device_it);
1314 } else if (IsVideoMediaType(device_it->device.type)) {
1315 video_devices.push_back(*device_it);
1321 request->requester->StreamGenerated(
1322 request->requesting_view_id,
1323 request->page_request_id,
1324 label, audio_devices, video_devices);
1327 void MediaStreamManager::FinalizeRequestFailed(
1328 const std::string& label,
1329 DeviceRequest* request,
1330 content::MediaStreamRequestResult result) {
1331 if (request->requester)
1332 request->requester->StreamGenerationFailed(
1333 request->requesting_view_id,
1334 request->page_request_id,
1337 if (request->request_type == MEDIA_DEVICE_ACCESS &&
1338 !request->callback.is_null()) {
1339 request->callback.Run(MediaStreamDevices(), request->ui_proxy.Pass());
1342 DeleteRequest(label);
1345 void MediaStreamManager::FinalizeOpenDevice(const std::string& label,
1346 DeviceRequest* request) {
1347 const StreamDeviceInfoArray& requested_devices = request->devices;
1348 request->requester->DeviceOpened(request->requesting_view_id,
1349 request->page_request_id,
1350 label, requested_devices.front());
1353 void MediaStreamManager::FinalizeEnumerateDevices(const std::string& label,
1354 DeviceRequest* request) {
1355 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1356 DCHECK_EQ(request->request_type, MEDIA_ENUMERATE_DEVICES);
1358 if (request->security_origin.is_valid()) {
1359 for (StreamDeviceInfoArray::iterator it = request->devices.begin();
1360 it != request->devices.end(); ++it) {
1361 TranslateDeviceIdToSourceId(request, &it->device);
1364 request->devices.clear();
1367 request->requester->DevicesEnumerated(
1368 request->requesting_view_id,
1369 request->page_request_id,
1374 // Ideally enumeration requests should be deleted once they have been served
1375 // (as any request). However, this implementation mixes requests and
1376 // notifications together so enumeration requests are kept open by some
1377 // implementations (only Pepper?) and enumerations are done again when
1378 // device notifications are fired.
1379 // Implementations that just want to request the device list and be done
1380 // (e.g. DeviceRequestMessageFilter), they must (confusingly) call
1381 // CancelRequest() after the request has been fulfilled. This is not
1382 // obvious, not consistent in this class (see e.g. FinalizeMediaAccessRequest)
1383 // and can lead to subtle bugs (requests not deleted at all deleted too
1386 // Basically, it is not clear that using requests as an additional layer on
1387 // top of device notifications is necessary or good.
1389 // To add to this, MediaStreamManager currently relies on the external
1390 // implementations of MediaStreamRequester to delete enumeration requests via
1391 // CancelRequest and e.g. DeviceRequestMessageFilter does this. However the
1392 // Pepper implementation does not seem to to this at all (and from what I can
1393 // see, it is the only implementation that uses an enumeration request as a
1394 // notification mechanism).
1396 // We should decouple notifications from enumeration requests and once that
1397 // has been done, remove the requirement to call CancelRequest() to delete
1398 // enumeration requests and uncomment the following line:
1400 // DeleteRequest(label);
1403 void MediaStreamManager::FinalizeMediaAccessRequest(
1404 const std::string& label,
1405 DeviceRequest* request,
1406 const MediaStreamDevices& devices) {
1407 if (!request->callback.is_null())
1408 request->callback.Run(devices, request->ui_proxy.Pass());
1410 // Delete the request since it is done.
1411 DeleteRequest(label);
1414 void MediaStreamManager::InitializeDeviceManagersOnIOThread() {
1415 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1416 if (device_task_runner_)
1419 device_task_runner_ = audio_manager_->GetWorkerTaskRunner();
1421 audio_input_device_manager_ = new AudioInputDeviceManager(audio_manager_);
1422 audio_input_device_manager_->Register(this, device_task_runner_);
1424 video_capture_manager_ = new VideoCaptureManager();
1425 video_capture_manager_->Register(this, device_task_runner_);
1427 // We want to be notified of IO message loop destruction to delete the thread
1428 // and the device managers.
1429 io_loop_ = base::MessageLoop::current();
1430 io_loop_->AddDestructionObserver(this);
1432 if (CommandLine::ForCurrentProcess()->HasSwitch(
1433 switches::kUseFakeDeviceForMediaStream)) {
1434 DVLOG(1) << "Using fake device";
1439 void MediaStreamManager::Opened(MediaStreamType stream_type,
1440 int capture_session_id) {
1441 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1442 DVLOG(1) << "Opened({stream_type = " << stream_type << "} "
1443 << "{capture_session_id = " << capture_session_id << "})";
1444 // Find the request(s) containing this device and mark it as used.
1445 // It can be used in several requests since the same device can be
1446 // requested from the same web page.
1447 for (DeviceRequests::iterator request_it = requests_.begin();
1448 request_it != requests_.end(); ++request_it) {
1449 const std::string& label = request_it->first;
1450 DeviceRequest* request = request_it->second;
1451 StreamDeviceInfoArray* devices = &(request->devices);
1452 for (StreamDeviceInfoArray::iterator device_it = devices->begin();
1453 device_it != devices->end(); ++device_it) {
1454 if (device_it->device.type == stream_type &&
1455 device_it->session_id == capture_session_id) {
1456 CHECK(request->state(device_it->device.type) ==
1457 MEDIA_REQUEST_STATE_OPENING);
1458 // We've found a matching request.
1459 request->SetState(device_it->device.type, MEDIA_REQUEST_STATE_DONE);
1461 if (IsAudioMediaType(device_it->device.type)) {
1462 // Store the native audio parameters in the device struct.
1463 // TODO(xians): Handle the tab capture sample rate/channel layout
1464 // in AudioInputDeviceManager::Open().
1465 if (device_it->device.type != content::MEDIA_TAB_AUDIO_CAPTURE) {
1466 const StreamDeviceInfo* info =
1467 audio_input_device_manager_->GetOpenedDeviceInfoById(
1468 device_it->session_id);
1469 device_it->device.input = info->device.input;
1470 device_it->device.matched_output = info->device.matched_output;
1473 if (RequestDone(*request))
1474 HandleRequestDone(label, request);
1481 void MediaStreamManager::HandleRequestDone(const std::string& label,
1482 DeviceRequest* request) {
1483 DCHECK(RequestDone(*request));
1484 DVLOG(1) << "HandleRequestDone("
1485 << ", {label = " << label << "})";
1487 switch (request->request_type) {
1488 case MEDIA_OPEN_DEVICE:
1489 FinalizeOpenDevice(label, request);
1491 case MEDIA_GENERATE_STREAM: {
1492 FinalizeGenerateStream(label, request);
1500 if (request->ui_proxy.get()) {
1501 request->ui_proxy->OnStarted(
1502 base::Bind(&MediaStreamManager::StopMediaStreamFromBrowser,
1503 base::Unretained(this),
1505 base::Bind(&MediaStreamManager::OnMediaStreamUIWindowId,
1506 base::Unretained(this),
1507 request->video_type(),
1512 void MediaStreamManager::Closed(MediaStreamType stream_type,
1513 int capture_session_id) {
1514 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1517 void MediaStreamManager::DevicesEnumerated(
1518 MediaStreamType stream_type, const StreamDeviceInfoArray& devices) {
1519 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1520 DVLOG(1) << "DevicesEnumerated("
1521 << "{stream_type = " << stream_type << "})" << std::endl;
1523 std::string log_message = "New device enumeration result:\n" +
1524 GetLogMessageString(stream_type, devices);
1525 SendMessageToNativeLog(log_message);
1527 // Only cache the device list when the device list has been changed.
1528 bool need_update_clients = false;
1529 EnumerationCache* cache =
1530 stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
1531 &audio_enumeration_cache_ : &video_enumeration_cache_;
1532 if (!cache->valid ||
1533 devices.size() != cache->devices.size() ||
1534 !std::equal(devices.begin(), devices.end(), cache->devices.begin(),
1535 StreamDeviceInfo::IsEqual)) {
1536 StopRemovedDevices(cache->devices, devices);
1537 cache->devices = devices;
1538 need_update_clients = true;
1540 // The device might not be able to be enumerated when it is not warmed up,
1541 // for example, when the machine just wakes up from sleep. We set the cache
1542 // to be invalid so that the next media request will trigger the
1543 // enumeration again. See issue/317673.
1544 cache->valid = !devices.empty();
1547 if (need_update_clients && monitoring_started_)
1548 NotifyDevicesChanged(stream_type, devices);
1550 // Publish the result for all requests waiting for device list(s).
1551 // Find the requests waiting for this device list, store their labels and
1552 // release the iterator before calling device settings. We might get a call
1553 // back from device_settings that will need to iterate through devices.
1554 std::list<std::string> label_list;
1555 for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
1557 if (it->second->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED &&
1558 (it->second->audio_type() == stream_type ||
1559 it->second->video_type() == stream_type)) {
1560 if (it->second->request_type != MEDIA_ENUMERATE_DEVICES)
1561 it->second->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
1562 label_list.push_back(it->first);
1566 for (std::list<std::string>::iterator it = label_list.begin();
1567 it != label_list.end(); ++it) {
1568 DeviceRequest* request = FindRequest(*it);
1569 switch (request->request_type) {
1570 case MEDIA_ENUMERATE_DEVICES:
1571 if (need_update_clients && request->requester) {
1572 request->devices = devices;
1573 FinalizeEnumerateDevices(*it, request);
1577 if (request->state(request->audio_type()) ==
1578 MEDIA_REQUEST_STATE_REQUESTED ||
1579 request->state(request->video_type()) ==
1580 MEDIA_REQUEST_STATE_REQUESTED) {
1581 // We are doing enumeration for other type of media, wait until it is
1582 // all done before posting the request to UI because UI needs
1583 // the device lists to handle the request.
1586 if (!SetupDeviceCaptureRequest(request)) {
1587 FinalizeRequestFailed(*it,
1589 MEDIA_DEVICE_NO_HARDWARE);
1591 PostRequestToUI(*it, request);
1597 --active_enumeration_ref_count_[stream_type];
1598 DCHECK_GE(active_enumeration_ref_count_[stream_type], 0);
1602 void MediaStreamManager::SendMessageToNativeLog(const std::string& message) {
1603 BrowserThread::PostTask(
1604 BrowserThread::UI, FROM_HERE,
1605 base::Bind(DoAddLogMessage, message));
1608 void MediaStreamManager::OnSuspend() {
1609 SendMessageToNativeLog("Power state suspended.");
1612 void MediaStreamManager::OnResume() {
1613 SendMessageToNativeLog("Power state resumed.");
1616 void MediaStreamManager::AddLogMessageOnIOThread(const std::string& message) {
1617 // Get render process ids on the IO thread.
1618 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1620 // Grab all unique process ids that request a MediaStream or have a
1621 // MediaStream running.
1622 std::set<int> requesting_process_ids;
1623 for (DeviceRequests::const_iterator it = requests_.begin();
1624 it != requests_.end(); ++it) {
1625 DeviceRequest* request = it->second;
1626 if (request->request_type == MEDIA_GENERATE_STREAM)
1627 requesting_process_ids.insert(request->requesting_process_id);
1630 // MediaStreamManager is a singleton in BrowserMainLoop, which owns the UI
1631 // thread. MediaStreamManager has the same lifetime as the UI thread, so it is
1632 // safe to use base::Unretained.
1633 BrowserThread::PostTask(
1636 base::Bind(&MediaStreamManager::AddLogMessageOnUIThread,
1637 base::Unretained(this),
1638 requesting_process_ids,
1642 void MediaStreamManager::AddLogMessageOnUIThread(
1643 const std::set<int>& requesting_process_ids,
1644 const std::string& message) {
1645 #if defined(ENABLE_WEBRTC)
1646 // Must be on the UI thread to access RenderProcessHost from process ID.
1647 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1649 for (std::set<int>::const_iterator it = requesting_process_ids.begin();
1650 it != requesting_process_ids.end(); ++it) {
1651 // Log the message to all renderers that are requesting a MediaStream or
1652 // have a MediaStream running.
1653 content::RenderProcessHostImpl* render_process_host_impl =
1654 static_cast<content::RenderProcessHostImpl*>(
1655 content::RenderProcessHost::FromID(*it));
1656 if (render_process_host_impl)
1657 render_process_host_impl->WebRtcLogMessage(message);
1662 void MediaStreamManager::HandleAccessRequestResponse(
1663 const std::string& label,
1664 const MediaStreamDevices& devices,
1665 content::MediaStreamRequestResult result) {
1666 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1667 DVLOG(1) << "HandleAccessRequestResponse("
1668 << ", {label = " << label << "})";
1670 DeviceRequest* request = FindRequest(label);
1672 // The request has been canceled before the UI returned.
1676 if (request->request_type == MEDIA_DEVICE_ACCESS) {
1677 FinalizeMediaAccessRequest(label, request, devices);
1681 // Handle the case when the request was denied.
1682 if (result != MEDIA_DEVICE_OK) {
1683 FinalizeRequestFailed(label, request, result);
1686 DCHECK(!devices.empty());
1688 // Process all newly-accepted devices for this request.
1689 bool found_audio = false;
1690 bool found_video = false;
1691 for (MediaStreamDevices::const_iterator device_it = devices.begin();
1692 device_it != devices.end(); ++device_it) {
1693 StreamDeviceInfo device_info;
1694 device_info.device = *device_it;
1696 // TODO(justinlin): Nicer way to do this?
1697 // Re-append the device's id since we lost it when posting request to UI.
1698 if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE ||
1699 device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
1700 device_info.device.id = request->UIRequest()->tab_capture_device_id;
1702 // Initialize the sample_rate and channel_layout here since for audio
1703 // mirroring, we don't go through EnumerateDevices where these are usually
1705 if (device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
1706 const media::AudioParameters parameters =
1707 audio_manager_->GetDefaultOutputStreamParameters();
1708 int sample_rate = parameters.sample_rate();
1709 // If we weren't able to get the native sampling rate or the sample_rate
1710 // is outside the valid range for input devices set reasonable defaults.
1711 if (sample_rate <= 0 || sample_rate > 96000)
1712 sample_rate = 44100;
1714 device_info.device.input.sample_rate = sample_rate;
1715 device_info.device.input.channel_layout = media::CHANNEL_LAYOUT_STEREO;
1719 if (device_info.device.type == request->audio_type()) {
1721 } else if (device_info.device.type == request->video_type()) {
1725 // If this is request for a new MediaStream, a device is only opened once
1726 // per render view. This is so that the permission to use a device can be
1727 // revoked by a single call to StopStreamDevice regardless of how many
1728 // MediaStreams it is being used in.
1729 if (request->request_type == MEDIA_GENERATE_STREAM) {
1730 MediaRequestState state;
1731 if (FindExistingRequestedDeviceInfo(*request,
1735 request->devices.push_back(device_info);
1736 request->SetState(device_info.device.type, state);
1737 DVLOG(1) << "HandleAccessRequestResponse - device already opened "
1738 << ", {label = " << label << "}"
1739 << ", device_id = " << device_it->id << "}";
1743 device_info.session_id =
1744 GetDeviceManager(device_info.device.type)->Open(device_info);
1745 TranslateDeviceIdToSourceId(request, &device_info.device);
1746 request->devices.push_back(device_info);
1748 request->SetState(device_info.device.type, MEDIA_REQUEST_STATE_OPENING);
1749 DVLOG(1) << "HandleAccessRequestResponse - opening device "
1750 << ", {label = " << label << "}"
1751 << ", {device_id = " << device_info.device.id << "}"
1752 << ", {session_id = " << device_info.session_id << "}";
1755 // Check whether we've received all stream types requested.
1756 if (!found_audio && IsAudioMediaType(request->audio_type())) {
1757 request->SetState(request->audio_type(), MEDIA_REQUEST_STATE_ERROR);
1758 DVLOG(1) << "Set no audio found label " << label;
1761 if (!found_video && IsVideoMediaType(request->video_type()))
1762 request->SetState(request->video_type(), MEDIA_REQUEST_STATE_ERROR);
1764 if (RequestDone(*request))
1765 HandleRequestDone(label, request);
1768 void MediaStreamManager::StopMediaStreamFromBrowser(const std::string& label) {
1769 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1771 DeviceRequest* request = FindRequest(label);
1775 // Notify renderers that the devices in the stream will be stopped.
1776 if (request->requester) {
1777 for (StreamDeviceInfoArray::iterator device_it = request->devices.begin();
1778 device_it != request->devices.end(); ++device_it) {
1779 request->requester->DeviceStopped(request->requesting_view_id,
1785 CancelRequest(label);
1788 void MediaStreamManager::UseFakeDevice() {
1789 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1790 video_capture_manager()->UseFakeDevice();
1791 audio_input_device_manager()->UseFakeDevice();
1794 void MediaStreamManager::UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy> fake_ui) {
1795 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1796 use_fake_ui_ = true;
1797 fake_ui_ = fake_ui.Pass();
1800 void MediaStreamManager::WillDestroyCurrentMessageLoop() {
1801 DVLOG(3) << "MediaStreamManager::WillDestroyCurrentMessageLoop()";
1802 DCHECK_EQ(base::MessageLoop::current(), io_loop_);
1803 DCHECK(requests_.empty());
1804 if (device_task_runner_) {
1807 video_capture_manager_->Unregister();
1808 audio_input_device_manager_->Unregister();
1809 device_task_runner_ = NULL;
1812 audio_input_device_manager_ = NULL;
1813 video_capture_manager_ = NULL;
1816 void MediaStreamManager::NotifyDevicesChanged(
1817 MediaStreamType stream_type,
1818 const StreamDeviceInfoArray& devices) {
1819 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1820 MediaObserver* media_observer =
1821 GetContentClient()->browser()->GetMediaObserver();
1822 if (media_observer == NULL)
1825 // Map the devices to MediaStreamDevices.
1826 MediaStreamDevices new_devices;
1827 for (StreamDeviceInfoArray::const_iterator it = devices.begin();
1828 it != devices.end(); ++it) {
1829 new_devices.push_back(it->device);
1832 if (IsAudioMediaType(stream_type)) {
1833 MediaCaptureDevicesImpl::GetInstance()->OnAudioCaptureDevicesChanged(
1835 media_observer->OnAudioCaptureDevicesChanged();
1836 } else if (IsVideoMediaType(stream_type)) {
1837 MediaCaptureDevicesImpl::GetInstance()->OnVideoCaptureDevicesChanged(
1839 media_observer->OnVideoCaptureDevicesChanged();
1845 bool MediaStreamManager::RequestDone(const DeviceRequest& request) const {
1846 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1848 const bool requested_audio = IsAudioMediaType(request.audio_type());
1849 const bool requested_video = IsVideoMediaType(request.video_type());
1851 const bool audio_done =
1853 request.state(request.audio_type()) == MEDIA_REQUEST_STATE_DONE ||
1854 request.state(request.audio_type()) == MEDIA_REQUEST_STATE_ERROR;
1858 const bool video_done =
1860 request.state(request.video_type()) == MEDIA_REQUEST_STATE_DONE ||
1861 request.state(request.video_type()) == MEDIA_REQUEST_STATE_ERROR;
1868 MediaStreamProvider* MediaStreamManager::GetDeviceManager(
1869 MediaStreamType stream_type) {
1870 if (IsVideoMediaType(stream_type)) {
1871 return video_capture_manager();
1872 } else if (IsAudioMediaType(stream_type)) {
1873 return audio_input_device_manager();
1879 void MediaStreamManager::OnDevicesChanged(
1880 base::SystemMonitor::DeviceType device_type) {
1881 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1883 // NOTE: This method is only called in response to physical audio/video device
1884 // changes (from the operating system).
1886 MediaStreamType stream_type;
1887 if (device_type == base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE) {
1888 stream_type = MEDIA_DEVICE_AUDIO_CAPTURE;
1889 } else if (device_type == base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE) {
1890 stream_type = MEDIA_DEVICE_VIDEO_CAPTURE;
1892 return; // Uninteresting device change.
1895 // Always do enumeration even though some enumeration is in progress,
1896 // because those enumeration commands could be sent before these devices
1898 ++active_enumeration_ref_count_[stream_type];
1899 GetDeviceManager(stream_type)->EnumerateDevices(stream_type);
1902 void MediaStreamManager::OnMediaStreamUIWindowId(MediaStreamType video_type,
1903 StreamDeviceInfoArray devices,
1904 gfx::NativeViewId window_id) {
1905 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1909 // Pass along for desktop capturing. Ignored for other stream types.
1910 if (video_type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
1911 for (StreamDeviceInfoArray::iterator it = devices.begin();
1912 it != devices.end();
1914 if (it->device.type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
1915 video_capture_manager_->SetDesktopCaptureWindowId(it->session_id,
1923 } // namespace content