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