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