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