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