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"
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/compiler_specific.h"
14 #include "base/logging.h"
15 #include "base/power_monitor/power_monitor.h"
16 #include "base/profiler/scoped_tracker.h"
17 #include "base/rand_util.h"
18 #include "base/run_loop.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/threading/thread.h"
22 #include "content/browser/browser_main_loop.h"
23 #include "content/browser/media/capture/web_contents_capture_util.h"
24 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
25 #include "content/browser/renderer_host/media/audio_output_device_enumerator.h"
26 #include "content/browser/renderer_host/media/media_capture_devices_impl.h"
27 #include "content/browser/renderer_host/media/media_stream_requester.h"
28 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
29 #include "content/browser/renderer_host/media/video_capture_manager.h"
30 #include "content/browser/renderer_host/render_process_host_impl.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/content_browser_client.h"
33 #include "content/public/browser/media_device_id.h"
34 #include "content/public/browser/media_observer.h"
35 #include "content/public/browser/media_request_state.h"
36 #include "content/public/browser/render_process_host.h"
37 #include "content/public/common/content_client.h"
38 #include "content/public/common/content_switches.h"
39 #include "content/public/common/media_stream_request.h"
40 #include "media/audio/audio_manager_base.h"
41 #include "media/audio/audio_parameters.h"
42 #include "media/base/channel_layout.h"
43 #include "media/base/media_switches.h"
44 #include "media/capture/video/video_capture_device_factory.h"
48 #include "base/win/scoped_com_initializer.h"
51 #if defined(OS_CHROMEOS)
52 #include "chromeos/audio/cras_audio_handler.h"
57 // Forward declaration of DeviceMonitorMac and its only useable method.
58 class DeviceMonitorMac
{
61 const scoped_refptr
<base::SingleThreadTaskRunner
>& device_task_runner
);
65 // Creates a random label used to identify requests.
66 std::string
RandomLabel() {
67 // An earlier PeerConnection spec [1] defined MediaStream::label alphabet as
68 // an uuid with characters from range: U+0021, U+0023 to U+0027, U+002A to
69 // U+002B, U+002D to U+002E, U+0030 to U+0039, U+0041 to U+005A, U+005E to
70 // U+007E. That causes problems with searching for labels in bots, so we use a
71 // safe alphanumeric subset |kAlphabet|.
72 // [1] http://dev.w3.org/2011/webrtc/editor/webrtc.html
73 static const char kAlphabet
[] = "0123456789"
74 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
76 static const size_t kRfc4122LengthLabel
= 36u;
77 std::string
label(kRfc4122LengthLabel
, ' ');
78 for (char& c
: label
) {
79 // Use |arraysize(kAlphabet) - 1| to avoid |kAlphabet|s terminating '\0';
80 c
= kAlphabet
[base::RandGenerator(arraysize(kAlphabet
) - 1)];
81 DCHECK(std::isalnum(c
)) << c
;
86 void ParseStreamType(const StreamOptions
& options
,
87 MediaStreamType
* audio_type
,
88 MediaStreamType
* video_type
) {
89 *audio_type
= MEDIA_NO_SERVICE
;
90 *video_type
= MEDIA_NO_SERVICE
;
91 if (options
.audio_requested
) {
92 std::string audio_stream_source
;
93 bool mandatory
= false;
94 if (options
.GetFirstAudioConstraintByName(kMediaStreamSource
,
98 // This is tab or screen capture.
99 if (audio_stream_source
== kMediaStreamSourceTab
) {
100 *audio_type
= content::MEDIA_TAB_AUDIO_CAPTURE
;
101 } else if (audio_stream_source
== kMediaStreamSourceSystem
) {
102 *audio_type
= content::MEDIA_DESKTOP_AUDIO_CAPTURE
;
105 // This is normal audio device capture.
106 *audio_type
= MEDIA_DEVICE_AUDIO_CAPTURE
;
109 if (options
.video_requested
) {
110 std::string video_stream_source
;
111 bool mandatory
= false;
112 if (options
.GetFirstVideoConstraintByName(kMediaStreamSource
,
113 &video_stream_source
,
116 // This is tab or screen capture.
117 if (video_stream_source
== kMediaStreamSourceTab
) {
118 *video_type
= content::MEDIA_TAB_VIDEO_CAPTURE
;
119 } else if (video_stream_source
== kMediaStreamSourceScreen
) {
120 *video_type
= content::MEDIA_DESKTOP_VIDEO_CAPTURE
;
121 } else if (video_stream_source
== kMediaStreamSourceDesktop
) {
122 *video_type
= content::MEDIA_DESKTOP_VIDEO_CAPTURE
;
125 // This is normal video device capture.
126 *video_type
= MEDIA_DEVICE_VIDEO_CAPTURE
;
131 // Turns off available audio effects (removes the flag) if the options
132 // explicitly turn them off.
133 void FilterAudioEffects(const StreamOptions
& options
, int* effects
) {
135 // TODO(ajm): Should we handle ECHO_CANCELLER here?
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
) {
142 #if defined(OS_CHROMEOS)
144 if (options
.GetFirstAudioConstraintByName(
145 kMediaStreamAudioHotword
, &value
, NULL
) && value
== "true") {
146 chromeos::AudioDeviceList devices
;
147 chromeos::CrasAudioHandler::Get()->GetAudioDevices(&devices
);
148 // Only enable if a hotword device exists.
149 for (const chromeos::AudioDevice
& device
: devices
) {
150 if (device
.type
== chromeos::AUDIO_TYPE_AOKR
) {
151 DCHECK(device
.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 const BrowserMainLoop
* browser_main_loop
=
170 content::BrowserMainLoop::GetInstance();
171 if (!browser_main_loop
)
173 BrowserThread::PostTask(
174 BrowserThread::IO
, FROM_HERE
,
175 base::Bind(&MediaStreamManager::AddLogMessageOnIOThread
,
176 base::Unretained(browser_main_loop
->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
& device_infos
) {
184 std::string output_string
=
185 base::StringPrintf("Getting devices for stream type %d:\n", stream_type
);
186 if (device_infos
.empty())
187 return output_string
+ "No devices found.";
188 for (const content::StreamDeviceInfo
& device_info
: device_infos
)
189 output_string
+= " " + device_info
.device
.name
+ "\n";
190 return output_string
;
193 // Needed for MediaStreamManager::GenerateStream below.
194 std::string
ReturnEmptySalt() {
195 return std::string();
198 // Clears the MediaStreamDevice.name from all devices in |devices|.
199 void ClearDeviceLabels(content::StreamDeviceInfoArray
* devices
) {
200 for (content::StreamDeviceInfo
& device_info
: *devices
)
201 device_info
.device
.name
.clear();
204 // Helper method that sends log messages to the render process hosts whose
205 // corresponding render processes are in |render_process_ids|, to be used by
206 // the webrtcLoggingPrivate API if requested.
207 void AddLogMessageOnUIThread(const std::set
<int>& requesting_process_ids
,
208 const std::string
& message
) {
209 #if defined(ENABLE_WEBRTC)
210 // Must be on the UI thread to access RenderProcessHost from process ID.
211 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
213 for (const int& requesting_process_id
: requesting_process_ids
) {
214 // Log the message to all renderers that are requesting a MediaStream or
215 // have a MediaStream running.
216 content::RenderProcessHostImpl
* const render_process_host_impl
=
217 static_cast<content::RenderProcessHostImpl
*>(
218 content::RenderProcessHost::FromID(requesting_process_id
));
219 if (render_process_host_impl
)
220 render_process_host_impl
->WebRtcLogMessage(message
);
225 bool CalledOnIOThread() {
226 // Check if this function call is on the IO thread, except for unittests where
227 // an IO thread might not have been created.
228 return BrowserThread::CurrentlyOn(BrowserThread::IO
) ||
229 !BrowserThread::IsMessageLoopValid(BrowserThread::IO
);
232 void DummyEnumerationCallback(const AudioOutputDeviceEnumeration
& e
) {}
237 // MediaStreamManager::DeviceRequest represents a request to either enumerate
238 // available devices or open one or more devices.
239 // TODO(perkj): MediaStreamManager still needs refactoring. I propose we create
240 // several subclasses of DeviceRequest and move some of the responsibility of
241 // the MediaStreamManager to the subclasses to get rid of the way too many if
242 // statements in MediaStreamManager.
243 class MediaStreamManager::DeviceRequest
{
245 DeviceRequest(MediaStreamRequester
* requester
,
246 int requesting_process_id
,
247 int requesting_frame_id
,
249 const GURL
& security_origin
,
251 MediaStreamRequestType request_type
,
252 const StreamOptions
& options
,
253 const ResourceContext::SaltCallback
& salt_callback
)
254 : requester(requester
),
255 requesting_process_id(requesting_process_id
),
256 requesting_frame_id(requesting_frame_id
),
257 page_request_id(page_request_id
),
258 security_origin(security_origin
),
259 user_gesture(user_gesture
),
260 request_type(request_type
),
262 salt_callback(salt_callback
),
263 state_(NUM_MEDIA_TYPES
, MEDIA_REQUEST_STATE_NOT_REQUESTED
),
264 audio_type_(MEDIA_NO_SERVICE
),
265 video_type_(MEDIA_NO_SERVICE
),
266 target_process_id_(-1),
267 target_frame_id_(-1) {
272 void SetAudioType(MediaStreamType audio_type
) {
273 DCHECK(IsAudioInputMediaType(audio_type
) ||
274 audio_type
== MEDIA_DEVICE_AUDIO_OUTPUT
||
275 audio_type
== MEDIA_NO_SERVICE
);
276 audio_type_
= audio_type
;
279 MediaStreamType
audio_type() const { return audio_type_
; }
281 void SetVideoType(MediaStreamType video_type
) {
282 DCHECK(IsVideoMediaType(video_type
) || video_type
== MEDIA_NO_SERVICE
);
283 video_type_
= video_type
;
286 MediaStreamType
video_type() const { return video_type_
; }
288 // Creates a MediaStreamRequest object that is used by this request when UI
289 // is asked for permission and device selection.
290 void CreateUIRequest(const std::string
& requested_audio_device_id
,
291 const std::string
& requested_video_device_id
) {
292 DCHECK(!ui_request_
);
293 target_process_id_
= requesting_process_id
;
294 target_frame_id_
= requesting_frame_id
;
295 ui_request_
.reset(new MediaStreamRequest(requesting_process_id
,
301 requested_audio_device_id
,
302 requested_video_device_id
,
307 // Creates a tab capture specific MediaStreamRequest object that is used by
308 // this request when UI is asked for permission and device selection.
309 void CreateTabCaptureUIRequest(int target_render_process_id
,
310 int target_render_frame_id
) {
311 DCHECK(!ui_request_
);
312 target_process_id_
= target_render_process_id
;
313 target_frame_id_
= target_render_frame_id
;
314 ui_request_
.reset(new MediaStreamRequest(target_render_process_id
,
315 target_render_frame_id
,
326 bool HasUIRequest() const { return ui_request_
.get() != nullptr; }
327 scoped_ptr
<MediaStreamRequest
> DetachUIRequest() {
328 return ui_request_
.Pass();
331 // Update the request state and notify observers.
332 void SetState(MediaStreamType stream_type
, MediaRequestState new_state
) {
333 if (stream_type
== NUM_MEDIA_TYPES
) {
334 for (int i
= MEDIA_NO_SERVICE
+ 1; i
< NUM_MEDIA_TYPES
; ++i
) {
335 const MediaStreamType stream_type
= static_cast<MediaStreamType
>(i
);
336 state_
[stream_type
] = new_state
;
339 state_
[stream_type
] = new_state
;
342 MediaObserver
* media_observer
=
343 GetContentClient()->browser()->GetMediaObserver();
347 media_observer
->OnMediaRequestStateChanged(
348 target_process_id_
, target_frame_id_
, page_request_id
, security_origin
,
349 stream_type
, new_state
);
352 MediaRequestState
state(MediaStreamType stream_type
) const {
353 return state_
[stream_type
];
356 MediaStreamRequester
* const requester
; // Can be NULL.
359 // The render process id that requested this stream to be generated and that
360 // will receive a handle to the MediaStream. This may be different from
361 // MediaStreamRequest::render_process_id which in the tab capture case
362 // specifies the target renderer from which audio and video is captured.
363 const int requesting_process_id
;
365 // The render frame id that requested this stream to be generated and that
366 // will receive a handle to the MediaStream. This may be different from
367 // MediaStreamRequest::render_frame_id which in the tab capture case
368 // specifies the target renderer from which audio and video is captured.
369 const int requesting_frame_id
;
371 // An ID the render frame provided to identify this request.
372 const int page_request_id
;
374 const GURL security_origin
;
376 const bool user_gesture
;
378 const MediaStreamRequestType request_type
;
380 const StreamOptions options
;
382 ResourceContext::SaltCallback salt_callback
;
384 StreamDeviceInfoArray devices
;
386 // Callback to the requester which audio/video devices have been selected.
387 // It can be null if the requester has no interest to know the result.
388 // Currently it is only used by |DEVICE_ACCESS| type.
389 MediaStreamManager::MediaRequestResponseCallback callback
;
391 scoped_ptr
<MediaStreamUIProxy
> ui_proxy
;
393 std::string tab_capture_device_id
;
396 std::vector
<MediaRequestState
> state_
;
397 scoped_ptr
<MediaStreamRequest
> ui_request_
;
398 MediaStreamType audio_type_
;
399 MediaStreamType video_type_
;
400 int target_process_id_
;
401 int target_frame_id_
;
404 MediaStreamManager::EnumerationCache::EnumerationCache()
408 MediaStreamManager::EnumerationCache::~EnumerationCache() {
412 void MediaStreamManager::SendMessageToNativeLog(const std::string
& message
) {
413 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
414 base::Bind(DoAddLogMessage
, message
));
417 MediaStreamManager::MediaStreamManager(media::AudioManager
* audio_manager
)
418 : audio_manager_(audio_manager
),
420 video_capture_thread_("VideoCaptureThread"),
422 monitoring_started_(false),
423 #if defined(OS_CHROMEOS)
424 has_checked_keyboard_mic_(false),
426 use_fake_ui_(base::CommandLine::ForCurrentProcess()->HasSwitch(
427 switches::kUseFakeUIForMediaStream
)) {
428 DCHECK(audio_manager_
);
429 memset(active_enumeration_ref_count_
, 0,
430 sizeof(active_enumeration_ref_count_
));
432 // Some unit tests create the MSM in the IO thread and assumes the
433 // initialization is done synchronously.
434 if (BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
435 InitializeDeviceManagersOnIOThread();
437 BrowserThread::PostTask(
438 BrowserThread::IO
, FROM_HERE
,
439 base::Bind(&MediaStreamManager::InitializeDeviceManagersOnIOThread
,
440 base::Unretained(this)));
443 base::PowerMonitor
* power_monitor
= base::PowerMonitor::Get();
444 // BrowserMainLoop always creates the PowerMonitor instance before creating
445 // MediaStreamManager, but power_monitor may be NULL in unit tests.
447 power_monitor
->AddObserver(this);
450 MediaStreamManager::~MediaStreamManager() {
451 DVLOG(1) << "~MediaStreamManager";
452 DCHECK(requests_
.empty());
453 DCHECK(!device_task_runner_
.get());
455 base::PowerMonitor
* power_monitor
= base::PowerMonitor::Get();
456 // The PowerMonitor instance owned by BrowserMainLoops always outlives the
457 // MediaStreamManager, but it may be NULL in unit tests.
459 power_monitor
->RemoveObserver(this);
462 VideoCaptureManager
* MediaStreamManager::video_capture_manager() {
463 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
464 DCHECK(video_capture_manager_
.get());
465 return video_capture_manager_
.get();
468 AudioInputDeviceManager
* MediaStreamManager::audio_input_device_manager() {
469 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
470 DCHECK(audio_input_device_manager_
.get());
471 return audio_input_device_manager_
.get();
474 AudioOutputDeviceEnumerator
*
475 MediaStreamManager::audio_output_device_enumerator() {
476 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
477 DCHECK(audio_output_device_enumerator_
.get());
478 return audio_output_device_enumerator_
.get();
481 std::string
MediaStreamManager::MakeMediaAccessRequest(
482 int render_process_id
,
485 const StreamOptions
& options
,
486 const GURL
& security_origin
,
487 const MediaRequestResponseCallback
& callback
) {
488 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
490 // TODO(perkj): The argument list with NULL parameters to DeviceRequest
491 // suggests that this is the wrong design. Can this be refactored?
492 DeviceRequest
* request
= new DeviceRequest(NULL
,
497 false, // user gesture
500 base::Bind(&ReturnEmptySalt
));
502 const std::string
& label
= AddRequest(request
);
504 request
->callback
= callback
;
505 // Post a task and handle the request asynchronously. The reason is that the
506 // requester won't have a label for the request until this function returns
507 // and thus can not handle a response. Using base::Unretained is safe since
508 // MediaStreamManager is deleted on the UI thread, after the IO thread has
510 BrowserThread::PostTask(
511 BrowserThread::IO
, FROM_HERE
,
512 base::Bind(&MediaStreamManager::SetupRequest
,
513 base::Unretained(this), label
));
517 void MediaStreamManager::GenerateStream(MediaStreamRequester
* requester
,
518 int render_process_id
,
520 const ResourceContext::SaltCallback
& sc
,
522 const StreamOptions
& options
,
523 const GURL
& security_origin
,
525 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
526 DVLOG(1) << "GenerateStream()";
528 DeviceRequest
* request
= new DeviceRequest(requester
,
534 MEDIA_GENERATE_STREAM
,
538 const std::string
& label
= AddRequest(request
);
540 // Post a task and handle the request asynchronously. The reason is that the
541 // requester won't have a label for the request until this function returns
542 // and thus can not handle a response. Using base::Unretained is safe since
543 // MediaStreamManager is deleted on the UI thread, after the IO thread has
545 BrowserThread::PostTask(
546 BrowserThread::IO
, FROM_HERE
,
547 base::Bind(&MediaStreamManager::SetupRequest
,
548 base::Unretained(this), label
));
551 void MediaStreamManager::CancelRequest(int render_process_id
,
553 int page_request_id
) {
554 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
555 for (const LabeledDeviceRequest
& labeled_request
: requests_
) {
556 DeviceRequest
* const request
= labeled_request
.second
;
557 if (request
->requesting_process_id
== render_process_id
&&
558 request
->requesting_frame_id
== render_frame_id
&&
559 request
->page_request_id
== page_request_id
) {
560 CancelRequest(labeled_request
.first
);
567 void MediaStreamManager::CancelRequest(const std::string
& label
) {
568 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
569 DVLOG(1) << "CancelRequest({label = " << label
<< "})";
570 DeviceRequest
* request
= FindRequest(label
);
572 // The request does not exist.
573 LOG(ERROR
) << "The request with label = " << label
<< " does not exist.";
577 if (request
->request_type
== MEDIA_ENUMERATE_DEVICES
) {
578 // It isn't an ideal use of "CancelRequest" to make it a requirement
579 // for enumeration requests to be deleted via "CancelRequest" _after_
580 // the request has been successfully fulfilled.
581 // See note in FinalizeEnumerateDevices for a recommendation on how
582 // we should refactor this.
583 DeleteRequest(label
);
587 // This is a request for opening one or more devices.
588 for (const StreamDeviceInfo
& device_info
: request
->devices
) {
589 const MediaRequestState state
= request
->state(device_info
.device
.type
);
590 // If we have not yet requested the device to be opened - just ignore it.
591 if (state
!= MEDIA_REQUEST_STATE_OPENING
&&
592 state
!= MEDIA_REQUEST_STATE_DONE
) {
595 // Stop the opening/opened devices of the requests.
596 CloseDevice(device_info
.device
.type
, device_info
.session_id
);
599 // Cancel the request if still pending at UI side.
600 request
->SetState(NUM_MEDIA_TYPES
, MEDIA_REQUEST_STATE_CLOSING
);
601 DeleteRequest(label
);
604 void MediaStreamManager::CancelAllRequests(int render_process_id
) {
605 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
606 DeviceRequests::iterator request_it
= requests_
.begin();
607 while (request_it
!= requests_
.end()) {
608 if (request_it
->second
->requesting_process_id
!= render_process_id
) {
612 const std::string label
= request_it
->first
;
614 CancelRequest(label
);
618 void MediaStreamManager::StopStreamDevice(int render_process_id
,
620 const std::string
& device_id
) {
621 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
622 DVLOG(1) << "StopStreamDevice({render_frame_id = " << render_frame_id
<< "} "
623 << ", {device_id = " << device_id
<< "})";
624 // Find the first request for this |render_process_id| and |render_frame_id|
625 // of type MEDIA_GENERATE_STREAM that has requested to use |device_id| and
627 for (const LabeledDeviceRequest
& device_request
: requests_
) {
628 DeviceRequest
* const request
= device_request
.second
;
629 if (request
->requesting_process_id
!= render_process_id
||
630 request
->requesting_frame_id
!= render_frame_id
||
631 request
->request_type
!= MEDIA_GENERATE_STREAM
) {
635 for (const StreamDeviceInfo
& device_info
: request
->devices
) {
636 if (device_info
.device
.id
== device_id
) {
637 StopDevice(device_info
.device
.type
, device_info
.session_id
);
644 void MediaStreamManager::StopDevice(MediaStreamType type
, int session_id
) {
645 DVLOG(1) << "StopDevice"
646 << "{type = " << type
<< "}"
647 << "{session_id = " << session_id
<< "}";
648 DeviceRequests::iterator request_it
= requests_
.begin();
649 while (request_it
!= requests_
.end()) {
650 DeviceRequest
* request
= request_it
->second
;
651 StreamDeviceInfoArray
* devices
= &request
->devices
;
652 if (devices
->empty()) {
653 // There is no device in use yet by this request.
657 StreamDeviceInfoArray::iterator device_it
= devices
->begin();
658 while (device_it
!= devices
->end()) {
659 if (device_it
->device
.type
!= type
||
660 device_it
->session_id
!= session_id
) {
665 if (request
->state(type
) == MEDIA_REQUEST_STATE_DONE
)
666 CloseDevice(type
, session_id
);
667 device_it
= devices
->erase(device_it
);
670 // If this request doesn't have any active devices after a device
671 // has been stopped above, remove the request. Note that the request is
672 // only deleted if a device as been removed from |devices|.
673 if (devices
->empty()) {
674 std::string label
= request_it
->first
;
676 DeleteRequest(label
);
683 void MediaStreamManager::CloseDevice(MediaStreamType type
, int session_id
) {
684 DVLOG(1) << "CloseDevice("
685 << "{type = " << type
<< "} "
686 << "{session_id = " << session_id
<< "})";
687 GetDeviceManager(type
)->Close(session_id
);
689 for (const LabeledDeviceRequest
& labeled_request
: requests_
) {
690 DeviceRequest
* const request
= labeled_request
.second
;
691 for (const StreamDeviceInfo
& device_info
: request
->devices
) {
692 if (device_info
.session_id
== session_id
&&
693 device_info
.device
.type
== type
) {
694 // Notify observers that this device is being closed.
695 // Note that only one device per type can be opened.
696 request
->SetState(type
, MEDIA_REQUEST_STATE_CLOSING
);
702 std::string
MediaStreamManager::EnumerateDevices(
703 MediaStreamRequester
* requester
,
704 int render_process_id
,
706 const ResourceContext::SaltCallback
& sc
,
708 MediaStreamType type
,
709 const GURL
& security_origin
) {
710 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
712 DCHECK(type
== MEDIA_DEVICE_AUDIO_CAPTURE
||
713 type
== MEDIA_DEVICE_VIDEO_CAPTURE
||
714 type
== MEDIA_DEVICE_AUDIO_OUTPUT
);
716 DeviceRequest
* request
= new DeviceRequest(requester
,
721 false, // user gesture
722 MEDIA_ENUMERATE_DEVICES
,
725 if (IsAudioInputMediaType(type
) || type
== MEDIA_DEVICE_AUDIO_OUTPUT
)
726 request
->SetAudioType(type
);
727 else if (IsVideoMediaType(type
))
728 request
->SetVideoType(type
);
730 const std::string
& label
= AddRequest(request
);
731 // Post a task and handle the request asynchronously. The reason is that the
732 // requester won't have a label for the request until this function returns
733 // and thus can not handle a response. Using base::Unretained is safe since
734 // MediaStreamManager is deleted on the UI thread, after the IO thread has
736 BrowserThread::PostTask(
737 BrowserThread::IO
, FROM_HERE
,
738 base::Bind(&MediaStreamManager::DoEnumerateDevices
,
739 base::Unretained(this), label
));
743 void MediaStreamManager::DoEnumerateDevices(const std::string
& label
) {
744 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
745 DeviceRequest
* request
= FindRequest(label
);
747 return; // This can happen if the request has been canceled.
749 if (request
->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT
) {
750 DCHECK_EQ(MEDIA_NO_SERVICE
, request
->video_type());
751 DCHECK_GE(active_enumeration_ref_count_
[MEDIA_DEVICE_AUDIO_OUTPUT
], 0);
752 request
->SetState(MEDIA_DEVICE_AUDIO_OUTPUT
, MEDIA_REQUEST_STATE_REQUESTED
);
753 if (active_enumeration_ref_count_
[MEDIA_DEVICE_AUDIO_OUTPUT
] == 0) {
754 ++active_enumeration_ref_count_
[MEDIA_DEVICE_AUDIO_OUTPUT
];
755 DCHECK(audio_output_device_enumerator_
);
756 audio_output_device_enumerator_
->Enumerate(
757 base::Bind(&MediaStreamManager::AudioOutputDevicesEnumerated
,
758 base::Unretained(this)));
763 MediaStreamType type
;
764 EnumerationCache
* cache
;
765 if (request
->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE
) {
766 DCHECK_EQ(MEDIA_NO_SERVICE
, request
->video_type());
767 type
= MEDIA_DEVICE_AUDIO_CAPTURE
;
768 cache
= &audio_enumeration_cache_
;
770 DCHECK_EQ(MEDIA_DEVICE_VIDEO_CAPTURE
, request
->video_type());
771 DCHECK_EQ(MEDIA_NO_SERVICE
, request
->audio_type());
772 type
= MEDIA_DEVICE_VIDEO_CAPTURE
;
773 cache
= &video_enumeration_cache_
;
776 if (!EnumerationRequired(cache
, type
)) {
777 // Cached device list of this type exists. Just send it out.
778 request
->SetState(type
, MEDIA_REQUEST_STATE_REQUESTED
);
779 request
->devices
= cache
->devices
;
780 FinalizeEnumerateDevices(label
, request
);
782 StartEnumeration(request
);
784 DVLOG(1) << "Enumerate Devices ({label = " << label
<< "})";
787 void MediaStreamManager::AudioOutputDevicesEnumerated(
788 const AudioOutputDeviceEnumeration
& device_enumeration
) {
789 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
790 DVLOG(1) << "AudioOutputDevicesEnumerated()";
791 StreamDeviceInfoArray device_infos
;
792 for (const auto& entry
: device_enumeration
) {
793 StreamDeviceInfo
device_info(MEDIA_DEVICE_AUDIO_OUTPUT
, entry
.device_name
,
795 device_infos
.push_back(device_info
);
798 const std::string log_message
=
799 "New device enumeration result:\n" +
800 GetLogMessageString(MEDIA_DEVICE_AUDIO_OUTPUT
, device_infos
);
801 SendMessageToNativeLog(log_message
);
803 // Publish the result for all requests waiting for device list(s).
804 for (const LabeledDeviceRequest
& request
: requests_
) {
805 if (request
.second
->state(MEDIA_DEVICE_AUDIO_OUTPUT
) ==
806 MEDIA_REQUEST_STATE_REQUESTED
&&
807 request
.second
->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT
) {
808 DCHECK_EQ(MEDIA_ENUMERATE_DEVICES
, request
.second
->request_type
);
809 request
.second
->SetState(MEDIA_DEVICE_AUDIO_OUTPUT
,
810 MEDIA_REQUEST_STATE_PENDING_APPROVAL
);
811 request
.second
->devices
= device_infos
;
812 FinalizeEnumerateDevices(request
.first
, request
.second
);
816 --active_enumeration_ref_count_
[MEDIA_DEVICE_AUDIO_OUTPUT
];
817 DCHECK_GE(active_enumeration_ref_count_
[MEDIA_DEVICE_AUDIO_OUTPUT
], 0);
820 void MediaStreamManager::OpenDevice(MediaStreamRequester
* requester
,
821 int render_process_id
,
823 const ResourceContext::SaltCallback
& sc
,
825 const std::string
& device_id
,
826 MediaStreamType type
,
827 const GURL
& security_origin
) {
828 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
829 DCHECK(type
== MEDIA_DEVICE_AUDIO_CAPTURE
||
830 type
== MEDIA_DEVICE_VIDEO_CAPTURE
);
831 DVLOG(1) << "OpenDevice ({page_request_id = " << page_request_id
<< "})";
832 StreamOptions options
;
833 if (IsAudioInputMediaType(type
)) {
834 options
.audio_requested
= true;
835 options
.mandatory_audio
.push_back(
836 StreamOptions::Constraint(kMediaStreamSourceInfoId
, device_id
));
837 } else if (IsVideoMediaType(type
)) {
838 options
.video_requested
= true;
839 options
.mandatory_video
.push_back(
840 StreamOptions::Constraint(kMediaStreamSourceInfoId
, device_id
));
844 DeviceRequest
* request
= new DeviceRequest(requester
,
849 false, // user gesture
854 const std::string
& label
= AddRequest(request
);
855 // Post a task and handle the request asynchronously. The reason is that the
856 // requester won't have a label for the request until this function returns
857 // and thus can not handle a response. Using base::Unretained is safe since
858 // MediaStreamManager is deleted on the UI thread, after the IO thread has
860 BrowserThread::PostTask(
861 BrowserThread::IO
, FROM_HERE
,
862 base::Bind(&MediaStreamManager::SetupRequest
,
863 base::Unretained(this), label
));
866 bool MediaStreamManager::TranslateSourceIdToDeviceId(
867 MediaStreamType stream_type
,
868 const ResourceContext::SaltCallback
& sc
,
869 const GURL
& security_origin
,
870 const std::string
& source_id
,
871 std::string
* device_id
) const {
872 DCHECK(stream_type
== MEDIA_DEVICE_AUDIO_CAPTURE
||
873 stream_type
== MEDIA_DEVICE_VIDEO_CAPTURE
);
874 // The source_id can be empty if the constraint is set but empty.
875 if (source_id
.empty())
878 const EnumerationCache
* cache
=
879 stream_type
== MEDIA_DEVICE_AUDIO_CAPTURE
?
880 &audio_enumeration_cache_
: &video_enumeration_cache_
;
882 // If device monitoring hasn't started, the |device_guid| is not valid.
886 for (const StreamDeviceInfo
& device_info
: cache
->devices
) {
887 if (content::DoesMediaDeviceIDMatchHMAC(sc
, security_origin
, source_id
,
888 device_info
.device
.id
)) {
889 *device_id
= device_info
.device
.id
;
896 void MediaStreamManager::EnsureDeviceMonitorStarted() {
897 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
901 void MediaStreamManager::StopRemovedDevices(
902 const StreamDeviceInfoArray
& old_devices
,
903 const StreamDeviceInfoArray
& new_devices
) {
904 DVLOG(1) << "StopRemovedDevices("
905 << "{#old_devices = " << old_devices
.size() << "} "
906 << "{#new_devices = " << new_devices
.size() << "})";
907 for (const StreamDeviceInfo
& old_device_info
: old_devices
) {
908 bool device_found
= false;
909 for (const StreamDeviceInfo
& new_device_info
: new_devices
) {
910 if (old_device_info
.device
.id
== new_device_info
.device
.id
) {
917 // A device has been removed. We need to check if it is used by a
918 // MediaStream and in that case cleanup and notify the render process.
919 StopRemovedDevice(old_device_info
.device
);
924 void MediaStreamManager::StopRemovedDevice(const MediaStreamDevice
& device
) {
925 std::vector
<int> session_ids
;
926 for (const LabeledDeviceRequest
& labeled_request
: requests_
) {
927 const DeviceRequest
* request
= labeled_request
.second
;
928 for (const StreamDeviceInfo
& device_info
: request
->devices
) {
929 const std::string source_id
= content::GetHMACForMediaDeviceID(
930 request
->salt_callback
, request
->security_origin
, device
.id
);
931 if (device_info
.device
.id
== source_id
&&
932 device_info
.device
.type
== device
.type
) {
933 session_ids
.push_back(device_info
.session_id
);
934 if (labeled_request
.second
->requester
) {
935 labeled_request
.second
->requester
->DeviceStopped(
936 labeled_request
.second
->requesting_frame_id
,
937 labeled_request
.first
, device_info
);
942 for (const int session_id
: session_ids
)
943 StopDevice(device
.type
, session_id
);
945 AddLogMessageOnIOThread(
947 "Media input device removed: type = %s, id = %s, name = %s ",
948 (device
.type
== MEDIA_DEVICE_AUDIO_CAPTURE
? "audio" : "video"),
949 device
.id
.c_str(), device
.name
.c_str()).c_str());
952 void MediaStreamManager::StartMonitoring() {
953 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
954 if (monitoring_started_
)
957 if (!base::SystemMonitor::Get())
960 monitoring_started_
= true;
961 base::SystemMonitor::Get()->AddDevicesChangedObserver(this);
963 // Enable caching for audio output device enumerations and do an enumeration
964 // to populate the cache.
965 audio_output_device_enumerator_
->SetCachePolicy(
966 AudioOutputDeviceEnumerator::CACHE_POLICY_MANUAL_INVALIDATION
);
967 audio_output_device_enumerator_
->Enumerate(
968 base::Bind(&DummyEnumerationCallback
));
970 // Enumerate both the audio and video input devices to cache the device lists
971 // and send them to media observer.
972 ++active_enumeration_ref_count_
[MEDIA_DEVICE_AUDIO_CAPTURE
];
973 audio_input_device_manager_
->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE
);
974 ++active_enumeration_ref_count_
[MEDIA_DEVICE_VIDEO_CAPTURE
];
975 video_capture_manager_
->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE
);
977 #if defined(OS_MACOSX)
978 BrowserThread::PostTask(
979 BrowserThread::UI
, FROM_HERE
,
980 base::Bind(&MediaStreamManager::StartMonitoringOnUIThread
,
981 base::Unretained(this)));
985 void MediaStreamManager::StopMonitoring() {
986 DCHECK(CalledOnIOThread());
987 if (!monitoring_started_
)
989 base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this);
990 monitoring_started_
= false;
991 ClearEnumerationCache(&audio_enumeration_cache_
);
992 ClearEnumerationCache(&video_enumeration_cache_
);
993 audio_output_device_enumerator_
->SetCachePolicy(
994 AudioOutputDeviceEnumerator::CACHE_POLICY_NO_CACHING
);
997 #if defined(OS_MACOSX)
998 void MediaStreamManager::StartMonitoringOnUIThread() {
999 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
1000 // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is fixed.
1001 tracked_objects::ScopedTracker
tracking_profile1(
1002 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1003 "458404 MediaStreamManager::GetBrowserMainLoop"));
1004 BrowserMainLoop
* browser_main_loop
= content::BrowserMainLoop::GetInstance();
1005 if (!browser_main_loop
)
1008 // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is
1010 tracked_objects::ScopedTracker
tracking_profile2(
1011 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1012 "458404 MediaStreamManager::GetWorkerTaskRunner"));
1013 const scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
=
1014 audio_manager_
->GetWorkerTaskRunner();
1015 // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is
1017 tracked_objects::ScopedTracker
tracking_profile3(
1018 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1019 "458404 MediaStreamManager::DeviceMonitorMac::StartMonitoring"));
1020 browser_main_loop
->device_monitor_mac()->StartMonitoring(task_runner
);
1024 bool MediaStreamManager::GetRequestedDeviceCaptureId(
1025 const DeviceRequest
* request
,
1026 MediaStreamType type
,
1027 std::string
* device_id
) const {
1028 DCHECK(type
== MEDIA_DEVICE_AUDIO_CAPTURE
||
1029 type
== MEDIA_DEVICE_VIDEO_CAPTURE
);
1030 const StreamOptions::Constraints
* mandatory
=
1031 (type
== MEDIA_DEVICE_AUDIO_CAPTURE
) ?
1032 &request
->options
.mandatory_audio
: &request
->options
.mandatory_video
;
1033 const StreamOptions::Constraints
* optional
=
1034 (type
== MEDIA_DEVICE_AUDIO_CAPTURE
) ?
1035 &request
->options
.optional_audio
: &request
->options
.optional_video
;
1037 std::vector
<std::string
> source_ids
;
1038 StreamOptions::GetConstraintsByName(*mandatory
,
1039 kMediaStreamSourceInfoId
, &source_ids
);
1040 if (source_ids
.size() > 1) {
1041 LOG(ERROR
) << "Only one mandatory " << kMediaStreamSourceInfoId
1042 << " is supported.";
1045 // If a specific device has been requested we need to find the real device
1047 if (source_ids
.size() == 1 &&
1048 !TranslateSourceIdToDeviceId(type
,
1049 request
->salt_callback
,
1050 request
->security_origin
,
1051 source_ids
[0], device_id
)) {
1052 LOG(WARNING
) << "Invalid mandatory " << kMediaStreamSourceInfoId
1053 << " = " << source_ids
[0] << ".";
1056 // Check for optional audio sourceIDs.
1057 if (device_id
->empty()) {
1058 StreamOptions::GetConstraintsByName(*optional
,
1059 kMediaStreamSourceInfoId
,
1061 // Find the first sourceID that translates to device. Note that only one
1062 // device per type can call to GenerateStream is ever opened.
1063 for (const std::string
& source_id
: source_ids
) {
1064 if (TranslateSourceIdToDeviceId(type
,
1065 request
->salt_callback
,
1066 request
->security_origin
,
1076 void MediaStreamManager::TranslateDeviceIdToSourceId(
1077 DeviceRequest
* request
,
1078 MediaStreamDevice
* device
) {
1079 if (request
->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE
||
1080 request
->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT
||
1081 request
->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE
) {
1082 device
->id
= content::GetHMACForMediaDeviceID(
1083 request
->salt_callback
,
1084 request
->security_origin
,
1089 void MediaStreamManager::ClearEnumerationCache(EnumerationCache
* cache
) {
1090 DCHECK(CalledOnIOThread());
1091 cache
->valid
= false;
1094 bool MediaStreamManager::EnumerationRequired(EnumerationCache
* cache
,
1095 MediaStreamType stream_type
) {
1096 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1097 if (stream_type
== MEDIA_NO_SERVICE
)
1100 DCHECK(stream_type
== MEDIA_DEVICE_AUDIO_CAPTURE
||
1101 stream_type
== MEDIA_DEVICE_VIDEO_CAPTURE
);
1103 #if defined(OS_ANDROID)
1104 // There's no SystemMonitor on Android that notifies us when devices are
1105 // added or removed, so we need to populate the cache on every request.
1106 // Fortunately, there is an already up-to-date cache in the browser side
1107 // audio manager that we can rely on, so the performance impact of
1108 // invalidating the cache like this, is minimal.
1109 if (stream_type
== MEDIA_DEVICE_AUDIO_CAPTURE
) {
1110 // Make sure the cache is marked as invalid so that FinalizeEnumerateDevices
1111 // will be called at the end of the enumeration.
1112 ClearEnumerationCache(cache
);
1115 // If the cache isn't valid, we need to start a full enumeration.
1116 return !cache
->valid
;
1119 void MediaStreamManager::StartEnumeration(DeviceRequest
* request
) {
1120 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1122 // Start monitoring the devices when doing the first enumeration.
1125 // Start enumeration for devices of all requested device types.
1126 const MediaStreamType stream_types
[] = {request
->audio_type(),
1127 request
->video_type()};
1128 for (const MediaStreamType stream_type
: stream_types
) {
1129 if (stream_type
== MEDIA_NO_SERVICE
)
1131 request
->SetState(stream_type
, MEDIA_REQUEST_STATE_REQUESTED
);
1132 DCHECK_GE(active_enumeration_ref_count_
[stream_type
], 0);
1133 if (active_enumeration_ref_count_
[stream_type
] == 0) {
1134 ++active_enumeration_ref_count_
[stream_type
];
1135 GetDeviceManager(stream_type
)->EnumerateDevices(stream_type
);
1140 std::string
MediaStreamManager::AddRequest(DeviceRequest
* request
) {
1141 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1143 // Create a label for this request and verify it is unique.
1144 std::string unique_label
;
1146 unique_label
= RandomLabel();
1147 } while (FindRequest(unique_label
) != NULL
);
1149 requests_
.push_back(std::make_pair(unique_label
, request
));
1151 return unique_label
;
1154 MediaStreamManager::DeviceRequest
*
1155 MediaStreamManager::FindRequest(const std::string
& label
) const {
1156 for (const LabeledDeviceRequest
& labeled_request
: requests_
) {
1157 if (labeled_request
.first
== label
)
1158 return labeled_request
.second
;
1163 void MediaStreamManager::DeleteRequest(const std::string
& label
) {
1164 DVLOG(1) << "DeleteRequest({label= " << label
<< "})";
1165 for (DeviceRequests::iterator request_it
= requests_
.begin();
1166 request_it
!= requests_
.end(); ++request_it
) {
1167 if (request_it
->first
== label
) {
1168 scoped_ptr
<DeviceRequest
> request(request_it
->second
);
1169 requests_
.erase(request_it
);
1176 void MediaStreamManager::PostRequestToUI(const std::string
& label
,
1177 DeviceRequest
* request
) {
1178 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1179 DCHECK(request
->HasUIRequest());
1180 DVLOG(1) << "PostRequestToUI({label= " << label
<< "})";
1182 const MediaStreamType audio_type
= request
->audio_type();
1183 const MediaStreamType video_type
= request
->video_type();
1185 // Post the request to UI and set the state.
1186 if (IsAudioInputMediaType(audio_type
))
1187 request
->SetState(audio_type
, MEDIA_REQUEST_STATE_PENDING_APPROVAL
);
1188 if (IsVideoMediaType(video_type
))
1189 request
->SetState(video_type
, MEDIA_REQUEST_STATE_PENDING_APPROVAL
);
1193 fake_ui_
.reset(new FakeMediaStreamUIProxy());
1195 MediaStreamDevices devices
;
1196 if (audio_enumeration_cache_
.valid
) {
1197 for (const StreamDeviceInfo
& device_info
:
1198 audio_enumeration_cache_
.devices
) {
1199 devices
.push_back(device_info
.device
);
1202 if (video_enumeration_cache_
.valid
) {
1203 for (const StreamDeviceInfo
& device_info
:
1204 video_enumeration_cache_
.devices
) {
1205 devices
.push_back(device_info
.device
);
1209 fake_ui_
->SetAvailableDevices(devices
);
1211 request
->ui_proxy
= fake_ui_
.Pass();
1213 request
->ui_proxy
= MediaStreamUIProxy::Create();
1216 request
->ui_proxy
->RequestAccess(
1217 request
->DetachUIRequest(),
1218 base::Bind(&MediaStreamManager::HandleAccessRequestResponse
,
1219 base::Unretained(this), label
));
1222 void MediaStreamManager::SetupRequest(const std::string
& label
) {
1223 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1224 DeviceRequest
* request
= FindRequest(label
);
1226 DVLOG(1) << "SetupRequest label " << label
<< " doesn't exist!!";
1227 return; // This can happen if the request has been canceled.
1230 if (!request
->security_origin
.is_valid()) {
1231 LOG(ERROR
) << "Invalid security origin. " << request
->security_origin
;
1232 FinalizeRequestFailed(label
,
1234 MEDIA_DEVICE_INVALID_SECURITY_ORIGIN
);
1238 MediaStreamType audio_type
= MEDIA_NO_SERVICE
;
1239 MediaStreamType video_type
= MEDIA_NO_SERVICE
;
1240 ParseStreamType(request
->options
, &audio_type
, &video_type
);
1241 request
->SetAudioType(audio_type
);
1242 request
->SetVideoType(video_type
);
1244 const bool is_web_contents_capture
= audio_type
== MEDIA_TAB_AUDIO_CAPTURE
||
1245 video_type
== MEDIA_TAB_VIDEO_CAPTURE
;
1246 if (is_web_contents_capture
&& !SetupTabCaptureRequest(request
)) {
1247 FinalizeRequestFailed(label
,
1249 MEDIA_DEVICE_TAB_CAPTURE_FAILURE
);
1253 const bool is_screen_capture
= video_type
== MEDIA_DESKTOP_VIDEO_CAPTURE
;
1254 if (is_screen_capture
&& !SetupScreenCaptureRequest(request
)) {
1255 FinalizeRequestFailed(label
,
1257 MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE
);
1261 #if defined(OS_CHROMEOS)
1262 EnsureKeyboardMicChecked();
1265 if (!is_web_contents_capture
&& !is_screen_capture
) {
1266 if (EnumerationRequired(&audio_enumeration_cache_
, audio_type
) ||
1267 EnumerationRequired(&video_enumeration_cache_
, video_type
)) {
1268 // Enumerate the devices if there is no valid device lists to be used.
1269 StartEnumeration(request
);
1272 // Cache is valid, so log the cached devices for MediaStream requests.
1273 if (request
->request_type
== MEDIA_GENERATE_STREAM
) {
1274 std::string
log_message("Using cached devices for request.\n");
1275 if (audio_type
!= MEDIA_NO_SERVICE
) {
1277 GetLogMessageString(audio_type
, audio_enumeration_cache_
.devices
);
1279 if (video_type
!= MEDIA_NO_SERVICE
) {
1281 GetLogMessageString(video_type
, video_enumeration_cache_
.devices
);
1283 SendMessageToNativeLog(log_message
);
1287 if (!SetupDeviceCaptureRequest(request
)) {
1288 FinalizeRequestFailed(label
, request
, MEDIA_DEVICE_NO_HARDWARE
);
1292 PostRequestToUI(label
, request
);
1295 bool MediaStreamManager::SetupDeviceCaptureRequest(DeviceRequest
* request
) {
1296 DCHECK((request
->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE
||
1297 request
->audio_type() == MEDIA_NO_SERVICE
) &&
1298 (request
->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE
||
1299 request
->video_type() == MEDIA_NO_SERVICE
));
1300 std::string audio_device_id
;
1301 if (request
->options
.audio_requested
&&
1302 !GetRequestedDeviceCaptureId(request
, request
->audio_type(),
1303 &audio_device_id
)) {
1307 std::string video_device_id
;
1308 if (request
->options
.video_requested
&&
1309 !GetRequestedDeviceCaptureId(request
, request
->video_type(),
1310 &video_device_id
)) {
1313 request
->CreateUIRequest(audio_device_id
, video_device_id
);
1314 DVLOG(3) << "Audio requested " << request
->options
.audio_requested
1315 << " device id = " << audio_device_id
1316 << "Video requested " << request
->options
.video_requested
1317 << " device id = " << video_device_id
;
1321 bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest
* request
) {
1322 DCHECK(request
->audio_type() == MEDIA_TAB_AUDIO_CAPTURE
||
1323 request
->video_type() == MEDIA_TAB_VIDEO_CAPTURE
);
1325 std::string capture_device_id
;
1326 bool mandatory_audio
= false;
1327 bool mandatory_video
= false;
1328 if (!request
->options
.GetFirstAudioConstraintByName(kMediaStreamSourceId
,
1330 &mandatory_audio
) &&
1331 !request
->options
.GetFirstVideoConstraintByName(kMediaStreamSourceId
,
1333 &mandatory_video
)) {
1336 DCHECK(mandatory_audio
|| mandatory_video
);
1338 // Customize options for a WebContents based capture.
1339 int target_render_process_id
= 0;
1340 int target_render_frame_id
= 0;
1342 bool has_valid_device_id
= WebContentsCaptureUtil::ExtractTabCaptureTarget(
1343 capture_device_id
, &target_render_process_id
, &target_render_frame_id
);
1344 if (!has_valid_device_id
||
1345 (request
->audio_type() != MEDIA_TAB_AUDIO_CAPTURE
&&
1346 request
->audio_type() != MEDIA_NO_SERVICE
) ||
1347 (request
->video_type() != MEDIA_TAB_VIDEO_CAPTURE
&&
1348 request
->video_type() != MEDIA_NO_SERVICE
)) {
1351 request
->tab_capture_device_id
= capture_device_id
;
1353 request
->CreateTabCaptureUIRequest(target_render_process_id
,
1354 target_render_frame_id
);
1356 DVLOG(3) << "SetupTabCaptureRequest "
1357 << ", {capture_device_id = " << capture_device_id
<< "}"
1358 << ", {target_render_process_id = " << target_render_process_id
1360 << ", {target_render_frame_id = " << target_render_frame_id
<< "}";
1364 bool MediaStreamManager::SetupScreenCaptureRequest(DeviceRequest
* request
) {
1365 DCHECK(request
->audio_type() == MEDIA_DESKTOP_AUDIO_CAPTURE
||
1366 request
->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE
);
1368 // For screen capture we only support two valid combinations:
1369 // (1) screen video capture only, or
1370 // (2) screen video capture with loopback audio capture.
1371 if (request
->video_type() != MEDIA_DESKTOP_VIDEO_CAPTURE
||
1372 (request
->audio_type() != MEDIA_NO_SERVICE
&&
1373 request
->audio_type() != MEDIA_DESKTOP_AUDIO_CAPTURE
)) {
1374 LOG(ERROR
) << "Invalid screen capture request.";
1378 std::string video_device_id
;
1379 if (request
->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE
) {
1380 std::string video_stream_source
;
1381 bool mandatory
= false;
1382 if (!request
->options
.GetFirstVideoConstraintByName(
1384 &video_stream_source
,
1386 LOG(ERROR
) << kMediaStreamSource
<< " not found.";
1391 if (video_stream_source
== kMediaStreamSourceDesktop
) {
1392 if (!request
->options
.GetFirstVideoConstraintByName(
1393 kMediaStreamSourceId
,
1396 LOG(ERROR
) << kMediaStreamSourceId
<< " not found.";
1403 request
->CreateUIRequest("", video_device_id
);
1407 StreamDeviceInfoArray
MediaStreamManager::GetDevicesOpenedByRequest(
1408 const std::string
& label
) const {
1409 DeviceRequest
* request
= FindRequest(label
);
1411 return StreamDeviceInfoArray();
1412 return request
->devices
;
1415 bool MediaStreamManager::FindExistingRequestedDeviceInfo(
1416 const DeviceRequest
& new_request
,
1417 const MediaStreamDevice
& new_device_info
,
1418 StreamDeviceInfo
* existing_device_info
,
1419 MediaRequestState
* existing_request_state
) const {
1420 DCHECK(existing_device_info
);
1421 DCHECK(existing_request_state
);
1423 std::string source_id
= content::GetHMACForMediaDeviceID(
1424 new_request
.salt_callback
,
1425 new_request
.security_origin
,
1426 new_device_info
.id
);
1428 for (const LabeledDeviceRequest
& labeled_request
: requests_
) {
1429 const DeviceRequest
* request
= labeled_request
.second
;
1430 if (request
->requesting_process_id
== new_request
.requesting_process_id
&&
1431 request
->requesting_frame_id
== new_request
.requesting_frame_id
&&
1432 request
->request_type
== new_request
.request_type
) {
1433 for (const StreamDeviceInfo
& device_info
: request
->devices
) {
1434 if (device_info
.device
.id
== source_id
&&
1435 device_info
.device
.type
== new_device_info
.type
) {
1436 *existing_device_info
= device_info
;
1437 // Make sure that the audio |effects| reflect what the request
1438 // is set to and not what the capabilities are.
1439 FilterAudioEffects(request
->options
,
1440 &existing_device_info
->device
.input
.effects
);
1441 EnableHotwordEffect(request
->options
,
1442 &existing_device_info
->device
.input
.effects
);
1443 *existing_request_state
= request
->state(device_info
.device
.type
);
1452 void MediaStreamManager::FinalizeGenerateStream(const std::string
& label
,
1453 DeviceRequest
* request
) {
1454 DVLOG(1) << "FinalizeGenerateStream label " << label
;
1455 // Partition the array of devices into audio vs video.
1456 StreamDeviceInfoArray audio_devices
, video_devices
;
1457 for (const StreamDeviceInfo
& device_info
: request
->devices
) {
1458 if (IsAudioInputMediaType(device_info
.device
.type
))
1459 audio_devices
.push_back(device_info
);
1460 else if (IsVideoMediaType(device_info
.device
.type
))
1461 video_devices
.push_back(device_info
);
1466 request
->requester
->StreamGenerated(request
->requesting_frame_id
,
1467 request
->page_request_id
, label
,
1468 audio_devices
, video_devices
);
1471 void MediaStreamManager::FinalizeRequestFailed(
1472 const std::string
& label
,
1473 DeviceRequest
* request
,
1474 content::MediaStreamRequestResult result
) {
1475 if (request
->requester
)
1476 request
->requester
->StreamGenerationFailed(
1477 request
->requesting_frame_id
,
1478 request
->page_request_id
,
1481 if (request
->request_type
== MEDIA_DEVICE_ACCESS
&&
1482 !request
->callback
.is_null()) {
1483 request
->callback
.Run(MediaStreamDevices(), request
->ui_proxy
.Pass());
1486 DeleteRequest(label
);
1489 void MediaStreamManager::FinalizeOpenDevice(const std::string
& label
,
1490 DeviceRequest
* request
) {
1491 const StreamDeviceInfoArray
& requested_devices
= request
->devices
;
1492 request
->requester
->DeviceOpened(request
->requesting_frame_id
,
1493 request
->page_request_id
,
1494 label
, requested_devices
.front());
1497 void MediaStreamManager::FinalizeEnumerateDevices(const std::string
& label
,
1498 DeviceRequest
* request
) {
1499 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1500 DCHECK_EQ(request
->request_type
, MEDIA_ENUMERATE_DEVICES
);
1501 DCHECK(((request
->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE
||
1502 request
->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT
) &&
1503 request
->video_type() == MEDIA_NO_SERVICE
) ||
1504 (request
->audio_type() == MEDIA_NO_SERVICE
&&
1505 request
->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE
));
1507 if (request
->security_origin
.is_valid()) {
1508 for (StreamDeviceInfo
& device_info
: request
->devices
)
1509 TranslateDeviceIdToSourceId(request
, &device_info
.device
);
1511 request
->devices
.clear();
1516 fake_ui_
.reset(new FakeMediaStreamUIProxy());
1517 request
->ui_proxy
= fake_ui_
.Pass();
1519 request
->ui_proxy
= MediaStreamUIProxy::Create();
1522 // Output label permissions are based on input permission.
1523 const MediaStreamType type
=
1524 request
->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE
||
1525 request
->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT
1526 ? MEDIA_DEVICE_AUDIO_CAPTURE
1527 : MEDIA_DEVICE_VIDEO_CAPTURE
;
1529 request
->ui_proxy
->CheckAccess(
1530 request
->security_origin
,
1532 request
->requesting_process_id
,
1533 request
->requesting_frame_id
,
1534 base::Bind(&MediaStreamManager::HandleCheckMediaAccessResponse
,
1535 base::Unretained(this),
1539 void MediaStreamManager::HandleCheckMediaAccessResponse(
1540 const std::string
& label
,
1542 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1544 DeviceRequest
* request
= FindRequest(label
);
1546 // This can happen if the request was cancelled.
1547 DVLOG(1) << "The request with label " << label
<< " does not exist.";
1552 ClearDeviceLabels(&request
->devices
);
1554 request
->requester
->DevicesEnumerated(
1555 request
->requesting_frame_id
,
1556 request
->page_request_id
,
1561 // Ideally enumeration requests should be deleted once they have been served
1562 // (as any request). However, this implementation mixes requests and
1563 // notifications together so enumeration requests are kept open by some
1564 // implementations (only Pepper?) and enumerations are done again when
1565 // device notifications are fired.
1566 // Implementations that just want to request the device list and be done
1567 // (e.g. DeviceRequestMessageFilter), they must (confusingly) call
1568 // CancelRequest() after the request has been fulfilled. This is not
1569 // obvious, not consistent in this class (see e.g. FinalizeMediaAccessRequest)
1570 // and can lead to subtle bugs (requests not deleted at all deleted too
1573 // Basically, it is not clear that using requests as an additional layer on
1574 // top of device notifications is necessary or good.
1576 // To add to this, MediaStreamManager currently relies on the external
1577 // implementations of MediaStreamRequester to delete enumeration requests via
1578 // CancelRequest and e.g. DeviceRequestMessageFilter does this. However the
1579 // Pepper implementation does not seem to to this at all (and from what I can
1580 // see, it is the only implementation that uses an enumeration request as a
1581 // notification mechanism).
1583 // We should decouple notifications from enumeration requests and once that
1584 // has been done, remove the requirement to call CancelRequest() to delete
1585 // enumeration requests and uncomment the following line:
1587 // DeleteRequest(label);
1590 void MediaStreamManager::FinalizeMediaAccessRequest(
1591 const std::string
& label
,
1592 DeviceRequest
* request
,
1593 const MediaStreamDevices
& devices
) {
1594 if (!request
->callback
.is_null())
1595 request
->callback
.Run(devices
, request
->ui_proxy
.Pass());
1597 // Delete the request since it is done.
1598 DeleteRequest(label
);
1601 void MediaStreamManager::InitializeDeviceManagersOnIOThread() {
1602 // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is
1604 tracked_objects::ScopedTracker
tracking_profile1(
1605 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1606 "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 1"));
1607 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1608 DCHECK(!device_task_runner_
.get());
1609 device_task_runner_
= audio_manager_
->GetWorkerTaskRunner();
1611 // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is
1613 tracked_objects::ScopedTracker
tracking_profile2(
1614 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1615 "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 2"));
1616 audio_input_device_manager_
= new AudioInputDeviceManager(audio_manager_
);
1617 audio_input_device_manager_
->Register(this, device_task_runner_
);
1619 // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is
1621 tracked_objects::ScopedTracker
tracking_profile3(
1622 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1623 "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 3"));
1624 // We want to be notified of IO message loop destruction to delete the thread
1625 // and the device managers.
1626 base::MessageLoop::current()->AddDestructionObserver(this);
1628 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1629 switches::kUseFakeDeviceForMediaStream
)) {
1630 audio_input_device_manager()->UseFakeDevice();
1633 // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is
1635 tracked_objects::ScopedTracker
tracking_profile4(
1636 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1637 "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 4"));
1638 video_capture_manager_
=
1639 new VideoCaptureManager(media::VideoCaptureDeviceFactory::CreateFactory(
1640 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI
)));
1642 // Use an STA Video Capture Thread to try to avoid crashes on enumeration of
1643 // buggy third party Direct Show modules, http://crbug.com/428958.
1644 video_capture_thread_
.init_com_with_mta(false);
1645 CHECK(video_capture_thread_
.Start());
1646 video_capture_manager_
->Register(this, video_capture_thread_
.task_runner());
1648 video_capture_manager_
->Register(this, device_task_runner_
);
1651 audio_output_device_enumerator_
.reset(new AudioOutputDeviceEnumerator(
1652 audio_manager_
, AudioOutputDeviceEnumerator::CACHE_POLICY_NO_CACHING
));
1655 void MediaStreamManager::Opened(MediaStreamType stream_type
,
1656 int capture_session_id
) {
1657 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1658 DVLOG(1) << "Opened({stream_type = " << stream_type
<< "} "
1659 << "{capture_session_id = " << capture_session_id
<< "})";
1660 // Find the request(s) containing this device and mark it as used.
1661 // It can be used in several requests since the same device can be
1662 // requested from the same web page.
1663 for (const LabeledDeviceRequest
& labeled_request
: requests_
) {
1664 const std::string
& label
= labeled_request
.first
;
1665 DeviceRequest
* request
= labeled_request
.second
;
1666 for (StreamDeviceInfo
& device_info
: request
->devices
) {
1667 if (device_info
.device
.type
== stream_type
&&
1668 device_info
.session_id
== capture_session_id
) {
1669 CHECK(request
->state(device_info
.device
.type
) ==
1670 MEDIA_REQUEST_STATE_OPENING
);
1671 // We've found a matching request.
1672 request
->SetState(device_info
.device
.type
, MEDIA_REQUEST_STATE_DONE
);
1674 if (IsAudioInputMediaType(device_info
.device
.type
)) {
1675 // Store the native audio parameters in the device struct.
1676 // TODO(xians): Handle the tab capture sample rate/channel layout
1677 // in AudioInputDeviceManager::Open().
1678 if (device_info
.device
.type
!= content::MEDIA_TAB_AUDIO_CAPTURE
) {
1679 const StreamDeviceInfo
* info
=
1680 audio_input_device_manager_
->GetOpenedDeviceInfoById(
1681 device_info
.session_id
);
1682 device_info
.device
.input
= info
->device
.input
;
1684 // Since the audio input device manager will set the input
1685 // parameters to the default settings (including supported effects),
1686 // we need to adjust those settings here according to what the
1687 // request asks for.
1688 FilterAudioEffects(request
->options
,
1689 &device_info
.device
.input
.effects
);
1690 EnableHotwordEffect(request
->options
,
1691 &device_info
.device
.input
.effects
);
1693 device_info
.device
.matched_output
= info
->device
.matched_output
;
1696 if (RequestDone(*request
))
1697 HandleRequestDone(label
, request
);
1704 void MediaStreamManager::HandleRequestDone(const std::string
& label
,
1705 DeviceRequest
* request
) {
1706 DCHECK(RequestDone(*request
));
1707 DVLOG(1) << "HandleRequestDone("
1708 << ", {label = " << label
<< "})";
1710 switch (request
->request_type
) {
1711 case MEDIA_OPEN_DEVICE
:
1712 FinalizeOpenDevice(label
, request
);
1714 case MEDIA_GENERATE_STREAM
: {
1715 FinalizeGenerateStream(label
, request
);
1723 if (request
->ui_proxy
.get()) {
1724 request
->ui_proxy
->OnStarted(
1725 base::Bind(&MediaStreamManager::StopMediaStreamFromBrowser
,
1726 base::Unretained(this),
1728 base::Bind(&MediaStreamManager::OnMediaStreamUIWindowId
,
1729 base::Unretained(this),
1730 request
->video_type(),
1735 void MediaStreamManager::Closed(MediaStreamType stream_type
,
1736 int capture_session_id
) {
1737 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1740 void MediaStreamManager::DevicesEnumerated(
1741 MediaStreamType stream_type
, const StreamDeviceInfoArray
& devices
) {
1742 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1743 DVLOG(1) << "DevicesEnumerated("
1744 << "{stream_type = " << stream_type
<< "})";
1746 std::string log_message
= "New device enumeration result:\n" +
1747 GetLogMessageString(stream_type
, devices
);
1748 SendMessageToNativeLog(log_message
);
1750 // Only cache the device list when the device list has been changed.
1751 bool need_update_clients
= false;
1752 EnumerationCache
* cache
= stream_type
== MEDIA_DEVICE_AUDIO_CAPTURE
1753 ? &audio_enumeration_cache_
1754 : &video_enumeration_cache_
;
1755 if (!cache
->valid
|| devices
.size() != cache
->devices
.size() ||
1756 !std::equal(devices
.begin(), devices
.end(), cache
->devices
.begin(),
1757 StreamDeviceInfo::IsEqual
)) {
1758 StopRemovedDevices(cache
->devices
, devices
);
1759 cache
->devices
= devices
;
1760 need_update_clients
= true;
1762 // The device might not be able to be enumerated when it is not warmed up,
1763 // for example, when the machine just wakes up from sleep. We set the cache
1764 // to be invalid so that the next media request will trigger the
1765 // enumeration again. See issue/317673.
1766 cache
->valid
= !devices
.empty();
1769 if (need_update_clients
&& monitoring_started_
)
1770 NotifyDevicesChanged(stream_type
, devices
);
1772 // Publish the result for all requests waiting for device list(s).
1773 // Find the requests waiting for this device list, store their labels and
1774 // release the iterator before calling device settings. We might get a call
1775 // back from device_settings that will need to iterate through devices.
1776 std::list
<std::string
> label_list
;
1777 for (const LabeledDeviceRequest
& labeled_request
: requests_
) {
1778 DeviceRequest
* const request
= labeled_request
.second
;
1779 if (request
->state(stream_type
) == MEDIA_REQUEST_STATE_REQUESTED
&&
1780 (request
->audio_type() == stream_type
||
1781 request
->video_type() == stream_type
)) {
1782 if (request
->request_type
!= MEDIA_ENUMERATE_DEVICES
)
1783 request
->SetState(stream_type
, MEDIA_REQUEST_STATE_PENDING_APPROVAL
);
1784 label_list
.push_back(labeled_request
.first
);
1788 for (const std::string
& label
: label_list
) {
1789 DeviceRequest
* const request
= FindRequest(label
);
1790 switch (request
->request_type
) {
1791 case MEDIA_ENUMERATE_DEVICES
:
1792 if (need_update_clients
&& request
->requester
) {
1793 request
->devices
= devices
;
1794 FinalizeEnumerateDevices(label
, request
);
1798 if (request
->state(request
->audio_type()) ==
1799 MEDIA_REQUEST_STATE_REQUESTED
||
1800 request
->state(request
->video_type()) ==
1801 MEDIA_REQUEST_STATE_REQUESTED
) {
1802 // We are doing enumeration for other type of media, wait until it is
1803 // all done before posting the request to UI because UI needs
1804 // the device lists to handle the request.
1807 if (!SetupDeviceCaptureRequest(request
))
1808 FinalizeRequestFailed(label
, request
, MEDIA_DEVICE_NO_HARDWARE
);
1810 PostRequestToUI(label
, request
);
1815 --active_enumeration_ref_count_
[stream_type
];
1816 DCHECK_GE(active_enumeration_ref_count_
[stream_type
], 0);
1819 void MediaStreamManager::Aborted(MediaStreamType stream_type
,
1820 int capture_session_id
) {
1821 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1822 DVLOG(1) << "Aborted({stream_type = " << stream_type
<< "} "
1823 << "{capture_session_id = " << capture_session_id
<< "})";
1824 StopDevice(stream_type
, capture_session_id
);
1827 void MediaStreamManager::OnSuspend() {
1828 SendMessageToNativeLog("Power state suspended.");
1831 void MediaStreamManager::OnResume() {
1832 SendMessageToNativeLog("Power state resumed.");
1835 void MediaStreamManager::UseFakeUIForTests(
1836 scoped_ptr
<FakeMediaStreamUIProxy
> fake_ui
) {
1837 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1838 use_fake_ui_
= true;
1839 fake_ui_
= fake_ui
.Pass();
1842 void MediaStreamManager::AddLogMessageOnIOThread(const std::string
& message
) {
1843 // Get render process ids on the IO thread.
1844 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1846 // Grab all unique process ids that request a MediaStream or have a
1847 // MediaStream running.
1848 std::set
<int> requesting_process_ids
;
1849 for (const LabeledDeviceRequest
& labeled_request
: requests_
) {
1850 DeviceRequest
* const request
= labeled_request
.second
;
1851 if (request
->request_type
== MEDIA_GENERATE_STREAM
)
1852 requesting_process_ids
.insert(request
->requesting_process_id
);
1855 // MediaStreamManager is a singleton in BrowserMainLoop, which owns the UI
1856 // thread. MediaStreamManager has the same lifetime as the UI thread, so it is
1857 // safe to use base::Unretained.
1858 BrowserThread::PostTask(
1861 base::Bind(AddLogMessageOnUIThread
,
1862 requesting_process_ids
,
1866 void MediaStreamManager::HandleAccessRequestResponse(
1867 const std::string
& label
,
1868 const MediaStreamDevices
& devices
,
1869 content::MediaStreamRequestResult result
) {
1870 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1871 DVLOG(1) << "HandleAccessRequestResponse("
1872 << ", {label = " << label
<< "})";
1874 DeviceRequest
* request
= FindRequest(label
);
1876 // The request has been canceled before the UI returned.
1880 if (request
->request_type
== MEDIA_DEVICE_ACCESS
) {
1881 FinalizeMediaAccessRequest(label
, request
, devices
);
1885 // Handle the case when the request was denied.
1886 if (result
!= MEDIA_DEVICE_OK
) {
1887 FinalizeRequestFailed(label
, request
, result
);
1890 DCHECK(!devices
.empty());
1892 // Process all newly-accepted devices for this request.
1893 bool found_audio
= false;
1894 bool found_video
= false;
1895 for (const MediaStreamDevice
& device
: devices
) {
1896 StreamDeviceInfo device_info
;
1897 device_info
.device
= device
;
1899 if (device_info
.device
.type
== content::MEDIA_TAB_VIDEO_CAPTURE
||
1900 device_info
.device
.type
== content::MEDIA_TAB_AUDIO_CAPTURE
) {
1901 device_info
.device
.id
= request
->tab_capture_device_id
;
1903 // Initialize the sample_rate and channel_layout here since for audio
1904 // mirroring, we don't go through EnumerateDevices where these are usually
1906 if (device_info
.device
.type
== content::MEDIA_TAB_AUDIO_CAPTURE
) {
1907 const media::AudioParameters parameters
=
1908 audio_manager_
->GetDefaultOutputStreamParameters();
1909 int sample_rate
= parameters
.sample_rate();
1910 // If we weren't able to get the native sampling rate or the sample_rate
1911 // is outside the valid range for input devices set reasonable defaults.
1912 if (sample_rate
<= 0 || sample_rate
> 96000)
1913 sample_rate
= 44100;
1915 device_info
.device
.input
.sample_rate
= sample_rate
;
1916 device_info
.device
.input
.channel_layout
= media::CHANNEL_LAYOUT_STEREO
;
1920 if (device_info
.device
.type
== request
->audio_type()) {
1922 } else if (device_info
.device
.type
== request
->video_type()) {
1926 // If this is request for a new MediaStream, a device is only opened once
1927 // per render frame. This is so that the permission to use a device can be
1928 // revoked by a single call to StopStreamDevice regardless of how many
1929 // MediaStreams it is being used in.
1930 if (request
->request_type
== MEDIA_GENERATE_STREAM
) {
1931 MediaRequestState state
;
1932 if (FindExistingRequestedDeviceInfo(*request
,
1936 request
->devices
.push_back(device_info
);
1937 request
->SetState(device_info
.device
.type
, state
);
1938 DVLOG(1) << "HandleAccessRequestResponse - device already opened "
1939 << ", {label = " << label
<< "}"
1940 << ", device_id = " << device
.id
<< "}";
1944 device_info
.session_id
=
1945 GetDeviceManager(device_info
.device
.type
)->Open(device_info
);
1946 TranslateDeviceIdToSourceId(request
, &device_info
.device
);
1947 request
->devices
.push_back(device_info
);
1949 request
->SetState(device_info
.device
.type
, MEDIA_REQUEST_STATE_OPENING
);
1950 DVLOG(1) << "HandleAccessRequestResponse - opening device "
1951 << ", {label = " << label
<< "}"
1952 << ", {device_id = " << device_info
.device
.id
<< "}"
1953 << ", {session_id = " << device_info
.session_id
<< "}";
1956 // Check whether we've received all stream types requested.
1957 if (!found_audio
&& IsAudioInputMediaType(request
->audio_type())) {
1958 request
->SetState(request
->audio_type(), MEDIA_REQUEST_STATE_ERROR
);
1959 DVLOG(1) << "Set no audio found label " << label
;
1962 if (!found_video
&& IsVideoMediaType(request
->video_type()))
1963 request
->SetState(request
->video_type(), MEDIA_REQUEST_STATE_ERROR
);
1965 if (RequestDone(*request
))
1966 HandleRequestDone(label
, request
);
1969 void MediaStreamManager::StopMediaStreamFromBrowser(const std::string
& label
) {
1970 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1972 DeviceRequest
* request
= FindRequest(label
);
1976 // Notify renderers that the devices in the stream will be stopped.
1977 if (request
->requester
) {
1978 for (const StreamDeviceInfo
& device
: request
->devices
) {
1979 request
->requester
->DeviceStopped(request
->requesting_frame_id
, label
,
1984 CancelRequest(label
);
1987 void MediaStreamManager::WillDestroyCurrentMessageLoop() {
1988 DVLOG(3) << "MediaStreamManager::WillDestroyCurrentMessageLoop()";
1989 DCHECK(CalledOnIOThread());
1990 DCHECK(requests_
.empty());
1991 if (device_task_runner_
.get()) {
1994 video_capture_manager_
->Unregister();
1995 audio_input_device_manager_
->Unregister();
1996 device_task_runner_
= NULL
;
1999 audio_input_device_manager_
= NULL
;
2000 video_capture_manager_
= NULL
;
2001 audio_output_device_enumerator_
= NULL
;
2004 void MediaStreamManager::NotifyDevicesChanged(
2005 MediaStreamType stream_type
,
2006 const StreamDeviceInfoArray
& devices
) {
2007 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
2008 MediaObserver
* media_observer
=
2009 GetContentClient()->browser()->GetMediaObserver();
2011 // Map the devices to MediaStreamDevices.
2012 MediaStreamDevices new_devices
;
2013 for (const StreamDeviceInfo
& device_info
: devices
)
2014 new_devices
.push_back(device_info
.device
);
2016 if (IsAudioInputMediaType(stream_type
)) {
2017 MediaCaptureDevicesImpl::GetInstance()->OnAudioCaptureDevicesChanged(
2020 media_observer
->OnAudioCaptureDevicesChanged();
2021 } else if (IsVideoMediaType(stream_type
)) {
2022 MediaCaptureDevicesImpl::GetInstance()->OnVideoCaptureDevicesChanged(
2025 media_observer
->OnVideoCaptureDevicesChanged();
2031 bool MediaStreamManager::RequestDone(const DeviceRequest
& request
) const {
2032 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
2034 const bool requested_audio
= IsAudioInputMediaType(request
.audio_type());
2035 const bool requested_video
= IsVideoMediaType(request
.video_type());
2037 const bool audio_done
=
2039 request
.state(request
.audio_type()) == MEDIA_REQUEST_STATE_DONE
||
2040 request
.state(request
.audio_type()) == MEDIA_REQUEST_STATE_ERROR
;
2044 const bool video_done
=
2046 request
.state(request
.video_type()) == MEDIA_REQUEST_STATE_DONE
||
2047 request
.state(request
.video_type()) == MEDIA_REQUEST_STATE_ERROR
;
2054 MediaStreamProvider
* MediaStreamManager::GetDeviceManager(
2055 MediaStreamType stream_type
) {
2056 if (IsVideoMediaType(stream_type
))
2057 return video_capture_manager();
2058 else if (IsAudioInputMediaType(stream_type
))
2059 return audio_input_device_manager();
2064 void MediaStreamManager::OnDevicesChanged(
2065 base::SystemMonitor::DeviceType device_type
) {
2066 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
2068 // NOTE: This method is only called in response to physical audio/video device
2069 // changes (from the operating system).
2071 MediaStreamType stream_type
;
2072 if (device_type
== base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE
) {
2073 stream_type
= MEDIA_DEVICE_AUDIO_CAPTURE
;
2074 audio_output_device_enumerator_
->InvalidateCache();
2075 } else if (device_type
== base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE
) {
2076 stream_type
= MEDIA_DEVICE_VIDEO_CAPTURE
;
2078 return; // Uninteresting device change.
2081 // Always do enumeration even though some enumeration is in progress, because
2082 // those enumeration commands could be sent before these devices change.
2083 ++active_enumeration_ref_count_
[stream_type
];
2084 GetDeviceManager(stream_type
)->EnumerateDevices(stream_type
);
2087 void MediaStreamManager::OnMediaStreamUIWindowId(MediaStreamType video_type
,
2088 StreamDeviceInfoArray devices
,
2089 gfx::NativeViewId window_id
) {
2090 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
2094 // Pass along for desktop capturing. Ignored for other stream types.
2095 if (video_type
== MEDIA_DESKTOP_VIDEO_CAPTURE
) {
2096 for (const StreamDeviceInfo
& device_info
: devices
) {
2097 if (device_info
.device
.type
== MEDIA_DESKTOP_VIDEO_CAPTURE
) {
2098 video_capture_manager_
->SetDesktopCaptureWindowId(
2099 device_info
.session_id
, window_id
);
2106 #if defined(OS_CHROMEOS)
2107 void MediaStreamManager::EnsureKeyboardMicChecked() {
2108 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
2109 if (!has_checked_keyboard_mic_
) {
2110 has_checked_keyboard_mic_
= true;
2111 BrowserThread::PostTask(
2112 BrowserThread::UI
, FROM_HERE
,
2113 base::Bind(&MediaStreamManager::CheckKeyboardMicOnUIThread
,
2114 base::Unretained(this)));
2118 void MediaStreamManager::CheckKeyboardMicOnUIThread() {
2119 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
2121 // We will post this on the device thread before the media media access
2122 // request is posted on the UI thread, so setting the keyboard mic info will
2123 // be done before any stream is created.
2124 if (chromeos::CrasAudioHandler::Get()->HasKeyboardMic()) {
2125 device_task_runner_
->PostTask(
2127 base::Bind(&MediaStreamManager::SetKeyboardMicOnDeviceThread
,
2128 base::Unretained(this)));
2132 void MediaStreamManager::SetKeyboardMicOnDeviceThread() {
2133 DCHECK(device_task_runner_
->BelongsToCurrentThread());
2134 audio_manager_
->SetHasKeyboardMic();
2138 } // namespace content