Home | History | Annotate | Download | only in media
      1 // Copyright 2013 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 
      6 #include "content/browser/renderer_host/media/device_request_message_filter.h"
      7 
      8 #include "base/strings/string_number_conversions.h"
      9 #include "base/strings/string_util.h"
     10 #include "content/browser/browser_main_loop.h"
     11 #include "content/browser/renderer_host/media/media_stream_manager.h"
     12 #include "content/common/media/media_stream_messages.h"
     13 #include "content/public/browser/resource_context.h"
     14 #include "crypto/hmac.h"
     15 
     16 // Clears the MediaStreamDevice.name from all devices in |device_list|.
     17 static void ClearDeviceLabels(content::StreamDeviceInfoArray* devices) {
     18   for (content::StreamDeviceInfoArray::iterator device_itr = devices->begin();
     19        device_itr != devices->end();
     20        ++device_itr) {
     21     device_itr->device.name.clear();
     22   }
     23 }
     24 
     25 namespace content {
     26 
     27 DeviceRequestMessageFilter::DeviceRequestMessageFilter(
     28     ResourceContext* resource_context,
     29     MediaStreamManager* media_stream_manager)
     30     : resource_context_(resource_context),
     31       media_stream_manager_(media_stream_manager) {
     32   DCHECK(resource_context);
     33   DCHECK(media_stream_manager);
     34 }
     35 
     36 DeviceRequestMessageFilter::~DeviceRequestMessageFilter() {
     37   DCHECK(requests_.empty());
     38 }
     39 
     40 struct DeviceRequestMessageFilter::DeviceRequest {
     41   DeviceRequest(int request_id,
     42                 const GURL& origin,
     43                 const std::string& audio_devices_label,
     44                 const std::string& video_devices_label)
     45       : request_id(request_id),
     46         origin(origin),
     47         has_audio_returned(false),
     48         has_video_returned(false),
     49         audio_devices_label(audio_devices_label),
     50         video_devices_label(video_devices_label) {}
     51 
     52   int request_id;
     53   GURL origin;
     54   bool has_audio_returned;
     55   bool has_video_returned;
     56   std::string audio_devices_label;
     57   std::string video_devices_label;
     58   StreamDeviceInfoArray audio_devices;
     59   StreamDeviceInfoArray video_devices;
     60 };
     61 
     62 void DeviceRequestMessageFilter::StreamGenerated(
     63     const std::string& label,
     64     const StreamDeviceInfoArray& audio_devices,
     65     const StreamDeviceInfoArray& video_devices) {
     66   NOTIMPLEMENTED();
     67 }
     68 
     69 void DeviceRequestMessageFilter::StreamGenerationFailed(
     70     const std::string& label) {
     71   NOTIMPLEMENTED();
     72 }
     73 
     74 void DeviceRequestMessageFilter::StopGeneratedStream(
     75     const std::string& label) {
     76   NOTIMPLEMENTED();
     77 }
     78 
     79 void DeviceRequestMessageFilter::DevicesEnumerated(
     80     const std::string& label,
     81     const StreamDeviceInfoArray& new_devices) {
     82   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     83 
     84   // Look up the DeviceRequest by id.
     85   DeviceRequestList::iterator request_it = requests_.begin();
     86   for (; request_it != requests_.end(); ++request_it) {
     87     if (label == request_it->audio_devices_label ||
     88         label == request_it->video_devices_label) {
     89       break;
     90     }
     91   }
     92   DCHECK(request_it != requests_.end());
     93 
     94   StreamDeviceInfoArray* audio_devices = &request_it->audio_devices;
     95   StreamDeviceInfoArray* video_devices = &request_it->video_devices;
     96 
     97   // Store hmac'd device ids instead of raw device ids.
     98   if (label == request_it->audio_devices_label) {
     99     request_it->has_audio_returned = true;
    100     DCHECK(audio_devices->empty());
    101     HmacDeviceIds(request_it->origin, new_devices, audio_devices);
    102   } else {
    103     DCHECK(label == request_it->video_devices_label);
    104     request_it->has_video_returned = true;
    105     DCHECK(video_devices->empty());
    106     HmacDeviceIds(request_it->origin, new_devices, video_devices);
    107   }
    108 
    109   if (!request_it->has_audio_returned || !request_it->has_video_returned) {
    110     // Wait for the rest of the devices to complete.
    111     return;
    112   }
    113 
    114   // Query for mic and camera permissions.
    115   if (!resource_context_->AllowMicAccess(request_it->origin))
    116     ClearDeviceLabels(audio_devices);
    117   if (!resource_context_->AllowCameraAccess(request_it->origin))
    118     ClearDeviceLabels(video_devices);
    119 
    120   // Both audio and video devices are ready for copying.
    121   StreamDeviceInfoArray all_devices = *audio_devices;
    122   all_devices.insert(
    123       all_devices.end(), video_devices->begin(), video_devices->end());
    124 
    125   Send(new MediaStreamMsg_GetSourcesACK(request_it->request_id, all_devices));
    126 
    127   // TODO(vrk): Rename StopGeneratedStream() to CancelDeviceRequest().
    128   media_stream_manager_->StopGeneratedStream(request_it->audio_devices_label);
    129   media_stream_manager_->StopGeneratedStream(request_it->video_devices_label);
    130   requests_.erase(request_it);
    131 }
    132 
    133 void DeviceRequestMessageFilter::DeviceOpened(
    134     const std::string& label,
    135     const StreamDeviceInfo& video_device) {
    136   NOTIMPLEMENTED();
    137 }
    138 
    139 bool DeviceRequestMessageFilter::OnMessageReceived(const IPC::Message& message,
    140                                                    bool* message_was_ok) {
    141   bool handled = true;
    142   IPC_BEGIN_MESSAGE_MAP_EX(DeviceRequestMessageFilter, message, *message_was_ok)
    143     IPC_MESSAGE_HANDLER(MediaStreamHostMsg_GetSources, OnGetSources)
    144     IPC_MESSAGE_UNHANDLED(handled = false)
    145   IPC_END_MESSAGE_MAP_EX()
    146   return handled;
    147 }
    148 
    149 void DeviceRequestMessageFilter::OnChannelClosing() {
    150   BrowserMessageFilter::OnChannelClosing();
    151 
    152   // Since the IPC channel is gone, cancel outstanding device requests.
    153   for (DeviceRequestList::iterator it = requests_.begin();
    154        it != requests_.end();
    155        ++it) {
    156     // TODO(vrk): Rename StopGeneratedStream() to CancelDeviceRequest().
    157     media_stream_manager_->StopGeneratedStream(it->audio_devices_label);
    158     media_stream_manager_->StopGeneratedStream(it->video_devices_label);
    159   }
    160   requests_.clear();
    161 }
    162 
    163 void DeviceRequestMessageFilter::HmacDeviceIds(
    164     const GURL& origin,
    165     const StreamDeviceInfoArray& raw_devices,
    166     StreamDeviceInfoArray* devices_with_guids) {
    167   DCHECK(devices_with_guids);
    168 
    169   // Replace raw ids with hmac'd ids before returning to renderer process.
    170   for (StreamDeviceInfoArray::const_iterator device_itr = raw_devices.begin();
    171        device_itr != raw_devices.end();
    172        ++device_itr) {
    173     crypto::HMAC hmac(crypto::HMAC::SHA256);
    174     const size_t digest_length = hmac.DigestLength();
    175     std::vector<uint8> digest(digest_length);
    176     bool result = hmac.Init(origin.spec()) &&
    177                   hmac.Sign(device_itr->device.id, &digest[0], digest.size());
    178     DCHECK(result);
    179     if (result) {
    180       StreamDeviceInfo current_device_info = *device_itr;
    181       current_device_info.device.id =
    182           StringToLowerASCII(base::HexEncode(&digest[0], digest.size()));
    183       devices_with_guids->push_back(current_device_info);
    184     }
    185   }
    186 }
    187 
    188 bool DeviceRequestMessageFilter::DoesRawIdMatchGuid(
    189     const GURL& security_origin,
    190     const std::string& device_guid,
    191     const std::string& raw_device_id) {
    192   crypto::HMAC hmac(crypto::HMAC::SHA256);
    193   bool result = hmac.Init(security_origin.spec());
    194   DCHECK(result);
    195   std::vector<uint8> converted_guid;
    196   base::HexStringToBytes(device_guid, &converted_guid);
    197   return hmac.Verify(
    198       raw_device_id,
    199       base::StringPiece(reinterpret_cast<const char*>(&converted_guid[0]),
    200                         converted_guid.size()));
    201 }
    202 
    203 void DeviceRequestMessageFilter::OnGetSources(int request_id,
    204                                               const GURL& security_origin) {
    205   // Make request to get audio devices.
    206   const std::string& audio_label = media_stream_manager_->EnumerateDevices(
    207       this, -1, -1, -1, MEDIA_DEVICE_AUDIO_CAPTURE, security_origin);
    208   DCHECK(!audio_label.empty());
    209 
    210   // Make request for video devices.
    211   const std::string& video_label = media_stream_manager_->EnumerateDevices(
    212       this, -1, -1, -1, MEDIA_DEVICE_VIDEO_CAPTURE, security_origin);
    213   DCHECK(!video_label.empty());
    214 
    215   requests_.push_back(DeviceRequest(
    216       request_id, security_origin, audio_label, video_label));
    217 }
    218 
    219 }  // namespace content
    220