Add yet more profiling to MediaStreamManager::StartMonitoringOnUIThread.
[chromium-blink-merge.git] / content / browser / renderer_host / media / media_stream_manager.cc
blob63ef21941c9ef5a8ad00d4ed6f9b50a7bd065019
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/profiler/scoped_tracker.h"
16 #include "base/rand_util.h"
17 #include "base/run_loop.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/threading/thread.h"
20 #include "content/browser/browser_main_loop.h"
21 #include "content/browser/media/capture/web_contents_capture_util.h"
22 #include "content/browser/renderer_host/media/audio_input_device_manager.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_client.h"
35 #include "content/public/common/content_switches.h"
36 #include "content/public/common/media_stream_request.h"
37 #include "media/audio/audio_manager_base.h"
38 #include "media/audio/audio_parameters.h"
39 #include "media/base/channel_layout.h"
40 #include "media/base/media_switches.h"
41 #include "media/video/capture/video_capture_device_factory.h"
42 #include "url/gurl.h"
44 #if defined(OS_WIN)
45 #include "base/win/scoped_com_initializer.h"
46 #endif
48 #if defined(OS_CHROMEOS)
49 #include "chromeos/audio/cras_audio_handler.h"
50 #endif
52 namespace content {
54 // Forward declaration of DeviceMonitorMac and its only useable method.
55 class DeviceMonitorMac {
56 public:
57 void StartMonitoring(
58 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
61 namespace {
62 // Creates a random label used to identify requests.
63 std::string RandomLabel() {
64 // An earlier PeerConnection spec,
65 // http://dev.w3.org/2011/webrtc/editor/webrtc.html, specified the
66 // MediaStream::label alphabet as containing 36 characters from
67 // range: U+0021, U+0023 to U+0027, U+002A to U+002B, U+002D to U+002E,
68 // U+0030 to U+0039, U+0041 to U+005A, U+005E to U+007E.
69 // Here we use a safe subset.
70 static const char kAlphabet[] = "0123456789"
71 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
73 std::string label(36, ' ');
74 for (size_t i = 0; i < label.size(); ++i) {
75 int random_char = base::RandGenerator(sizeof(kAlphabet) - 1);
76 label[i] = kAlphabet[random_char];
78 return label;
81 void ParseStreamType(const StreamOptions& options,
82 MediaStreamType* audio_type,
83 MediaStreamType* video_type) {
84 *audio_type = MEDIA_NO_SERVICE;
85 *video_type = MEDIA_NO_SERVICE;
86 if (options.audio_requested) {
87 std::string audio_stream_source;
88 bool mandatory = false;
89 if (options.GetFirstAudioConstraintByName(kMediaStreamSource,
90 &audio_stream_source,
91 &mandatory)) {
92 DCHECK(mandatory);
93 // This is tab or screen capture.
94 if (audio_stream_source == kMediaStreamSourceTab) {
95 *audio_type = content::MEDIA_TAB_AUDIO_CAPTURE;
96 } else if (audio_stream_source == kMediaStreamSourceSystem) {
97 *audio_type = content::MEDIA_DESKTOP_AUDIO_CAPTURE;
99 } else {
100 // This is normal audio device capture.
101 *audio_type = MEDIA_DEVICE_AUDIO_CAPTURE;
104 if (options.video_requested) {
105 std::string video_stream_source;
106 bool mandatory = false;
107 if (options.GetFirstVideoConstraintByName(kMediaStreamSource,
108 &video_stream_source,
109 &mandatory)) {
110 DCHECK(mandatory);
111 // This is tab or screen capture.
112 if (video_stream_source == kMediaStreamSourceTab) {
113 *video_type = content::MEDIA_TAB_VIDEO_CAPTURE;
114 } else if (video_stream_source == kMediaStreamSourceScreen) {
115 *video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
116 } else if (video_stream_source == kMediaStreamSourceDesktop) {
117 *video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
119 } else {
120 // This is normal video device capture.
121 *video_type = MEDIA_DEVICE_VIDEO_CAPTURE;
126 // Turns off available audio effects (removes the flag) if the options
127 // explicitly turn them off.
128 void FilterAudioEffects(const StreamOptions& options, int* effects) {
129 DCHECK(effects);
130 // TODO(ajm): Should we also handle ECHO_CANCELLER here?
131 std::string value;
132 if (options.GetFirstAudioConstraintByName(
133 kMediaStreamAudioDucking, &value, NULL) && value == "false") {
134 *effects &= ~media::AudioParameters::DUCKING;
138 // Unlike other effects, hotword is off by default, so turn it on if it's
139 // requested and available.
140 void EnableHotwordEffect(const StreamOptions& options, int* effects) {
141 DCHECK(effects);
142 std::string value;
143 if (options.GetFirstAudioConstraintByName(
144 kMediaStreamAudioHotword, &value, NULL) && value == "true") {
145 #if defined(OS_CHROMEOS)
146 chromeos::AudioDeviceList devices;
147 chromeos::CrasAudioHandler::Get()->GetAudioDevices(&devices);
148 // Only enable if a hotword device exists.
149 for (size_t i = 0; i < devices.size(); ++i) {
150 if (devices[i].type == chromeos::AUDIO_TYPE_AOKR) {
151 DCHECK(devices[i].is_input);
152 *effects |= media::AudioParameters::HOTWORD;
155 #endif
159 // Private helper method for SendMessageToNativeLog() that obtains the global
160 // MediaStreamManager instance on the UI thread before sending |message| to the
161 // webrtcLoggingPrivate API.
162 void DoAddLogMessage(const std::string& message) {
163 // Must be on the UI thread to access BrowserMainLoop.
164 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
165 // May be null in tests.
166 // TODO(vrk): Handle this more elegantly by having native log messages become
167 // no-ops until MediaStreamManager is aware that a renderer process has
168 // started logging. crbug.com/333894
169 if (content::BrowserMainLoop::GetInstance()) {
170 BrowserThread::PostTask(
171 BrowserThread::IO,
172 FROM_HERE,
173 base::Bind(&MediaStreamManager::AddLogMessageOnIOThread,
174 base::Unretained(content::BrowserMainLoop::GetInstance()
175 ->media_stream_manager()),
176 message));
180 // Private helper method to generate a string for the log message that lists the
181 // human readable names of |devices|.
182 std::string GetLogMessageString(MediaStreamType stream_type,
183 const StreamDeviceInfoArray& devices) {
184 std::string output_string =
185 base::StringPrintf("Getting devices for stream type %d:\n", stream_type);
186 if (devices.empty()) {
187 output_string += "No devices found.";
188 } else {
189 for (StreamDeviceInfoArray::const_iterator it = devices.begin();
190 it != devices.end(); ++it) {
191 output_string += " " + it->device.name + "\n";
194 return output_string;
197 // Needed for MediaStreamManager::GenerateStream below.
198 std::string ReturnEmptySalt() {
199 return std::string();
202 // Clears the MediaStreamDevice.name from all devices in |devices|.
203 static void ClearDeviceLabels(content::StreamDeviceInfoArray* devices) {
204 for (content::StreamDeviceInfoArray::iterator device_itr = devices->begin();
205 device_itr != devices->end();
206 ++device_itr) {
207 device_itr->device.name.clear();
211 } // namespace
214 // MediaStreamManager::DeviceRequest represents a request to either enumerate
215 // available devices or open one or more devices.
216 // TODO(perkj): MediaStreamManager still needs refactoring. I propose we create
217 // several subclasses of DeviceRequest and move some of the responsibility of
218 // the MediaStreamManager to the subclasses to get rid of the way too many if
219 // statements in MediaStreamManager.
220 class MediaStreamManager::DeviceRequest {
221 public:
222 DeviceRequest(MediaStreamRequester* requester,
223 int requesting_process_id,
224 int requesting_frame_id,
225 int page_request_id,
226 const GURL& security_origin,
227 bool user_gesture,
228 MediaStreamRequestType request_type,
229 const StreamOptions& options,
230 const ResourceContext::SaltCallback& salt_callback)
231 : requester(requester),
232 requesting_process_id(requesting_process_id),
233 requesting_frame_id(requesting_frame_id),
234 page_request_id(page_request_id),
235 security_origin(security_origin),
236 user_gesture(user_gesture),
237 request_type(request_type),
238 options(options),
239 salt_callback(salt_callback),
240 state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED),
241 audio_type_(MEDIA_NO_SERVICE),
242 video_type_(MEDIA_NO_SERVICE),
243 target_process_id_(-1),
244 target_frame_id_(-1) {
247 ~DeviceRequest() {}
249 void SetAudioType(MediaStreamType audio_type) {
250 DCHECK(IsAudioInputMediaType(audio_type) ||
251 audio_type == MEDIA_DEVICE_AUDIO_OUTPUT ||
252 audio_type == MEDIA_NO_SERVICE);
253 audio_type_ = audio_type;
256 MediaStreamType audio_type() const { return audio_type_; }
258 void SetVideoType(MediaStreamType video_type) {
259 DCHECK(IsVideoMediaType(video_type) || video_type == MEDIA_NO_SERVICE);
260 video_type_ = video_type;
263 MediaStreamType video_type() const { return video_type_; }
265 // Creates a MediaStreamRequest object that is used by this request when UI
266 // is asked for permission and device selection.
267 void CreateUIRequest(const std::string& requested_audio_device_id,
268 const std::string& requested_video_device_id) {
269 DCHECK(!ui_request_);
270 target_process_id_ = requesting_process_id;
271 target_frame_id_ = requesting_frame_id;
272 ui_request_.reset(new MediaStreamRequest(requesting_process_id,
273 requesting_frame_id,
274 page_request_id,
275 security_origin,
276 user_gesture,
277 request_type,
278 requested_audio_device_id,
279 requested_video_device_id,
280 audio_type_,
281 video_type_));
284 // Creates a tab capture specific MediaStreamRequest object that is used by
285 // this request when UI is asked for permission and device selection.
286 void CreateTabCaptureUIRequest(int target_render_process_id,
287 int target_render_frame_id) {
288 DCHECK(!ui_request_);
289 target_process_id_ = target_render_process_id;
290 target_frame_id_ = target_render_frame_id;
291 ui_request_.reset(new MediaStreamRequest(target_render_process_id,
292 target_render_frame_id,
293 page_request_id,
294 security_origin,
295 user_gesture,
296 request_type,
299 audio_type_,
300 video_type_));
303 bool HasUIRequest() const { return ui_request_.get() != nullptr; }
304 scoped_ptr<MediaStreamRequest> DetachUIRequest() {
305 return ui_request_.Pass();
308 // Update the request state and notify observers.
309 void SetState(MediaStreamType stream_type, MediaRequestState new_state) {
310 if (stream_type == NUM_MEDIA_TYPES) {
311 for (int i = MEDIA_NO_SERVICE + 1; i < NUM_MEDIA_TYPES; ++i) {
312 const MediaStreamType stream_type = static_cast<MediaStreamType>(i);
313 state_[stream_type] = new_state;
315 } else {
316 state_[stream_type] = new_state;
319 MediaObserver* media_observer =
320 GetContentClient()->browser()->GetMediaObserver();
321 if (!media_observer)
322 return;
324 media_observer->OnMediaRequestStateChanged(
325 target_process_id_, target_frame_id_, page_request_id, security_origin,
326 stream_type, new_state);
329 MediaRequestState state(MediaStreamType stream_type) const {
330 return state_[stream_type];
333 MediaStreamRequester* const requester; // Can be NULL.
336 // The render process id that requested this stream to be generated and that
337 // will receive a handle to the MediaStream. This may be different from
338 // MediaStreamRequest::render_process_id which in the tab capture case
339 // specifies the target renderer from which audio and video is captured.
340 const int requesting_process_id;
342 // The render frame id that requested this stream to be generated and that
343 // will receive a handle to the MediaStream. This may be different from
344 // MediaStreamRequest::render_frame_id which in the tab capture case
345 // specifies the target renderer from which audio and video is captured.
346 const int requesting_frame_id;
348 // An ID the render frame provided to identify this request.
349 const int page_request_id;
351 const GURL security_origin;
353 const bool user_gesture;
355 const MediaStreamRequestType request_type;
357 const StreamOptions options;
359 ResourceContext::SaltCallback salt_callback;
361 StreamDeviceInfoArray devices;
363 // Callback to the requester which audio/video devices have been selected.
364 // It can be null if the requester has no interest to know the result.
365 // Currently it is only used by |DEVICE_ACCESS| type.
366 MediaStreamManager::MediaRequestResponseCallback callback;
368 scoped_ptr<MediaStreamUIProxy> ui_proxy;
370 std::string tab_capture_device_id;
372 private:
373 std::vector<MediaRequestState> state_;
374 scoped_ptr<MediaStreamRequest> ui_request_;
375 MediaStreamType audio_type_;
376 MediaStreamType video_type_;
377 int target_process_id_;
378 int target_frame_id_;
381 MediaStreamManager::EnumerationCache::EnumerationCache()
382 : valid(false) {
385 MediaStreamManager::EnumerationCache::~EnumerationCache() {
388 MediaStreamManager::MediaStreamManager()
389 : audio_manager_(NULL),
390 #if defined(OS_WIN)
391 video_capture_thread_("VideoCaptureThread"),
392 #endif
393 monitoring_started_(false),
394 #if defined(OS_CHROMEOS)
395 has_checked_keyboard_mic_(false),
396 #endif
397 io_loop_(NULL),
398 use_fake_ui_(false) {}
400 MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager)
401 : audio_manager_(audio_manager),
402 #if defined(OS_WIN)
403 video_capture_thread_("VideoCaptureThread"),
404 #endif
405 monitoring_started_(false),
406 #if defined(OS_CHROMEOS)
407 has_checked_keyboard_mic_(false),
408 #endif
409 io_loop_(NULL),
410 use_fake_ui_(false) {
411 DCHECK(audio_manager_);
412 memset(active_enumeration_ref_count_, 0,
413 sizeof(active_enumeration_ref_count_));
415 // Some unit tests create the MSM in the IO thread and assumes the
416 // initialization is done synchronously.
417 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
418 InitializeDeviceManagersOnIOThread();
419 } else {
420 BrowserThread::PostTask(
421 BrowserThread::IO, FROM_HERE,
422 base::Bind(&MediaStreamManager::InitializeDeviceManagersOnIOThread,
423 base::Unretained(this)));
426 base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
427 // BrowserMainLoop always creates the PowerMonitor instance before creating
428 // MediaStreamManager, but power_monitor may be NULL in unit tests.
429 if (power_monitor)
430 power_monitor->AddObserver(this);
433 MediaStreamManager::~MediaStreamManager() {
434 DVLOG(1) << "~MediaStreamManager";
435 DCHECK(requests_.empty());
436 DCHECK(!device_task_runner_.get());
438 base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
439 // The PowerMonitor instance owned by BrowserMainLoops always outlives the
440 // MediaStreamManager, but it may be NULL in unit tests.
441 if (power_monitor)
442 power_monitor->RemoveObserver(this);
445 VideoCaptureManager* MediaStreamManager::video_capture_manager() {
446 DCHECK_CURRENTLY_ON(BrowserThread::IO);
447 DCHECK(video_capture_manager_.get());
448 return video_capture_manager_.get();
451 AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() {
452 DCHECK_CURRENTLY_ON(BrowserThread::IO);
453 DCHECK(audio_input_device_manager_.get());
454 return audio_input_device_manager_.get();
457 std::string MediaStreamManager::MakeMediaAccessRequest(
458 int render_process_id,
459 int render_frame_id,
460 int page_request_id,
461 const StreamOptions& options,
462 const GURL& security_origin,
463 const MediaRequestResponseCallback& callback) {
464 DCHECK_CURRENTLY_ON(BrowserThread::IO);
466 // TODO(perkj): The argument list with NULL parameters to DeviceRequest
467 // suggests that this is the wrong design. Can this be refactored?
468 DeviceRequest* request = new DeviceRequest(NULL,
469 render_process_id,
470 render_frame_id,
471 page_request_id,
472 security_origin,
473 false, // user gesture
474 MEDIA_DEVICE_ACCESS,
475 options,
476 base::Bind(&ReturnEmptySalt));
478 const std::string& label = AddRequest(request);
480 request->callback = callback;
481 // Post a task and handle the request asynchronously. The reason is that the
482 // requester won't have a label for the request until this function returns
483 // and thus can not handle a response. Using base::Unretained is safe since
484 // MediaStreamManager is deleted on the UI thread, after the IO thread has
485 // been stopped.
486 BrowserThread::PostTask(
487 BrowserThread::IO, FROM_HERE,
488 base::Bind(&MediaStreamManager::SetupRequest,
489 base::Unretained(this), label));
490 return label;
493 void MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
494 int render_process_id,
495 int render_frame_id,
496 const ResourceContext::SaltCallback& sc,
497 int page_request_id,
498 const StreamOptions& options,
499 const GURL& security_origin,
500 bool user_gesture) {
501 DCHECK_CURRENTLY_ON(BrowserThread::IO);
502 DVLOG(1) << "GenerateStream()";
503 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
504 switches::kUseFakeUIForMediaStream)) {
505 UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy>());
508 DeviceRequest* request = new DeviceRequest(requester,
509 render_process_id,
510 render_frame_id,
511 page_request_id,
512 security_origin,
513 user_gesture,
514 MEDIA_GENERATE_STREAM,
515 options,
516 sc);
518 const std::string& label = AddRequest(request);
520 // Post a task and handle the request asynchronously. The reason is that the
521 // requester won't have a label for the request until this function returns
522 // and thus can not handle a response. Using base::Unretained is safe since
523 // MediaStreamManager is deleted on the UI thread, after the IO thread has
524 // been stopped.
525 BrowserThread::PostTask(
526 BrowserThread::IO, FROM_HERE,
527 base::Bind(&MediaStreamManager::SetupRequest,
528 base::Unretained(this), label));
531 void MediaStreamManager::CancelRequest(int render_process_id,
532 int render_frame_id,
533 int page_request_id) {
534 for (DeviceRequests::const_iterator request_it = requests_.begin();
535 request_it != requests_.end(); ++request_it) {
536 const DeviceRequest* request = request_it->second;
537 if (request->requesting_process_id == render_process_id &&
538 request->requesting_frame_id == render_frame_id &&
539 request->page_request_id == page_request_id) {
540 CancelRequest(request_it->first);
541 return;
544 NOTREACHED();
547 void MediaStreamManager::CancelRequest(const std::string& label) {
548 DCHECK_CURRENTLY_ON(BrowserThread::IO);
549 DVLOG(1) << "CancelRequest({label = " << label << "})";
550 DeviceRequest* request = FindRequest(label);
551 if (!request) {
552 // The request does not exist.
553 LOG(ERROR) << "The request with label = " << label << " does not exist.";
554 return;
557 if (request->request_type == MEDIA_ENUMERATE_DEVICES) {
558 // It isn't an ideal use of "CancelRequest" to make it a requirement
559 // for enumeration requests to be deleted via "CancelRequest" _after_
560 // the request has been successfully fulfilled.
561 // See note in FinalizeEnumerateDevices for a recommendation on how
562 // we should refactor this.
563 DeleteRequest(label);
564 return;
567 // This is a request for opening one or more devices.
568 for (StreamDeviceInfoArray::iterator device_it = request->devices.begin();
569 device_it != request->devices.end(); ++device_it) {
570 MediaRequestState state = request->state(device_it->device.type);
571 // If we have not yet requested the device to be opened - just ignore it.
572 if (state != MEDIA_REQUEST_STATE_OPENING &&
573 state != MEDIA_REQUEST_STATE_DONE) {
574 continue;
576 // Stop the opening/opened devices of the requests.
577 CloseDevice(device_it->device.type, device_it->session_id);
580 // Cancel the request if still pending at UI side.
581 request->SetState(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_CLOSING);
582 DeleteRequest(label);
585 void MediaStreamManager::CancelAllRequests(int render_process_id) {
586 DeviceRequests::iterator request_it = requests_.begin();
587 while (request_it != requests_.end()) {
588 if (request_it->second->requesting_process_id != render_process_id) {
589 ++request_it;
590 continue;
593 std::string label = request_it->first;
594 ++request_it;
595 CancelRequest(label);
599 void MediaStreamManager::StopStreamDevice(int render_process_id,
600 int render_frame_id,
601 const std::string& device_id) {
602 DCHECK_CURRENTLY_ON(BrowserThread::IO);
603 DVLOG(1) << "StopStreamDevice({render_frame_id = " << render_frame_id << "} "
604 << ", {device_id = " << device_id << "})";
605 // Find the first request for this |render_process_id| and |render_frame_id|
606 // of type MEDIA_GENERATE_STREAM that has requested to use |device_id| and
607 // stop it.
608 for (DeviceRequests::iterator request_it = requests_.begin();
609 request_it != requests_.end(); ++request_it) {
610 DeviceRequest* request = request_it->second;
611 if (request->requesting_process_id != render_process_id ||
612 request->requesting_frame_id != render_frame_id ||
613 request->request_type != MEDIA_GENERATE_STREAM) {
614 continue;
617 StreamDeviceInfoArray& devices = request->devices;
618 for (StreamDeviceInfoArray::iterator device_it = devices.begin();
619 device_it != devices.end(); ++device_it) {
620 if (device_it->device.id == device_id) {
621 StopDevice(device_it->device.type, device_it->session_id);
622 return;
628 void MediaStreamManager::StopDevice(MediaStreamType type, int session_id) {
629 DVLOG(1) << "StopDevice"
630 << "{type = " << type << "}"
631 << "{session_id = " << session_id << "}";
632 DeviceRequests::iterator request_it = requests_.begin();
633 while (request_it != requests_.end()) {
634 DeviceRequest* request = request_it->second;
635 StreamDeviceInfoArray* devices = &request->devices;
636 if (devices->empty()) {
637 // There is no device in use yet by this request.
638 ++request_it;
639 continue;
641 StreamDeviceInfoArray::iterator device_it = devices->begin();
642 while (device_it != devices->end()) {
643 if (device_it->device.type != type ||
644 device_it->session_id != session_id) {
645 ++device_it;
646 continue;
649 if (request->state(type) == MEDIA_REQUEST_STATE_DONE)
650 CloseDevice(type, session_id);
651 device_it = devices->erase(device_it);
654 // If this request doesn't have any active devices after a device
655 // has been stopped above, remove the request. Note that the request is
656 // only deleted if a device as been removed from |devices|.
657 if (devices->empty()) {
658 std::string label = request_it->first;
659 ++request_it;
660 DeleteRequest(label);
661 } else {
662 ++request_it;
667 void MediaStreamManager::CloseDevice(MediaStreamType type, int session_id) {
668 DVLOG(1) << "CloseDevice("
669 << "{type = " << type << "} "
670 << "{session_id = " << session_id << "})";
671 GetDeviceManager(type)->Close(session_id);
673 for (DeviceRequests::iterator request_it = requests_.begin();
674 request_it != requests_.end() ; ++request_it) {
675 StreamDeviceInfoArray* devices = &request_it->second->devices;
676 for (StreamDeviceInfoArray::iterator device_it = devices->begin();
677 device_it != devices->end(); ++device_it) {
678 if (device_it->session_id == session_id &&
679 device_it->device.type == type) {
680 // Notify observers that this device is being closed.
681 // Note that only one device per type can be opened.
682 request_it->second->SetState(type, MEDIA_REQUEST_STATE_CLOSING);
688 std::string MediaStreamManager::EnumerateDevices(
689 MediaStreamRequester* requester,
690 int render_process_id,
691 int render_frame_id,
692 const ResourceContext::SaltCallback& sc,
693 int page_request_id,
694 MediaStreamType type,
695 const GURL& security_origin) {
696 DCHECK_CURRENTLY_ON(BrowserThread::IO);
697 DCHECK(requester);
698 DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
699 type == MEDIA_DEVICE_VIDEO_CAPTURE ||
700 type == MEDIA_DEVICE_AUDIO_OUTPUT);
702 DeviceRequest* request = new DeviceRequest(requester,
703 render_process_id,
704 render_frame_id,
705 page_request_id,
706 security_origin,
707 false, // user gesture
708 MEDIA_ENUMERATE_DEVICES,
709 StreamOptions(),
710 sc);
711 if (IsAudioInputMediaType(type) || type == MEDIA_DEVICE_AUDIO_OUTPUT)
712 request->SetAudioType(type);
713 else if (IsVideoMediaType(type))
714 request->SetVideoType(type);
716 const std::string& label = AddRequest(request);
717 // Post a task and handle the request asynchronously. The reason is that the
718 // requester won't have a label for the request until this function returns
719 // and thus can not handle a response. Using base::Unretained is safe since
720 // MediaStreamManager is deleted on the UI thread, after the IO thread has
721 // been stopped.
722 BrowserThread::PostTask(
723 BrowserThread::IO, FROM_HERE,
724 base::Bind(&MediaStreamManager::DoEnumerateDevices,
725 base::Unretained(this), label));
726 return label;
729 void MediaStreamManager::DoEnumerateDevices(const std::string& label) {
730 DCHECK_CURRENTLY_ON(BrowserThread::IO);
731 DeviceRequest* request = FindRequest(label);
732 if (!request)
733 return; // This can happen if the request has been canceled.
735 if (request->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT) {
736 DCHECK_EQ(MEDIA_NO_SERVICE, request->video_type());
737 DCHECK_GE(active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT], 0);
738 request->SetState(MEDIA_DEVICE_AUDIO_OUTPUT, MEDIA_REQUEST_STATE_REQUESTED);
739 if (active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT] == 0) {
740 ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT];
741 device_task_runner_->PostTask(
742 FROM_HERE,
743 base::Bind(&MediaStreamManager::EnumerateAudioOutputDevices,
744 base::Unretained(this),
745 label));
747 return;
750 MediaStreamType type;
751 EnumerationCache* cache;
752 if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE) {
753 DCHECK_EQ(MEDIA_NO_SERVICE, request->video_type());
754 type = MEDIA_DEVICE_AUDIO_CAPTURE;
755 cache = &audio_enumeration_cache_;
756 } else {
757 DCHECK_EQ(MEDIA_DEVICE_VIDEO_CAPTURE, request->video_type());
758 DCHECK_EQ(MEDIA_NO_SERVICE, request->audio_type());
759 type = MEDIA_DEVICE_VIDEO_CAPTURE;
760 cache = &video_enumeration_cache_;
763 if (!EnumerationRequired(cache, type)) {
764 // Cached device list of this type exists. Just send it out.
765 request->SetState(type, MEDIA_REQUEST_STATE_REQUESTED);
766 request->devices = cache->devices;
767 FinalizeEnumerateDevices(label, request);
768 } else {
769 StartEnumeration(request);
771 DVLOG(1) << "Enumerate Devices ({label = " << label << "})";
774 void MediaStreamManager::EnumerateAudioOutputDevices(const std::string& label) {
775 DCHECK(device_task_runner_->BelongsToCurrentThread());
777 scoped_ptr<media::AudioDeviceNames> device_names(
778 new media::AudioDeviceNames());
779 audio_manager_->GetAudioOutputDeviceNames(device_names.get());
780 StreamDeviceInfoArray devices;
781 for (media::AudioDeviceNames::iterator it = device_names->begin();
782 it != device_names->end(); ++it) {
783 StreamDeviceInfo device(MEDIA_DEVICE_AUDIO_OUTPUT,
784 it->device_name,
785 it->unique_id);
786 devices.push_back(device);
789 BrowserThread::PostTask(
790 BrowserThread::IO, FROM_HERE,
791 base::Bind(&MediaStreamManager::AudioOutputDevicesEnumerated,
792 base::Unretained(this),
793 devices));
796 void MediaStreamManager::AudioOutputDevicesEnumerated(
797 const StreamDeviceInfoArray& devices) {
798 DCHECK_CURRENTLY_ON(BrowserThread::IO);
799 DVLOG(1) << "AudioOutputDevicesEnumerated()";
801 std::string log_message = "New device enumeration result:\n" +
802 GetLogMessageString(MEDIA_DEVICE_AUDIO_OUTPUT,
803 devices);
804 SendMessageToNativeLog(log_message);
806 // Publish the result for all requests waiting for device list(s).
807 for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
808 ++it) {
809 if (it->second->state(MEDIA_DEVICE_AUDIO_OUTPUT) ==
810 MEDIA_REQUEST_STATE_REQUESTED &&
811 it->second->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT) {
812 DCHECK_EQ(MEDIA_ENUMERATE_DEVICES, it->second->request_type);
813 it->second->SetState(MEDIA_DEVICE_AUDIO_OUTPUT,
814 MEDIA_REQUEST_STATE_PENDING_APPROVAL);
815 it->second->devices = devices;
816 FinalizeEnumerateDevices(it->first, it->second);
820 --active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT];
821 DCHECK_GE(active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT], 0);
824 void MediaStreamManager::OpenDevice(MediaStreamRequester* requester,
825 int render_process_id,
826 int render_frame_id,
827 const ResourceContext::SaltCallback& sc,
828 int page_request_id,
829 const std::string& device_id,
830 MediaStreamType type,
831 const GURL& security_origin) {
832 DCHECK_CURRENTLY_ON(BrowserThread::IO);
833 DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
834 type == MEDIA_DEVICE_VIDEO_CAPTURE);
835 DVLOG(1) << "OpenDevice ({page_request_id = " << page_request_id << "})";
836 StreamOptions options;
837 if (IsAudioInputMediaType(type)) {
838 options.audio_requested = true;
839 options.mandatory_audio.push_back(
840 StreamOptions::Constraint(kMediaStreamSourceInfoId, device_id));
841 } else if (IsVideoMediaType(type)) {
842 options.video_requested = true;
843 options.mandatory_video.push_back(
844 StreamOptions::Constraint(kMediaStreamSourceInfoId, device_id));
845 } else {
846 NOTREACHED();
848 DeviceRequest* request = new DeviceRequest(requester,
849 render_process_id,
850 render_frame_id,
851 page_request_id,
852 security_origin,
853 false, // user gesture
854 MEDIA_OPEN_DEVICE,
855 options,
856 sc);
858 const std::string& label = AddRequest(request);
859 // Post a task and handle the request asynchronously. The reason is that the
860 // requester won't have a label for the request until this function returns
861 // and thus can not handle a response. Using base::Unretained is safe since
862 // MediaStreamManager is deleted on the UI thread, after the IO thread has
863 // been stopped.
864 BrowserThread::PostTask(
865 BrowserThread::IO, FROM_HERE,
866 base::Bind(&MediaStreamManager::SetupRequest,
867 base::Unretained(this), label));
870 bool MediaStreamManager::TranslateSourceIdToDeviceId(
871 MediaStreamType stream_type,
872 const ResourceContext::SaltCallback& sc,
873 const GURL& security_origin,
874 const std::string& source_id,
875 std::string* device_id) const {
876 DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ||
877 stream_type == MEDIA_DEVICE_VIDEO_CAPTURE);
878 // The source_id can be empty if the constraint is set but empty.
879 if (source_id.empty())
880 return false;
882 const EnumerationCache* cache =
883 stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
884 &audio_enumeration_cache_ : &video_enumeration_cache_;
886 // If device monitoring hasn't started, the |device_guid| is not valid.
887 if (!cache->valid)
888 return false;
890 for (StreamDeviceInfoArray::const_iterator it = cache->devices.begin();
891 it != cache->devices.end();
892 ++it) {
893 if (content::DoesMediaDeviceIDMatchHMAC(sc, security_origin, source_id,
894 it->device.id)) {
895 *device_id = it->device.id;
896 return true;
899 return false;
902 void MediaStreamManager::EnsureDeviceMonitorStarted() {
903 DCHECK_CURRENTLY_ON(BrowserThread::IO);
904 StartMonitoring();
907 void MediaStreamManager::StopRemovedDevices(
908 const StreamDeviceInfoArray& old_devices,
909 const StreamDeviceInfoArray& new_devices) {
910 DVLOG(1) << "StopRemovedDevices("
911 << "{#old_devices = " << old_devices.size() << "} "
912 << "{#new_devices = " << new_devices.size() << "})";
913 for (StreamDeviceInfoArray::const_iterator old_dev_it = old_devices.begin();
914 old_dev_it != old_devices.end(); ++old_dev_it) {
915 bool device_found = false;
916 StreamDeviceInfoArray::const_iterator new_dev_it = new_devices.begin();
917 for (; new_dev_it != new_devices.end(); ++new_dev_it) {
918 if (old_dev_it->device.id == new_dev_it->device.id) {
919 device_found = true;
920 break;
924 if (!device_found) {
925 // A device has been removed. We need to check if it is used by a
926 // MediaStream and in that case cleanup and notify the render process.
927 StopRemovedDevice(old_dev_it->device);
932 void MediaStreamManager::StopRemovedDevice(const MediaStreamDevice& device) {
933 std::vector<int> session_ids;
934 for (DeviceRequests::const_iterator it = requests_.begin();
935 it != requests_.end() ; ++it) {
936 const DeviceRequest* request = it->second;
937 for (StreamDeviceInfoArray::const_iterator device_it =
938 request->devices.begin();
939 device_it != request->devices.end(); ++device_it) {
940 std::string source_id = content::GetHMACForMediaDeviceID(
941 request->salt_callback,
942 request->security_origin,
943 device.id);
944 if (device_it->device.id == source_id &&
945 device_it->device.type == device.type) {
946 session_ids.push_back(device_it->session_id);
947 if (it->second->requester) {
948 it->second->requester->DeviceStopped(
949 it->second->requesting_frame_id,
950 it->first,
951 *device_it);
956 for (std::vector<int>::const_iterator it = session_ids.begin();
957 it != session_ids.end(); ++it) {
958 StopDevice(device.type, *it);
961 std::ostringstream oss;
962 oss << "Media input device removed: type = " <<
963 (device.type == MEDIA_DEVICE_AUDIO_CAPTURE ? "audio" : "video") <<
964 ", id = " << device.id << ", name = " << device.name;
965 AddLogMessageOnIOThread(oss.str());
968 void MediaStreamManager::StartMonitoring() {
969 DCHECK_CURRENTLY_ON(BrowserThread::IO);
970 if (monitoring_started_)
971 return;
973 if (!base::SystemMonitor::Get())
974 return;
976 monitoring_started_ = true;
977 base::SystemMonitor::Get()->AddDevicesChangedObserver(this);
979 // Enumerate both the audio and video devices to cache the device lists
980 // and send them to media observer.
981 ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_CAPTURE];
982 audio_input_device_manager_->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE);
983 ++active_enumeration_ref_count_[MEDIA_DEVICE_VIDEO_CAPTURE];
984 video_capture_manager_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
986 #if defined(OS_MACOSX)
987 BrowserThread::PostTask(
988 BrowserThread::UI, FROM_HERE,
989 base::Bind(&MediaStreamManager::StartMonitoringOnUIThread,
990 base::Unretained(this)));
991 #endif
994 #if defined(OS_MACOSX)
995 void MediaStreamManager::StartMonitoringOnUIThread() {
996 DCHECK_CURRENTLY_ON(BrowserThread::UI);
997 // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is fixed.
998 tracked_objects::ScopedTracker tracking_profile1(
999 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1000 "458404 MediaStreamManager::GetBrowserMainLoop"));
1001 BrowserMainLoop* browser_main_loop = content::BrowserMainLoop::GetInstance();
1002 if (browser_main_loop) {
1003 // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is
1004 // fixed.
1005 tracked_objects::ScopedTracker tracking_profile2(
1006 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1007 "458404 MediaStreamManager::GetWorkerTaskRunner"));
1008 const scoped_refptr<base::SingleThreadTaskRunner> task_runner =
1009 audio_manager_->GetWorkerTaskRunner();
1010 // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is
1011 // fixed.
1012 tracked_objects::ScopedTracker tracking_profile3(
1013 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1014 "458404 MediaStreamManager::DeviceMonitorMac::StartMonitoring"));
1015 browser_main_loop->device_monitor_mac()->StartMonitoring(task_runner);
1018 #endif
1020 void MediaStreamManager::StopMonitoring() {
1021 DCHECK_EQ(base::MessageLoop::current(), io_loop_);
1022 if (monitoring_started_) {
1023 base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this);
1024 monitoring_started_ = false;
1025 ClearEnumerationCache(&audio_enumeration_cache_);
1026 ClearEnumerationCache(&video_enumeration_cache_);
1030 bool MediaStreamManager::GetRequestedDeviceCaptureId(
1031 const DeviceRequest* request,
1032 MediaStreamType type,
1033 std::string* device_id) const {
1034 DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
1035 type == MEDIA_DEVICE_VIDEO_CAPTURE);
1036 const StreamOptions::Constraints* mandatory =
1037 (type == MEDIA_DEVICE_AUDIO_CAPTURE) ?
1038 &request->options.mandatory_audio : &request->options.mandatory_video;
1039 const StreamOptions::Constraints* optional =
1040 (type == MEDIA_DEVICE_AUDIO_CAPTURE) ?
1041 &request->options.optional_audio : &request->options.optional_video;
1043 std::vector<std::string> source_ids;
1044 StreamOptions::GetConstraintsByName(*mandatory,
1045 kMediaStreamSourceInfoId, &source_ids);
1046 if (source_ids.size() > 1) {
1047 LOG(ERROR) << "Only one mandatory " << kMediaStreamSourceInfoId
1048 << " is supported.";
1049 return false;
1051 // If a specific device has been requested we need to find the real device
1052 // id.
1053 if (source_ids.size() == 1 &&
1054 !TranslateSourceIdToDeviceId(type,
1055 request->salt_callback,
1056 request->security_origin,
1057 source_ids[0], device_id)) {
1058 LOG(WARNING) << "Invalid mandatory " << kMediaStreamSourceInfoId
1059 << " = " << source_ids[0] << ".";
1060 return false;
1062 // Check for optional audio sourceIDs.
1063 if (device_id->empty()) {
1064 StreamOptions::GetConstraintsByName(*optional,
1065 kMediaStreamSourceInfoId,
1066 &source_ids);
1067 // Find the first sourceID that translates to device. Note that only one
1068 // device per type can call to GenerateStream is ever opened.
1069 for (std::vector<std::string>::const_iterator it = source_ids.begin();
1070 it != source_ids.end(); ++it) {
1071 if (TranslateSourceIdToDeviceId(type,
1072 request->salt_callback,
1073 request->security_origin,
1074 *it,
1075 device_id)) {
1076 break;
1080 return true;
1083 void MediaStreamManager::TranslateDeviceIdToSourceId(
1084 DeviceRequest* request,
1085 MediaStreamDevice* device) {
1086 if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
1087 request->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT ||
1088 request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE) {
1089 device->id = content::GetHMACForMediaDeviceID(
1090 request->salt_callback,
1091 request->security_origin,
1092 device->id);
1096 void MediaStreamManager::ClearEnumerationCache(EnumerationCache* cache) {
1097 DCHECK_EQ(base::MessageLoop::current(), io_loop_);
1098 cache->valid = false;
1101 bool MediaStreamManager::EnumerationRequired(EnumerationCache* cache,
1102 MediaStreamType stream_type) {
1103 DCHECK_EQ(base::MessageLoop::current(), io_loop_);
1104 if (stream_type == MEDIA_NO_SERVICE)
1105 return false;
1107 DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ||
1108 stream_type == MEDIA_DEVICE_VIDEO_CAPTURE);
1110 #if defined(OS_ANDROID)
1111 // There's no SystemMonitor on Android that notifies us when devices are
1112 // added or removed, so we need to populate the cache on every request.
1113 // Fortunately, there is an already up-to-date cache in the browser side
1114 // audio manager that we can rely on, so the performance impact of
1115 // invalidating the cache like this, is minimal.
1116 if (stream_type == MEDIA_DEVICE_AUDIO_CAPTURE) {
1117 // Make sure the cache is marked as invalid so that FinalizeEnumerateDevices
1118 // will be called at the end of the enumeration.
1119 ClearEnumerationCache(cache);
1121 #endif
1122 // If the cache isn't valid, we need to start a full enumeration.
1123 return !cache->valid;
1126 void MediaStreamManager::StartEnumeration(DeviceRequest* request) {
1127 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1129 // Start monitoring the devices when doing the first enumeration.
1130 StartMonitoring();
1132 // Start enumeration for devices of all requested device types.
1133 const MediaStreamType streams[] = { request->audio_type(),
1134 request->video_type() };
1135 for (size_t i = 0; i < arraysize(streams); ++i) {
1136 if (streams[i] == MEDIA_NO_SERVICE)
1137 continue;
1138 request->SetState(streams[i], MEDIA_REQUEST_STATE_REQUESTED);
1139 DCHECK_GE(active_enumeration_ref_count_[streams[i]], 0);
1140 if (active_enumeration_ref_count_[streams[i]] == 0) {
1141 ++active_enumeration_ref_count_[streams[i]];
1142 GetDeviceManager(streams[i])->EnumerateDevices(streams[i]);
1147 std::string MediaStreamManager::AddRequest(DeviceRequest* request) {
1148 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1150 // Create a label for this request and verify it is unique.
1151 std::string unique_label;
1152 do {
1153 unique_label = RandomLabel();
1154 } while (FindRequest(unique_label) != NULL);
1156 requests_.push_back(std::make_pair(unique_label, request));
1158 return unique_label;
1161 MediaStreamManager::DeviceRequest*
1162 MediaStreamManager::FindRequest(const std::string& label) const {
1163 for (DeviceRequests::const_iterator request_it = requests_.begin();
1164 request_it != requests_.end(); ++request_it) {
1165 if (request_it->first == label)
1166 return request_it->second;
1168 return NULL;
1171 void MediaStreamManager::DeleteRequest(const std::string& label) {
1172 DVLOG(1) << "DeleteRequest({label= " << label << "})";
1173 for (DeviceRequests::iterator request_it = requests_.begin();
1174 request_it != requests_.end(); ++request_it) {
1175 if (request_it->first == label) {
1176 scoped_ptr<DeviceRequest> request(request_it->second);
1177 requests_.erase(request_it);
1178 return;
1181 NOTREACHED();
1184 void MediaStreamManager::PostRequestToUI(const std::string& label,
1185 DeviceRequest* request) {
1186 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1187 DCHECK(request->HasUIRequest());
1188 DVLOG(1) << "PostRequestToUI({label= " << label << "})";
1190 const MediaStreamType audio_type = request->audio_type();
1191 const MediaStreamType video_type = request->video_type();
1193 // Post the request to UI and set the state.
1194 if (IsAudioInputMediaType(audio_type))
1195 request->SetState(audio_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
1196 if (IsVideoMediaType(video_type))
1197 request->SetState(video_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
1199 if (use_fake_ui_) {
1200 if (!fake_ui_)
1201 fake_ui_.reset(new FakeMediaStreamUIProxy());
1203 MediaStreamDevices devices;
1204 if (audio_enumeration_cache_.valid) {
1205 for (StreamDeviceInfoArray::const_iterator it =
1206 audio_enumeration_cache_.devices.begin();
1207 it != audio_enumeration_cache_.devices.end(); ++it) {
1208 devices.push_back(it->device);
1211 if (video_enumeration_cache_.valid) {
1212 for (StreamDeviceInfoArray::const_iterator it =
1213 video_enumeration_cache_.devices.begin();
1214 it != video_enumeration_cache_.devices.end(); ++it) {
1215 devices.push_back(it->device);
1219 fake_ui_->SetAvailableDevices(devices);
1221 request->ui_proxy = fake_ui_.Pass();
1222 } else {
1223 request->ui_proxy = MediaStreamUIProxy::Create();
1226 request->ui_proxy->RequestAccess(
1227 request->DetachUIRequest(),
1228 base::Bind(&MediaStreamManager::HandleAccessRequestResponse,
1229 base::Unretained(this), label));
1232 void MediaStreamManager::SetupRequest(const std::string& label) {
1233 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1234 DeviceRequest* request = FindRequest(label);
1235 if (!request) {
1236 DVLOG(1) << "SetupRequest label " << label << " doesn't exist!!";
1237 return; // This can happen if the request has been canceled.
1240 if (!request->security_origin.is_valid()) {
1241 LOG(ERROR) << "Invalid security origin. "
1242 << request->security_origin;
1243 FinalizeRequestFailed(label,
1244 request,
1245 MEDIA_DEVICE_INVALID_SECURITY_ORIGIN);
1246 return;
1249 MediaStreamType audio_type = MEDIA_NO_SERVICE;
1250 MediaStreamType video_type = MEDIA_NO_SERVICE;
1251 ParseStreamType(request->options, &audio_type, &video_type);
1252 request->SetAudioType(audio_type);
1253 request->SetVideoType(video_type);
1255 bool is_web_contents_capture =
1256 audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
1257 video_type == MEDIA_TAB_VIDEO_CAPTURE;
1258 if (is_web_contents_capture && !SetupTabCaptureRequest(request)) {
1259 FinalizeRequestFailed(label,
1260 request,
1261 MEDIA_DEVICE_TAB_CAPTURE_FAILURE);
1262 return;
1265 bool is_screen_capture =
1266 video_type == MEDIA_DESKTOP_VIDEO_CAPTURE;
1267 if (is_screen_capture && !SetupScreenCaptureRequest(request)) {
1268 FinalizeRequestFailed(label,
1269 request,
1270 MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE);
1271 return;
1274 #if defined(OS_CHROMEOS)
1275 EnsureKeyboardMicChecked();
1276 #endif
1278 if (!is_web_contents_capture && !is_screen_capture) {
1279 if (EnumerationRequired(&audio_enumeration_cache_, audio_type) ||
1280 EnumerationRequired(&video_enumeration_cache_, video_type)) {
1281 // Enumerate the devices if there is no valid device lists to be used.
1282 StartEnumeration(request);
1283 return;
1284 } else {
1285 // Cache is valid, so log the cached devices for MediaStream requests.
1286 if (request->request_type == MEDIA_GENERATE_STREAM) {
1287 std::string log_message("Using cached devices for request.\n");
1288 if (audio_type != MEDIA_NO_SERVICE) {
1289 log_message +=
1290 GetLogMessageString(audio_type, audio_enumeration_cache_.devices);
1292 if (video_type != MEDIA_NO_SERVICE) {
1293 log_message +=
1294 GetLogMessageString(video_type, video_enumeration_cache_.devices);
1296 SendMessageToNativeLog(log_message);
1300 if (!SetupDeviceCaptureRequest(request)) {
1301 FinalizeRequestFailed(label, request, MEDIA_DEVICE_NO_HARDWARE);
1302 return;
1305 PostRequestToUI(label, request);
1308 bool MediaStreamManager::SetupDeviceCaptureRequest(DeviceRequest* request) {
1309 DCHECK((request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
1310 request->audio_type() == MEDIA_NO_SERVICE) &&
1311 (request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE ||
1312 request->video_type() == MEDIA_NO_SERVICE));
1313 std::string audio_device_id;
1314 if (request->options.audio_requested &&
1315 !GetRequestedDeviceCaptureId(request, request->audio_type(),
1316 &audio_device_id)) {
1317 return false;
1320 std::string video_device_id;
1321 if (request->options.video_requested &&
1322 !GetRequestedDeviceCaptureId(request, request->video_type(),
1323 &video_device_id)) {
1324 return false;
1326 request->CreateUIRequest(audio_device_id, video_device_id);
1327 DVLOG(3) << "Audio requested " << request->options.audio_requested
1328 << " device id = " << audio_device_id
1329 << "Video requested " << request->options.video_requested
1330 << " device id = " << video_device_id;
1331 return true;
1334 bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
1335 DCHECK(request->audio_type() == MEDIA_TAB_AUDIO_CAPTURE ||
1336 request->video_type() == MEDIA_TAB_VIDEO_CAPTURE);
1338 std::string capture_device_id;
1339 bool mandatory_audio = false;
1340 bool mandatory_video = false;
1341 if (!request->options.GetFirstAudioConstraintByName(kMediaStreamSourceId,
1342 &capture_device_id,
1343 &mandatory_audio) &&
1344 !request->options.GetFirstVideoConstraintByName(kMediaStreamSourceId,
1345 &capture_device_id,
1346 &mandatory_video)) {
1347 return false;
1349 DCHECK(mandatory_audio || mandatory_video);
1351 // Customize options for a WebContents based capture.
1352 int target_render_process_id = 0;
1353 int target_render_frame_id = 0;
1355 bool has_valid_device_id = WebContentsCaptureUtil::ExtractTabCaptureTarget(
1356 capture_device_id, &target_render_process_id, &target_render_frame_id);
1357 if (!has_valid_device_id ||
1358 (request->audio_type() != MEDIA_TAB_AUDIO_CAPTURE &&
1359 request->audio_type() != MEDIA_NO_SERVICE) ||
1360 (request->video_type() != MEDIA_TAB_VIDEO_CAPTURE &&
1361 request->video_type() != MEDIA_NO_SERVICE)) {
1362 return false;
1364 request->tab_capture_device_id = capture_device_id;
1366 request->CreateTabCaptureUIRequest(target_render_process_id,
1367 target_render_frame_id);
1369 DVLOG(3) << "SetupTabCaptureRequest "
1370 << ", {capture_device_id = " << capture_device_id << "}"
1371 << ", {target_render_process_id = " << target_render_process_id
1372 << "}"
1373 << ", {target_render_frame_id = " << target_render_frame_id << "}";
1374 return true;
1377 bool MediaStreamManager::SetupScreenCaptureRequest(DeviceRequest* request) {
1378 DCHECK(request->audio_type() == MEDIA_DESKTOP_AUDIO_CAPTURE ||
1379 request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE);
1381 // For screen capture we only support two valid combinations:
1382 // (1) screen video capture only, or
1383 // (2) screen video capture with loopback audio capture.
1384 if (request->video_type() != MEDIA_DESKTOP_VIDEO_CAPTURE ||
1385 (request->audio_type() != MEDIA_NO_SERVICE &&
1386 request->audio_type() != MEDIA_DESKTOP_AUDIO_CAPTURE)) {
1387 LOG(ERROR) << "Invalid screen capture request.";
1388 return false;
1391 std::string video_device_id;
1392 if (request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE) {
1393 std::string video_stream_source;
1394 bool mandatory = false;
1395 if (!request->options.GetFirstVideoConstraintByName(
1396 kMediaStreamSource,
1397 &video_stream_source,
1398 &mandatory)) {
1399 LOG(ERROR) << kMediaStreamSource << " not found.";
1400 return false;
1402 DCHECK(mandatory);
1404 if (video_stream_source == kMediaStreamSourceDesktop) {
1405 if (!request->options.GetFirstVideoConstraintByName(
1406 kMediaStreamSourceId,
1407 &video_device_id,
1408 &mandatory)) {
1409 LOG(ERROR) << kMediaStreamSourceId << " not found.";
1410 return false;
1412 DCHECK(mandatory);
1416 request->CreateUIRequest("", video_device_id);
1417 return true;
1420 StreamDeviceInfoArray MediaStreamManager::GetDevicesOpenedByRequest(
1421 const std::string& label) const {
1422 DeviceRequest* request = FindRequest(label);
1423 if (!request)
1424 return StreamDeviceInfoArray();
1425 return request->devices;
1428 bool MediaStreamManager::FindExistingRequestedDeviceInfo(
1429 const DeviceRequest& new_request,
1430 const MediaStreamDevice& new_device_info,
1431 StreamDeviceInfo* existing_device_info,
1432 MediaRequestState* existing_request_state) const {
1433 DCHECK(existing_device_info);
1434 DCHECK(existing_request_state);
1436 std::string source_id = content::GetHMACForMediaDeviceID(
1437 new_request.salt_callback,
1438 new_request.security_origin,
1439 new_device_info.id);
1441 for (DeviceRequests::const_iterator it = requests_.begin();
1442 it != requests_.end() ; ++it) {
1443 const DeviceRequest* request = it->second;
1444 if (request->requesting_process_id == new_request.requesting_process_id &&
1445 request->requesting_frame_id == new_request.requesting_frame_id &&
1446 request->request_type == new_request.request_type) {
1447 for (StreamDeviceInfoArray::const_iterator device_it =
1448 request->devices.begin();
1449 device_it != request->devices.end(); ++device_it) {
1450 if (device_it->device.id == source_id &&
1451 device_it->device.type == new_device_info.type) {
1452 *existing_device_info = *device_it;
1453 // Make sure that the audio |effects| reflect what the request
1454 // is set to and not what the capabilities are.
1455 FilterAudioEffects(request->options,
1456 &existing_device_info->device.input.effects);
1457 EnableHotwordEffect(request->options,
1458 &existing_device_info->device.input.effects);
1459 *existing_request_state = request->state(device_it->device.type);
1460 return true;
1465 return false;
1468 void MediaStreamManager::FinalizeGenerateStream(const std::string& label,
1469 DeviceRequest* request) {
1470 DVLOG(1) << "FinalizeGenerateStream label " << label;
1471 const StreamDeviceInfoArray& requested_devices = request->devices;
1473 // Partition the array of devices into audio vs video.
1474 StreamDeviceInfoArray audio_devices, video_devices;
1475 for (StreamDeviceInfoArray::const_iterator device_it =
1476 requested_devices.begin();
1477 device_it != requested_devices.end(); ++device_it) {
1478 if (IsAudioInputMediaType(device_it->device.type)) {
1479 audio_devices.push_back(*device_it);
1480 } else if (IsVideoMediaType(device_it->device.type)) {
1481 video_devices.push_back(*device_it);
1482 } else {
1483 NOTREACHED();
1487 request->requester->StreamGenerated(
1488 request->requesting_frame_id,
1489 request->page_request_id,
1490 label, audio_devices, video_devices);
1493 void MediaStreamManager::FinalizeRequestFailed(
1494 const std::string& label,
1495 DeviceRequest* request,
1496 content::MediaStreamRequestResult result) {
1497 if (request->requester)
1498 request->requester->StreamGenerationFailed(
1499 request->requesting_frame_id,
1500 request->page_request_id,
1501 result);
1503 if (request->request_type == MEDIA_DEVICE_ACCESS &&
1504 !request->callback.is_null()) {
1505 request->callback.Run(MediaStreamDevices(), request->ui_proxy.Pass());
1508 DeleteRequest(label);
1511 void MediaStreamManager::FinalizeOpenDevice(const std::string& label,
1512 DeviceRequest* request) {
1513 const StreamDeviceInfoArray& requested_devices = request->devices;
1514 request->requester->DeviceOpened(request->requesting_frame_id,
1515 request->page_request_id,
1516 label, requested_devices.front());
1519 void MediaStreamManager::FinalizeEnumerateDevices(const std::string& label,
1520 DeviceRequest* request) {
1521 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1522 DCHECK_EQ(request->request_type, MEDIA_ENUMERATE_DEVICES);
1523 DCHECK(((request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
1524 request->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT) &&
1525 request->video_type() == MEDIA_NO_SERVICE) ||
1526 (request->audio_type() == MEDIA_NO_SERVICE &&
1527 request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE));
1529 if (request->security_origin.is_valid()) {
1530 for (StreamDeviceInfoArray::iterator it = request->devices.begin();
1531 it != request->devices.end(); ++it) {
1532 TranslateDeviceIdToSourceId(request, &it->device);
1534 } else {
1535 request->devices.clear();
1538 if (use_fake_ui_) {
1539 if (!fake_ui_)
1540 fake_ui_.reset(new FakeMediaStreamUIProxy());
1541 request->ui_proxy = fake_ui_.Pass();
1542 } else {
1543 request->ui_proxy = MediaStreamUIProxy::Create();
1546 // Output label permissions are based on input permission.
1547 MediaStreamType type =
1548 request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
1549 request->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT
1550 ? MEDIA_DEVICE_AUDIO_CAPTURE
1551 : MEDIA_DEVICE_VIDEO_CAPTURE;
1553 request->ui_proxy->CheckAccess(
1554 request->security_origin,
1555 type,
1556 request->requesting_process_id,
1557 request->requesting_frame_id,
1558 base::Bind(&MediaStreamManager::HandleCheckMediaAccessResponse,
1559 base::Unretained(this),
1560 label));
1563 void MediaStreamManager::HandleCheckMediaAccessResponse(
1564 const std::string& label,
1565 bool have_access) {
1566 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1568 DeviceRequest* request = FindRequest(label);
1569 if (!request) {
1570 // This can happen if the request was cancelled.
1571 DVLOG(1) << "The request with label " << label << " does not exist.";
1572 return;
1575 if (!have_access)
1576 ClearDeviceLabels(&request->devices);
1578 request->requester->DevicesEnumerated(
1579 request->requesting_frame_id,
1580 request->page_request_id,
1581 label,
1582 request->devices);
1584 // TODO(tommi):
1585 // Ideally enumeration requests should be deleted once they have been served
1586 // (as any request). However, this implementation mixes requests and
1587 // notifications together so enumeration requests are kept open by some
1588 // implementations (only Pepper?) and enumerations are done again when
1589 // device notifications are fired.
1590 // Implementations that just want to request the device list and be done
1591 // (e.g. DeviceRequestMessageFilter), they must (confusingly) call
1592 // CancelRequest() after the request has been fulfilled. This is not
1593 // obvious, not consistent in this class (see e.g. FinalizeMediaAccessRequest)
1594 // and can lead to subtle bugs (requests not deleted at all deleted too
1595 // early).
1597 // Basically, it is not clear that using requests as an additional layer on
1598 // top of device notifications is necessary or good.
1600 // To add to this, MediaStreamManager currently relies on the external
1601 // implementations of MediaStreamRequester to delete enumeration requests via
1602 // CancelRequest and e.g. DeviceRequestMessageFilter does this. However the
1603 // Pepper implementation does not seem to to this at all (and from what I can
1604 // see, it is the only implementation that uses an enumeration request as a
1605 // notification mechanism).
1607 // We should decouple notifications from enumeration requests and once that
1608 // has been done, remove the requirement to call CancelRequest() to delete
1609 // enumeration requests and uncomment the following line:
1611 // DeleteRequest(label);
1614 void MediaStreamManager::FinalizeMediaAccessRequest(
1615 const std::string& label,
1616 DeviceRequest* request,
1617 const MediaStreamDevices& devices) {
1618 if (!request->callback.is_null())
1619 request->callback.Run(devices, request->ui_proxy.Pass());
1621 // Delete the request since it is done.
1622 DeleteRequest(label);
1625 void MediaStreamManager::InitializeDeviceManagersOnIOThread() {
1626 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1627 if (device_task_runner_.get())
1628 return;
1630 device_task_runner_ = audio_manager_->GetWorkerTaskRunner();
1632 audio_input_device_manager_ = new AudioInputDeviceManager(audio_manager_);
1633 audio_input_device_manager_->Register(this, device_task_runner_);
1635 // We want to be notified of IO message loop destruction to delete the thread
1636 // and the device managers.
1637 io_loop_ = base::MessageLoop::current();
1638 io_loop_->AddDestructionObserver(this);
1640 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1641 switches::kUseFakeDeviceForMediaStream)) {
1642 audio_input_device_manager()->UseFakeDevice();
1645 video_capture_manager_ =
1646 new VideoCaptureManager(media::VideoCaptureDeviceFactory::CreateFactory(
1647 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI)));
1648 #if defined(OS_WIN)
1649 // Use an STA Video Capture Thread to try to avoid crashes on enumeration of
1650 // buggy third party Direct Show modules, http://crbug.com/428958.
1651 video_capture_thread_.init_com_with_mta(false);
1653 // TODO(pkasting): Remove ScopedTracker below once crbug.com/457525 is
1654 // fixed.
1655 tracked_objects::ScopedTracker tracking_profile(
1656 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1657 "457525 "
1658 "MediaStreamManager::InitializeDeviceManagersOnIOThread -> Start"));
1659 CHECK(video_capture_thread_.Start());
1661 video_capture_manager_->Register(this,
1662 video_capture_thread_.message_loop_proxy());
1663 #else
1664 video_capture_manager_->Register(this, device_task_runner_);
1665 #endif
1668 void MediaStreamManager::Opened(MediaStreamType stream_type,
1669 int capture_session_id) {
1670 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1671 DVLOG(1) << "Opened({stream_type = " << stream_type << "} "
1672 << "{capture_session_id = " << capture_session_id << "})";
1673 // Find the request(s) containing this device and mark it as used.
1674 // It can be used in several requests since the same device can be
1675 // requested from the same web page.
1676 for (DeviceRequests::iterator request_it = requests_.begin();
1677 request_it != requests_.end(); ++request_it) {
1678 const std::string& label = request_it->first;
1679 DeviceRequest* request = request_it->second;
1680 StreamDeviceInfoArray* devices = &(request->devices);
1681 for (StreamDeviceInfoArray::iterator device_it = devices->begin();
1682 device_it != devices->end(); ++device_it) {
1683 if (device_it->device.type == stream_type &&
1684 device_it->session_id == capture_session_id) {
1685 CHECK(request->state(device_it->device.type) ==
1686 MEDIA_REQUEST_STATE_OPENING);
1687 // We've found a matching request.
1688 request->SetState(device_it->device.type, MEDIA_REQUEST_STATE_DONE);
1690 if (IsAudioInputMediaType(device_it->device.type)) {
1691 // Store the native audio parameters in the device struct.
1692 // TODO(xians): Handle the tab capture sample rate/channel layout
1693 // in AudioInputDeviceManager::Open().
1694 if (device_it->device.type != content::MEDIA_TAB_AUDIO_CAPTURE) {
1695 const StreamDeviceInfo* info =
1696 audio_input_device_manager_->GetOpenedDeviceInfoById(
1697 device_it->session_id);
1698 device_it->device.input = info->device.input;
1700 // Since the audio input device manager will set the input
1701 // parameters to the default settings (including supported effects),
1702 // we need to adjust those settings here according to what the
1703 // request asks for.
1704 FilterAudioEffects(request->options,
1705 &device_it->device.input.effects);
1706 EnableHotwordEffect(request->options,
1707 &device_it->device.input.effects);
1709 device_it->device.matched_output = info->device.matched_output;
1712 if (RequestDone(*request))
1713 HandleRequestDone(label, request);
1714 break;
1720 void MediaStreamManager::HandleRequestDone(const std::string& label,
1721 DeviceRequest* request) {
1722 DCHECK(RequestDone(*request));
1723 DVLOG(1) << "HandleRequestDone("
1724 << ", {label = " << label << "})";
1726 switch (request->request_type) {
1727 case MEDIA_OPEN_DEVICE:
1728 FinalizeOpenDevice(label, request);
1729 break;
1730 case MEDIA_GENERATE_STREAM: {
1731 FinalizeGenerateStream(label, request);
1732 break;
1734 default:
1735 NOTREACHED();
1736 break;
1739 if (request->ui_proxy.get()) {
1740 request->ui_proxy->OnStarted(
1741 base::Bind(&MediaStreamManager::StopMediaStreamFromBrowser,
1742 base::Unretained(this),
1743 label),
1744 base::Bind(&MediaStreamManager::OnMediaStreamUIWindowId,
1745 base::Unretained(this),
1746 request->video_type(),
1747 request->devices));
1751 void MediaStreamManager::Closed(MediaStreamType stream_type,
1752 int capture_session_id) {
1753 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1756 void MediaStreamManager::DevicesEnumerated(
1757 MediaStreamType stream_type, const StreamDeviceInfoArray& devices) {
1758 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1759 DVLOG(1) << "DevicesEnumerated("
1760 << "{stream_type = " << stream_type << "})" << std::endl;
1762 std::string log_message = "New device enumeration result:\n" +
1763 GetLogMessageString(stream_type, devices);
1764 SendMessageToNativeLog(log_message);
1766 // Only cache the device list when the device list has been changed.
1767 bool need_update_clients = false;
1768 EnumerationCache* cache =
1769 stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
1770 &audio_enumeration_cache_ : &video_enumeration_cache_;
1771 if (!cache->valid ||
1772 devices.size() != cache->devices.size() ||
1773 !std::equal(devices.begin(), devices.end(), cache->devices.begin(),
1774 StreamDeviceInfo::IsEqual)) {
1775 StopRemovedDevices(cache->devices, devices);
1776 cache->devices = devices;
1777 need_update_clients = true;
1779 // The device might not be able to be enumerated when it is not warmed up,
1780 // for example, when the machine just wakes up from sleep. We set the cache
1781 // to be invalid so that the next media request will trigger the
1782 // enumeration again. See issue/317673.
1783 cache->valid = !devices.empty();
1786 if (need_update_clients && monitoring_started_)
1787 NotifyDevicesChanged(stream_type, devices);
1789 // Publish the result for all requests waiting for device list(s).
1790 // Find the requests waiting for this device list, store their labels and
1791 // release the iterator before calling device settings. We might get a call
1792 // back from device_settings that will need to iterate through devices.
1793 std::list<std::string> label_list;
1794 for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
1795 ++it) {
1796 if (it->second->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED &&
1797 (it->second->audio_type() == stream_type ||
1798 it->second->video_type() == stream_type)) {
1799 if (it->second->request_type != MEDIA_ENUMERATE_DEVICES)
1800 it->second->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
1801 label_list.push_back(it->first);
1805 for (std::list<std::string>::iterator it = label_list.begin();
1806 it != label_list.end(); ++it) {
1807 DeviceRequest* request = FindRequest(*it);
1808 switch (request->request_type) {
1809 case MEDIA_ENUMERATE_DEVICES:
1810 if (need_update_clients && request->requester) {
1811 request->devices = devices;
1812 FinalizeEnumerateDevices(*it, request);
1814 break;
1815 default:
1816 if (request->state(request->audio_type()) ==
1817 MEDIA_REQUEST_STATE_REQUESTED ||
1818 request->state(request->video_type()) ==
1819 MEDIA_REQUEST_STATE_REQUESTED) {
1820 // We are doing enumeration for other type of media, wait until it is
1821 // all done before posting the request to UI because UI needs
1822 // the device lists to handle the request.
1823 break;
1825 if (!SetupDeviceCaptureRequest(request)) {
1826 FinalizeRequestFailed(*it,
1827 request,
1828 MEDIA_DEVICE_NO_HARDWARE);
1829 } else {
1830 PostRequestToUI(*it, request);
1832 break;
1835 label_list.clear();
1836 --active_enumeration_ref_count_[stream_type];
1837 DCHECK_GE(active_enumeration_ref_count_[stream_type], 0);
1840 void MediaStreamManager::Aborted(MediaStreamType stream_type,
1841 int capture_session_id) {
1842 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1843 DVLOG(1) << "Aborted({stream_type = " << stream_type << "} "
1844 << "{capture_session_id = " << capture_session_id << "})";
1845 StopDevice(stream_type, capture_session_id);
1848 // static
1849 void MediaStreamManager::SendMessageToNativeLog(const std::string& message) {
1850 BrowserThread::PostTask(
1851 BrowserThread::UI, FROM_HERE,
1852 base::Bind(DoAddLogMessage, message));
1855 void MediaStreamManager::OnSuspend() {
1856 SendMessageToNativeLog("Power state suspended.");
1859 void MediaStreamManager::OnResume() {
1860 SendMessageToNativeLog("Power state resumed.");
1863 void MediaStreamManager::AddLogMessageOnIOThread(const std::string& message) {
1864 // Get render process ids on the IO thread.
1865 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1867 // Grab all unique process ids that request a MediaStream or have a
1868 // MediaStream running.
1869 std::set<int> requesting_process_ids;
1870 for (DeviceRequests::const_iterator it = requests_.begin();
1871 it != requests_.end(); ++it) {
1872 DeviceRequest* request = it->second;
1873 if (request->request_type == MEDIA_GENERATE_STREAM)
1874 requesting_process_ids.insert(request->requesting_process_id);
1877 // MediaStreamManager is a singleton in BrowserMainLoop, which owns the UI
1878 // thread. MediaStreamManager has the same lifetime as the UI thread, so it is
1879 // safe to use base::Unretained.
1880 BrowserThread::PostTask(
1881 BrowserThread::UI,
1882 FROM_HERE,
1883 base::Bind(&MediaStreamManager::AddLogMessageOnUIThread,
1884 base::Unretained(this),
1885 requesting_process_ids,
1886 message));
1889 void MediaStreamManager::AddLogMessageOnUIThread(
1890 const std::set<int>& requesting_process_ids,
1891 const std::string& message) {
1892 #if defined(ENABLE_WEBRTC)
1893 // Must be on the UI thread to access RenderProcessHost from process ID.
1894 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1896 for (std::set<int>::const_iterator it = requesting_process_ids.begin();
1897 it != requesting_process_ids.end(); ++it) {
1898 // Log the message to all renderers that are requesting a MediaStream or
1899 // have a MediaStream running.
1900 content::RenderProcessHostImpl* render_process_host_impl =
1901 static_cast<content::RenderProcessHostImpl*>(
1902 content::RenderProcessHost::FromID(*it));
1903 if (render_process_host_impl)
1904 render_process_host_impl->WebRtcLogMessage(message);
1906 #endif
1909 void MediaStreamManager::HandleAccessRequestResponse(
1910 const std::string& label,
1911 const MediaStreamDevices& devices,
1912 content::MediaStreamRequestResult result) {
1913 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1914 DVLOG(1) << "HandleAccessRequestResponse("
1915 << ", {label = " << label << "})";
1917 DeviceRequest* request = FindRequest(label);
1918 if (!request) {
1919 // The request has been canceled before the UI returned.
1920 return;
1923 if (request->request_type == MEDIA_DEVICE_ACCESS) {
1924 FinalizeMediaAccessRequest(label, request, devices);
1925 return;
1928 // Handle the case when the request was denied.
1929 if (result != MEDIA_DEVICE_OK) {
1930 FinalizeRequestFailed(label, request, result);
1931 return;
1933 DCHECK(!devices.empty());
1935 // Process all newly-accepted devices for this request.
1936 bool found_audio = false;
1937 bool found_video = false;
1938 for (MediaStreamDevices::const_iterator device_it = devices.begin();
1939 device_it != devices.end(); ++device_it) {
1940 StreamDeviceInfo device_info;
1941 device_info.device = *device_it;
1943 if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE ||
1944 device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
1945 device_info.device.id = request->tab_capture_device_id;
1947 // Initialize the sample_rate and channel_layout here since for audio
1948 // mirroring, we don't go through EnumerateDevices where these are usually
1949 // initialized.
1950 if (device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
1951 const media::AudioParameters parameters =
1952 audio_manager_->GetDefaultOutputStreamParameters();
1953 int sample_rate = parameters.sample_rate();
1954 // If we weren't able to get the native sampling rate or the sample_rate
1955 // is outside the valid range for input devices set reasonable defaults.
1956 if (sample_rate <= 0 || sample_rate > 96000)
1957 sample_rate = 44100;
1959 device_info.device.input.sample_rate = sample_rate;
1960 device_info.device.input.channel_layout = media::CHANNEL_LAYOUT_STEREO;
1964 if (device_info.device.type == request->audio_type()) {
1965 found_audio = true;
1966 } else if (device_info.device.type == request->video_type()) {
1967 found_video = true;
1970 // If this is request for a new MediaStream, a device is only opened once
1971 // per render frame. This is so that the permission to use a device can be
1972 // revoked by a single call to StopStreamDevice regardless of how many
1973 // MediaStreams it is being used in.
1974 if (request->request_type == MEDIA_GENERATE_STREAM) {
1975 MediaRequestState state;
1976 if (FindExistingRequestedDeviceInfo(*request,
1977 device_info.device,
1978 &device_info,
1979 &state)) {
1980 request->devices.push_back(device_info);
1981 request->SetState(device_info.device.type, state);
1982 DVLOG(1) << "HandleAccessRequestResponse - device already opened "
1983 << ", {label = " << label << "}"
1984 << ", device_id = " << device_it->id << "}";
1985 continue;
1988 device_info.session_id =
1989 GetDeviceManager(device_info.device.type)->Open(device_info);
1990 TranslateDeviceIdToSourceId(request, &device_info.device);
1991 request->devices.push_back(device_info);
1993 request->SetState(device_info.device.type, MEDIA_REQUEST_STATE_OPENING);
1994 DVLOG(1) << "HandleAccessRequestResponse - opening device "
1995 << ", {label = " << label << "}"
1996 << ", {device_id = " << device_info.device.id << "}"
1997 << ", {session_id = " << device_info.session_id << "}";
2000 // Check whether we've received all stream types requested.
2001 if (!found_audio && IsAudioInputMediaType(request->audio_type())) {
2002 request->SetState(request->audio_type(), MEDIA_REQUEST_STATE_ERROR);
2003 DVLOG(1) << "Set no audio found label " << label;
2006 if (!found_video && IsVideoMediaType(request->video_type()))
2007 request->SetState(request->video_type(), MEDIA_REQUEST_STATE_ERROR);
2009 if (RequestDone(*request))
2010 HandleRequestDone(label, request);
2013 void MediaStreamManager::StopMediaStreamFromBrowser(const std::string& label) {
2014 DCHECK_CURRENTLY_ON(BrowserThread::IO);
2016 DeviceRequest* request = FindRequest(label);
2017 if (!request)
2018 return;
2020 // Notify renderers that the devices in the stream will be stopped.
2021 if (request->requester) {
2022 for (StreamDeviceInfoArray::iterator device_it = request->devices.begin();
2023 device_it != request->devices.end(); ++device_it) {
2024 request->requester->DeviceStopped(request->requesting_frame_id,
2025 label,
2026 *device_it);
2030 CancelRequest(label);
2033 void MediaStreamManager::UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy> fake_ui) {
2034 DCHECK_CURRENTLY_ON(BrowserThread::IO);
2035 use_fake_ui_ = true;
2036 fake_ui_ = fake_ui.Pass();
2039 void MediaStreamManager::WillDestroyCurrentMessageLoop() {
2040 DVLOG(3) << "MediaStreamManager::WillDestroyCurrentMessageLoop()";
2041 DCHECK_EQ(base::MessageLoop::current(), io_loop_);
2042 DCHECK(requests_.empty());
2043 if (device_task_runner_.get()) {
2044 StopMonitoring();
2046 video_capture_manager_->Unregister();
2047 audio_input_device_manager_->Unregister();
2048 device_task_runner_ = NULL;
2051 audio_input_device_manager_ = NULL;
2052 video_capture_manager_ = NULL;
2055 void MediaStreamManager::NotifyDevicesChanged(
2056 MediaStreamType stream_type,
2057 const StreamDeviceInfoArray& devices) {
2058 DCHECK_CURRENTLY_ON(BrowserThread::IO);
2059 MediaObserver* media_observer =
2060 GetContentClient()->browser()->GetMediaObserver();
2062 // Map the devices to MediaStreamDevices.
2063 MediaStreamDevices new_devices;
2064 for (StreamDeviceInfoArray::const_iterator it = devices.begin();
2065 it != devices.end(); ++it) {
2066 new_devices.push_back(it->device);
2069 if (IsAudioInputMediaType(stream_type)) {
2070 MediaCaptureDevicesImpl::GetInstance()->OnAudioCaptureDevicesChanged(
2071 new_devices);
2072 if (media_observer)
2073 media_observer->OnAudioCaptureDevicesChanged();
2074 } else if (IsVideoMediaType(stream_type)) {
2075 MediaCaptureDevicesImpl::GetInstance()->OnVideoCaptureDevicesChanged(
2076 new_devices);
2077 if (media_observer)
2078 media_observer->OnVideoCaptureDevicesChanged();
2079 } else {
2080 NOTREACHED();
2084 bool MediaStreamManager::RequestDone(const DeviceRequest& request) const {
2085 DCHECK_CURRENTLY_ON(BrowserThread::IO);
2087 const bool requested_audio = IsAudioInputMediaType(request.audio_type());
2088 const bool requested_video = IsVideoMediaType(request.video_type());
2090 const bool audio_done =
2091 !requested_audio ||
2092 request.state(request.audio_type()) == MEDIA_REQUEST_STATE_DONE ||
2093 request.state(request.audio_type()) == MEDIA_REQUEST_STATE_ERROR;
2094 if (!audio_done)
2095 return false;
2097 const bool video_done =
2098 !requested_video ||
2099 request.state(request.video_type()) == MEDIA_REQUEST_STATE_DONE ||
2100 request.state(request.video_type()) == MEDIA_REQUEST_STATE_ERROR;
2101 if (!video_done)
2102 return false;
2104 return true;
2107 MediaStreamProvider* MediaStreamManager::GetDeviceManager(
2108 MediaStreamType stream_type) {
2109 if (IsVideoMediaType(stream_type)) {
2110 return video_capture_manager();
2111 } else if (IsAudioInputMediaType(stream_type)) {
2112 return audio_input_device_manager();
2114 NOTREACHED();
2115 return NULL;
2118 void MediaStreamManager::OnDevicesChanged(
2119 base::SystemMonitor::DeviceType device_type) {
2120 DCHECK_CURRENTLY_ON(BrowserThread::IO);
2122 // NOTE: This method is only called in response to physical audio/video device
2123 // changes (from the operating system).
2125 MediaStreamType stream_type;
2126 if (device_type == base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE) {
2127 stream_type = MEDIA_DEVICE_AUDIO_CAPTURE;
2128 } else if (device_type == base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE) {
2129 stream_type = MEDIA_DEVICE_VIDEO_CAPTURE;
2130 } else {
2131 return; // Uninteresting device change.
2134 // Always do enumeration even though some enumeration is in progress,
2135 // because those enumeration commands could be sent before these devices
2136 // change.
2137 ++active_enumeration_ref_count_[stream_type];
2138 GetDeviceManager(stream_type)->EnumerateDevices(stream_type);
2141 void MediaStreamManager::OnMediaStreamUIWindowId(MediaStreamType video_type,
2142 StreamDeviceInfoArray devices,
2143 gfx::NativeViewId window_id) {
2144 DCHECK_CURRENTLY_ON(BrowserThread::IO);
2145 if (!window_id)
2146 return;
2148 // Pass along for desktop capturing. Ignored for other stream types.
2149 if (video_type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
2150 for (StreamDeviceInfoArray::iterator it = devices.begin();
2151 it != devices.end();
2152 ++it) {
2153 if (it->device.type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
2154 video_capture_manager_->SetDesktopCaptureWindowId(it->session_id,
2155 window_id);
2156 break;
2162 #if defined(OS_CHROMEOS)
2163 void MediaStreamManager::EnsureKeyboardMicChecked() {
2164 DCHECK_CURRENTLY_ON(BrowserThread::IO);
2165 if (!has_checked_keyboard_mic_) {
2166 has_checked_keyboard_mic_ = true;
2167 BrowserThread::PostTask(
2168 BrowserThread::UI, FROM_HERE,
2169 base::Bind(&MediaStreamManager::CheckKeyboardMicOnUIThread,
2170 base::Unretained(this)));
2174 void MediaStreamManager::CheckKeyboardMicOnUIThread() {
2175 DCHECK_CURRENTLY_ON(BrowserThread::UI);
2177 // We will post this on the device thread before the media media access
2178 // request is posted on the UI thread, so setting the keyboard mic info will
2179 // be done before any stream is created.
2180 if (chromeos::CrasAudioHandler::Get()->HasKeyboardMic()) {
2181 device_task_runner_->PostTask(
2182 FROM_HERE,
2183 base::Bind(&MediaStreamManager::SetKeyboardMicOnDeviceThread,
2184 base::Unretained(this)));
2188 void MediaStreamManager::SetKeyboardMicOnDeviceThread() {
2189 DCHECK(device_task_runner_->BelongsToCurrentThread());
2190 audio_manager_->SetHasKeyboardMic();
2192 #endif
2194 } // namespace content