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/rand_util.h"
15 #include "base/run_loop.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/threading/thread.h"
18 #include "content/browser/browser_main_loop.h"
19 #include "content/browser/media/capture/web_contents_capture_util.h"
20 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
21 #include "content/browser/renderer_host/media/device_request_message_filter.h"
22 #include "content/browser/renderer_host/media/media_capture_devices_impl.h"
23 #include "content/browser/renderer_host/media/media_stream_requester.h"
24 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
25 #include "content/browser/renderer_host/media/video_capture_manager.h"
26 #include "content/browser/renderer_host/render_process_host_impl.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/content_browser_client.h"
29 #include "content/public/browser/media_device_id.h"
30 #include "content/public/browser/media_observer.h"
31 #include "content/public/browser/media_request_state.h"
32 #include "content/public/browser/render_process_host.h"
33 #include "content/public/common/content_switches.h"
34 #include "content/public/common/media_stream_request.h"
35 #include "media/audio/audio_manager_base.h"
36 #include "media/audio/audio_parameters.h"
37 #include "media/base/channel_layout.h"
41 #include "base/win/scoped_com_initializer.h"
46 // Forward declaration of DeviceMonitorMac and its only useable method.
47 class DeviceMonitorMac
{
49 void StartMonitoring();
53 // Creates a random label used to identify requests.
54 std::string
RandomLabel() {
55 // An earlier PeerConnection spec,
56 // http://dev.w3.org/2011/webrtc/editor/webrtc.html, specified the
57 // MediaStream::label alphabet as containing 36 characters from
58 // range: U+0021, U+0023 to U+0027, U+002A to U+002B, U+002D to U+002E,
59 // U+0030 to U+0039, U+0041 to U+005A, U+005E to U+007E.
60 // Here we use a safe subset.
61 static const char kAlphabet
[] = "0123456789"
62 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
64 std::string
label(36, ' ');
65 for (size_t i
= 0; i
< label
.size(); ++i
) {
66 int random_char
= base::RandGenerator(sizeof(kAlphabet
) - 1);
67 label
[i
] = kAlphabet
[random_char
];
72 void ParseStreamType(const StreamOptions
& options
,
73 MediaStreamType
* audio_type
,
74 MediaStreamType
* video_type
) {
75 *audio_type
= MEDIA_NO_SERVICE
;
76 *video_type
= MEDIA_NO_SERVICE
;
77 if (options
.audio_requested
) {
78 std::string audio_stream_source
;
79 bool mandatory
= false;
80 if (options
.GetFirstAudioConstraintByName(kMediaStreamSource
,
84 // This is tab or screen capture.
85 if (audio_stream_source
== kMediaStreamSourceTab
) {
86 *audio_type
= content::MEDIA_TAB_AUDIO_CAPTURE
;
87 } else if (audio_stream_source
== kMediaStreamSourceSystem
) {
88 *audio_type
= content::MEDIA_LOOPBACK_AUDIO_CAPTURE
;
91 // This is normal audio device capture.
92 *audio_type
= MEDIA_DEVICE_AUDIO_CAPTURE
;
95 if (options
.video_requested
) {
96 std::string video_stream_source
;
97 bool mandatory
= false;
98 if (options
.GetFirstVideoConstraintByName(kMediaStreamSource
,
102 // This is tab or screen capture.
103 if (video_stream_source
== kMediaStreamSourceTab
) {
104 *video_type
= content::MEDIA_TAB_VIDEO_CAPTURE
;
105 } else if (video_stream_source
== kMediaStreamSourceScreen
) {
106 *video_type
= content::MEDIA_DESKTOP_VIDEO_CAPTURE
;
107 } else if (video_stream_source
== kMediaStreamSourceDesktop
) {
108 *video_type
= content::MEDIA_DESKTOP_VIDEO_CAPTURE
;
111 // This is normal video device capture.
112 *video_type
= MEDIA_DEVICE_VIDEO_CAPTURE
;
117 // Private helper method for SendMessageToNativeLog() that obtains the global
118 // MediaStreamManager instance on the UI thread before sending |message| to the
119 // webrtcLoggingPrivate API.
120 void DoAddLogMessage(const std::string
& message
) {
121 // Must be on the UI thread to access BrowserMainLoop.
122 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
123 // May be null in tests.
124 // TODO(vrk): Handle this more elegantly by having native log messages become
125 // no-ops until MediaStreamManager is aware that a renderer process has
126 // started logging. crbug.com/333894
127 if (content::BrowserMainLoop::GetInstance()) {
128 BrowserThread::PostTask(
131 base::Bind(&MediaStreamManager::AddLogMessageOnIOThread
,
132 base::Unretained(content::BrowserMainLoop::GetInstance()
133 ->media_stream_manager()),
138 // Private helper method to generate a string for the log message that lists the
139 // human readable names of |devices|.
140 std::string
GetLogMessageString(MediaStreamType stream_type
,
141 const StreamDeviceInfoArray
& devices
) {
142 std::string output_string
=
143 base::StringPrintf("Getting devices for stream type %d:\n", stream_type
);
144 if (devices
.empty()) {
145 output_string
+= "No devices found.";
147 for (StreamDeviceInfoArray::const_iterator it
= devices
.begin();
148 it
!= devices
.end(); ++it
) {
149 output_string
+= " " + it
->device
.name
+ "\n";
152 return output_string
;
155 // Needed for MediaStreamManager::GenerateStream below.
156 std::string
ReturnEmptySalt() {
157 return std::string();
163 // MediaStreamManager::DeviceRequest represents a request to either enumerate
164 // available devices or open one or more devices.
165 // TODO(perkj): MediaStreamManager still needs refactoring. I propose we create
166 // several subclasses of DeviceRequest and move some of the responsibility of
167 // the MediaStreamManager to the subclasses to get rid of the way too many if
168 // statements in MediaStreamManager.
169 class MediaStreamManager::DeviceRequest
{
171 DeviceRequest(MediaStreamRequester
* requester
,
172 int requesting_process_id
,
173 int requesting_view_id
,
175 const GURL
& security_origin
,
176 MediaStreamRequestType request_type
,
177 const StreamOptions
& options
,
178 const ResourceContext::SaltCallback
& salt_callback
)
179 : requester(requester
),
180 requesting_process_id(requesting_process_id
),
181 requesting_view_id(requesting_view_id
),
182 page_request_id(page_request_id
),
183 security_origin(security_origin
),
184 request_type(request_type
),
186 salt_callback(salt_callback
),
187 state_(NUM_MEDIA_TYPES
, MEDIA_REQUEST_STATE_NOT_REQUESTED
),
188 audio_type_(MEDIA_NO_SERVICE
),
189 video_type_(MEDIA_NO_SERVICE
) {
194 void SetAudioType(MediaStreamType audio_type
) {
195 DCHECK(IsAudioMediaType(audio_type
) || audio_type
== MEDIA_NO_SERVICE
);
196 audio_type_
= audio_type
;
199 MediaStreamType
audio_type() const { return audio_type_
; }
201 void SetVideoType(MediaStreamType video_type
) {
202 DCHECK(IsVideoMediaType(video_type
) || video_type
== MEDIA_NO_SERVICE
);
203 video_type_
= video_type
;
206 MediaStreamType
video_type() const { return video_type_
; }
208 // Creates a MediaStreamRequest object that is used by this request when UI
209 // is asked for permission and device selection.
210 void CreateUIRequest(const std::string
& requested_audio_device_id
,
211 const std::string
& requested_video_device_id
) {
212 DCHECK(!ui_request_
);
213 ui_request_
.reset(new MediaStreamRequest(requesting_process_id
,
218 requested_audio_device_id
,
219 requested_video_device_id
,
224 // Creates a tab capture specific MediaStreamRequest object that is used by
225 // this request when UI is asked for permission and device selection.
226 void CreateTabCatureUIRequest(int target_render_process_id
,
227 int target_render_view_id
,
228 const std::string
& tab_capture_id
) {
229 DCHECK(!ui_request_
);
230 ui_request_
.reset(new MediaStreamRequest(target_render_process_id
,
231 target_render_view_id
,
239 ui_request_
->tab_capture_device_id
= tab_capture_id
;
242 const MediaStreamRequest
* UIRequest() const { return ui_request_
.get(); }
244 // Update the request state and notify observers.
245 void SetState(MediaStreamType stream_type
, MediaRequestState new_state
) {
246 if (stream_type
== NUM_MEDIA_TYPES
) {
247 for (int i
= MEDIA_NO_SERVICE
+ 1; i
< NUM_MEDIA_TYPES
; ++i
) {
248 const MediaStreamType stream_type
= static_cast<MediaStreamType
>(i
);
249 state_
[stream_type
] = new_state
;
252 state_
[stream_type
] = new_state
;
255 MediaObserver
* media_observer
=
256 GetContentClient()->browser()->GetMediaObserver();
260 // If |ui_request_| doesn't exist, it means that the request has not yet
261 // been setup fully and there are no valid observers.
265 // If we appended a device_id scheme, we want to remove it when notifying
266 // observers which may be in different modules since this scheme is only
267 // used internally within the content module.
268 std::string device_id
=
269 WebContentsCaptureUtil::StripWebContentsDeviceScheme(
270 ui_request_
->tab_capture_device_id
);
272 media_observer
->OnMediaRequestStateChanged(
273 ui_request_
->render_process_id
, ui_request_
->render_view_id
,
274 ui_request_
->page_request_id
, ui_request_
->security_origin
,
275 MediaStreamDevice(stream_type
, device_id
, device_id
), new_state
);
278 MediaRequestState
state(MediaStreamType stream_type
) const {
279 return state_
[stream_type
];
282 MediaStreamRequester
* const requester
; // Can be NULL.
285 // The render process id that requested this stream to be generated and that
286 // will receive a handle to the MediaStream. This may be different from
287 // MediaStreamRequest::render_process_id which in the tab capture case
288 // specifies the target renderer from which audio and video is captured.
289 const int requesting_process_id
;
291 // The render view id that requested this stream to be generated and that
292 // will receive a handle to the MediaStream. This may be different from
293 // MediaStreamRequest::render_view_id which in the tab capture case
294 // specifies the target renderer from which audio and video is captured.
295 const int requesting_view_id
;
297 // An ID the render view provided to identify this request.
298 const int page_request_id
;
300 const GURL security_origin
;
302 const MediaStreamRequestType request_type
;
304 const StreamOptions options
;
306 ResourceContext::SaltCallback salt_callback
;
308 StreamDeviceInfoArray devices
;
310 // Callback to the requester which audio/video devices have been selected.
311 // It can be null if the requester has no interest to know the result.
312 // Currently it is only used by |DEVICE_ACCESS| type.
313 MediaStreamManager::MediaRequestResponseCallback callback
;
315 scoped_ptr
<MediaStreamUIProxy
> ui_proxy
;
318 std::vector
<MediaRequestState
> state_
;
319 scoped_ptr
<MediaStreamRequest
> ui_request_
;
320 MediaStreamType audio_type_
;
321 MediaStreamType video_type_
;
324 MediaStreamManager::EnumerationCache::EnumerationCache()
328 MediaStreamManager::EnumerationCache::~EnumerationCache() {
331 MediaStreamManager::MediaStreamManager()
332 : audio_manager_(NULL
),
333 monitoring_started_(false),
335 use_fake_ui_(false) {}
337 MediaStreamManager::MediaStreamManager(media::AudioManager
* audio_manager
)
338 : audio_manager_(audio_manager
),
339 monitoring_started_(false),
341 use_fake_ui_(false) {
342 DCHECK(audio_manager_
);
343 memset(active_enumeration_ref_count_
, 0,
344 sizeof(active_enumeration_ref_count_
));
346 // Some unit tests create the MSM in the IO thread and assumes the
347 // initialization is done synchronously.
348 if (BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
349 InitializeDeviceManagersOnIOThread();
351 BrowserThread::PostTask(
352 BrowserThread::IO
, FROM_HERE
,
353 base::Bind(&MediaStreamManager::InitializeDeviceManagersOnIOThread
,
354 base::Unretained(this)));
358 MediaStreamManager::~MediaStreamManager() {
359 DVLOG(1) << "~MediaStreamManager";
360 DCHECK(requests_
.empty());
361 DCHECK(!device_task_runner_
);
364 VideoCaptureManager
* MediaStreamManager::video_capture_manager() {
365 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
366 DCHECK(video_capture_manager_
.get());
367 return video_capture_manager_
.get();
370 AudioInputDeviceManager
* MediaStreamManager::audio_input_device_manager() {
371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
372 DCHECK(audio_input_device_manager_
.get());
373 return audio_input_device_manager_
.get();
376 std::string
MediaStreamManager::MakeMediaAccessRequest(
377 int render_process_id
,
380 const StreamOptions
& options
,
381 const GURL
& security_origin
,
382 const MediaRequestResponseCallback
& callback
) {
383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
385 // TODO(perkj): The argument list with NULL parameters to DeviceRequest
386 // suggests that this is the wrong design. Can this be refactored?
387 DeviceRequest
* request
= new DeviceRequest(NULL
,
394 base::Bind(&ReturnEmptySalt
));
396 const std::string
& label
= AddRequest(request
);
398 request
->callback
= callback
;
399 // Post a task and handle the request asynchronously. The reason is that the
400 // requester won't have a label for the request until this function returns
401 // and thus can not handle a response. Using base::Unretained is safe since
402 // MediaStreamManager is deleted on the UI thread, after the IO thread has
404 BrowserThread::PostTask(
405 BrowserThread::IO
, FROM_HERE
,
406 base::Bind(&MediaStreamManager::SetupRequest
,
407 base::Unretained(this), label
));
411 void MediaStreamManager::GenerateStream(MediaStreamRequester
* requester
,
412 int render_process_id
,
414 const ResourceContext::SaltCallback
& sc
,
416 const StreamOptions
& options
,
417 const GURL
& security_origin
) {
418 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
419 DVLOG(1) << "GenerateStream()";
420 if (CommandLine::ForCurrentProcess()->HasSwitch(
421 switches::kUseFakeUIForMediaStream
)) {
422 UseFakeUI(scoped_ptr
<FakeMediaStreamUIProxy
>());
425 DeviceRequest
* request
= new DeviceRequest(requester
,
430 MEDIA_GENERATE_STREAM
,
434 const std::string
& label
= AddRequest(request
);
436 // Post a task and handle the request asynchronously. The reason is that the
437 // requester won't have a label for the request until this function returns
438 // and thus can not handle a response. Using base::Unretained is safe since
439 // MediaStreamManager is deleted on the UI thread, after the IO thread has
441 BrowserThread::PostTask(
442 BrowserThread::IO
, FROM_HERE
,
443 base::Bind(&MediaStreamManager::SetupRequest
,
444 base::Unretained(this), label
));
447 void MediaStreamManager::CancelRequest(int render_process_id
,
449 int page_request_id
) {
450 for (DeviceRequests::const_iterator request_it
= requests_
.begin();
451 request_it
!= requests_
.end(); ++request_it
) {
452 const DeviceRequest
* request
= request_it
->second
;
453 if (request
->requesting_process_id
== render_process_id
&&
454 request
->requesting_view_id
== render_view_id
&&
455 request
->page_request_id
== page_request_id
) {
456 CancelRequest(request_it
->first
);
463 void MediaStreamManager::CancelRequest(const std::string
& label
) {
464 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
465 DVLOG(1) << "CancelRequest({label = " << label
<< "})";
466 DeviceRequest
* request
= FindRequest(label
);
468 // The request does not exist.
469 LOG(ERROR
) << "The request with label = " << label
<< " does not exist.";
473 if (request
->request_type
== MEDIA_ENUMERATE_DEVICES
) {
474 // It isn't an ideal use of "CancelRequest" to make it a requirement
475 // for enumeration requests to be deleted via "CancelRequest" _after_
476 // the request has been successfully fulfilled.
477 // See note in FinalizeEnumerateDevices for a recommendation on how
478 // we should refactor this.
479 DeleteRequest(label
);
483 // This is a request for opening one or more devices.
484 for (StreamDeviceInfoArray::iterator device_it
= request
->devices
.begin();
485 device_it
!= request
->devices
.end(); ++device_it
) {
486 MediaRequestState state
= request
->state(device_it
->device
.type
);
487 // If we have not yet requested the device to be opened - just ignore it.
488 if (state
!= MEDIA_REQUEST_STATE_OPENING
&&
489 state
!= MEDIA_REQUEST_STATE_DONE
) {
492 // Stop the opening/opened devices of the requests.
493 CloseDevice(device_it
->device
.type
, device_it
->session_id
);
496 // Cancel the request if still pending at UI side.
497 request
->SetState(NUM_MEDIA_TYPES
, MEDIA_REQUEST_STATE_CLOSING
);
498 DeleteRequest(label
);
501 void MediaStreamManager::CancelAllRequests(int render_process_id
) {
502 DeviceRequests::iterator request_it
= requests_
.begin();
503 while (request_it
!= requests_
.end()) {
504 if (request_it
->second
->requesting_process_id
!= render_process_id
) {
509 std::string label
= request_it
->first
;
511 CancelRequest(label
);
515 void MediaStreamManager::StopStreamDevice(int render_process_id
,
517 const std::string
& device_id
) {
518 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
519 DVLOG(1) << "StopStreamDevice({render_view_id = " << render_view_id
<< "} "
520 << ", {device_id = " << device_id
<< "})";
521 // Find the first request for this |render_process_id| and |render_view_id|
522 // of type MEDIA_GENERATE_STREAM that has requested to use |device_id| and
524 for (DeviceRequests::iterator request_it
= requests_
.begin();
525 request_it
!= requests_
.end(); ++request_it
) {
526 DeviceRequest
* request
= request_it
->second
;
527 if (request
->requesting_process_id
!= render_process_id
||
528 request
->requesting_view_id
!= render_view_id
||
529 request
->request_type
!= MEDIA_GENERATE_STREAM
) {
533 StreamDeviceInfoArray
& devices
= request
->devices
;
534 for (StreamDeviceInfoArray::iterator device_it
= devices
.begin();
535 device_it
!= devices
.end(); ++device_it
) {
536 if (device_it
->device
.id
== device_id
) {
537 StopDevice(device_it
->device
.type
, device_it
->session_id
);
544 void MediaStreamManager::StopDevice(MediaStreamType type
, int session_id
) {
545 DVLOG(1) << "StopDevice"
546 << "{type = " << type
<< "}"
547 << "{session_id = " << session_id
<< "}";
548 DeviceRequests::iterator request_it
= requests_
.begin();
549 while (request_it
!= requests_
.end()) {
550 DeviceRequest
* request
= request_it
->second
;
551 StreamDeviceInfoArray
* devices
= &request
->devices
;
552 if (devices
->empty()) {
553 // There is no device in use yet by this request.
557 StreamDeviceInfoArray::iterator device_it
= devices
->begin();
558 while (device_it
!= devices
->end()) {
559 if (device_it
->device
.type
!= type
||
560 device_it
->session_id
!= session_id
) {
565 if (request
->state(type
) == MEDIA_REQUEST_STATE_DONE
)
566 CloseDevice(type
, session_id
);
567 device_it
= devices
->erase(device_it
);
570 // If this request doesn't have any active devices after a device
571 // has been stopped above, remove the request. Note that the request is
572 // only deleted if a device as been removed from |devices|.
573 if (devices
->empty()) {
574 std::string label
= request_it
->first
;
576 DeleteRequest(label
);
583 void MediaStreamManager::CloseDevice(MediaStreamType type
, int session_id
) {
584 DVLOG(1) << "CloseDevice("
585 << "{type = " << type
<< "} "
586 << "{session_id = " << session_id
<< "})";
587 GetDeviceManager(type
)->Close(session_id
);
589 for (DeviceRequests::iterator request_it
= requests_
.begin();
590 request_it
!= requests_
.end() ; ++request_it
) {
591 StreamDeviceInfoArray
* devices
= &request_it
->second
->devices
;
592 for (StreamDeviceInfoArray::iterator device_it
= devices
->begin();
593 device_it
!= devices
->end(); ++device_it
) {
594 if (device_it
->session_id
== session_id
&&
595 device_it
->device
.type
== type
) {
596 // Notify observers that this device is being closed.
597 // Note that only one device per type can be opened.
598 request_it
->second
->SetState(type
, MEDIA_REQUEST_STATE_CLOSING
);
604 std::string
MediaStreamManager::EnumerateDevices(
605 MediaStreamRequester
* requester
,
606 int render_process_id
,
608 const ResourceContext::SaltCallback
& sc
,
610 MediaStreamType type
,
611 const GURL
& security_origin
) {
612 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
614 DCHECK(type
== MEDIA_DEVICE_AUDIO_CAPTURE
||
615 type
== MEDIA_DEVICE_VIDEO_CAPTURE
);
617 DeviceRequest
* request
= new DeviceRequest(requester
,
622 MEDIA_ENUMERATE_DEVICES
,
625 if (IsAudioMediaType(type
))
626 request
->SetAudioType(type
);
627 else if (IsVideoMediaType(type
))
628 request
->SetVideoType(type
);
630 const std::string
& label
= AddRequest(request
);
631 // Post a task and handle the request asynchronously. The reason is that the
632 // requester won't have a label for the request until this function returns
633 // and thus can not handle a response. Using base::Unretained is safe since
634 // MediaStreamManager is deleted on the UI thread, after the IO thread has
636 BrowserThread::PostTask(
637 BrowserThread::IO
, FROM_HERE
,
638 base::Bind(&MediaStreamManager::DoEnumerateDevices
,
639 base::Unretained(this), label
));
643 void MediaStreamManager::DoEnumerateDevices(const std::string
& label
) {
644 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
645 DeviceRequest
* request
= FindRequest(label
);
647 return; // This can happen if the request has been canceled.
649 MediaStreamType type
;
650 EnumerationCache
* cache
;
651 if (request
->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE
) {
652 DCHECK_EQ(MEDIA_NO_SERVICE
, request
->video_type());
653 type
= MEDIA_DEVICE_AUDIO_CAPTURE
;
654 cache
= &audio_enumeration_cache_
;
656 DCHECK_EQ(MEDIA_DEVICE_VIDEO_CAPTURE
, request
->video_type());
657 type
= MEDIA_DEVICE_VIDEO_CAPTURE
;
658 cache
= &video_enumeration_cache_
;
661 if (!EnumerationRequired(cache
, type
)) {
662 // Cached device list of this type exists. Just send it out.
663 request
->SetState(type
, MEDIA_REQUEST_STATE_REQUESTED
);
664 request
->devices
= cache
->devices
;
665 FinalizeEnumerateDevices(label
, request
);
667 StartEnumeration(request
);
669 DVLOG(1) << "Enumerate Devices ({label = " << label
<< "})";
672 void MediaStreamManager::OpenDevice(MediaStreamRequester
* requester
,
673 int render_process_id
,
675 const ResourceContext::SaltCallback
& sc
,
677 const std::string
& device_id
,
678 MediaStreamType type
,
679 const GURL
& security_origin
) {
680 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
681 DCHECK(type
== MEDIA_DEVICE_AUDIO_CAPTURE
||
682 type
== MEDIA_DEVICE_VIDEO_CAPTURE
);
683 DVLOG(1) << "OpenDevice ({page_request_id = " << page_request_id
<< "})";
684 StreamOptions options
;
685 if (IsAudioMediaType(type
)) {
686 options
.audio_requested
= true;
687 options
.mandatory_audio
.push_back(
688 StreamOptions::Constraint(kMediaStreamSourceInfoId
, device_id
));
689 } else if (IsVideoMediaType(type
)) {
690 options
.video_requested
= true;
691 options
.mandatory_video
.push_back(
692 StreamOptions::Constraint(kMediaStreamSourceInfoId
, device_id
));
696 DeviceRequest
* request
= new DeviceRequest(requester
,
705 const std::string
& label
= AddRequest(request
);
706 // Post a task and handle the request asynchronously. The reason is that the
707 // requester won't have a label for the request until this function returns
708 // and thus can not handle a response. Using base::Unretained is safe since
709 // MediaStreamManager is deleted on the UI thread, after the IO thread has
711 BrowserThread::PostTask(
712 BrowserThread::IO
, FROM_HERE
,
713 base::Bind(&MediaStreamManager::SetupRequest
,
714 base::Unretained(this), label
));
717 void MediaStreamManager::EnsureDeviceMonitorStarted() {
718 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
722 void MediaStreamManager::StopRemovedDevices(
723 const StreamDeviceInfoArray
& old_devices
,
724 const StreamDeviceInfoArray
& new_devices
) {
725 DVLOG(1) << "StopRemovedDevices("
726 << "{#old_devices = " << old_devices
.size() << "} "
727 << "{#new_devices = " << new_devices
.size() << "})";
728 for (StreamDeviceInfoArray::const_iterator old_dev_it
= old_devices
.begin();
729 old_dev_it
!= old_devices
.end(); ++old_dev_it
) {
730 bool device_found
= false;
731 StreamDeviceInfoArray::const_iterator new_dev_it
= new_devices
.begin();
732 for (; new_dev_it
!= new_devices
.end(); ++new_dev_it
) {
733 if (old_dev_it
->device
.id
== new_dev_it
->device
.id
) {
740 // A device has been removed. We need to check if it is used by a
741 // MediaStream and in that case cleanup and notify the render process.
742 StopRemovedDevice(old_dev_it
->device
);
747 void MediaStreamManager::StopRemovedDevice(const MediaStreamDevice
& device
) {
748 std::vector
<int> session_ids
;
749 for (DeviceRequests::const_iterator it
= requests_
.begin();
750 it
!= requests_
.end() ; ++it
) {
751 const DeviceRequest
* request
= it
->second
;
752 for (StreamDeviceInfoArray::const_iterator device_it
=
753 request
->devices
.begin();
754 device_it
!= request
->devices
.end(); ++device_it
) {
755 std::string source_id
= content::GetHMACForMediaDeviceID(
756 request
->salt_callback
,
757 request
->security_origin
,
759 if (device_it
->device
.id
== source_id
&&
760 device_it
->device
.type
== device
.type
) {
761 session_ids
.push_back(device_it
->session_id
);
762 if (it
->second
->requester
) {
763 it
->second
->requester
->DeviceStopped(
764 it
->second
->requesting_view_id
,
771 for (std::vector
<int>::const_iterator it
= session_ids
.begin();
772 it
!= session_ids
.end(); ++it
) {
773 StopDevice(device
.type
, *it
);
777 void MediaStreamManager::StartMonitoring() {
778 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
779 if (monitoring_started_
)
782 if (!base::SystemMonitor::Get())
785 monitoring_started_
= true;
786 base::SystemMonitor::Get()->AddDevicesChangedObserver(this);
788 // Enumerate both the audio and video devices to cache the device lists
789 // and send them to media observer.
790 ++active_enumeration_ref_count_
[MEDIA_DEVICE_AUDIO_CAPTURE
];
791 audio_input_device_manager_
->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE
);
792 ++active_enumeration_ref_count_
[MEDIA_DEVICE_VIDEO_CAPTURE
];
793 video_capture_manager_
->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE
);
795 #if defined(OS_MACOSX)
796 BrowserThread::PostTask(
797 BrowserThread::UI
, FROM_HERE
,
798 base::Bind(&MediaStreamManager::StartMonitoringOnUIThread
,
799 base::Unretained(this)));
803 #if defined(OS_MACOSX)
804 void MediaStreamManager::StartMonitoringOnUIThread() {
805 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
806 BrowserMainLoop
* browser_main_loop
= content::BrowserMainLoop::GetInstance();
807 if (browser_main_loop
)
808 browser_main_loop
->device_monitor_mac()->StartMonitoring();
812 void MediaStreamManager::StopMonitoring() {
813 DCHECK_EQ(base::MessageLoop::current(), io_loop_
);
814 if (monitoring_started_
) {
815 base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this);
816 monitoring_started_
= false;
817 ClearEnumerationCache(&audio_enumeration_cache_
);
818 ClearEnumerationCache(&video_enumeration_cache_
);
822 bool MediaStreamManager::GetRequestedDeviceCaptureId(
823 const DeviceRequest
* request
,
824 MediaStreamType type
,
825 std::string
* device_id
) const {
826 DCHECK(type
== MEDIA_DEVICE_AUDIO_CAPTURE
||
827 type
== MEDIA_DEVICE_VIDEO_CAPTURE
);
828 const StreamOptions::Constraints
* mandatory
=
829 (type
== MEDIA_DEVICE_AUDIO_CAPTURE
) ?
830 &request
->options
.mandatory_audio
: &request
->options
.mandatory_video
;
831 const StreamOptions::Constraints
* optional
=
832 (type
== MEDIA_DEVICE_AUDIO_CAPTURE
) ?
833 &request
->options
.optional_audio
: &request
->options
.optional_video
;
835 std::vector
<std::string
> source_ids
;
836 StreamOptions::GetConstraintsByName(*mandatory
,
837 kMediaStreamSourceInfoId
, &source_ids
);
838 if (source_ids
.size() > 1) {
839 LOG(ERROR
) << "Only one mandatory " << kMediaStreamSourceInfoId
843 // If a specific device has been requested we need to find the real device
845 if (source_ids
.size() == 1 &&
846 !TranslateSourceIdToDeviceId(type
,
847 request
->salt_callback
,
848 request
->security_origin
,
849 source_ids
[0], device_id
)) {
850 LOG(WARNING
) << "Invalid mandatory " << kMediaStreamSourceInfoId
851 << " = " << source_ids
[0] << ".";
854 // Check for optional audio sourceIDs.
855 if (device_id
->empty()) {
856 StreamOptions::GetConstraintsByName(*optional
,
857 kMediaStreamSourceInfoId
,
859 // Find the first sourceID that translates to device. Note that only one
860 // device per type can call to GenerateStream is ever opened.
861 for (std::vector
<std::string
>::const_iterator it
= source_ids
.begin();
862 it
!= source_ids
.end(); ++it
) {
863 if (TranslateSourceIdToDeviceId(type
,
864 request
->salt_callback
,
865 request
->security_origin
,
875 void MediaStreamManager::TranslateDeviceIdToSourceId(
876 DeviceRequest
* request
,
877 MediaStreamDevice
* device
) {
878 if (request
->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE
||
879 request
->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE
) {
880 device
->id
= content::GetHMACForMediaDeviceID(
881 request
->salt_callback
,
882 request
->security_origin
,
887 bool MediaStreamManager::TranslateSourceIdToDeviceId(
888 MediaStreamType stream_type
,
889 const ResourceContext::SaltCallback
& sc
,
890 const GURL
& security_origin
,
891 const std::string
& source_id
,
892 std::string
* device_id
) const {
893 DCHECK(stream_type
== MEDIA_DEVICE_AUDIO_CAPTURE
||
894 stream_type
== MEDIA_DEVICE_VIDEO_CAPTURE
);
895 // The source_id can be empty if the constraint is set but empty.
896 if (source_id
.empty())
899 const EnumerationCache
* cache
=
900 stream_type
== MEDIA_DEVICE_AUDIO_CAPTURE
?
901 &audio_enumeration_cache_
: &video_enumeration_cache_
;
903 // If device monitoring hasn't started, the |device_guid| is not valid.
907 for (StreamDeviceInfoArray::const_iterator it
= cache
->devices
.begin();
908 it
!= cache
->devices
.end();
910 if (content::DoesMediaDeviceIDMatchHMAC(sc
, security_origin
, source_id
,
912 *device_id
= it
->device
.id
;
919 void MediaStreamManager::ClearEnumerationCache(EnumerationCache
* cache
) {
920 DCHECK_EQ(base::MessageLoop::current(), io_loop_
);
921 cache
->valid
= false;
924 bool MediaStreamManager::EnumerationRequired(EnumerationCache
* cache
,
925 MediaStreamType stream_type
) {
926 DCHECK_EQ(base::MessageLoop::current(), io_loop_
);
927 if (stream_type
== MEDIA_NO_SERVICE
)
930 DCHECK(stream_type
== MEDIA_DEVICE_AUDIO_CAPTURE
||
931 stream_type
== MEDIA_DEVICE_VIDEO_CAPTURE
);
933 #if defined(OS_ANDROID)
934 // There's no SystemMonitor on Android that notifies us when devices are
935 // added or removed, so we need to populate the cache on every request.
936 // Fortunately, there is an already up-to-date cache in the browser side
937 // audio manager that we can rely on, so the performance impact of
938 // invalidating the cache like this, is minimal.
939 if (stream_type
== MEDIA_DEVICE_AUDIO_CAPTURE
) {
940 // Make sure the cache is marked as invalid so that FinalizeEnumerateDevices
941 // will be called at the end of the enumeration.
942 ClearEnumerationCache(cache
);
945 // If the cache isn't valid, we need to start a full enumeration.
946 return !cache
->valid
;
949 void MediaStreamManager::StartEnumeration(DeviceRequest
* request
) {
950 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
952 // Start monitoring the devices when doing the first enumeration.
955 // Start enumeration for devices of all requested device types.
956 const MediaStreamType streams
[] = { request
->audio_type(),
957 request
->video_type() };
958 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(streams
); ++i
) {
959 if (streams
[i
] == MEDIA_NO_SERVICE
)
961 request
->SetState(streams
[i
], MEDIA_REQUEST_STATE_REQUESTED
);
962 DCHECK_GE(active_enumeration_ref_count_
[streams
[i
]], 0);
963 if (active_enumeration_ref_count_
[streams
[i
]] == 0) {
964 ++active_enumeration_ref_count_
[streams
[i
]];
965 GetDeviceManager(streams
[i
])->EnumerateDevices(streams
[i
]);
970 std::string
MediaStreamManager::AddRequest(DeviceRequest
* request
) {
971 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
973 // Create a label for this request and verify it is unique.
974 std::string unique_label
;
976 unique_label
= RandomLabel();
977 } while (requests_
.find(unique_label
) != requests_
.end());
979 requests_
.insert(std::make_pair(unique_label
, request
));
984 MediaStreamManager::DeviceRequest
*
985 MediaStreamManager::FindRequest(const std::string
& label
) const {
986 DeviceRequests::const_iterator request_it
= requests_
.find(label
);
987 return request_it
== requests_
.end() ? NULL
: request_it
->second
;
990 void MediaStreamManager::DeleteRequest(const std::string
& label
) {
991 DVLOG(1) << "DeleteRequest({label= " << label
<< "})";
992 DeviceRequests::iterator it
= requests_
.find(label
);
993 scoped_ptr
<DeviceRequest
> request(it
->second
);
997 void MediaStreamManager::PostRequestToUI(const std::string
& label
,
998 DeviceRequest
* request
) {
999 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1000 DCHECK(request
->UIRequest());
1001 DVLOG(1) << "PostRequestToUI({label= " << label
<< "})";
1003 const MediaStreamType audio_type
= request
->audio_type();
1004 const MediaStreamType video_type
= request
->video_type();
1006 // Post the request to UI and set the state.
1007 if (IsAudioMediaType(audio_type
))
1008 request
->SetState(audio_type
, MEDIA_REQUEST_STATE_PENDING_APPROVAL
);
1009 if (IsVideoMediaType(video_type
))
1010 request
->SetState(video_type
, MEDIA_REQUEST_STATE_PENDING_APPROVAL
);
1014 fake_ui_
.reset(new FakeMediaStreamUIProxy());
1016 MediaStreamDevices devices
;
1017 if (audio_enumeration_cache_
.valid
) {
1018 for (StreamDeviceInfoArray::const_iterator it
=
1019 audio_enumeration_cache_
.devices
.begin();
1020 it
!= audio_enumeration_cache_
.devices
.end(); ++it
) {
1021 devices
.push_back(it
->device
);
1024 if (video_enumeration_cache_
.valid
) {
1025 for (StreamDeviceInfoArray::const_iterator it
=
1026 video_enumeration_cache_
.devices
.begin();
1027 it
!= video_enumeration_cache_
.devices
.end(); ++it
) {
1028 devices
.push_back(it
->device
);
1032 fake_ui_
->SetAvailableDevices(devices
);
1034 request
->ui_proxy
= fake_ui_
.Pass();
1036 request
->ui_proxy
= MediaStreamUIProxy::Create();
1039 request
->ui_proxy
->RequestAccess(
1040 *request
->UIRequest(),
1041 base::Bind(&MediaStreamManager::HandleAccessRequestResponse
,
1042 base::Unretained(this), label
));
1045 void MediaStreamManager::SetupRequest(const std::string
& label
) {
1046 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1047 DeviceRequest
* request
= FindRequest(label
);
1049 DVLOG(1) << "SetupRequest label " << label
<< " doesn't exist!!";
1050 return; // This can happen if the request has been canceled.
1053 if (!request
->security_origin
.is_valid()) {
1054 LOG(ERROR
) << "Invalid security origin. "
1055 << request
->security_origin
;
1056 FinalizeRequestFailed(label
,
1058 MEDIA_DEVICE_INVALID_SECURITY_ORIGIN
);
1062 MediaStreamType audio_type
= MEDIA_NO_SERVICE
;
1063 MediaStreamType video_type
= MEDIA_NO_SERVICE
;
1064 ParseStreamType(request
->options
, &audio_type
, &video_type
);
1065 request
->SetAudioType(audio_type
);
1066 request
->SetVideoType(video_type
);
1068 bool is_web_contents_capture
=
1069 audio_type
== MEDIA_TAB_AUDIO_CAPTURE
||
1070 video_type
== MEDIA_TAB_VIDEO_CAPTURE
;
1071 if (is_web_contents_capture
&& !SetupTabCaptureRequest(request
)) {
1072 FinalizeRequestFailed(label
,
1074 MEDIA_DEVICE_TAB_CAPTURE_FAILURE
);
1078 bool is_screen_capture
=
1079 video_type
== MEDIA_DESKTOP_VIDEO_CAPTURE
;
1080 if (is_screen_capture
&& !SetupScreenCaptureRequest(request
)) {
1081 FinalizeRequestFailed(label
,
1083 MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE
);
1087 if (!is_web_contents_capture
&& !is_screen_capture
) {
1088 if (EnumerationRequired(&audio_enumeration_cache_
, audio_type
) ||
1089 EnumerationRequired(&video_enumeration_cache_
, video_type
)) {
1090 // Enumerate the devices if there is no valid device lists to be used.
1091 StartEnumeration(request
);
1094 // Cache is valid, so log the cached devices for MediaStream requests.
1095 if (request
->request_type
== MEDIA_GENERATE_STREAM
) {
1096 std::string
log_message("Using cached devices for request.\n");
1097 if (audio_type
!= MEDIA_NO_SERVICE
) {
1099 GetLogMessageString(audio_type
, audio_enumeration_cache_
.devices
);
1101 if (video_type
!= MEDIA_NO_SERVICE
) {
1103 GetLogMessageString(video_type
, video_enumeration_cache_
.devices
);
1105 SendMessageToNativeLog(log_message
);
1109 if (!SetupDeviceCaptureRequest(request
)) {
1110 FinalizeRequestFailed(label
, request
, MEDIA_DEVICE_NO_HARDWARE
);
1114 PostRequestToUI(label
, request
);
1117 bool MediaStreamManager::SetupDeviceCaptureRequest(DeviceRequest
* request
) {
1118 DCHECK((request
->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE
||
1119 request
->audio_type() == MEDIA_NO_SERVICE
) &&
1120 (request
->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE
||
1121 request
->video_type() == MEDIA_NO_SERVICE
));
1122 std::string audio_device_id
;
1123 if (request
->options
.audio_requested
&&
1124 !GetRequestedDeviceCaptureId(request
, request
->audio_type(),
1125 &audio_device_id
)) {
1129 std::string video_device_id
;
1130 if (request
->options
.video_requested
&&
1131 !GetRequestedDeviceCaptureId(request
, request
->video_type(),
1132 &video_device_id
)) {
1135 request
->CreateUIRequest(audio_device_id
, video_device_id
);
1136 DVLOG(3) << "Audio requested " << request
->options
.audio_requested
1137 << " device id = " << audio_device_id
1138 << "Video requested " << request
->options
.video_requested
1139 << " device id = " << video_device_id
;
1143 bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest
* request
) {
1144 DCHECK(request
->audio_type() == MEDIA_TAB_AUDIO_CAPTURE
||
1145 request
->video_type() == MEDIA_TAB_VIDEO_CAPTURE
);
1147 std::string capture_device_id
;
1148 bool mandatory_audio
= false;
1149 bool mandatory_video
= false;
1150 if (!request
->options
.GetFirstAudioConstraintByName(kMediaStreamSourceId
,
1152 &mandatory_audio
) &&
1153 !request
->options
.GetFirstVideoConstraintByName(kMediaStreamSourceId
,
1155 &mandatory_video
)) {
1158 DCHECK(mandatory_audio
|| mandatory_video
);
1160 // Customize options for a WebContents based capture.
1161 int target_render_process_id
= 0;
1162 int target_render_view_id
= 0;
1164 // TODO(justinlin): Can't plumb audio mirroring using stream type right
1165 // now, so plumbing by device_id. Will revisit once it's refactored.
1166 // http://crbug.com/163100
1167 std::string tab_capture_device_id
=
1168 WebContentsCaptureUtil::AppendWebContentsDeviceScheme(capture_device_id
);
1170 bool has_valid_device_id
= WebContentsCaptureUtil::ExtractTabCaptureTarget(
1171 tab_capture_device_id
, &target_render_process_id
,
1172 &target_render_view_id
);
1173 if (!has_valid_device_id
||
1174 (request
->audio_type() != MEDIA_TAB_AUDIO_CAPTURE
&&
1175 request
->audio_type() != MEDIA_NO_SERVICE
) ||
1176 (request
->video_type() != MEDIA_TAB_VIDEO_CAPTURE
&&
1177 request
->video_type() != MEDIA_NO_SERVICE
)) {
1181 request
->CreateTabCatureUIRequest(target_render_process_id
,
1182 target_render_view_id
,
1183 tab_capture_device_id
);
1185 DVLOG(3) << "SetupTabCaptureRequest "
1186 << ", {tab_capture_device_id = " << tab_capture_device_id
<< "}"
1187 << ", {target_render_process_id = " << target_render_process_id
1189 << ", {target_render_view_id = " << target_render_view_id
<< "}";
1193 bool MediaStreamManager::SetupScreenCaptureRequest(DeviceRequest
* request
) {
1194 DCHECK(request
->audio_type() == MEDIA_LOOPBACK_AUDIO_CAPTURE
||
1195 request
->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE
);
1197 // For screen capture we only support two valid combinations:
1198 // (1) screen video capture only, or
1199 // (2) screen video capture with loopback audio capture.
1200 if (request
->video_type() != MEDIA_DESKTOP_VIDEO_CAPTURE
||
1201 (request
->audio_type() != MEDIA_NO_SERVICE
&&
1202 request
->audio_type() != MEDIA_LOOPBACK_AUDIO_CAPTURE
)) {
1203 LOG(ERROR
) << "Invalid screen capture request.";
1207 std::string video_device_id
;
1208 if (request
->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE
) {
1209 std::string video_stream_source
;
1210 bool mandatory
= false;
1211 if (!request
->options
.GetFirstVideoConstraintByName(
1213 &video_stream_source
,
1215 LOG(ERROR
) << kMediaStreamSource
<< " not found.";
1220 if (video_stream_source
== kMediaStreamSourceDesktop
) {
1221 if (!request
->options
.GetFirstVideoConstraintByName(
1222 kMediaStreamSourceId
,
1225 LOG(ERROR
) << kMediaStreamSourceId
<< " not found.";
1232 request
->CreateUIRequest("", video_device_id
);
1236 StreamDeviceInfoArray
MediaStreamManager::GetDevicesOpenedByRequest(
1237 const std::string
& label
) const {
1238 DeviceRequest
* request
= FindRequest(label
);
1240 return StreamDeviceInfoArray();
1241 return request
->devices
;
1244 bool MediaStreamManager::FindExistingRequestedDeviceInfo(
1245 const DeviceRequest
& new_request
,
1246 const MediaStreamDevice
& new_device_info
,
1247 StreamDeviceInfo
* existing_device_info
,
1248 MediaRequestState
* existing_request_state
) const {
1249 DCHECK(existing_device_info
);
1250 DCHECK(existing_request_state
);
1252 std::string source_id
= content::GetHMACForMediaDeviceID(
1253 new_request
.salt_callback
,
1254 new_request
.security_origin
,
1255 new_device_info
.id
);
1257 for (DeviceRequests::const_iterator it
= requests_
.begin();
1258 it
!= requests_
.end() ; ++it
) {
1259 const DeviceRequest
* request
= it
->second
;
1260 if (request
->requesting_process_id
== new_request
.requesting_process_id
&&
1261 request
->requesting_view_id
== new_request
.requesting_view_id
&&
1262 request
->request_type
== new_request
.request_type
) {
1263 for (StreamDeviceInfoArray::const_iterator device_it
=
1264 request
->devices
.begin();
1265 device_it
!= request
->devices
.end(); ++device_it
) {
1266 if (device_it
->device
.id
== source_id
&&
1267 device_it
->device
.type
== new_device_info
.type
) {
1268 *existing_device_info
= *device_it
;
1269 *existing_request_state
= request
->state(device_it
->device
.type
);
1278 void MediaStreamManager::FinalizeGenerateStream(const std::string
& label
,
1279 DeviceRequest
* request
) {
1280 DVLOG(1) << "FinalizeGenerateStream label " << label
;
1281 const StreamDeviceInfoArray
& requested_devices
= request
->devices
;
1283 // Partition the array of devices into audio vs video.
1284 StreamDeviceInfoArray audio_devices
, video_devices
;
1285 for (StreamDeviceInfoArray::const_iterator device_it
=
1286 requested_devices
.begin();
1287 device_it
!= requested_devices
.end(); ++device_it
) {
1288 if (IsAudioMediaType(device_it
->device
.type
)) {
1289 audio_devices
.push_back(*device_it
);
1290 } else if (IsVideoMediaType(device_it
->device
.type
)) {
1291 video_devices
.push_back(*device_it
);
1297 request
->requester
->StreamGenerated(
1298 request
->requesting_view_id
,
1299 request
->page_request_id
,
1300 label
, audio_devices
, video_devices
);
1303 void MediaStreamManager::FinalizeRequestFailed(
1304 const std::string
& label
,
1305 DeviceRequest
* request
,
1306 content::MediaStreamRequestResult result
) {
1307 if (request
->requester
)
1308 request
->requester
->StreamGenerationFailed(
1309 request
->requesting_view_id
,
1310 request
->page_request_id
,
1313 if (request
->request_type
== MEDIA_DEVICE_ACCESS
&&
1314 !request
->callback
.is_null()) {
1315 request
->callback
.Run(MediaStreamDevices(), request
->ui_proxy
.Pass());
1318 DeleteRequest(label
);
1321 void MediaStreamManager::FinalizeOpenDevice(const std::string
& label
,
1322 DeviceRequest
* request
) {
1323 const StreamDeviceInfoArray
& requested_devices
= request
->devices
;
1324 request
->requester
->DeviceOpened(request
->requesting_view_id
,
1325 request
->page_request_id
,
1326 label
, requested_devices
.front());
1329 void MediaStreamManager::FinalizeEnumerateDevices(const std::string
& label
,
1330 DeviceRequest
* request
) {
1331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1332 DCHECK_EQ(request
->request_type
, MEDIA_ENUMERATE_DEVICES
);
1334 if (request
->security_origin
.is_valid()) {
1335 for (StreamDeviceInfoArray::iterator it
= request
->devices
.begin();
1336 it
!= request
->devices
.end(); ++it
) {
1337 TranslateDeviceIdToSourceId(request
, &it
->device
);
1340 request
->devices
.clear();
1343 request
->requester
->DevicesEnumerated(
1344 request
->requesting_view_id
,
1345 request
->page_request_id
,
1350 // Ideally enumeration requests should be deleted once they have been served
1351 // (as any request). However, this implementation mixes requests and
1352 // notifications together so enumeration requests are kept open by some
1353 // implementations (only Pepper?) and enumerations are done again when
1354 // device notifications are fired.
1355 // Implementations that just want to request the device list and be done
1356 // (e.g. DeviceRequestMessageFilter), they must (confusingly) call
1357 // CancelRequest() after the request has been fulfilled. This is not
1358 // obvious, not consistent in this class (see e.g. FinalizeMediaAccessRequest)
1359 // and can lead to subtle bugs (requests not deleted at all deleted too
1362 // Basically, it is not clear that using requests as an additional layer on
1363 // top of device notifications is necessary or good.
1365 // To add to this, MediaStreamManager currently relies on the external
1366 // implementations of MediaStreamRequester to delete enumeration requests via
1367 // CancelRequest and e.g. DeviceRequestMessageFilter does this. However the
1368 // Pepper implementation does not seem to to this at all (and from what I can
1369 // see, it is the only implementation that uses an enumeration request as a
1370 // notification mechanism).
1372 // We should decouple notifications from enumeration requests and once that
1373 // has been done, remove the requirement to call CancelRequest() to delete
1374 // enumeration requests and uncomment the following line:
1376 // DeleteRequest(label);
1379 void MediaStreamManager::FinalizeMediaAccessRequest(
1380 const std::string
& label
,
1381 DeviceRequest
* request
,
1382 const MediaStreamDevices
& devices
) {
1383 if (!request
->callback
.is_null())
1384 request
->callback
.Run(devices
, request
->ui_proxy
.Pass());
1386 // Delete the request since it is done.
1387 DeleteRequest(label
);
1390 void MediaStreamManager::InitializeDeviceManagersOnIOThread() {
1391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1392 if (device_task_runner_
)
1395 device_task_runner_
= audio_manager_
->GetWorkerTaskRunner();
1397 audio_input_device_manager_
= new AudioInputDeviceManager(audio_manager_
);
1398 audio_input_device_manager_
->Register(this, device_task_runner_
);
1400 video_capture_manager_
= new VideoCaptureManager();
1401 video_capture_manager_
->Register(this, device_task_runner_
);
1403 // We want to be notified of IO message loop destruction to delete the thread
1404 // and the device managers.
1405 io_loop_
= base::MessageLoop::current();
1406 io_loop_
->AddDestructionObserver(this);
1408 if (CommandLine::ForCurrentProcess()->HasSwitch(
1409 switches::kUseFakeDeviceForMediaStream
)) {
1410 DVLOG(1) << "Using fake device";
1415 void MediaStreamManager::Opened(MediaStreamType stream_type
,
1416 int capture_session_id
) {
1417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1418 DVLOG(1) << "Opened({stream_type = " << stream_type
<< "} "
1419 << "{capture_session_id = " << capture_session_id
<< "})";
1420 // Find the request(s) containing this device and mark it as used.
1421 // It can be used in several requests since the same device can be
1422 // requested from the same web page.
1423 for (DeviceRequests::iterator request_it
= requests_
.begin();
1424 request_it
!= requests_
.end(); ++request_it
) {
1425 const std::string
& label
= request_it
->first
;
1426 DeviceRequest
* request
= request_it
->second
;
1427 StreamDeviceInfoArray
* devices
= &(request
->devices
);
1428 for (StreamDeviceInfoArray::iterator device_it
= devices
->begin();
1429 device_it
!= devices
->end(); ++device_it
) {
1430 if (device_it
->device
.type
== stream_type
&&
1431 device_it
->session_id
== capture_session_id
) {
1432 CHECK(request
->state(device_it
->device
.type
) ==
1433 MEDIA_REQUEST_STATE_OPENING
);
1434 // We've found a matching request.
1435 request
->SetState(device_it
->device
.type
, MEDIA_REQUEST_STATE_DONE
);
1437 if (IsAudioMediaType(device_it
->device
.type
)) {
1438 // Store the native audio parameters in the device struct.
1439 // TODO(xians): Handle the tab capture sample rate/channel layout
1440 // in AudioInputDeviceManager::Open().
1441 if (device_it
->device
.type
!= content::MEDIA_TAB_AUDIO_CAPTURE
) {
1442 const StreamDeviceInfo
* info
=
1443 audio_input_device_manager_
->GetOpenedDeviceInfoById(
1444 device_it
->session_id
);
1445 device_it
->device
.input
= info
->device
.input
;
1446 device_it
->device
.matched_output
= info
->device
.matched_output
;
1449 if (RequestDone(*request
))
1450 HandleRequestDone(label
, request
);
1457 void MediaStreamManager::HandleRequestDone(const std::string
& label
,
1458 DeviceRequest
* request
) {
1459 DCHECK(RequestDone(*request
));
1460 DVLOG(1) << "HandleRequestDone("
1461 << ", {label = " << label
<< "})";
1463 switch (request
->request_type
) {
1464 case MEDIA_OPEN_DEVICE
:
1465 FinalizeOpenDevice(label
, request
);
1467 case MEDIA_GENERATE_STREAM
: {
1468 FinalizeGenerateStream(label
, request
);
1476 if (request
->ui_proxy
.get()) {
1477 request
->ui_proxy
->OnStarted(
1478 base::Bind(&MediaStreamManager::StopMediaStreamFromBrowser
,
1479 base::Unretained(this), label
));
1483 void MediaStreamManager::Closed(MediaStreamType stream_type
,
1484 int capture_session_id
) {
1485 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1488 void MediaStreamManager::DevicesEnumerated(
1489 MediaStreamType stream_type
, const StreamDeviceInfoArray
& devices
) {
1490 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1491 DVLOG(1) << "DevicesEnumerated("
1492 << "{stream_type = " << stream_type
<< "})" << std::endl
;
1494 std::string log_message
= "New device enumeration result:\n" +
1495 GetLogMessageString(stream_type
, devices
);
1496 SendMessageToNativeLog(log_message
);
1498 // Only cache the device list when the device list has been changed.
1499 bool need_update_clients
= false;
1500 EnumerationCache
* cache
=
1501 stream_type
== MEDIA_DEVICE_AUDIO_CAPTURE
?
1502 &audio_enumeration_cache_
: &video_enumeration_cache_
;
1503 if (!cache
->valid
||
1504 devices
.size() != cache
->devices
.size() ||
1505 !std::equal(devices
.begin(), devices
.end(), cache
->devices
.begin(),
1506 StreamDeviceInfo::IsEqual
)) {
1507 StopRemovedDevices(cache
->devices
, devices
);
1508 cache
->devices
= devices
;
1509 need_update_clients
= true;
1511 // The device might not be able to be enumerated when it is not warmed up,
1512 // for example, when the machine just wakes up from sleep. We set the cache
1513 // to be invalid so that the next media request will trigger the
1514 // enumeration again. See issue/317673.
1515 cache
->valid
= !devices
.empty();
1518 if (need_update_clients
&& monitoring_started_
)
1519 NotifyDevicesChanged(stream_type
, devices
);
1521 // Publish the result for all requests waiting for device list(s).
1522 // Find the requests waiting for this device list, store their labels and
1523 // release the iterator before calling device settings. We might get a call
1524 // back from device_settings that will need to iterate through devices.
1525 std::list
<std::string
> label_list
;
1526 for (DeviceRequests::iterator it
= requests_
.begin(); it
!= requests_
.end();
1528 if (it
->second
->state(stream_type
) == MEDIA_REQUEST_STATE_REQUESTED
&&
1529 (it
->second
->audio_type() == stream_type
||
1530 it
->second
->video_type() == stream_type
)) {
1531 if (it
->second
->request_type
!= MEDIA_ENUMERATE_DEVICES
)
1532 it
->second
->SetState(stream_type
, MEDIA_REQUEST_STATE_PENDING_APPROVAL
);
1533 label_list
.push_back(it
->first
);
1537 for (std::list
<std::string
>::iterator it
= label_list
.begin();
1538 it
!= label_list
.end(); ++it
) {
1539 DeviceRequest
* request
= FindRequest(*it
);
1540 switch (request
->request_type
) {
1541 case MEDIA_ENUMERATE_DEVICES
:
1542 if (need_update_clients
&& request
->requester
) {
1543 request
->devices
= devices
;
1544 FinalizeEnumerateDevices(*it
, request
);
1548 if (request
->state(request
->audio_type()) ==
1549 MEDIA_REQUEST_STATE_REQUESTED
||
1550 request
->state(request
->video_type()) ==
1551 MEDIA_REQUEST_STATE_REQUESTED
) {
1552 // We are doing enumeration for other type of media, wait until it is
1553 // all done before posting the request to UI because UI needs
1554 // the device lists to handle the request.
1557 if (!SetupDeviceCaptureRequest(request
)) {
1558 FinalizeRequestFailed(*it
,
1560 MEDIA_DEVICE_NO_HARDWARE
);
1562 PostRequestToUI(*it
, request
);
1568 --active_enumeration_ref_count_
[stream_type
];
1569 DCHECK_GE(active_enumeration_ref_count_
[stream_type
], 0);
1573 void MediaStreamManager::SendMessageToNativeLog(const std::string
& message
) {
1574 BrowserThread::PostTask(
1575 BrowserThread::UI
, FROM_HERE
,
1576 base::Bind(DoAddLogMessage
, message
));
1579 void MediaStreamManager::AddLogMessageOnIOThread(const std::string
& message
) {
1580 // Get render process ids on the IO thread.
1581 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1583 // Grab all unique process ids that request a MediaStream or have a
1584 // MediaStream running.
1585 std::set
<int> requesting_process_ids
;
1586 for (DeviceRequests::const_iterator it
= requests_
.begin();
1587 it
!= requests_
.end(); ++it
) {
1588 DeviceRequest
* request
= it
->second
;
1589 if (request
->request_type
== MEDIA_GENERATE_STREAM
)
1590 requesting_process_ids
.insert(request
->requesting_process_id
);
1593 // MediaStreamManager is a singleton in BrowserMainLoop, which owns the UI
1594 // thread. MediaStreamManager has the same lifetime as the UI thread, so it is
1595 // safe to use base::Unretained.
1596 BrowserThread::PostTask(
1599 base::Bind(&MediaStreamManager::AddLogMessageOnUIThread
,
1600 base::Unretained(this),
1601 requesting_process_ids
,
1605 void MediaStreamManager::AddLogMessageOnUIThread(
1606 const std::set
<int>& requesting_process_ids
,
1607 const std::string
& message
) {
1608 #if defined(ENABLE_WEBRTC)
1609 // Must be on the UI thread to access RenderProcessHost from process ID.
1610 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1612 for (std::set
<int>::const_iterator it
= requesting_process_ids
.begin();
1613 it
!= requesting_process_ids
.end(); ++it
) {
1614 // Log the message to all renderers that are requesting a MediaStream or
1615 // have a MediaStream running.
1616 content::RenderProcessHostImpl
* render_process_host_impl
=
1617 static_cast<content::RenderProcessHostImpl
*>(
1618 content::RenderProcessHost::FromID(*it
));
1619 if (render_process_host_impl
)
1620 render_process_host_impl
->WebRtcLogMessage(message
);
1625 void MediaStreamManager::HandleAccessRequestResponse(
1626 const std::string
& label
,
1627 const MediaStreamDevices
& devices
,
1628 content::MediaStreamRequestResult result
) {
1629 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1630 DVLOG(1) << "HandleAccessRequestResponse("
1631 << ", {label = " << label
<< "})";
1633 DeviceRequest
* request
= FindRequest(label
);
1635 // The request has been canceled before the UI returned.
1639 if (request
->request_type
== MEDIA_DEVICE_ACCESS
) {
1640 FinalizeMediaAccessRequest(label
, request
, devices
);
1644 // Handle the case when the request was denied.
1645 if (result
!= MEDIA_DEVICE_OK
) {
1646 FinalizeRequestFailed(label
, request
, result
);
1650 // Process all newly-accepted devices for this request.
1651 bool found_audio
= false;
1652 bool found_video
= false;
1653 for (MediaStreamDevices::const_iterator device_it
= devices
.begin();
1654 device_it
!= devices
.end(); ++device_it
) {
1655 StreamDeviceInfo device_info
;
1656 device_info
.device
= *device_it
;
1658 // TODO(justinlin): Nicer way to do this?
1659 // Re-append the device's id since we lost it when posting request to UI.
1660 if (device_info
.device
.type
== content::MEDIA_TAB_VIDEO_CAPTURE
||
1661 device_info
.device
.type
== content::MEDIA_TAB_AUDIO_CAPTURE
) {
1662 device_info
.device
.id
= request
->UIRequest()->tab_capture_device_id
;
1664 // Initialize the sample_rate and channel_layout here since for audio
1665 // mirroring, we don't go through EnumerateDevices where these are usually
1667 if (device_info
.device
.type
== content::MEDIA_TAB_AUDIO_CAPTURE
) {
1668 const media::AudioParameters parameters
=
1669 audio_manager_
->GetDefaultOutputStreamParameters();
1670 int sample_rate
= parameters
.sample_rate();
1671 // If we weren't able to get the native sampling rate or the sample_rate
1672 // is outside the valid range for input devices set reasonable defaults.
1673 if (sample_rate
<= 0 || sample_rate
> 96000)
1674 sample_rate
= 44100;
1676 device_info
.device
.input
.sample_rate
= sample_rate
;
1677 device_info
.device
.input
.channel_layout
= media::CHANNEL_LAYOUT_STEREO
;
1681 if (device_info
.device
.type
== request
->audio_type()) {
1683 } else if (device_info
.device
.type
== request
->video_type()) {
1687 // If this is request for a new MediaStream, a device is only opened once
1688 // per render view. This is so that the permission to use a device can be
1689 // revoked by a single call to StopStreamDevice regardless of how many
1690 // MediaStreams it is being used in.
1691 if (request
->request_type
== MEDIA_GENERATE_STREAM
) {
1692 MediaRequestState state
;
1693 if (FindExistingRequestedDeviceInfo(*request
,
1697 request
->devices
.push_back(device_info
);
1698 request
->SetState(device_info
.device
.type
, state
);
1699 DVLOG(1) << "HandleAccessRequestResponse - device already opened "
1700 << ", {label = " << label
<< "}"
1701 << ", device_id = " << device_it
->id
<< "}";
1705 device_info
.session_id
=
1706 GetDeviceManager(device_info
.device
.type
)->Open(device_info
);
1707 TranslateDeviceIdToSourceId(request
, &device_info
.device
);
1708 request
->devices
.push_back(device_info
);
1710 request
->SetState(device_info
.device
.type
, MEDIA_REQUEST_STATE_OPENING
);
1711 DVLOG(1) << "HandleAccessRequestResponse - opening device "
1712 << ", {label = " << label
<< "}"
1713 << ", {device_id = " << device_info
.device
.id
<< "}"
1714 << ", {session_id = " << device_info
.session_id
<< "}";
1717 // Check whether we've received all stream types requested.
1718 if (!found_audio
&& IsAudioMediaType(request
->audio_type())) {
1719 request
->SetState(request
->audio_type(), MEDIA_REQUEST_STATE_ERROR
);
1720 DVLOG(1) << "Set no audio found label " << label
;
1723 if (!found_video
&& IsVideoMediaType(request
->video_type()))
1724 request
->SetState(request
->video_type(), MEDIA_REQUEST_STATE_ERROR
);
1726 if (RequestDone(*request
))
1727 HandleRequestDone(label
, request
);
1730 void MediaStreamManager::StopMediaStreamFromBrowser(const std::string
& label
) {
1731 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1733 DeviceRequest
* request
= FindRequest(label
);
1737 // Notify renderers that the devices in the stream will be stopped.
1738 if (request
->requester
) {
1739 for (StreamDeviceInfoArray::iterator device_it
= request
->devices
.begin();
1740 device_it
!= request
->devices
.end(); ++device_it
) {
1741 request
->requester
->DeviceStopped(request
->requesting_view_id
,
1747 CancelRequest(label
);
1750 void MediaStreamManager::UseFakeDevice() {
1751 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1752 video_capture_manager()->UseFakeDevice();
1753 audio_input_device_manager()->UseFakeDevice();
1756 void MediaStreamManager::UseFakeUI(scoped_ptr
<FakeMediaStreamUIProxy
> fake_ui
) {
1757 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1758 use_fake_ui_
= true;
1759 fake_ui_
= fake_ui
.Pass();
1762 void MediaStreamManager::WillDestroyCurrentMessageLoop() {
1763 DVLOG(3) << "MediaStreamManager::WillDestroyCurrentMessageLoop()";
1764 DCHECK_EQ(base::MessageLoop::current(), io_loop_
);
1765 DCHECK(requests_
.empty());
1766 if (device_task_runner_
) {
1769 video_capture_manager_
->Unregister();
1770 audio_input_device_manager_
->Unregister();
1771 device_task_runner_
= NULL
;
1774 audio_input_device_manager_
= NULL
;
1775 video_capture_manager_
= NULL
;
1778 void MediaStreamManager::NotifyDevicesChanged(
1779 MediaStreamType stream_type
,
1780 const StreamDeviceInfoArray
& devices
) {
1781 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1782 MediaObserver
* media_observer
=
1783 GetContentClient()->browser()->GetMediaObserver();
1784 if (media_observer
== NULL
)
1787 // Map the devices to MediaStreamDevices.
1788 MediaStreamDevices new_devices
;
1789 for (StreamDeviceInfoArray::const_iterator it
= devices
.begin();
1790 it
!= devices
.end(); ++it
) {
1791 new_devices
.push_back(it
->device
);
1794 if (IsAudioMediaType(stream_type
)) {
1795 MediaCaptureDevicesImpl::GetInstance()->OnAudioCaptureDevicesChanged(
1797 media_observer
->OnAudioCaptureDevicesChanged();
1798 } else if (IsVideoMediaType(stream_type
)) {
1799 MediaCaptureDevicesImpl::GetInstance()->OnVideoCaptureDevicesChanged(
1801 media_observer
->OnVideoCaptureDevicesChanged();
1807 bool MediaStreamManager::RequestDone(const DeviceRequest
& request
) const {
1808 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1810 const bool requested_audio
= IsAudioMediaType(request
.audio_type());
1811 const bool requested_video
= IsVideoMediaType(request
.video_type());
1813 const bool audio_done
=
1815 request
.state(request
.audio_type()) == MEDIA_REQUEST_STATE_DONE
||
1816 request
.state(request
.audio_type()) == MEDIA_REQUEST_STATE_ERROR
;
1820 const bool video_done
=
1822 request
.state(request
.video_type()) == MEDIA_REQUEST_STATE_DONE
||
1823 request
.state(request
.video_type()) == MEDIA_REQUEST_STATE_ERROR
;
1830 MediaStreamProvider
* MediaStreamManager::GetDeviceManager(
1831 MediaStreamType stream_type
) {
1832 if (IsVideoMediaType(stream_type
)) {
1833 return video_capture_manager();
1834 } else if (IsAudioMediaType(stream_type
)) {
1835 return audio_input_device_manager();
1841 void MediaStreamManager::OnDevicesChanged(
1842 base::SystemMonitor::DeviceType device_type
) {
1843 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1845 // NOTE: This method is only called in response to physical audio/video device
1846 // changes (from the operating system).
1848 MediaStreamType stream_type
;
1849 if (device_type
== base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE
) {
1850 stream_type
= MEDIA_DEVICE_AUDIO_CAPTURE
;
1851 } else if (device_type
== base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE
) {
1852 stream_type
= MEDIA_DEVICE_VIDEO_CAPTURE
;
1854 return; // Uninteresting device change.
1857 // Always do enumeration even though some enumeration is in progress,
1858 // because those enumeration commands could be sent before these devices
1860 ++active_enumeration_ref_count_
[stream_type
];
1861 GetDeviceManager(stream_type
)->EnumerateDevices(stream_type
);
1864 } // namespace content