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