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 9 #include "base/bind.h" 10 #include "base/command_line.h" 11 #include "base/compiler_specific.h" 12 #include "base/logging.h" 13 #include "base/rand_util.h" 14 #include "base/threading/thread.h" 15 #include "content/browser/renderer_host/media/audio_input_device_manager.h" 16 #include "content/browser/renderer_host/media/device_request_message_filter.h" 17 #include "content/browser/renderer_host/media/media_stream_requester.h" 18 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" 19 #include "content/browser/renderer_host/media/video_capture_manager.h" 20 #include "content/browser/renderer_host/media/web_contents_capture_util.h" 21 #include "content/public/browser/browser_thread.h" 22 #include "content/public/browser/content_browser_client.h" 23 #include "content/public/browser/media_observer.h" 24 #include "content/public/browser/media_request_state.h" 25 #include "content/public/common/content_switches.h" 26 #include "content/public/common/media_stream_request.h" 27 #include "media/audio/audio_manager_base.h" 28 #include "media/audio/audio_parameters.h" 29 #include "media/base/channel_layout.h" 30 #include "url/gurl.h" 31 32 #if defined(OS_WIN) 33 #include "base/win/scoped_com_initializer.h" 34 #endif 35 36 namespace content { 37 38 // Creates a random label used to identify requests. 39 static std::string RandomLabel() { 40 // An earlier PeerConnection spec, 41 // http://dev.w3.org/2011/webrtc/editor/webrtc.html, specified the 42 // MediaStream::label alphabet as containing 36 characters from 43 // range: U+0021, U+0023 to U+0027, U+002A to U+002B, U+002D to U+002E, 44 // U+0030 to U+0039, U+0041 to U+005A, U+005E to U+007E. 45 // Here we use a safe subset. 46 static const char kAlphabet[] = "0123456789" 47 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 48 49 std::string label(36, ' '); 50 for (size_t i = 0; i < label.size(); ++i) { 51 int random_char = base::RandGenerator(sizeof(kAlphabet) - 1); 52 label[i] = kAlphabet[random_char]; 53 } 54 return label; 55 } 56 57 // Helper to verify if a media stream type is part of options or not. 58 static bool Requested(const MediaStreamRequest& request, 59 MediaStreamType stream_type) { 60 return (request.audio_type == stream_type || 61 request.video_type == stream_type); 62 } 63 64 // TODO(xians): Merge DeviceRequest with MediaStreamRequest. 65 class MediaStreamManager::DeviceRequest { 66 public: 67 DeviceRequest(MediaStreamRequester* requester, 68 const MediaStreamRequest& request) 69 : requester(requester), 70 request(request), 71 state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED) { 72 } 73 74 ~DeviceRequest() {} 75 76 // Update the request state and notify observers. 77 void SetState(MediaStreamType stream_type, MediaRequestState new_state) { 78 if (stream_type == NUM_MEDIA_TYPES) { 79 for (int i = MEDIA_NO_SERVICE + 1; i < NUM_MEDIA_TYPES; ++i) { 80 const MediaStreamType stream_type = static_cast<MediaStreamType>(i); 81 state_[stream_type] = new_state; 82 } 83 } else { 84 state_[stream_type] = new_state; 85 } 86 87 if (request.video_type != MEDIA_TAB_VIDEO_CAPTURE && 88 request.audio_type != MEDIA_TAB_AUDIO_CAPTURE && 89 new_state != MEDIA_REQUEST_STATE_CLOSING) { 90 return; 91 } 92 93 MediaObserver* media_observer = 94 GetContentClient()->browser()->GetMediaObserver(); 95 if (media_observer == NULL) 96 return; 97 98 // If we appended a device_id scheme, we want to remove it when notifying 99 // observers which may be in different modules since this scheme is only 100 // used internally within the content module. 101 std::string device_id = 102 WebContentsCaptureUtil::StripWebContentsDeviceScheme( 103 request.tab_capture_device_id); 104 105 media_observer->OnMediaRequestStateChanged( 106 request.render_process_id, request.render_view_id, 107 request.page_request_id, 108 MediaStreamDevice(stream_type, device_id, device_id), new_state); 109 } 110 111 MediaRequestState state(MediaStreamType stream_type) const { 112 return state_[stream_type]; 113 } 114 115 MediaStreamRequester* const requester; // Can be NULL. 116 MediaStreamRequest request; 117 118 StreamDeviceInfoArray devices; 119 120 // Callback to the requester which audio/video devices have been selected. 121 // It can be null if the requester has no interest to know the result. 122 // Currently it is only used by |DEVICE_ACCESS| type. 123 MediaStreamManager::MediaRequestResponseCallback callback; 124 125 scoped_ptr<MediaStreamUIProxy> ui_proxy; 126 127 private: 128 std::vector<MediaRequestState> state_; 129 }; 130 131 MediaStreamManager::EnumerationCache::EnumerationCache() 132 : valid(false) { 133 } 134 135 MediaStreamManager::EnumerationCache::~EnumerationCache() { 136 } 137 138 MediaStreamManager::MediaStreamManager() 139 : audio_manager_(NULL), 140 monitoring_started_(false), 141 io_loop_(NULL), 142 use_fake_ui_(false) {} 143 144 MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager) 145 : audio_manager_(audio_manager), 146 monitoring_started_(false), 147 io_loop_(NULL), 148 use_fake_ui_(false) { 149 DCHECK(audio_manager_); 150 memset(active_enumeration_ref_count_, 0, 151 sizeof(active_enumeration_ref_count_)); 152 153 // Some unit tests create the MSM in the IO thread and assumes the 154 // initialization is done synchronously. 155 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { 156 InitializeDeviceManagersOnIOThread(); 157 } else { 158 BrowserThread::PostTask( 159 BrowserThread::IO, FROM_HERE, 160 base::Bind(&MediaStreamManager::InitializeDeviceManagersOnIOThread, 161 base::Unretained(this))); 162 } 163 } 164 165 MediaStreamManager::~MediaStreamManager() { 166 DCHECK(requests_.empty()); 167 DCHECK(!device_thread_.get()); 168 } 169 170 VideoCaptureManager* MediaStreamManager::video_capture_manager() { 171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 172 DCHECK(video_capture_manager_.get()); 173 return video_capture_manager_.get(); 174 } 175 176 AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() { 177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 178 DCHECK(audio_input_device_manager_.get()); 179 return audio_input_device_manager_.get(); 180 } 181 182 std::string MediaStreamManager::MakeMediaAccessRequest( 183 int render_process_id, 184 int render_view_id, 185 int page_request_id, 186 const StreamOptions& options, 187 const GURL& security_origin, 188 const MediaRequestResponseCallback& callback) { 189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 190 // Create a new request based on options. 191 MediaStreamRequest stream_request( 192 render_process_id, render_view_id, page_request_id, std::string(), 193 security_origin, MEDIA_DEVICE_ACCESS, std::string(), std::string(), 194 options.audio_type, options.video_type); 195 DeviceRequest* request = new DeviceRequest(NULL, stream_request); 196 const std::string& label = AddRequest(request); 197 198 request->callback = callback; 199 200 HandleRequest(label); 201 202 return label; 203 } 204 205 std::string MediaStreamManager::GenerateStream( 206 MediaStreamRequester* requester, 207 int render_process_id, 208 int render_view_id, 209 int page_request_id, 210 const StreamOptions& options, 211 const GURL& security_origin) { 212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 213 if (CommandLine::ForCurrentProcess()->HasSwitch( 214 switches::kUseFakeDeviceForMediaStream)) { 215 UseFakeDevice(); 216 } 217 if (CommandLine::ForCurrentProcess()->HasSwitch( 218 switches::kUseFakeUIForMediaStream)) { 219 UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy>()); 220 } 221 222 int target_render_process_id = render_process_id; 223 int target_render_view_id = render_view_id; 224 std::string tab_capture_device_id; 225 226 // Customize options for a WebContents based capture. 227 if (options.audio_type == MEDIA_TAB_AUDIO_CAPTURE || 228 options.video_type == MEDIA_TAB_VIDEO_CAPTURE) { 229 // TODO(justinlin): Can't plumb audio mirroring using stream type right 230 // now, so plumbing by device_id. Will revisit once it's refactored. 231 // http://crbug.com/163100 232 tab_capture_device_id = 233 WebContentsCaptureUtil::AppendWebContentsDeviceScheme( 234 !options.video_device_id.empty() ? 235 options.video_device_id : options.audio_device_id); 236 237 bool has_valid_device_id = WebContentsCaptureUtil::ExtractTabCaptureTarget( 238 tab_capture_device_id, &target_render_process_id, 239 &target_render_view_id); 240 if (!has_valid_device_id || 241 (options.audio_type != MEDIA_TAB_AUDIO_CAPTURE && 242 options.audio_type != MEDIA_NO_SERVICE) || 243 (options.video_type != MEDIA_TAB_VIDEO_CAPTURE && 244 options.video_type != MEDIA_NO_SERVICE)) { 245 LOG(ERROR) << "Invalid request."; 246 return std::string(); 247 } 248 } 249 250 std::string translated_audio_device_id; 251 std::string translated_video_device_id; 252 if (options.audio_type == MEDIA_DEVICE_AUDIO_CAPTURE) { 253 bool found_match = TranslateGUIDToRawId( 254 MEDIA_DEVICE_AUDIO_CAPTURE, security_origin, options.audio_device_id, 255 &translated_audio_device_id); 256 DCHECK(found_match || translated_audio_device_id.empty()); 257 } 258 259 if (options.video_type == MEDIA_DEVICE_VIDEO_CAPTURE) { 260 bool found_match = TranslateGUIDToRawId( 261 MEDIA_DEVICE_VIDEO_CAPTURE, security_origin, options.video_device_id, 262 &translated_video_device_id); 263 DCHECK(found_match || translated_video_device_id.empty()); 264 } 265 266 if (options.video_type == MEDIA_DESKTOP_VIDEO_CAPTURE || 267 options.audio_type == MEDIA_SYSTEM_AUDIO_CAPTURE) { 268 // For screen capture we only support two valid combinations: 269 // (1) screen video capture only, or 270 // (2) screen video capture with system audio capture. 271 if (options.video_type != MEDIA_DESKTOP_VIDEO_CAPTURE || 272 (options.audio_type != MEDIA_NO_SERVICE && 273 options.audio_type != MEDIA_SYSTEM_AUDIO_CAPTURE)) { 274 // TODO(sergeyu): Surface error message to the calling JS code. 275 LOG(ERROR) << "Invalid screen capture request."; 276 return std::string(); 277 } 278 translated_video_device_id = options.video_device_id; 279 } 280 281 // Create a new request based on options. 282 MediaStreamRequest stream_request( 283 target_render_process_id, target_render_view_id, page_request_id, 284 tab_capture_device_id, security_origin, MEDIA_GENERATE_STREAM, 285 translated_audio_device_id, translated_video_device_id, 286 options.audio_type, options.video_type); 287 DeviceRequest* request = new DeviceRequest(requester, stream_request); 288 const std::string& label = AddRequest(request); 289 HandleRequest(label); 290 return label; 291 } 292 293 void MediaStreamManager::CancelRequest(const std::string& label) { 294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 295 296 DeviceRequests::iterator it = requests_.find(label); 297 if (it != requests_.end()) { 298 if (!RequestDone(*it->second)) { 299 // TODO(xians): update the |state| to STATE_DONE to trigger a state 300 // changed notification to UI before deleting the request? 301 scoped_ptr<DeviceRequest> request(it->second); 302 RemoveRequest(it); 303 for (int i = MEDIA_NO_SERVICE + 1; i < NUM_MEDIA_TYPES; ++i) { 304 const MediaStreamType stream_type = static_cast<MediaStreamType>(i); 305 MediaStreamProvider* device_manager = GetDeviceManager(stream_type); 306 if (!device_manager) 307 continue; 308 if (request->state(stream_type) != MEDIA_REQUEST_STATE_OPENING && 309 request->state(stream_type) != MEDIA_REQUEST_STATE_DONE) { 310 continue; 311 } 312 for (StreamDeviceInfoArray::const_iterator device_it = 313 request->devices.begin(); 314 device_it != request->devices.end(); ++device_it) { 315 if (device_it->device.type == stream_type) { 316 device_manager->Close(device_it->session_id); 317 } 318 } 319 } 320 // Cancel the request if still pending at UI side. 321 request->SetState(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_CLOSING); 322 } else { 323 StopGeneratedStream(label); 324 } 325 } 326 } 327 328 void MediaStreamManager::StopGeneratedStream(const std::string& label) { 329 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 330 331 // Find the request and close all open devices for the request. 332 DeviceRequests::iterator it = requests_.find(label); 333 if (it != requests_.end()) { 334 if (it->second->request.request_type == MEDIA_ENUMERATE_DEVICES) { 335 StopEnumerateDevices(label); 336 return; 337 } 338 339 scoped_ptr<DeviceRequest> request(it->second); 340 RemoveRequest(it); 341 for (StreamDeviceInfoArray::const_iterator device_it = 342 request->devices.begin(); 343 device_it != request->devices.end(); ++device_it) { 344 GetDeviceManager(device_it->device.type)->Close(device_it->session_id); 345 } 346 if (request->request.request_type == MEDIA_GENERATE_STREAM && 347 RequestDone(*request)) { 348 // Notify observers that this device is being closed. 349 for (int i = MEDIA_NO_SERVICE + 1; i != NUM_MEDIA_TYPES; ++i) { 350 if (request->state(static_cast<MediaStreamType>(i)) != 351 MEDIA_REQUEST_STATE_NOT_REQUESTED) { 352 request->SetState(static_cast<MediaStreamType>(i), 353 MEDIA_REQUEST_STATE_CLOSING); 354 } 355 } 356 } 357 } 358 } 359 360 std::string MediaStreamManager::EnumerateDevices( 361 MediaStreamRequester* requester, 362 int render_process_id, 363 int render_view_id, 364 int page_request_id, 365 MediaStreamType type, 366 const GURL& security_origin) { 367 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 368 DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE || 369 type == MEDIA_DEVICE_VIDEO_CAPTURE); 370 371 // When the requester is NULL, the request is made by the UI to ensure MSM 372 // starts monitoring devices. 373 if (!requester) { 374 if (!monitoring_started_) 375 StartMonitoring(); 376 377 return std::string(); 378 } 379 380 // Create a new request. 381 StreamOptions options; 382 EnumerationCache* cache = NULL; 383 if (type == MEDIA_DEVICE_AUDIO_CAPTURE) { 384 options.audio_type = type; 385 cache = &audio_enumeration_cache_; 386 } else if (type == MEDIA_DEVICE_VIDEO_CAPTURE) { 387 options.video_type = type; 388 cache = &video_enumeration_cache_; 389 } else { 390 NOTREACHED(); 391 return std::string(); 392 } 393 394 MediaStreamRequest stream_request( 395 render_process_id, render_view_id, page_request_id, std::string(), 396 security_origin, MEDIA_ENUMERATE_DEVICES, std::string(), std::string(), 397 options.audio_type, options.video_type); 398 DeviceRequest* request = new DeviceRequest(requester, stream_request); 399 const std::string& label = AddRequest(request); 400 401 if (cache->valid) { 402 // Cached device list of this type exists. Just send it out. 403 request->SetState(type, MEDIA_REQUEST_STATE_REQUESTED); 404 405 // Need to post a task since the requester won't have label till 406 // this function returns. 407 BrowserThread::PostTask( 408 BrowserThread::IO, FROM_HERE, 409 base::Bind(&MediaStreamManager::SendCachedDeviceList, 410 base::Unretained(this), cache, label)); 411 } else { 412 StartEnumeration(request); 413 } 414 415 return label; 416 } 417 418 void MediaStreamManager::StopEnumerateDevices(const std::string& label) { 419 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 420 421 DeviceRequests::iterator it = requests_.find(label); 422 if (it != requests_.end()) { 423 DCHECK_EQ(it->second->request.request_type, MEDIA_ENUMERATE_DEVICES); 424 // Delete the DeviceRequest. 425 scoped_ptr<DeviceRequest> request(it->second); 426 RemoveRequest(it); 427 } 428 } 429 430 std::string MediaStreamManager::OpenDevice( 431 MediaStreamRequester* requester, 432 int render_process_id, 433 int render_view_id, 434 int page_request_id, 435 const std::string& device_id, 436 MediaStreamType type, 437 const GURL& security_origin) { 438 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 439 DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE || 440 type == MEDIA_DEVICE_VIDEO_CAPTURE); 441 442 // Create a new request. 443 StreamOptions options; 444 if (IsAudioMediaType(type)) { 445 options.audio_type = type; 446 options.audio_device_id = device_id; 447 } else if (IsVideoMediaType(type)) { 448 options.video_type = type; 449 options.video_device_id = device_id; 450 } else { 451 NOTREACHED(); 452 return std::string(); 453 } 454 455 MediaStreamRequest stream_request( 456 render_process_id, render_view_id, page_request_id, std::string(), 457 security_origin, MEDIA_OPEN_DEVICE, options.audio_device_id, 458 options.video_device_id, options.audio_type, options.video_type); 459 DeviceRequest* request = new DeviceRequest(requester, stream_request); 460 const std::string& label = AddRequest(request); 461 StartEnumeration(request); 462 463 return label; 464 } 465 466 void MediaStreamManager::SendCachedDeviceList( 467 EnumerationCache* cache, 468 const std::string& label) { 469 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 470 if (cache->valid) { 471 DeviceRequests::iterator it = requests_.find(label); 472 if (it != requests_.end()) { 473 it->second->requester->DevicesEnumerated(label, cache->devices); 474 } 475 } 476 } 477 478 void MediaStreamManager::StartMonitoring() { 479 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 480 if (!base::SystemMonitor::Get()) 481 return; 482 483 if (!monitoring_started_) { 484 monitoring_started_ = true; 485 base::SystemMonitor::Get()->AddDevicesChangedObserver(this); 486 487 // Enumerate both the audio and video devices to cache the device lists 488 // and send them to media observer. 489 ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_CAPTURE]; 490 audio_input_device_manager_->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE); 491 ++active_enumeration_ref_count_[MEDIA_DEVICE_VIDEO_CAPTURE]; 492 video_capture_manager_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); 493 } 494 } 495 496 void MediaStreamManager::StopMonitoring() { 497 DCHECK_EQ(base::MessageLoop::current(), io_loop_); 498 if (monitoring_started_) { 499 base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this); 500 monitoring_started_ = false; 501 ClearEnumerationCache(&audio_enumeration_cache_); 502 ClearEnumerationCache(&video_enumeration_cache_); 503 } 504 } 505 506 bool MediaStreamManager::TranslateGUIDToRawId(MediaStreamType stream_type, 507 const GURL& security_origin, 508 const std::string& device_guid, 509 std::string* raw_device_id) { 510 DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE || 511 stream_type == MEDIA_DEVICE_VIDEO_CAPTURE); 512 if (device_guid.empty()) 513 return false; 514 515 EnumerationCache* cache = 516 stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ? 517 &audio_enumeration_cache_ : &video_enumeration_cache_; 518 519 // If device monitoring hasn't started, the |device_guid| is not valid. 520 if (!cache->valid) 521 return false; 522 523 for (StreamDeviceInfoArray::const_iterator it = cache->devices.begin(); 524 it != cache->devices.end(); 525 ++it) { 526 if (DeviceRequestMessageFilter::DoesRawIdMatchGuid( 527 security_origin, device_guid, it->device.id)) { 528 *raw_device_id = it->device.id; 529 return true; 530 } 531 } 532 return false; 533 } 534 535 void MediaStreamManager::ClearEnumerationCache(EnumerationCache* cache) { 536 DCHECK_EQ(base::MessageLoop::current(), io_loop_); 537 cache->valid = false; 538 } 539 540 void MediaStreamManager::StartEnumeration(DeviceRequest* request) { 541 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 542 543 // Start monitoring the devices when doing the first enumeration. 544 if (!monitoring_started_ && base::SystemMonitor::Get()) { 545 StartMonitoring(); 546 } 547 548 // Start enumeration for devices of all requested device types. 549 for (int i = MEDIA_NO_SERVICE + 1; i < NUM_MEDIA_TYPES; ++i) { 550 const MediaStreamType stream_type = static_cast<MediaStreamType>(i); 551 if (Requested(request->request, stream_type)) { 552 request->SetState(stream_type, MEDIA_REQUEST_STATE_REQUESTED); 553 DCHECK_GE(active_enumeration_ref_count_[stream_type], 0); 554 if (active_enumeration_ref_count_[stream_type] == 0) { 555 ++active_enumeration_ref_count_[stream_type]; 556 GetDeviceManager(stream_type)->EnumerateDevices(stream_type); 557 } 558 } 559 } 560 } 561 562 std::string MediaStreamManager::AddRequest(DeviceRequest* request) { 563 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 564 565 // Create a label for this request and verify it is unique. 566 std::string unique_label; 567 do { 568 unique_label = RandomLabel(); 569 } while (requests_.find(unique_label) != requests_.end()); 570 571 requests_.insert(std::make_pair(unique_label, request)); 572 573 return unique_label; 574 } 575 576 void MediaStreamManager::RemoveRequest(DeviceRequests::iterator it) { 577 requests_.erase(it); 578 } 579 580 void MediaStreamManager::PostRequestToUI(const std::string& label) { 581 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 582 DeviceRequest* request = requests_[label]; 583 584 if (use_fake_ui_) { 585 if (!fake_ui_) 586 fake_ui_.reset(new FakeMediaStreamUIProxy()); 587 588 MediaStreamDevices devices; 589 if (audio_enumeration_cache_.valid) { 590 for (StreamDeviceInfoArray::const_iterator it = 591 audio_enumeration_cache_.devices.begin(); 592 it != audio_enumeration_cache_.devices.end(); ++it) { 593 devices.push_back(it->device); 594 } 595 } 596 if (video_enumeration_cache_.valid) { 597 for (StreamDeviceInfoArray::const_iterator it = 598 video_enumeration_cache_.devices.begin(); 599 it != video_enumeration_cache_.devices.end(); ++it) { 600 devices.push_back(it->device); 601 } 602 } 603 604 fake_ui_->SetAvailableDevices(devices); 605 606 request->ui_proxy = fake_ui_.Pass(); 607 } else { 608 request->ui_proxy = MediaStreamUIProxy::Create(); 609 } 610 611 request->ui_proxy->RequestAccess( 612 request->request, 613 base::Bind(&MediaStreamManager::HandleAccessRequestResponse, 614 base::Unretained(this), label)); 615 } 616 617 void MediaStreamManager::HandleRequest(const std::string& label) { 618 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 619 DeviceRequest* request = requests_[label]; 620 621 const MediaStreamType audio_type = request->request.audio_type; 622 const MediaStreamType video_type = request->request.video_type; 623 624 bool is_web_contents_capture = 625 audio_type == MEDIA_TAB_AUDIO_CAPTURE || 626 video_type == MEDIA_TAB_VIDEO_CAPTURE; 627 628 bool is_screen_capture = 629 video_type == MEDIA_DESKTOP_VIDEO_CAPTURE; 630 631 if (!is_web_contents_capture && 632 !is_screen_capture && 633 ((IsAudioMediaType(audio_type) && !audio_enumeration_cache_.valid) || 634 (IsVideoMediaType(video_type) && !video_enumeration_cache_.valid))) { 635 // Enumerate the devices if there is no valid device lists to be used. 636 StartEnumeration(request); 637 return; 638 } 639 640 // No need to do new device enumerations, post the request to UI 641 // immediately. 642 if (IsAudioMediaType(audio_type)) 643 request->SetState(audio_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); 644 if (IsVideoMediaType(video_type)) 645 request->SetState(video_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); 646 647 PostRequestToUI(label); 648 } 649 650 void MediaStreamManager::InitializeDeviceManagersOnIOThread() { 651 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 652 if (device_thread_) 653 return; 654 655 device_thread_.reset(new base::Thread("MediaStreamDeviceThread")); 656 #if defined(OS_WIN) 657 device_thread_->init_com_with_mta(true); 658 #endif 659 CHECK(device_thread_->Start()); 660 661 audio_input_device_manager_ = new AudioInputDeviceManager(audio_manager_); 662 audio_input_device_manager_->Register( 663 this, device_thread_->message_loop_proxy().get()); 664 665 video_capture_manager_ = new VideoCaptureManager(); 666 video_capture_manager_->Register(this, 667 device_thread_->message_loop_proxy().get()); 668 669 // We want to be notified of IO message loop destruction to delete the thread 670 // and the device managers. 671 io_loop_ = base::MessageLoop::current(); 672 io_loop_->AddDestructionObserver(this); 673 } 674 675 void MediaStreamManager::Opened(MediaStreamType stream_type, 676 int capture_session_id) { 677 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 678 679 // Find the request containing this device and mark it as used. 680 DeviceRequest* request = NULL; 681 StreamDeviceInfoArray* devices = NULL; 682 std::string label; 683 for (DeviceRequests::iterator request_it = requests_.begin(); 684 request_it != requests_.end() && request == NULL; ++request_it) { 685 devices = &(request_it->second->devices); 686 for (StreamDeviceInfoArray::iterator device_it = devices->begin(); 687 device_it != devices->end(); ++device_it) { 688 if (device_it->device.type == stream_type && 689 device_it->session_id == capture_session_id) { 690 // We've found the request. 691 device_it->in_use = true; 692 label = request_it->first; 693 request = request_it->second; 694 break; 695 } 696 } 697 } 698 if (request == NULL) { 699 // The request doesn't exist. 700 return; 701 } 702 703 DCHECK_NE(request->state(stream_type), MEDIA_REQUEST_STATE_REQUESTED); 704 705 // Check if all devices for this stream type are opened. Update the state if 706 // they are. 707 for (StreamDeviceInfoArray::iterator device_it = devices->begin(); 708 device_it != devices->end(); ++device_it) { 709 if (device_it->device.type != stream_type) { 710 continue; 711 } 712 if (device_it->in_use == false) { 713 // Wait for more devices to be opened before we're done. 714 return; 715 } 716 } 717 718 request->SetState(stream_type, MEDIA_REQUEST_STATE_DONE); 719 720 if (!RequestDone(*request)) { 721 // This stream_type is done, but not the other type. 722 return; 723 } 724 725 switch (request->request.request_type) { 726 case MEDIA_OPEN_DEVICE: 727 request->requester->DeviceOpened(label, devices->front()); 728 break; 729 case MEDIA_GENERATE_STREAM: { 730 // Partition the array of devices into audio vs video. 731 StreamDeviceInfoArray audio_devices, video_devices; 732 for (StreamDeviceInfoArray::iterator device_it = devices->begin(); 733 device_it != devices->end(); ++device_it) { 734 if (IsAudioMediaType(device_it->device.type)) { 735 // Store the native audio parameters in the device struct. 736 // TODO(xians): Handle the tab capture sample rate/channel layout 737 // in AudioInputDeviceManager::Open(). 738 if (device_it->device.type != content::MEDIA_TAB_AUDIO_CAPTURE) { 739 const StreamDeviceInfo* info = 740 audio_input_device_manager_->GetOpenedDeviceInfoById( 741 device_it->session_id); 742 DCHECK_EQ(info->device.id, device_it->device.id); 743 device_it->device.sample_rate = info->device.sample_rate; 744 device_it->device.channel_layout = info->device.channel_layout; 745 } 746 audio_devices.push_back(*device_it); 747 } else if (IsVideoMediaType(device_it->device.type)) { 748 video_devices.push_back(*device_it); 749 } else { 750 NOTREACHED(); 751 } 752 } 753 754 request->requester->StreamGenerated(label, audio_devices, video_devices); 755 request->ui_proxy->OnStarted( 756 base::Bind(&MediaStreamManager::StopStreamFromUI, 757 base::Unretained(this), label)); 758 break; 759 } 760 default: 761 NOTREACHED(); 762 break; 763 } 764 } 765 766 void MediaStreamManager::Closed(MediaStreamType stream_type, 767 int capture_session_id) { 768 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 769 } 770 771 void MediaStreamManager::DevicesEnumerated( 772 MediaStreamType stream_type, const StreamDeviceInfoArray& devices) { 773 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 774 775 // Only cache the device list when the device list has been changed. 776 bool need_update_clients = false; 777 EnumerationCache* cache = 778 stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ? 779 &audio_enumeration_cache_ : &video_enumeration_cache_; 780 if (!cache->valid || 781 devices.size() != cache->devices.size() || 782 !std::equal(devices.begin(), devices.end(), cache->devices.begin(), 783 StreamDeviceInfo::IsEqual)) { 784 cache->valid = true; 785 cache->devices = devices; 786 need_update_clients = true; 787 } 788 789 if (need_update_clients && monitoring_started_) 790 NotifyDevicesChanged(stream_type, devices); 791 792 // Publish the result for all requests waiting for device list(s). 793 // Find the requests waiting for this device list, store their labels and 794 // release the iterator before calling device settings. We might get a call 795 // back from device_settings that will need to iterate through devices. 796 std::list<std::string> label_list; 797 for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end(); 798 ++it) { 799 if (it->second->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED && 800 Requested(it->second->request, stream_type)) { 801 if (it->second->request.request_type != MEDIA_ENUMERATE_DEVICES) 802 it->second->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); 803 label_list.push_back(it->first); 804 } 805 } 806 for (std::list<std::string>::iterator it = label_list.begin(); 807 it != label_list.end(); ++it) { 808 DeviceRequest* request = requests_[*it]; 809 switch (request->request.request_type) { 810 case MEDIA_ENUMERATE_DEVICES: 811 if (need_update_clients && request->requester) 812 request->requester->DevicesEnumerated(*it, devices); 813 break; 814 default: 815 if (request->state(request->request.audio_type) == 816 MEDIA_REQUEST_STATE_REQUESTED || 817 request->state(request->request.video_type) == 818 MEDIA_REQUEST_STATE_REQUESTED) { 819 // We are doing enumeration for other type of media, wait until it is 820 // all done before posting the request to UI because UI needs 821 // the device lists to handle the request. 822 break; 823 } 824 825 // Post the request to UI for permission approval. 826 PostRequestToUI(*it); 827 break; 828 } 829 } 830 label_list.clear(); 831 --active_enumeration_ref_count_[stream_type]; 832 DCHECK_GE(active_enumeration_ref_count_[stream_type], 0); 833 } 834 835 void MediaStreamManager::Error(MediaStreamType stream_type, 836 int capture_session_id, 837 MediaStreamProviderError error) { 838 // Find the device for the error call. 839 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 840 841 for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end(); 842 ++it) { 843 StreamDeviceInfoArray& devices = it->second->devices; 844 845 // TODO(miu): BUG. It's possible for the audio (or video) device array in 846 // the "requester" to become out-of-sync with the order of devices we have 847 // here. See http://crbug.com/147650 848 int audio_device_idx = -1; 849 int video_device_idx = -1; 850 for (StreamDeviceInfoArray::iterator device_it = devices.begin(); 851 device_it != devices.end(); ++device_it) { 852 if (IsAudioMediaType(device_it->device.type)) { 853 ++audio_device_idx; 854 } else if (IsVideoMediaType(device_it->device.type)) { 855 ++video_device_idx; 856 } else { 857 NOTREACHED(); 858 continue; 859 } 860 if (device_it->device.type != stream_type || 861 device_it->session_id != capture_session_id) { 862 continue; 863 } 864 // We've found the failing device. Find the error case: 865 // An error should only be reported to the MediaStreamManager if 866 // the request has not been fulfilled yet. 867 DCHECK(it->second->state(stream_type) != MEDIA_REQUEST_STATE_DONE); 868 if (it->second->state(stream_type) != MEDIA_REQUEST_STATE_DONE) { 869 // Request is not done, devices are not opened in this case. 870 if (devices.size() <= 1) { 871 scoped_ptr<DeviceRequest> request(it->second); 872 // 1. Device not opened and no other devices for this request -> 873 // signal stream error and remove the request. 874 if (request->requester) 875 request->requester->StreamGenerationFailed(it->first); 876 877 RemoveRequest(it); 878 } else { 879 // 2. Not opened but other devices exists for this request -> remove 880 // device from list, but don't signal an error. 881 devices.erase(device_it); // NOTE: This invalidates device_it! 882 } 883 } 884 return; 885 } 886 } 887 } 888 889 void MediaStreamManager::HandleAccessRequestResponse( 890 const std::string& label, 891 const MediaStreamDevices& devices) { 892 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 893 894 DeviceRequests::iterator request_it = requests_.find(label); 895 if (request_it == requests_.end()) { 896 return; 897 } 898 899 // Handle the case when the request was denied. 900 if (devices.empty()) { 901 // Notify the users about the request result. 902 scoped_ptr<DeviceRequest> request(request_it->second); 903 if (request->requester) 904 request->requester->StreamGenerationFailed(label); 905 906 if (request->request.request_type == MEDIA_DEVICE_ACCESS && 907 !request->callback.is_null()) { 908 request->callback.Run(MediaStreamDevices(), request->ui_proxy.Pass()); 909 } 910 911 RemoveRequest(request_it); 912 return; 913 } 914 915 if (request_it->second->request.request_type == MEDIA_DEVICE_ACCESS) { 916 scoped_ptr<DeviceRequest> request(request_it->second); 917 if (!request->callback.is_null()) 918 request->callback.Run(devices, request->ui_proxy.Pass()); 919 920 // Delete the request since it is done. 921 RemoveRequest(request_it); 922 return; 923 } 924 925 // Process all newly-accepted devices for this request. 926 DeviceRequest* request = request_it->second; 927 bool found_audio = false; 928 bool found_video = false; 929 for (MediaStreamDevices::const_iterator device_it = devices.begin(); 930 device_it != devices.end(); ++device_it) { 931 StreamDeviceInfo device_info; 932 device_info.device = *device_it; 933 934 // TODO(justinlin): Nicer way to do this? 935 // Re-append the device's id since we lost it when posting request to UI. 936 if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE || 937 device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) { 938 device_info.device.id = request->request.tab_capture_device_id; 939 940 // Initialize the sample_rate and channel_layout here since for audio 941 // mirroring, we don't go through EnumerateDevices where these are usually 942 // initialized. 943 if (device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) { 944 const media::AudioParameters parameters = 945 audio_manager_->GetDefaultOutputStreamParameters(); 946 int sample_rate = parameters.sample_rate(); 947 // If we weren't able to get the native sampling rate or the sample_rate 948 // is outside the valid range for input devices set reasonable defaults. 949 if (sample_rate <= 0 || sample_rate > 96000) 950 sample_rate = 44100; 951 952 device_info.device.sample_rate = sample_rate; 953 device_info.device.channel_layout = media::CHANNEL_LAYOUT_STEREO; 954 } 955 } 956 957 // Set in_use to false to be able to track if this device has been 958 // opened. in_use might be true if the device type can be used in more 959 // than one session. 960 device_info.in_use = false; 961 962 device_info.session_id = 963 GetDeviceManager(device_info.device.type)->Open(device_info); 964 request->SetState(device_info.device.type, MEDIA_REQUEST_STATE_OPENING); 965 request->devices.push_back(device_info); 966 967 if (device_info.device.type == request->request.audio_type) { 968 found_audio = true; 969 } else if (device_info.device.type == request->request.video_type) { 970 found_video = true; 971 } 972 } 973 974 // Check whether we've received all stream types requested. 975 if (!found_audio && IsAudioMediaType(request->request.audio_type)) 976 request->SetState(request->request.audio_type, MEDIA_REQUEST_STATE_ERROR); 977 978 if (!found_video && IsVideoMediaType(request->request.video_type)) 979 request->SetState(request->request.video_type, MEDIA_REQUEST_STATE_ERROR); 980 } 981 982 void MediaStreamManager::StopStreamFromUI(const std::string& label) { 983 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 984 985 DeviceRequests::iterator it = requests_.find(label); 986 if (it == requests_.end()) 987 return; 988 989 // Notify renderers that the stream has been stopped. 990 if (it->second->requester) 991 it->second->requester->StopGeneratedStream(label); 992 993 StopGeneratedStream(label); 994 } 995 996 void MediaStreamManager::UseFakeDevice() { 997 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 998 video_capture_manager()->UseFakeDevice(); 999 audio_input_device_manager()->UseFakeDevice(); 1000 } 1001 1002 void MediaStreamManager::UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy> fake_ui) { 1003 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1004 use_fake_ui_ = true; 1005 fake_ui_ = fake_ui.Pass(); 1006 } 1007 1008 void MediaStreamManager::WillDestroyCurrentMessageLoop() { 1009 DCHECK_EQ(base::MessageLoop::current(), io_loop_); 1010 DCHECK(requests_.empty()); 1011 if (device_thread_) { 1012 StopMonitoring(); 1013 1014 video_capture_manager_->Unregister(); 1015 audio_input_device_manager_->Unregister(); 1016 device_thread_.reset(); 1017 } 1018 1019 audio_input_device_manager_ = NULL; 1020 video_capture_manager_ = NULL; 1021 } 1022 1023 void MediaStreamManager::NotifyDevicesChanged( 1024 MediaStreamType stream_type, 1025 const StreamDeviceInfoArray& devices) { 1026 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1027 MediaObserver* media_observer = 1028 GetContentClient()->browser()->GetMediaObserver(); 1029 if (media_observer == NULL) 1030 return; 1031 1032 // Map the devices to MediaStreamDevices. 1033 MediaStreamDevices new_devices; 1034 for (StreamDeviceInfoArray::const_iterator it = devices.begin(); 1035 it != devices.end(); ++it) { 1036 new_devices.push_back(it->device); 1037 } 1038 1039 if (IsAudioMediaType(stream_type)) { 1040 media_observer->OnAudioCaptureDevicesChanged(new_devices); 1041 } else if (IsVideoMediaType(stream_type)) { 1042 media_observer->OnVideoCaptureDevicesChanged(new_devices); 1043 } else { 1044 NOTREACHED(); 1045 } 1046 } 1047 1048 bool MediaStreamManager::RequestDone(const DeviceRequest& request) const { 1049 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1050 1051 const bool requested_audio = IsAudioMediaType(request.request.audio_type); 1052 const bool requested_video = IsVideoMediaType(request.request.video_type); 1053 1054 const bool audio_done = 1055 !requested_audio || 1056 request.state(request.request.audio_type) == 1057 MEDIA_REQUEST_STATE_DONE || 1058 request.state(request.request.audio_type) == 1059 MEDIA_REQUEST_STATE_ERROR; 1060 if (!audio_done) 1061 return false; 1062 1063 const bool video_done = 1064 !requested_video || 1065 request.state(request.request.video_type) == 1066 MEDIA_REQUEST_STATE_DONE || 1067 request.state(request.request.video_type) == 1068 MEDIA_REQUEST_STATE_ERROR; 1069 if (!video_done) 1070 return false; 1071 1072 for (StreamDeviceInfoArray::const_iterator it = request.devices.begin(); 1073 it != request.devices.end(); ++it) { 1074 if (it->in_use == false) 1075 return false; 1076 } 1077 1078 return true; 1079 } 1080 1081 MediaStreamProvider* MediaStreamManager::GetDeviceManager( 1082 MediaStreamType stream_type) { 1083 if (IsVideoMediaType(stream_type)) { 1084 return video_capture_manager(); 1085 } else if (IsAudioMediaType(stream_type)) { 1086 return audio_input_device_manager(); 1087 } 1088 NOTREACHED(); 1089 return NULL; 1090 } 1091 1092 void MediaStreamManager::OnDevicesChanged( 1093 base::SystemMonitor::DeviceType device_type) { 1094 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1095 1096 // NOTE: This method is only called in response to physical audio/video device 1097 // changes (from the operating system). 1098 1099 MediaStreamType stream_type; 1100 if (device_type == base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE) { 1101 stream_type = MEDIA_DEVICE_AUDIO_CAPTURE; 1102 } else if (device_type == base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE) { 1103 stream_type = MEDIA_DEVICE_VIDEO_CAPTURE; 1104 } else { 1105 return; // Uninteresting device change. 1106 } 1107 1108 // Always do enumeration even though some enumeration is in progress, 1109 // because those enumeration commands could be sent before these devices 1110 // change. 1111 ++active_enumeration_ref_count_[stream_type]; 1112 GetDeviceManager(stream_type)->EnumerateDevices(stream_type); 1113 } 1114 1115 } // namespace content 1116