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