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