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/rand_util.h" 15 #include "base/run_loop.h" 16 #include "base/threading/thread.h" 17 #include "content/browser/renderer_host/media/audio_input_device_manager.h" 18 #include "content/browser/renderer_host/media/device_request_message_filter.h" 19 #include "content/browser/renderer_host/media/media_stream_requester.h" 20 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" 21 #include "content/browser/renderer_host/media/video_capture_manager.h" 22 #include "content/browser/renderer_host/media/web_contents_capture_util.h" 23 #include "content/public/browser/browser_thread.h" 24 #include "content/public/browser/content_browser_client.h" 25 #include "content/public/browser/media_device_id.h" 26 #include "content/public/browser/media_observer.h" 27 #include "content/public/browser/media_request_state.h" 28 #include "content/public/common/content_switches.h" 29 #include "content/public/common/media_stream_request.h" 30 #include "media/audio/audio_manager_base.h" 31 #include "media/audio/audio_parameters.h" 32 #include "media/base/channel_layout.h" 33 #include "url/gurl.h" 34 35 #if defined(OS_WIN) 36 #include "base/win/scoped_com_initializer.h" 37 #endif 38 39 namespace content { 40 41 namespace { 42 // Creates a random label used to identify requests. 43 std::string RandomLabel() { 44 // An earlier PeerConnection spec, 45 // http://dev.w3.org/2011/webrtc/editor/webrtc.html, specified the 46 // MediaStream::label alphabet as containing 36 characters from 47 // range: U+0021, U+0023 to U+0027, U+002A to U+002B, U+002D to U+002E, 48 // U+0030 to U+0039, U+0041 to U+005A, U+005E to U+007E. 49 // Here we use a safe subset. 50 static const char kAlphabet[] = "0123456789" 51 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 52 53 std::string label(36, ' '); 54 for (size_t i = 0; i < label.size(); ++i) { 55 int random_char = base::RandGenerator(sizeof(kAlphabet) - 1); 56 label[i] = kAlphabet[random_char]; 57 } 58 return label; 59 } 60 61 void ParseStreamType(const StreamOptions& options, 62 MediaStreamType* audio_type, 63 MediaStreamType* video_type) { 64 *audio_type = MEDIA_NO_SERVICE; 65 *video_type = MEDIA_NO_SERVICE; 66 if (options.audio_requested) { 67 std::string audio_stream_source; 68 bool mandatory = false; 69 if (options.GetFirstAudioConstraintByName(kMediaStreamSource, 70 &audio_stream_source, 71 &mandatory)) { 72 DCHECK(mandatory); 73 // This is tab or screen capture. 74 if (audio_stream_source == kMediaStreamSourceTab) { 75 *audio_type = content::MEDIA_TAB_AUDIO_CAPTURE; 76 } else if (audio_stream_source == kMediaStreamSourceSystem) { 77 *audio_type = content::MEDIA_LOOPBACK_AUDIO_CAPTURE; 78 } 79 } else { 80 // This is normal audio device capture. 81 *audio_type = content::MEDIA_DEVICE_AUDIO_CAPTURE; 82 } 83 } 84 if (options.video_requested) { 85 std::string video_stream_source; 86 bool mandatory = false; 87 if (options.GetFirstVideoConstraintByName(kMediaStreamSource, 88 &video_stream_source, 89 &mandatory)) { 90 DCHECK(mandatory); 91 // This is tab or screen capture. 92 if (video_stream_source == kMediaStreamSourceTab) { 93 *video_type = content::MEDIA_TAB_VIDEO_CAPTURE; 94 } else if (video_stream_source == kMediaStreamSourceScreen) { 95 *video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE; 96 } else if (video_stream_source == kMediaStreamSourceDesktop) { 97 *video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE; 98 } 99 } else { 100 // This is normal video device capture. 101 *video_type = content::MEDIA_DEVICE_VIDEO_CAPTURE; 102 } 103 } 104 } 105 106 // Needed for MediaStreamManager::GenerateStream below. 107 std::string ReturnEmptySalt() { 108 return std::string(); 109 } 110 111 } // namespace 112 113 114 // MediaStreamManager::DeviceRequest represents a request to either enumerate 115 // available devices or open one or more devices. 116 // TODO(perkj): MediaStreamManager still needs refactoring. I propose we create 117 // several subclasses of DeviceRequest and move some of the responsibility of 118 // the MediaStreamManager to the subclasses to get rid of the way too many if 119 // statements in MediaStreamManager. 120 class MediaStreamManager::DeviceRequest { 121 public: 122 DeviceRequest(MediaStreamRequester* requester, 123 int requesting_process_id, 124 int requesting_view_id, 125 int page_request_id, 126 const GURL& security_origin, 127 MediaStreamRequestType request_type, 128 const StreamOptions& options, 129 const ResourceContext::SaltCallback& salt_callback) 130 : requester(requester), 131 requesting_process_id(requesting_process_id), 132 requesting_view_id(requesting_view_id), 133 page_request_id(page_request_id), 134 security_origin(security_origin), 135 request_type(request_type), 136 options(options), 137 salt_callback(salt_callback), 138 state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED), 139 audio_type_(MEDIA_NO_SERVICE), 140 video_type_(MEDIA_NO_SERVICE) { 141 } 142 143 ~DeviceRequest() {} 144 145 void SetAudioType(MediaStreamType audio_type) { 146 DCHECK(IsAudioMediaType(audio_type) || audio_type == MEDIA_NO_SERVICE); 147 audio_type_ = audio_type; 148 } 149 150 MediaStreamType audio_type() const { return audio_type_; } 151 152 void SetVideoType(MediaStreamType video_type) { 153 DCHECK(IsVideoMediaType(video_type) || video_type == MEDIA_NO_SERVICE); 154 video_type_ = video_type; 155 } 156 157 MediaStreamType video_type() const { return video_type_; } 158 159 // Creates a MediaStreamRequest object that is used by this request when UI 160 // is asked for permission and device selection. 161 void CreateUIRequest(const std::string& requested_audio_device_id, 162 const std::string& requested_video_device_id) { 163 DCHECK(!ui_request_); 164 ui_request_.reset(new MediaStreamRequest(requesting_process_id, 165 requesting_view_id, 166 page_request_id, 167 security_origin, 168 request_type, 169 requested_audio_device_id, 170 requested_video_device_id, 171 audio_type_, 172 video_type_)); 173 } 174 175 // Creates a tab capture specific MediaStreamRequest object that is used by 176 // this request when UI is asked for permission and device selection. 177 void CreateTabCatureUIRequest(int target_render_process_id, 178 int target_render_view_id, 179 const std::string& tab_capture_id) { 180 DCHECK(!ui_request_); 181 ui_request_.reset(new MediaStreamRequest(target_render_process_id, 182 target_render_view_id, 183 page_request_id, 184 security_origin, 185 request_type, 186 "", 187 "", 188 audio_type_, 189 video_type_)); 190 ui_request_->tab_capture_device_id = tab_capture_id; 191 } 192 193 const MediaStreamRequest* UIRequest() const { return ui_request_.get(); } 194 195 // Update the request state and notify observers. 196 void SetState(MediaStreamType stream_type, MediaRequestState new_state) { 197 if (stream_type == NUM_MEDIA_TYPES) { 198 for (int i = MEDIA_NO_SERVICE + 1; i < NUM_MEDIA_TYPES; ++i) { 199 const MediaStreamType stream_type = static_cast<MediaStreamType>(i); 200 state_[stream_type] = new_state; 201 } 202 } else { 203 state_[stream_type] = new_state; 204 } 205 206 MediaObserver* media_observer = 207 GetContentClient()->browser()->GetMediaObserver(); 208 if (!media_observer) 209 return; 210 211 // If |ui_request_| doesn't exist, it means that the request has not yet 212 // been setup fully and there are no valid observers. 213 if (!ui_request_) 214 return; 215 216 // If we appended a device_id scheme, we want to remove it when notifying 217 // observers which may be in different modules since this scheme is only 218 // used internally within the content module. 219 std::string device_id = 220 WebContentsCaptureUtil::StripWebContentsDeviceScheme( 221 ui_request_->tab_capture_device_id); 222 223 media_observer->OnMediaRequestStateChanged( 224 ui_request_->render_process_id, ui_request_->render_view_id, 225 ui_request_->page_request_id, 226 MediaStreamDevice(stream_type, device_id, device_id), new_state); 227 } 228 229 MediaRequestState state(MediaStreamType stream_type) const { 230 return state_[stream_type]; 231 } 232 233 MediaStreamRequester* const requester; // Can be NULL. 234 235 236 // The render process id that requested this stream to be generated and that 237 // will receive a handle to the MediaStream. This may be different from 238 // MediaStreamRequest::render_process_id which in the tab capture case 239 // specifies the target renderer from which audio and video is captured. 240 const int requesting_process_id; 241 242 // The render view id that requested this stream to be generated and that 243 // will receive a handle to the MediaStream. This may be different from 244 // MediaStreamRequest::render_view_id which in the tab capture case 245 // specifies the target renderer from which audio and video is captured. 246 const int requesting_view_id; 247 248 // An ID the render view provided to identify this request. 249 const int page_request_id; 250 251 const GURL security_origin; 252 253 const MediaStreamRequestType request_type; 254 255 const StreamOptions options; 256 257 ResourceContext::SaltCallback salt_callback; 258 259 StreamDeviceInfoArray devices; 260 261 // Callback to the requester which audio/video devices have been selected. 262 // It can be null if the requester has no interest to know the result. 263 // Currently it is only used by |DEVICE_ACCESS| type. 264 MediaStreamManager::MediaRequestResponseCallback callback; 265 266 scoped_ptr<MediaStreamUIProxy> ui_proxy; 267 268 private: 269 std::vector<MediaRequestState> state_; 270 scoped_ptr<MediaStreamRequest> ui_request_; 271 MediaStreamType audio_type_; 272 MediaStreamType video_type_; 273 }; 274 275 MediaStreamManager::EnumerationCache::EnumerationCache() 276 : valid(false) { 277 } 278 279 MediaStreamManager::EnumerationCache::~EnumerationCache() { 280 } 281 282 MediaStreamManager::MediaStreamManager() 283 : audio_manager_(NULL), 284 monitoring_started_(false), 285 io_loop_(NULL), 286 use_fake_ui_(false) {} 287 288 MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager) 289 : audio_manager_(audio_manager), 290 monitoring_started_(false), 291 io_loop_(NULL), 292 use_fake_ui_(false) { 293 DCHECK(audio_manager_); 294 memset(active_enumeration_ref_count_, 0, 295 sizeof(active_enumeration_ref_count_)); 296 297 // Some unit tests create the MSM in the IO thread and assumes the 298 // initialization is done synchronously. 299 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { 300 InitializeDeviceManagersOnIOThread(); 301 } else { 302 BrowserThread::PostTask( 303 BrowserThread::IO, FROM_HERE, 304 base::Bind(&MediaStreamManager::InitializeDeviceManagersOnIOThread, 305 base::Unretained(this))); 306 } 307 } 308 309 MediaStreamManager::~MediaStreamManager() { 310 DVLOG(1) << "~MediaStreamManager"; 311 DCHECK(requests_.empty()); 312 DCHECK(!device_thread_.get()); 313 } 314 315 VideoCaptureManager* MediaStreamManager::video_capture_manager() { 316 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 317 DCHECK(video_capture_manager_.get()); 318 return video_capture_manager_.get(); 319 } 320 321 AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() { 322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 323 DCHECK(audio_input_device_manager_.get()); 324 return audio_input_device_manager_.get(); 325 } 326 327 std::string MediaStreamManager::MakeMediaAccessRequest( 328 int render_process_id, 329 int render_view_id, 330 int page_request_id, 331 const StreamOptions& options, 332 const GURL& security_origin, 333 const MediaRequestResponseCallback& callback) { 334 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 335 336 // TODO(perkj): The argument list with NULL parameters to DeviceRequest 337 // suggests that this is the wrong design. Can this be refactored? 338 DeviceRequest* request = new DeviceRequest(NULL, 339 render_process_id, 340 render_view_id, 341 page_request_id, 342 security_origin, 343 MEDIA_DEVICE_ACCESS, 344 options, 345 base::Bind(&ReturnEmptySalt)); 346 347 const std::string& label = AddRequest(request); 348 349 request->callback = callback; 350 // Post a task and handle the request asynchronously. The reason is that the 351 // requester won't have a label for the request until this function returns 352 // and thus can not handle a response. Using base::Unretained is safe since 353 // MediaStreamManager is deleted on the UI thread, after the IO thread has 354 // been stopped. 355 BrowserThread::PostTask( 356 BrowserThread::IO, FROM_HERE, 357 base::Bind(&MediaStreamManager::SetupRequest, 358 base::Unretained(this), label)); 359 return label; 360 } 361 362 void MediaStreamManager::GenerateStream(MediaStreamRequester* requester, 363 int render_process_id, 364 int render_view_id, 365 const ResourceContext::SaltCallback& sc, 366 int page_request_id, 367 const StreamOptions& options, 368 const GURL& security_origin) { 369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 370 DVLOG(1) << "GenerateStream()"; 371 if (CommandLine::ForCurrentProcess()->HasSwitch( 372 switches::kUseFakeUIForMediaStream)) { 373 UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy>()); 374 } 375 376 DeviceRequest* request = new DeviceRequest(requester, 377 render_process_id, 378 render_view_id, 379 page_request_id, 380 security_origin, 381 MEDIA_GENERATE_STREAM, 382 options, 383 sc); 384 385 const std::string& label = AddRequest(request); 386 387 // Post a task and handle the request asynchronously. The reason is that the 388 // requester won't have a label for the request until this function returns 389 // and thus can not handle a response. Using base::Unretained is safe since 390 // MediaStreamManager is deleted on the UI thread, after the IO thread has 391 // been stopped. 392 BrowserThread::PostTask( 393 BrowserThread::IO, FROM_HERE, 394 base::Bind(&MediaStreamManager::SetupRequest, 395 base::Unretained(this), label)); 396 } 397 398 void MediaStreamManager::CancelRequest(int render_process_id, 399 int render_view_id, 400 int page_request_id) { 401 for (DeviceRequests::const_iterator request_it = requests_.begin(); 402 request_it != requests_.end(); ++request_it) { 403 const DeviceRequest* request = request_it->second; 404 if (request->requesting_process_id == render_process_id && 405 request->requesting_view_id == render_view_id && 406 request->page_request_id == page_request_id) { 407 CancelRequest(request_it->first); 408 return; 409 } 410 } 411 NOTREACHED(); 412 } 413 414 void MediaStreamManager::CancelRequest(const std::string& label) { 415 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 416 DVLOG(1) << "CancelRequest({label = " << label << "})"; 417 DeviceRequest* request = FindRequest(label); 418 if (!request) { 419 // The request does not exist. 420 LOG(ERROR) << "The request with label = " << label << " does not exist."; 421 return; 422 } 423 if (request->request_type == MEDIA_ENUMERATE_DEVICES) { 424 DeleteRequest(label); 425 return; 426 } 427 428 // This is a request for opening one or more devices. 429 for (StreamDeviceInfoArray::iterator device_it = request->devices.begin(); 430 device_it != request->devices.end(); ++device_it) { 431 MediaRequestState state = request->state(device_it->device.type); 432 // If we have not yet requested the device to be opened - just ignore it. 433 if (state != MEDIA_REQUEST_STATE_OPENING && 434 state != MEDIA_REQUEST_STATE_DONE) { 435 continue; 436 } 437 // Stop the opening/opened devices of the requests. 438 CloseDevice(device_it->device.type, device_it->session_id); 439 } 440 441 // Cancel the request if still pending at UI side. 442 request->SetState(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_CLOSING); 443 DeleteRequest(label); 444 } 445 446 void MediaStreamManager::CancelAllRequests(int render_process_id) { 447 DeviceRequests::iterator request_it = requests_.begin(); 448 while (request_it != requests_.end()) { 449 if (request_it->second->requesting_process_id != render_process_id) { 450 ++request_it; 451 continue; 452 } 453 454 std::string label = request_it->first; 455 ++request_it; 456 CancelRequest(label); 457 } 458 } 459 460 void MediaStreamManager::StopStreamDevice(int render_process_id, 461 int render_view_id, 462 const std::string& device_id) { 463 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 464 DVLOG(1) << "StopStreamDevice({render_view_id = " << render_view_id << "} " 465 << ", {device_id = " << device_id << "})"; 466 // Find the first request for this |render_process_id| and |render_view_id| 467 // of type MEDIA_GENERATE_STREAM that has requested to use |device_id| and 468 // stop it. 469 for (DeviceRequests::iterator request_it = requests_.begin(); 470 request_it != requests_.end(); ++request_it) { 471 DeviceRequest* request = request_it->second; 472 if (request->requesting_process_id != render_process_id || 473 request->requesting_view_id != render_view_id || 474 request->request_type != MEDIA_GENERATE_STREAM) { 475 continue; 476 } 477 478 StreamDeviceInfoArray& devices = request->devices; 479 for (StreamDeviceInfoArray::iterator device_it = devices.begin(); 480 device_it != devices.end(); ++device_it) { 481 if (device_it->device.id == device_id) { 482 StopDevice(device_it->device.type, device_it->session_id); 483 return; 484 } 485 } 486 } 487 } 488 489 void MediaStreamManager::StopDevice(MediaStreamType type, int session_id) { 490 DVLOG(1) << "StopDevice" 491 << "{type = " << type << "}" 492 << "{session_id = " << session_id << "}"; 493 DeviceRequests::iterator request_it = requests_.begin(); 494 while (request_it != requests_.end()) { 495 DeviceRequest* request = request_it->second; 496 StreamDeviceInfoArray* devices = &request->devices; 497 StreamDeviceInfoArray::iterator device_it = devices->begin(); 498 while (device_it != devices->end()) { 499 if (device_it->device.type != type || 500 device_it->session_id != session_id) { 501 ++device_it; 502 continue; 503 } 504 if (request->state(type) == MEDIA_REQUEST_STATE_DONE) 505 CloseDevice(type, session_id); 506 device_it = devices->erase(device_it); 507 } 508 // If this request doesn't have any active devices, remove the request. 509 if (devices->empty()) { 510 std::string label = request_it->first; 511 ++request_it; 512 DeleteRequest(label); 513 } else { 514 ++request_it; 515 } 516 } 517 } 518 519 void MediaStreamManager::CloseDevice(MediaStreamType type, int session_id) { 520 DVLOG(1) << "CloseDevice(" 521 << "{type = " << type << "} " 522 << "{session_id = " << session_id << "})"; 523 GetDeviceManager(type)->Close(session_id); 524 525 for (DeviceRequests::iterator request_it = requests_.begin(); 526 request_it != requests_.end() ; ++request_it) { 527 StreamDeviceInfoArray* devices = &request_it->second->devices; 528 for (StreamDeviceInfoArray::iterator device_it = devices->begin(); 529 device_it != devices->end(); ++device_it) { 530 if (device_it->session_id == session_id && 531 device_it->device.type == type) { 532 // Notify observers that this device is being closed. 533 // Note that only one device per type can be opened. 534 request_it->second->SetState(type, MEDIA_REQUEST_STATE_CLOSING); 535 } 536 } 537 } 538 } 539 540 std::string MediaStreamManager::EnumerateDevices( 541 MediaStreamRequester* requester, 542 int render_process_id, 543 int render_view_id, 544 const ResourceContext::SaltCallback& sc, 545 int page_request_id, 546 MediaStreamType type, 547 const GURL& security_origin) { 548 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 549 DCHECK(requester); 550 DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE || 551 type == MEDIA_DEVICE_VIDEO_CAPTURE); 552 553 DeviceRequest* request = new DeviceRequest(requester, 554 render_process_id, 555 render_view_id, 556 page_request_id, 557 security_origin, 558 MEDIA_ENUMERATE_DEVICES, 559 StreamOptions(), 560 sc); 561 if (IsAudioMediaType(type)) 562 request->SetAudioType(type); 563 else if (IsVideoMediaType(type)) 564 request->SetVideoType(type); 565 566 const std::string& label = AddRequest(request); 567 // Post a task and handle the request asynchronously. The reason is that the 568 // requester won't have a label for the request until this function returns 569 // and thus can not handle a response. Using base::Unretained is safe since 570 // MediaStreamManager is deleted on the UI thread, after the IO thread has 571 // been stopped. 572 BrowserThread::PostTask( 573 BrowserThread::IO, FROM_HERE, 574 base::Bind(&MediaStreamManager::DoEnumerateDevices, 575 base::Unretained(this), label)); 576 return label; 577 } 578 579 void MediaStreamManager::DoEnumerateDevices(const std::string& label) { 580 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 581 DeviceRequest* request = FindRequest(label); 582 if (!request) 583 return; // This can happen if the request has been canceled. 584 585 MediaStreamType type; 586 EnumerationCache* cache; 587 if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE) { 588 DCHECK_EQ(MEDIA_NO_SERVICE, request->video_type()); 589 type = MEDIA_DEVICE_AUDIO_CAPTURE; 590 cache = &audio_enumeration_cache_; 591 } else { 592 DCHECK_EQ(MEDIA_DEVICE_VIDEO_CAPTURE, request->video_type()); 593 type = MEDIA_DEVICE_VIDEO_CAPTURE; 594 cache = &video_enumeration_cache_; 595 } 596 597 if (cache->valid) { 598 // Cached device list of this type exists. Just send it out. 599 request->SetState(type, MEDIA_REQUEST_STATE_REQUESTED); 600 request->devices = cache->devices; 601 FinalizeEnumerateDevices(label, request); 602 } else { 603 StartEnumeration(request); 604 } 605 DVLOG(1) << "Enumerate Devices ({label = " << label << "})"; 606 } 607 608 void MediaStreamManager::OpenDevice(MediaStreamRequester* requester, 609 int render_process_id, 610 int render_view_id, 611 const ResourceContext::SaltCallback& sc, 612 int page_request_id, 613 const std::string& device_id, 614 MediaStreamType type, 615 const GURL& security_origin) { 616 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 617 DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE || 618 type == MEDIA_DEVICE_VIDEO_CAPTURE); 619 DVLOG(1) << "OpenDevice ({page_request_id = " << page_request_id << "})"; 620 StreamOptions options; 621 if (IsAudioMediaType(type)) { 622 options.audio_requested = true; 623 options.mandatory_audio.push_back( 624 StreamOptions::Constraint(kMediaStreamSourceInfoId, device_id)); 625 } else if (IsVideoMediaType(type)) { 626 options.video_requested = true; 627 options.mandatory_video.push_back( 628 StreamOptions::Constraint(kMediaStreamSourceInfoId, device_id)); 629 } else { 630 NOTREACHED(); 631 } 632 DeviceRequest* request = new DeviceRequest(requester, 633 render_process_id, 634 render_view_id, 635 page_request_id, 636 security_origin, 637 MEDIA_OPEN_DEVICE, 638 options, 639 sc); 640 641 const std::string& label = AddRequest(request); 642 // Post a task and handle the request asynchronously. The reason is that the 643 // requester won't have a label for the request until this function returns 644 // and thus can not handle a response. Using base::Unretained is safe since 645 // MediaStreamManager is deleted on the UI thread, after the IO thread has 646 // been stopped. 647 BrowserThread::PostTask( 648 BrowserThread::IO, FROM_HERE, 649 base::Bind(&MediaStreamManager::SetupRequest, 650 base::Unretained(this), label)); 651 } 652 653 void MediaStreamManager::EnsureDeviceMonitorStarted() { 654 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 655 if (!monitoring_started_) 656 StartMonitoring(); 657 } 658 659 void MediaStreamManager::StopRemovedDevices( 660 const StreamDeviceInfoArray& old_devices, 661 const StreamDeviceInfoArray& new_devices) { 662 DVLOG(1) << "StopRemovedDevices(" 663 << "{#old_devices = " << old_devices.size() << "} " 664 << "{#new_devices = " << new_devices.size() << "})"; 665 for (StreamDeviceInfoArray::const_iterator old_dev_it = old_devices.begin(); 666 old_dev_it != old_devices.end(); ++old_dev_it) { 667 bool device_found = false; 668 StreamDeviceInfoArray::const_iterator new_dev_it = new_devices.begin(); 669 for (; new_dev_it != new_devices.end(); ++new_dev_it) { 670 if (old_dev_it->device.id == new_dev_it->device.id) { 671 device_found = true; 672 break; 673 } 674 } 675 676 if (!device_found) { 677 // A device has been removed. We need to check if it is used by a 678 // MediaStream and in that case cleanup and notify the render process. 679 StopRemovedDevice(old_dev_it->device); 680 } 681 } 682 } 683 684 void MediaStreamManager::StopRemovedDevice(const MediaStreamDevice& device) { 685 std::vector<int> session_ids; 686 for (DeviceRequests::const_iterator it = requests_.begin(); 687 it != requests_.end() ; ++it) { 688 const DeviceRequest* request = it->second; 689 for (StreamDeviceInfoArray::const_iterator device_it = 690 request->devices.begin(); 691 device_it != request->devices.end(); ++device_it) { 692 std::string source_id = content::GetHMACForMediaDeviceID( 693 request->salt_callback, 694 request->security_origin, 695 device.id); 696 if (device_it->device.id == source_id && 697 device_it->device.type == device.type) { 698 session_ids.push_back(device_it->session_id); 699 if (it->second->requester) { 700 it->second->requester->DeviceStopped( 701 it->second->requesting_view_id, 702 it->first, 703 *device_it); 704 } 705 } 706 } 707 } 708 for (std::vector<int>::const_iterator it = session_ids.begin(); 709 it != session_ids.end(); ++it) { 710 StopDevice(device.type, *it); 711 } 712 } 713 714 void MediaStreamManager::StartMonitoring() { 715 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 716 if (!base::SystemMonitor::Get()) 717 return; 718 719 if (!monitoring_started_) { 720 monitoring_started_ = true; 721 base::SystemMonitor::Get()->AddDevicesChangedObserver(this); 722 723 // Enumerate both the audio and video devices to cache the device lists 724 // and send them to media observer. 725 ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_CAPTURE]; 726 audio_input_device_manager_->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE); 727 ++active_enumeration_ref_count_[MEDIA_DEVICE_VIDEO_CAPTURE]; 728 video_capture_manager_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); 729 } 730 } 731 732 void MediaStreamManager::StopMonitoring() { 733 DCHECK_EQ(base::MessageLoop::current(), io_loop_); 734 if (monitoring_started_) { 735 base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this); 736 monitoring_started_ = false; 737 ClearEnumerationCache(&audio_enumeration_cache_); 738 ClearEnumerationCache(&video_enumeration_cache_); 739 } 740 } 741 742 bool MediaStreamManager::GetRequestedDeviceCaptureId( 743 const DeviceRequest* request, 744 MediaStreamType type, 745 std::string* device_id) const { 746 DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE || 747 type == MEDIA_DEVICE_VIDEO_CAPTURE); 748 const StreamOptions::Constraints* mandatory = 749 (type == MEDIA_DEVICE_AUDIO_CAPTURE) ? 750 &request->options.mandatory_audio : &request->options.mandatory_video; 751 const StreamOptions::Constraints* optional = 752 (type == MEDIA_DEVICE_AUDIO_CAPTURE) ? 753 &request->options.optional_audio : &request->options.optional_video; 754 755 std::vector<std::string> source_ids; 756 StreamOptions::GetConstraintsByName(*mandatory, 757 kMediaStreamSourceInfoId, &source_ids); 758 if (source_ids.size() > 1) { 759 LOG(ERROR) << "Only one mandatory audio " << kMediaStreamSourceInfoId 760 << " is supported."; 761 return false; 762 } 763 // If a specific device has been requested we need to find the real device 764 // id. 765 if (source_ids.size() == 1 && 766 !TranslateSourceIdToDeviceId(type, 767 request->salt_callback, 768 request->security_origin, 769 source_ids[0], device_id)) { 770 LOG(WARNING) << "Invalid mandatory audio " << kMediaStreamSourceInfoId 771 << " = " << source_ids[0] << "."; 772 return false; 773 } 774 // Check for optional audio sourceIDs. 775 if (device_id->empty()) { 776 StreamOptions::GetConstraintsByName(*optional, 777 kMediaStreamSourceInfoId, 778 &source_ids); 779 // Find the first sourceID that translates to device. Note that only one 780 // device per type can call to GenerateStream is ever opened. 781 for (std::vector<std::string>::const_iterator it = source_ids.begin(); 782 it != source_ids.end(); ++it) { 783 if (TranslateSourceIdToDeviceId(type, 784 request->salt_callback, 785 request->security_origin, 786 *it, 787 device_id)) { 788 break; 789 } 790 } 791 } 792 return true; 793 } 794 795 void MediaStreamManager::TranslateDeviceIdToSourceId( 796 DeviceRequest* request, 797 MediaStreamDevice* device) { 798 if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE || 799 request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE) { 800 device->id = content::GetHMACForMediaDeviceID( 801 request->salt_callback, 802 request->security_origin, 803 device->id); 804 } 805 } 806 807 bool MediaStreamManager::TranslateSourceIdToDeviceId( 808 MediaStreamType stream_type, 809 const ResourceContext::SaltCallback& sc, 810 const GURL& security_origin, 811 const std::string& source_id, 812 std::string* device_id) const { 813 DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE || 814 stream_type == MEDIA_DEVICE_VIDEO_CAPTURE); 815 // The source_id can be empty if the constraint is set but empty. 816 if (source_id.empty()) 817 return false; 818 819 const EnumerationCache* cache = 820 stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ? 821 &audio_enumeration_cache_ : &video_enumeration_cache_; 822 823 // If device monitoring hasn't started, the |device_guid| is not valid. 824 if (!cache->valid) 825 return false; 826 827 for (StreamDeviceInfoArray::const_iterator it = cache->devices.begin(); 828 it != cache->devices.end(); 829 ++it) { 830 if (content::DoesMediaDeviceIDMatchHMAC(sc, security_origin, source_id, 831 it->device.id)) { 832 *device_id = it->device.id; 833 return true; 834 } 835 } 836 return false; 837 } 838 839 void MediaStreamManager::ClearEnumerationCache(EnumerationCache* cache) { 840 DCHECK_EQ(base::MessageLoop::current(), io_loop_); 841 cache->valid = false; 842 } 843 844 void MediaStreamManager::StartEnumeration(DeviceRequest* request) { 845 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 846 847 // Start monitoring the devices when doing the first enumeration. 848 if (!monitoring_started_ && base::SystemMonitor::Get()) { 849 StartMonitoring(); 850 } 851 852 // Start enumeration for devices of all requested device types. 853 if (request->audio_type() != MEDIA_NO_SERVICE) { 854 const MediaStreamType stream_type = request->audio_type(); 855 request->SetState(stream_type, MEDIA_REQUEST_STATE_REQUESTED); 856 DCHECK_GE(active_enumeration_ref_count_[stream_type], 0); 857 if (active_enumeration_ref_count_[stream_type] == 0) { 858 ++active_enumeration_ref_count_[stream_type]; 859 GetDeviceManager(stream_type)->EnumerateDevices(stream_type); 860 } 861 } 862 if (request->video_type() != MEDIA_NO_SERVICE) { 863 const MediaStreamType stream_type = request->video_type(); 864 request->SetState(stream_type, MEDIA_REQUEST_STATE_REQUESTED); 865 DCHECK_GE(active_enumeration_ref_count_[stream_type], 0); 866 if (active_enumeration_ref_count_[stream_type] == 0) { 867 ++active_enumeration_ref_count_[stream_type]; 868 GetDeviceManager(stream_type)->EnumerateDevices(stream_type); 869 } 870 } 871 } 872 873 std::string MediaStreamManager::AddRequest(DeviceRequest* request) { 874 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 875 876 // Create a label for this request and verify it is unique. 877 std::string unique_label; 878 do { 879 unique_label = RandomLabel(); 880 } while (requests_.find(unique_label) != requests_.end()); 881 882 requests_.insert(std::make_pair(unique_label, request)); 883 884 return unique_label; 885 } 886 887 MediaStreamManager::DeviceRequest* 888 MediaStreamManager::FindRequest(const std::string& label) const { 889 DeviceRequests::const_iterator request_it = requests_.find(label); 890 return request_it == requests_.end() ? NULL : request_it->second; 891 } 892 893 void MediaStreamManager::DeleteRequest(const std::string& label) { 894 DeviceRequests::iterator it = requests_.find(label); 895 scoped_ptr<DeviceRequest> request(it->second); 896 requests_.erase(it); 897 } 898 899 void MediaStreamManager::PostRequestToUI(const std::string& label, 900 DeviceRequest* request) { 901 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 902 DCHECK(request->UIRequest()); 903 DVLOG(1) << "PostRequestToUI({label= " << label << "})"; 904 905 const MediaStreamType audio_type = request->audio_type(); 906 const MediaStreamType video_type = request->video_type(); 907 908 // Post the request to UI and set the state. 909 if (IsAudioMediaType(audio_type)) 910 request->SetState(audio_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); 911 if (IsVideoMediaType(video_type)) 912 request->SetState(video_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); 913 914 if (use_fake_ui_) { 915 if (!fake_ui_) 916 fake_ui_.reset(new FakeMediaStreamUIProxy()); 917 918 MediaStreamDevices devices; 919 if (audio_enumeration_cache_.valid) { 920 for (StreamDeviceInfoArray::const_iterator it = 921 audio_enumeration_cache_.devices.begin(); 922 it != audio_enumeration_cache_.devices.end(); ++it) { 923 devices.push_back(it->device); 924 } 925 } 926 if (video_enumeration_cache_.valid) { 927 for (StreamDeviceInfoArray::const_iterator it = 928 video_enumeration_cache_.devices.begin(); 929 it != video_enumeration_cache_.devices.end(); ++it) { 930 devices.push_back(it->device); 931 } 932 } 933 934 fake_ui_->SetAvailableDevices(devices); 935 936 request->ui_proxy = fake_ui_.Pass(); 937 } else { 938 request->ui_proxy = MediaStreamUIProxy::Create(); 939 } 940 941 request->ui_proxy->RequestAccess( 942 *request->UIRequest(), 943 base::Bind(&MediaStreamManager::HandleAccessRequestResponse, 944 base::Unretained(this), label)); 945 } 946 947 void MediaStreamManager::SetupRequest(const std::string& label) { 948 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 949 DeviceRequest* request = FindRequest(label); 950 if (!request) { 951 DVLOG(1) << "SetupRequest label " << label << " doesn't exist!!"; 952 return; // This can happen if the request has been canceled. 953 } 954 955 if (!request->security_origin.is_valid()) { 956 LOG(ERROR) << "Invalid security origin. " 957 << request->security_origin; 958 FinalizeRequestFailed(label, request); 959 return; 960 } 961 962 MediaStreamType audio_type = MEDIA_NO_SERVICE; 963 MediaStreamType video_type = MEDIA_NO_SERVICE; 964 ParseStreamType(request->options, &audio_type, &video_type); 965 request->SetAudioType(audio_type); 966 request->SetVideoType(video_type); 967 968 bool is_web_contents_capture = 969 audio_type == MEDIA_TAB_AUDIO_CAPTURE || 970 video_type == MEDIA_TAB_VIDEO_CAPTURE; 971 if (is_web_contents_capture && !SetupTabCaptureRequest(request)) { 972 FinalizeRequestFailed(label, request); 973 return; 974 } 975 976 bool is_screen_capture = 977 video_type == MEDIA_DESKTOP_VIDEO_CAPTURE; 978 if (is_screen_capture && !SetupScreenCaptureRequest(request)) { 979 FinalizeRequestFailed(label, request); 980 return; 981 } 982 983 if (!is_web_contents_capture && !is_screen_capture) { 984 if ((!audio_enumeration_cache_.valid && IsAudioMediaType(audio_type)) || 985 (!video_enumeration_cache_.valid && IsVideoMediaType(video_type))) { 986 // Enumerate the devices if there is no valid device lists to be used. 987 StartEnumeration(request); 988 return; 989 } 990 if (!SetupDeviceCaptureRequest(request)) { 991 FinalizeRequestFailed(label, request); 992 return; 993 } 994 } 995 PostRequestToUI(label, request); 996 } 997 998 bool MediaStreamManager::SetupDeviceCaptureRequest(DeviceRequest* request) { 999 DCHECK((request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE || 1000 request->audio_type() == MEDIA_NO_SERVICE) && 1001 (request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE || 1002 request->video_type() == MEDIA_NO_SERVICE)); 1003 std::string audio_device_id; 1004 if (request->options.audio_requested && 1005 !GetRequestedDeviceCaptureId(request, request->audio_type(), 1006 &audio_device_id)) { 1007 return false; 1008 } 1009 1010 std::string video_device_id; 1011 if (request->options.video_requested && 1012 !GetRequestedDeviceCaptureId(request, request->video_type(), 1013 &video_device_id)) { 1014 return false; 1015 } 1016 request->CreateUIRequest(audio_device_id, video_device_id); 1017 DVLOG(3) << "Audio requested " << request->options.audio_requested 1018 << " device id = " << audio_device_id 1019 << "Video requested " << request->options.video_requested 1020 << " device id = " << video_device_id; 1021 return true; 1022 } 1023 1024 bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) { 1025 DCHECK(request->audio_type() == MEDIA_TAB_AUDIO_CAPTURE || 1026 request->video_type() == MEDIA_TAB_VIDEO_CAPTURE); 1027 1028 std::string capture_device_id; 1029 bool mandatory_audio = false; 1030 bool mandatory_video = false; 1031 if (!request->options.GetFirstAudioConstraintByName(kMediaStreamSourceId, 1032 &capture_device_id, 1033 &mandatory_audio) && 1034 !request->options.GetFirstVideoConstraintByName(kMediaStreamSourceId, 1035 &capture_device_id, 1036 &mandatory_video)) { 1037 return false; 1038 } 1039 DCHECK(mandatory_audio || mandatory_video); 1040 1041 // Customize options for a WebContents based capture. 1042 int target_render_process_id = 0; 1043 int target_render_view_id = 0; 1044 1045 // TODO(justinlin): Can't plumb audio mirroring using stream type right 1046 // now, so plumbing by device_id. Will revisit once it's refactored. 1047 // http://crbug.com/163100 1048 std::string tab_capture_device_id = 1049 WebContentsCaptureUtil::AppendWebContentsDeviceScheme(capture_device_id); 1050 1051 bool has_valid_device_id = WebContentsCaptureUtil::ExtractTabCaptureTarget( 1052 tab_capture_device_id, &target_render_process_id, 1053 &target_render_view_id); 1054 if (!has_valid_device_id || 1055 (request->audio_type() != MEDIA_TAB_AUDIO_CAPTURE && 1056 request->audio_type() != MEDIA_NO_SERVICE) || 1057 (request->video_type() != MEDIA_TAB_VIDEO_CAPTURE && 1058 request->video_type() != MEDIA_NO_SERVICE)) { 1059 return false; 1060 } 1061 1062 request->CreateTabCatureUIRequest(target_render_process_id, 1063 target_render_view_id, 1064 tab_capture_device_id); 1065 1066 DVLOG(3) << "SetupTabCaptureRequest " 1067 << ", {tab_capture_device_id = " << tab_capture_device_id << "}" 1068 << ", {target_render_process_id = " << target_render_process_id 1069 << "}" 1070 << ", {target_render_view_id = " << target_render_view_id << "}"; 1071 return true; 1072 } 1073 1074 bool MediaStreamManager::SetupScreenCaptureRequest(DeviceRequest* request) { 1075 DCHECK(request->audio_type() == MEDIA_LOOPBACK_AUDIO_CAPTURE || 1076 request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE); 1077 1078 // For screen capture we only support two valid combinations: 1079 // (1) screen video capture only, or 1080 // (2) screen video capture with loopback audio capture. 1081 if (request->video_type() != MEDIA_DESKTOP_VIDEO_CAPTURE || 1082 (request->audio_type() != MEDIA_NO_SERVICE && 1083 request->audio_type() != MEDIA_LOOPBACK_AUDIO_CAPTURE)) { 1084 LOG(ERROR) << "Invalid screen capture request."; 1085 return false; 1086 } 1087 1088 std::string video_device_id; 1089 if (request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE) { 1090 std::string video_stream_source; 1091 bool mandatory = false; 1092 if (!request->options.GetFirstVideoConstraintByName( 1093 kMediaStreamSource, 1094 &video_stream_source, 1095 &mandatory)) { 1096 LOG(ERROR) << kMediaStreamSource << " not found."; 1097 return false; 1098 } 1099 DCHECK(mandatory); 1100 1101 if (video_stream_source == kMediaStreamSourceDesktop) { 1102 if (!request->options.GetFirstVideoConstraintByName( 1103 kMediaStreamSourceId, 1104 &video_device_id, 1105 &mandatory)) { 1106 LOG(ERROR) << kMediaStreamSourceId << " not found."; 1107 return false; 1108 } 1109 DCHECK(mandatory); 1110 } 1111 } 1112 1113 request->CreateUIRequest("", video_device_id); 1114 return true; 1115 } 1116 1117 StreamDeviceInfoArray MediaStreamManager::GetDevicesOpenedByRequest( 1118 const std::string& label) const { 1119 DeviceRequest* request = FindRequest(label); 1120 if (!request) 1121 return StreamDeviceInfoArray(); 1122 return request->devices; 1123 } 1124 1125 bool MediaStreamManager::FindExistingRequestedDeviceInfo( 1126 const DeviceRequest& new_request, 1127 const MediaStreamDevice& new_device_info, 1128 StreamDeviceInfo* existing_device_info, 1129 MediaRequestState* existing_request_state) const { 1130 DCHECK(existing_device_info); 1131 DCHECK(existing_request_state); 1132 1133 std::string source_id = content::GetHMACForMediaDeviceID( 1134 new_request.salt_callback, 1135 new_request.security_origin, 1136 new_device_info.id); 1137 1138 for (DeviceRequests::const_iterator it = requests_.begin(); 1139 it != requests_.end() ; ++it) { 1140 const DeviceRequest* request = it->second; 1141 if (request->requesting_process_id == new_request.requesting_process_id && 1142 request->requesting_view_id == new_request.requesting_view_id && 1143 request->request_type == new_request.request_type) { 1144 for (StreamDeviceInfoArray::const_iterator device_it = 1145 request->devices.begin(); 1146 device_it != request->devices.end(); ++device_it) { 1147 if (device_it->device.id == source_id && 1148 device_it->device.type == new_device_info.type) { 1149 *existing_device_info = *device_it; 1150 *existing_request_state = request->state(device_it->device.type); 1151 return true; 1152 } 1153 } 1154 } 1155 } 1156 return false; 1157 } 1158 1159 void MediaStreamManager::FinalizeGenerateStream(const std::string& label, 1160 DeviceRequest* request) { 1161 DVLOG(1) << "FinalizeGenerateStream label " << label; 1162 const StreamDeviceInfoArray& requested_devices = request->devices; 1163 1164 // Partition the array of devices into audio vs video. 1165 StreamDeviceInfoArray audio_devices, video_devices; 1166 for (StreamDeviceInfoArray::const_iterator device_it = 1167 requested_devices.begin(); 1168 device_it != requested_devices.end(); ++device_it) { 1169 if (IsAudioMediaType(device_it->device.type)) { 1170 audio_devices.push_back(*device_it); 1171 } else if (IsVideoMediaType(device_it->device.type)) { 1172 video_devices.push_back(*device_it); 1173 } else { 1174 NOTREACHED(); 1175 } 1176 } 1177 1178 request->requester->StreamGenerated( 1179 request->requesting_view_id, 1180 request->page_request_id, 1181 label, audio_devices, video_devices); 1182 } 1183 1184 void MediaStreamManager::FinalizeRequestFailed( 1185 const std::string& label, 1186 DeviceRequest* request) { 1187 if (request->requester) 1188 request->requester->StreamGenerationFailed( 1189 request->requesting_view_id, 1190 request->page_request_id); 1191 1192 if (request->request_type == MEDIA_DEVICE_ACCESS && 1193 !request->callback.is_null()) { 1194 request->callback.Run(MediaStreamDevices(), request->ui_proxy.Pass()); 1195 } 1196 1197 DeleteRequest(label); 1198 } 1199 1200 void MediaStreamManager::FinalizeOpenDevice(const std::string& label, 1201 DeviceRequest* request) { 1202 const StreamDeviceInfoArray& requested_devices = request->devices; 1203 request->requester->DeviceOpened(request->requesting_view_id, 1204 request->page_request_id, 1205 label, requested_devices.front()); 1206 } 1207 1208 void MediaStreamManager::FinalizeEnumerateDevices(const std::string& label, 1209 DeviceRequest* request) { 1210 if (!request->security_origin.is_valid()) { 1211 request->requester->DevicesEnumerated( 1212 request->requesting_view_id, 1213 request->page_request_id, 1214 label, 1215 StreamDeviceInfoArray()); 1216 return; 1217 } 1218 for (StreamDeviceInfoArray::iterator it = request->devices.begin(); 1219 it != request->devices.end(); ++it) { 1220 TranslateDeviceIdToSourceId(request, &it->device); 1221 } 1222 request->requester->DevicesEnumerated(request->requesting_view_id, 1223 request->page_request_id, 1224 label, 1225 request->devices); 1226 } 1227 1228 void MediaStreamManager::FinalizeMediaAccessRequest( 1229 const std::string& label, 1230 DeviceRequest* request, 1231 const MediaStreamDevices& devices) { 1232 if (!request->callback.is_null()) 1233 request->callback.Run(devices, request->ui_proxy.Pass()); 1234 1235 // Delete the request since it is done. 1236 DeleteRequest(label); 1237 } 1238 1239 void MediaStreamManager::InitializeDeviceManagersOnIOThread() { 1240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1241 if (device_thread_) 1242 return; 1243 1244 device_thread_.reset(new base::Thread("MediaStreamDeviceThread")); 1245 #if defined(OS_WIN) 1246 device_thread_->init_com_with_mta(true); 1247 #endif 1248 CHECK(device_thread_->Start()); 1249 1250 audio_input_device_manager_ = new AudioInputDeviceManager(audio_manager_); 1251 audio_input_device_manager_->Register( 1252 this, device_thread_->message_loop_proxy().get()); 1253 1254 video_capture_manager_ = new VideoCaptureManager(); 1255 video_capture_manager_->Register(this, 1256 device_thread_->message_loop_proxy().get()); 1257 1258 // We want to be notified of IO message loop destruction to delete the thread 1259 // and the device managers. 1260 io_loop_ = base::MessageLoop::current(); 1261 io_loop_->AddDestructionObserver(this); 1262 1263 if (CommandLine::ForCurrentProcess()->HasSwitch( 1264 switches::kUseFakeDeviceForMediaStream)) { 1265 DVLOG(1) << "Using fake device"; 1266 UseFakeDevice(); 1267 } 1268 } 1269 1270 void MediaStreamManager::Opened(MediaStreamType stream_type, 1271 int capture_session_id) { 1272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1273 DVLOG(1) << "Opened({stream_type = " << stream_type << "} " 1274 << "{capture_session_id = " << capture_session_id << "})"; 1275 // Find the request(s) containing this device and mark it as used. 1276 // It can be used in several requests since the same device can be 1277 // requested from the same web page. 1278 for (DeviceRequests::iterator request_it = requests_.begin(); 1279 request_it != requests_.end(); ++request_it) { 1280 const std::string& label = request_it->first; 1281 DeviceRequest* request = request_it->second; 1282 StreamDeviceInfoArray* devices = &(request->devices); 1283 for (StreamDeviceInfoArray::iterator device_it = devices->begin(); 1284 device_it != devices->end(); ++device_it) { 1285 if (device_it->device.type == stream_type && 1286 device_it->session_id == capture_session_id) { 1287 CHECK(request->state(device_it->device.type) == 1288 MEDIA_REQUEST_STATE_OPENING); 1289 // We've found a matching request. 1290 request->SetState(device_it->device.type, MEDIA_REQUEST_STATE_DONE); 1291 1292 if (IsAudioMediaType(device_it->device.type)) { 1293 // Store the native audio parameters in the device struct. 1294 // TODO(xians): Handle the tab capture sample rate/channel layout 1295 // in AudioInputDeviceManager::Open(). 1296 if (device_it->device.type != content::MEDIA_TAB_AUDIO_CAPTURE) { 1297 const StreamDeviceInfo* info = 1298 audio_input_device_manager_->GetOpenedDeviceInfoById( 1299 device_it->session_id); 1300 device_it->device.input = info->device.input; 1301 device_it->device.matched_output = info->device.matched_output; 1302 } 1303 } 1304 if (RequestDone(*request)) 1305 HandleRequestDone(label, request); 1306 break; 1307 } 1308 } 1309 } 1310 } 1311 1312 void MediaStreamManager::HandleRequestDone(const std::string& label, 1313 DeviceRequest* request) { 1314 DCHECK(RequestDone(*request)); 1315 DVLOG(1) << "HandleRequestDone(" 1316 << ", {label = " << label << "})"; 1317 1318 switch (request->request_type) { 1319 case MEDIA_OPEN_DEVICE: 1320 FinalizeOpenDevice(label, request); 1321 break; 1322 case MEDIA_GENERATE_STREAM: { 1323 FinalizeGenerateStream(label, request); 1324 break; 1325 } 1326 default: 1327 NOTREACHED(); 1328 break; 1329 } 1330 1331 if (request->ui_proxy.get()) { 1332 request->ui_proxy->OnStarted( 1333 base::Bind(&MediaStreamManager::StopMediaStreamFromBrowser, 1334 base::Unretained(this), label)); 1335 } 1336 } 1337 1338 void MediaStreamManager::Closed(MediaStreamType stream_type, 1339 int capture_session_id) { 1340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1341 } 1342 1343 void MediaStreamManager::DevicesEnumerated( 1344 MediaStreamType stream_type, const StreamDeviceInfoArray& devices) { 1345 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1346 DVLOG(1) << "DevicesEnumerated(" 1347 << ", {stream_type = " << stream_type << "})"; 1348 1349 // Only cache the device list when the device list has been changed. 1350 bool need_update_clients = false; 1351 EnumerationCache* cache = 1352 stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ? 1353 &audio_enumeration_cache_ : &video_enumeration_cache_; 1354 if (!cache->valid || 1355 devices.size() != cache->devices.size() || 1356 !std::equal(devices.begin(), devices.end(), cache->devices.begin(), 1357 StreamDeviceInfo::IsEqual)) { 1358 StopRemovedDevices(cache->devices, devices); 1359 cache->devices = devices; 1360 need_update_clients = true; 1361 1362 // The device might not be able to be enumerated when it is not warmed up, 1363 // for example, when the machine just wakes up from sleep. We set the cache 1364 // to be invalid so that the next media request will trigger the 1365 // enumeration again. See issue/317673. 1366 cache->valid = !devices.empty(); 1367 } 1368 1369 if (need_update_clients && monitoring_started_) 1370 NotifyDevicesChanged(stream_type, devices); 1371 1372 // Publish the result for all requests waiting for device list(s). 1373 // Find the requests waiting for this device list, store their labels and 1374 // release the iterator before calling device settings. We might get a call 1375 // back from device_settings that will need to iterate through devices. 1376 std::list<std::string> label_list; 1377 for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end(); 1378 ++it) { 1379 if (it->second->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED && 1380 (it->second->audio_type() == stream_type || 1381 it->second->video_type() == stream_type)) { 1382 if (it->second->request_type != MEDIA_ENUMERATE_DEVICES) 1383 it->second->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); 1384 label_list.push_back(it->first); 1385 } 1386 } 1387 for (std::list<std::string>::iterator it = label_list.begin(); 1388 it != label_list.end(); ++it) { 1389 DeviceRequest* request = FindRequest(*it); 1390 switch (request->request_type) { 1391 case MEDIA_ENUMERATE_DEVICES: 1392 if (need_update_clients && request->requester) { 1393 request->devices = devices; 1394 FinalizeEnumerateDevices(*it, request); 1395 } 1396 break; 1397 default: 1398 if (request->state(request->audio_type()) == 1399 MEDIA_REQUEST_STATE_REQUESTED || 1400 request->state(request->video_type()) == 1401 MEDIA_REQUEST_STATE_REQUESTED) { 1402 // We are doing enumeration for other type of media, wait until it is 1403 // all done before posting the request to UI because UI needs 1404 // the device lists to handle the request. 1405 break; 1406 } 1407 if (!SetupDeviceCaptureRequest(request)) 1408 FinalizeRequestFailed(*it, request); 1409 else 1410 PostRequestToUI(*it, request); 1411 break; 1412 } 1413 } 1414 label_list.clear(); 1415 --active_enumeration_ref_count_[stream_type]; 1416 DCHECK_GE(active_enumeration_ref_count_[stream_type], 0); 1417 } 1418 1419 void MediaStreamManager::HandleAccessRequestResponse( 1420 const std::string& label, 1421 const MediaStreamDevices& devices) { 1422 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1423 DVLOG(1) << "HandleAccessRequestResponse(" 1424 << ", {label = " << label << "})"; 1425 1426 DeviceRequest* request = FindRequest(label); 1427 if (!request) { 1428 // The request has been canceled before the UI returned. 1429 return; 1430 } 1431 1432 if (request->request_type == MEDIA_DEVICE_ACCESS) { 1433 FinalizeMediaAccessRequest(label, request, devices); 1434 return; 1435 } 1436 1437 // Handle the case when the request was denied. 1438 if (devices.empty()) { 1439 FinalizeRequestFailed(label, request); 1440 return; 1441 } 1442 1443 // Process all newly-accepted devices for this request. 1444 bool found_audio = false; 1445 bool found_video = false; 1446 for (MediaStreamDevices::const_iterator device_it = devices.begin(); 1447 device_it != devices.end(); ++device_it) { 1448 StreamDeviceInfo device_info; 1449 device_info.device = *device_it; 1450 1451 // TODO(justinlin): Nicer way to do this? 1452 // Re-append the device's id since we lost it when posting request to UI. 1453 if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE || 1454 device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) { 1455 device_info.device.id = request->UIRequest()->tab_capture_device_id; 1456 1457 // Initialize the sample_rate and channel_layout here since for audio 1458 // mirroring, we don't go through EnumerateDevices where these are usually 1459 // initialized. 1460 if (device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) { 1461 const media::AudioParameters parameters = 1462 audio_manager_->GetDefaultOutputStreamParameters(); 1463 int sample_rate = parameters.sample_rate(); 1464 // If we weren't able to get the native sampling rate or the sample_rate 1465 // is outside the valid range for input devices set reasonable defaults. 1466 if (sample_rate <= 0 || sample_rate > 96000) 1467 sample_rate = 44100; 1468 1469 device_info.device.input.sample_rate = sample_rate; 1470 device_info.device.input.channel_layout = media::CHANNEL_LAYOUT_STEREO; 1471 } 1472 } 1473 1474 if (device_info.device.type == request->audio_type()) { 1475 found_audio = true; 1476 } else if (device_info.device.type == request->video_type()) { 1477 found_video = true; 1478 } 1479 1480 // If this is request for a new MediaStream, a device is only opened once 1481 // per render view. This is so that the permission to use a device can be 1482 // revoked by a single call to StopStreamDevice regardless of how many 1483 // MediaStreams it is being used in. 1484 if (request->request_type == MEDIA_GENERATE_STREAM) { 1485 MediaRequestState state; 1486 if (FindExistingRequestedDeviceInfo(*request, 1487 device_info.device, 1488 &device_info, 1489 &state)) { 1490 request->devices.push_back(device_info); 1491 request->SetState(device_info.device.type, state); 1492 DVLOG(1) << "HandleAccessRequestResponse - device already opened " 1493 << ", {label = " << label << "}" 1494 << ", device_id = " << device_it->id << "}"; 1495 continue; 1496 } 1497 } 1498 device_info.session_id = 1499 GetDeviceManager(device_info.device.type)->Open(device_info); 1500 TranslateDeviceIdToSourceId(request, &device_info.device); 1501 request->devices.push_back(device_info); 1502 1503 request->SetState(device_info.device.type, MEDIA_REQUEST_STATE_OPENING); 1504 DVLOG(1) << "HandleAccessRequestResponse - opening device " 1505 << ", {label = " << label << "}" 1506 << ", {device_id = " << device_info.device.id << "}" 1507 << ", {session_id = " << device_info.session_id << "}"; 1508 } 1509 1510 // Check whether we've received all stream types requested. 1511 if (!found_audio && IsAudioMediaType(request->audio_type())) { 1512 request->SetState(request->audio_type(), MEDIA_REQUEST_STATE_ERROR); 1513 DVLOG(1) << "Set no audio found label " << label; 1514 } 1515 1516 if (!found_video && IsVideoMediaType(request->video_type())) 1517 request->SetState(request->video_type(), MEDIA_REQUEST_STATE_ERROR); 1518 1519 if (RequestDone(*request)) 1520 HandleRequestDone(label, request); 1521 } 1522 1523 void MediaStreamManager::StopMediaStreamFromBrowser(const std::string& label) { 1524 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1525 1526 DeviceRequest* request = FindRequest(label); 1527 if (!request) 1528 return; 1529 1530 // Notify renderers that the devices in the stream will be stopped. 1531 if (request->requester) { 1532 for (StreamDeviceInfoArray::iterator device_it = request->devices.begin(); 1533 device_it != request->devices.end(); ++device_it) { 1534 request->requester->DeviceStopped(request->requesting_view_id, 1535 label, 1536 *device_it); 1537 } 1538 } 1539 1540 CancelRequest(label); 1541 } 1542 1543 void MediaStreamManager::UseFakeDevice() { 1544 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1545 video_capture_manager()->UseFakeDevice(); 1546 audio_input_device_manager()->UseFakeDevice(); 1547 } 1548 1549 void MediaStreamManager::UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy> fake_ui) { 1550 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1551 use_fake_ui_ = true; 1552 fake_ui_ = fake_ui.Pass(); 1553 } 1554 1555 void MediaStreamManager::WillDestroyCurrentMessageLoop() { 1556 DVLOG(3) << "MediaStreamManager::WillDestroyCurrentMessageLoop()"; 1557 DCHECK_EQ(base::MessageLoop::current(), io_loop_); 1558 DCHECK(requests_.empty()); 1559 if (device_thread_) { 1560 StopMonitoring(); 1561 1562 video_capture_manager_->Unregister(); 1563 audio_input_device_manager_->Unregister(); 1564 device_thread_.reset(); 1565 } 1566 1567 audio_input_device_manager_ = NULL; 1568 video_capture_manager_ = NULL; 1569 } 1570 1571 void MediaStreamManager::NotifyDevicesChanged( 1572 MediaStreamType stream_type, 1573 const StreamDeviceInfoArray& devices) { 1574 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1575 MediaObserver* media_observer = 1576 GetContentClient()->browser()->GetMediaObserver(); 1577 if (media_observer == NULL) 1578 return; 1579 1580 // Map the devices to MediaStreamDevices. 1581 MediaStreamDevices new_devices; 1582 for (StreamDeviceInfoArray::const_iterator it = devices.begin(); 1583 it != devices.end(); ++it) { 1584 new_devices.push_back(it->device); 1585 } 1586 1587 if (IsAudioMediaType(stream_type)) { 1588 media_observer->OnAudioCaptureDevicesChanged(new_devices); 1589 } else if (IsVideoMediaType(stream_type)) { 1590 media_observer->OnVideoCaptureDevicesChanged(new_devices); 1591 } else { 1592 NOTREACHED(); 1593 } 1594 } 1595 1596 bool MediaStreamManager::RequestDone(const DeviceRequest& request) const { 1597 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1598 1599 const bool requested_audio = IsAudioMediaType(request.audio_type()); 1600 const bool requested_video = IsVideoMediaType(request.video_type()); 1601 1602 const bool audio_done = 1603 !requested_audio || 1604 request.state(request.audio_type()) == MEDIA_REQUEST_STATE_DONE || 1605 request.state(request.audio_type()) == MEDIA_REQUEST_STATE_ERROR; 1606 if (!audio_done) 1607 return false; 1608 1609 const bool video_done = 1610 !requested_video || 1611 request.state(request.video_type()) == MEDIA_REQUEST_STATE_DONE || 1612 request.state(request.video_type()) == MEDIA_REQUEST_STATE_ERROR; 1613 if (!video_done) 1614 return false; 1615 1616 return true; 1617 } 1618 1619 MediaStreamProvider* MediaStreamManager::GetDeviceManager( 1620 MediaStreamType stream_type) { 1621 if (IsVideoMediaType(stream_type)) { 1622 return video_capture_manager(); 1623 } else if (IsAudioMediaType(stream_type)) { 1624 return audio_input_device_manager(); 1625 } 1626 NOTREACHED(); 1627 return NULL; 1628 } 1629 1630 void MediaStreamManager::OnDevicesChanged( 1631 base::SystemMonitor::DeviceType device_type) { 1632 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1633 1634 // NOTE: This method is only called in response to physical audio/video device 1635 // changes (from the operating system). 1636 1637 MediaStreamType stream_type; 1638 if (device_type == base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE) { 1639 stream_type = MEDIA_DEVICE_AUDIO_CAPTURE; 1640 } else if (device_type == base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE) { 1641 stream_type = MEDIA_DEVICE_VIDEO_CAPTURE; 1642 } else { 1643 return; // Uninteresting device change. 1644 } 1645 1646 // Always do enumeration even though some enumeration is in progress, 1647 // because those enumeration commands could be sent before these devices 1648 // change. 1649 ++active_enumeration_ref_count_[stream_type]; 1650 GetDeviceManager(stream_type)->EnumerateDevices(stream_type); 1651 } 1652 1653 } // namespace content 1654