1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/media/media_stream_manager.h"
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/compiler_specific.h"
13 #include "base/logging.h"
14 #include "base/power_monitor/power_monitor.h"
15 #include "base/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"
45 #include "base/win/scoped_com_initializer.h"
48 #if defined(OS_CHROMEOS)
49 #include "chromeos/audio/cras_audio_handler.h"
54 // Forward declaration of DeviceMonitorMac and its only useable method.
55 class DeviceMonitorMac
{
58 const scoped_refptr
<base::SingleThreadTaskRunner
>& device_task_runner
);
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
];
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
,
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
;
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
,
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
;
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
) {
130 // TODO(ajm): Should we also handle ECHO_CANCELLER here?
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
) {
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
;
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(
173 base::Bind(&MediaStreamManager::AddLogMessageOnIOThread
,
174 base::Unretained(content::BrowserMainLoop::GetInstance()
175 ->media_stream_manager()),
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.";
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();
207 device_itr
->device
.name
.clear();
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
{
222 DeviceRequest(MediaStreamRequester
* requester
,
223 int requesting_process_id
,
224 int requesting_frame_id
,
226 const GURL
& security_origin
,
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
),
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) {
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
,
278 requested_audio_device_id
,
279 requested_video_device_id
,
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
,
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
;
316 state_
[stream_type
] = new_state
;
319 MediaObserver
* media_observer
=
320 GetContentClient()->browser()->GetMediaObserver();
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
;
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()
385 MediaStreamManager::EnumerationCache::~EnumerationCache() {
388 MediaStreamManager::MediaStreamManager()
389 : audio_manager_(NULL
),
391 video_capture_thread_("VideoCaptureThread"),
393 monitoring_started_(false),
394 #if defined(OS_CHROMEOS)
395 has_checked_keyboard_mic_(false),
398 use_fake_ui_(false) {}
400 MediaStreamManager::MediaStreamManager(media::AudioManager
* audio_manager
)
401 : audio_manager_(audio_manager
),
403 video_capture_thread_("VideoCaptureThread"),
405 monitoring_started_(false),
406 #if defined(OS_CHROMEOS)
407 has_checked_keyboard_mic_(false),
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();
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.
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.
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
,
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
,
473 false, // user gesture
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
486 BrowserThread::PostTask(
487 BrowserThread::IO
, FROM_HERE
,
488 base::Bind(&MediaStreamManager::SetupRequest
,
489 base::Unretained(this), label
));
493 void MediaStreamManager::GenerateStream(MediaStreamRequester
* requester
,
494 int render_process_id
,
496 const ResourceContext::SaltCallback
& sc
,
498 const StreamOptions
& options
,
499 const GURL
& security_origin
,
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
,
514 MEDIA_GENERATE_STREAM
,
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
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
,
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
);
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
);
552 // The request does not exist.
553 LOG(ERROR
) << "The request with label = " << label
<< " does not exist.";
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
);
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
) {
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
) {
593 std::string label
= request_it
->first
;
595 CancelRequest(label
);
599 void MediaStreamManager::StopStreamDevice(int render_process_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
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
) {
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
);
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.
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
) {
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
;
660 DeleteRequest(label
);
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
,
692 const ResourceContext::SaltCallback
& sc
,
694 MediaStreamType type
,
695 const GURL
& security_origin
) {
696 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
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
,
707 false, // user gesture
708 MEDIA_ENUMERATE_DEVICES
,
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
722 BrowserThread::PostTask(
723 BrowserThread::IO
, FROM_HERE
,
724 base::Bind(&MediaStreamManager::DoEnumerateDevices
,
725 base::Unretained(this), label
));
729 void MediaStreamManager::DoEnumerateDevices(const std::string
& label
) {
730 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
731 DeviceRequest
* request
= FindRequest(label
);
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(
743 base::Bind(&MediaStreamManager::EnumerateAudioOutputDevices
,
744 base::Unretained(this),
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_
;
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
);
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
,
786 devices
.push_back(device
);
789 BrowserThread::PostTask(
790 BrowserThread::IO
, FROM_HERE
,
791 base::Bind(&MediaStreamManager::AudioOutputDevicesEnumerated
,
792 base::Unretained(this),
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
,
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();
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
,
827 const ResourceContext::SaltCallback
& sc
,
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
));
848 DeviceRequest
* request
= new DeviceRequest(requester
,
853 false, // user gesture
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
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())
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.
890 for (StreamDeviceInfoArray::const_iterator it
= cache
->devices
.begin();
891 it
!= cache
->devices
.end();
893 if (content::DoesMediaDeviceIDMatchHMAC(sc
, security_origin
, source_id
,
895 *device_id
= it
->device
.id
;
902 void MediaStreamManager::EnsureDeviceMonitorStarted() {
903 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
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
) {
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
,
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
,
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_
)
973 if (!base::SystemMonitor::Get())
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)));
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
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
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
);
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.";
1051 // If a specific device has been requested we need to find the real device
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] << ".";
1062 // Check for optional audio sourceIDs.
1063 if (device_id
->empty()) {
1064 StreamOptions::GetConstraintsByName(*optional
,
1065 kMediaStreamSourceInfoId
,
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
,
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
,
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
)
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
);
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.
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
)
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
;
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
;
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
);
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
);
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();
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
);
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
,
1245 MEDIA_DEVICE_INVALID_SECURITY_ORIGIN
);
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
,
1261 MEDIA_DEVICE_TAB_CAPTURE_FAILURE
);
1265 bool is_screen_capture
=
1266 video_type
== MEDIA_DESKTOP_VIDEO_CAPTURE
;
1267 if (is_screen_capture
&& !SetupScreenCaptureRequest(request
)) {
1268 FinalizeRequestFailed(label
,
1270 MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE
);
1274 #if defined(OS_CHROMEOS)
1275 EnsureKeyboardMicChecked();
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
);
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
) {
1290 GetLogMessageString(audio_type
, audio_enumeration_cache_
.devices
);
1292 if (video_type
!= MEDIA_NO_SERVICE
) {
1294 GetLogMessageString(video_type
, video_enumeration_cache_
.devices
);
1296 SendMessageToNativeLog(log_message
);
1300 if (!SetupDeviceCaptureRequest(request
)) {
1301 FinalizeRequestFailed(label
, request
, MEDIA_DEVICE_NO_HARDWARE
);
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
)) {
1320 std::string video_device_id
;
1321 if (request
->options
.video_requested
&&
1322 !GetRequestedDeviceCaptureId(request
, request
->video_type(),
1323 &video_device_id
)) {
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
;
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
,
1343 &mandatory_audio
) &&
1344 !request
->options
.GetFirstVideoConstraintByName(kMediaStreamSourceId
,
1346 &mandatory_video
)) {
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
)) {
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
1373 << ", {target_render_frame_id = " << target_render_frame_id
<< "}";
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.";
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(
1397 &video_stream_source
,
1399 LOG(ERROR
) << kMediaStreamSource
<< " not found.";
1404 if (video_stream_source
== kMediaStreamSourceDesktop
) {
1405 if (!request
->options
.GetFirstVideoConstraintByName(
1406 kMediaStreamSourceId
,
1409 LOG(ERROR
) << kMediaStreamSourceId
<< " not found.";
1416 request
->CreateUIRequest("", video_device_id
);
1420 StreamDeviceInfoArray
MediaStreamManager::GetDevicesOpenedByRequest(
1421 const std::string
& label
) const {
1422 DeviceRequest
* request
= FindRequest(label
);
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
);
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
);
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
,
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
);
1535 request
->devices
.clear();
1540 fake_ui_
.reset(new FakeMediaStreamUIProxy());
1541 request
->ui_proxy
= fake_ui_
.Pass();
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
,
1556 request
->requesting_process_id
,
1557 request
->requesting_frame_id
,
1558 base::Bind(&MediaStreamManager::HandleCheckMediaAccessResponse
,
1559 base::Unretained(this),
1563 void MediaStreamManager::HandleCheckMediaAccessResponse(
1564 const std::string
& label
,
1566 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1568 DeviceRequest
* request
= FindRequest(label
);
1570 // This can happen if the request was cancelled.
1571 DVLOG(1) << "The request with label " << label
<< " does not exist.";
1576 ClearDeviceLabels(&request
->devices
);
1578 request
->requester
->DevicesEnumerated(
1579 request
->requesting_frame_id
,
1580 request
->page_request_id
,
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
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())
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
)));
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
1655 tracked_objects::ScopedTracker
tracking_profile(
1656 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1658 "MediaStreamManager::InitializeDeviceManagersOnIOThread -> Start"));
1659 CHECK(video_capture_thread_
.Start());
1661 video_capture_manager_
->Register(this,
1662 video_capture_thread_
.message_loop_proxy());
1664 video_capture_manager_
->Register(this, device_task_runner_
);
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
);
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
);
1730 case MEDIA_GENERATE_STREAM
: {
1731 FinalizeGenerateStream(label
, request
);
1739 if (request
->ui_proxy
.get()) {
1740 request
->ui_proxy
->OnStarted(
1741 base::Bind(&MediaStreamManager::StopMediaStreamFromBrowser
,
1742 base::Unretained(this),
1744 base::Bind(&MediaStreamManager::OnMediaStreamUIWindowId
,
1745 base::Unretained(this),
1746 request
->video_type(),
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();
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
);
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.
1825 if (!SetupDeviceCaptureRequest(request
)) {
1826 FinalizeRequestFailed(*it
,
1828 MEDIA_DEVICE_NO_HARDWARE
);
1830 PostRequestToUI(*it
, request
);
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
);
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(
1883 base::Bind(&MediaStreamManager::AddLogMessageOnUIThread
,
1884 base::Unretained(this),
1885 requesting_process_ids
,
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
);
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
);
1919 // The request has been canceled before the UI returned.
1923 if (request
->request_type
== MEDIA_DEVICE_ACCESS
) {
1924 FinalizeMediaAccessRequest(label
, request
, devices
);
1928 // Handle the case when the request was denied.
1929 if (result
!= MEDIA_DEVICE_OK
) {
1930 FinalizeRequestFailed(label
, request
, result
);
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
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()) {
1966 } else if (device_info
.device
.type
== request
->video_type()) {
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
,
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
<< "}";
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
);
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
,
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()) {
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(
2073 media_observer
->OnAudioCaptureDevicesChanged();
2074 } else if (IsVideoMediaType(stream_type
)) {
2075 MediaCaptureDevicesImpl::GetInstance()->OnVideoCaptureDevicesChanged(
2078 media_observer
->OnVideoCaptureDevicesChanged();
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
=
2092 request
.state(request
.audio_type()) == MEDIA_REQUEST_STATE_DONE
||
2093 request
.state(request
.audio_type()) == MEDIA_REQUEST_STATE_ERROR
;
2097 const bool video_done
=
2099 request
.state(request
.video_type()) == MEDIA_REQUEST_STATE_DONE
||
2100 request
.state(request
.video_type()) == MEDIA_REQUEST_STATE_ERROR
;
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();
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
;
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
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
);
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();
2153 if (it
->device
.type
== MEDIA_DESKTOP_VIDEO_CAPTURE
) {
2154 video_capture_manager_
->SetDesktopCaptureWindowId(it
->session_id
,
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(
2183 base::Bind(&MediaStreamManager::SetKeyboardMicOnDeviceThread
,
2184 base::Unretained(this)));
2188 void MediaStreamManager::SetKeyboardMicOnDeviceThread() {
2189 DCHECK(device_task_runner_
->BelongsToCurrentThread());
2190 audio_manager_
->SetHasKeyboardMic();
2194 } // namespace content