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