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/renderer/media/media_stream_dispatcher.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/message_loop/message_loop_proxy.h"
      9 #include "content/common/media/media_stream_messages.h"
     10 #include "content/renderer/media/media_stream_dispatcher_eventhandler.h"
     11 #include "content/renderer/render_thread_impl.h"
     12 #include "content/renderer/render_view_impl.h"
     13 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
     14 #include "url/gurl.h"
     15 
     16 namespace content {
     17 
     18 namespace {
     19 
     20 bool RemoveStreamDeviceFromArray(const StreamDeviceInfo device_info,
     21                                  StreamDeviceInfoArray* array) {
     22   for (StreamDeviceInfoArray::iterator device_it = array->begin();
     23        device_it != array->end(); ++device_it) {
     24     if (StreamDeviceInfo::IsEqual(*device_it, device_info)) {
     25       array->erase(device_it);
     26       return true;
     27     }
     28   }
     29   return false;
     30 }
     31 
     32 }  // namespace
     33 
     34 // A request is identified by pair (request_id, handler), or ipc_request.
     35 // There could be multiple clients making requests and each has its own
     36 // request_id sequence.
     37 // The ipc_request is garanteed to be unique when it's created in
     38 // MediaStreamDispatcher.
     39 struct MediaStreamDispatcher::Request {
     40   Request(const base::WeakPtr<MediaStreamDispatcherEventHandler>& handler,
     41           int request_id,
     42           int ipc_request)
     43       : handler(handler),
     44         request_id(request_id),
     45         ipc_request(ipc_request) {
     46   }
     47   bool IsThisRequest(
     48       int request_id1,
     49       const base::WeakPtr<MediaStreamDispatcherEventHandler>& handler1) {
     50     return (request_id1 == request_id && handler1.get() == handler.get());
     51   }
     52   base::WeakPtr<MediaStreamDispatcherEventHandler> handler;
     53   int request_id;
     54   int ipc_request;
     55 };
     56 
     57 struct MediaStreamDispatcher::Stream {
     58   Stream() {}
     59   ~Stream() {}
     60   base::WeakPtr<MediaStreamDispatcherEventHandler> handler;
     61   StreamDeviceInfoArray audio_array;
     62   StreamDeviceInfoArray video_array;
     63 };
     64 
     65 MediaStreamDispatcher::MediaStreamDispatcher(RenderViewImpl* render_view)
     66     : RenderViewObserver(render_view),
     67       main_loop_(base::MessageLoopProxy::current()),
     68       next_ipc_id_(0) {
     69 }
     70 
     71 MediaStreamDispatcher::~MediaStreamDispatcher() {}
     72 
     73 void MediaStreamDispatcher::GenerateStream(
     74     int request_id,
     75     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler,
     76     const StreamOptions& components,
     77     const GURL& security_origin) {
     78   DCHECK(main_loop_->BelongsToCurrentThread());
     79   DVLOG(1) << "MediaStreamDispatcher::GenerateStream(" << request_id << ")";
     80 
     81   requests_.push_back(Request(event_handler, request_id, next_ipc_id_));
     82   Send(new MediaStreamHostMsg_GenerateStream(
     83       routing_id(), next_ipc_id_++, components, security_origin,
     84       blink::WebUserGestureIndicator::isProcessingUserGesture()));
     85 }
     86 
     87 void MediaStreamDispatcher::CancelGenerateStream(
     88     int request_id,
     89     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler) {
     90   DCHECK(main_loop_->BelongsToCurrentThread());
     91   DVLOG(1) << "MediaStreamDispatcher::CancelGenerateStream"
     92            << ", {request_id = " << request_id << "}";
     93 
     94   RequestList::iterator it = requests_.begin();
     95   for (; it != requests_.end(); ++it) {
     96     if (it->IsThisRequest(request_id, event_handler)) {
     97       int ipc_request = it->ipc_request;
     98       requests_.erase(it);
     99       Send(new MediaStreamHostMsg_CancelGenerateStream(routing_id(),
    100                                                        ipc_request));
    101       break;
    102     }
    103   }
    104 }
    105 
    106 void MediaStreamDispatcher::StopStreamDevice(
    107     const StreamDeviceInfo& device_info) {
    108   DVLOG(1) << "MediaStreamDispatcher::StopStreamDevice"
    109            << ", {device_id = " << device_info.device.id << "}";
    110   // Remove |device_info| from all streams in |label_stream_map_|.
    111   bool device_found = false;
    112   LabelStreamMap::iterator stream_it = label_stream_map_.begin();
    113   while (stream_it != label_stream_map_.end()) {
    114     StreamDeviceInfoArray& audio_array = stream_it->second.audio_array;
    115     StreamDeviceInfoArray& video_array = stream_it->second.video_array;
    116 
    117     if (RemoveStreamDeviceFromArray(device_info, &audio_array) ||
    118         RemoveStreamDeviceFromArray(device_info, &video_array)) {
    119       device_found = true;
    120       if (audio_array.empty() && video_array.empty()) {
    121         label_stream_map_.erase(stream_it++);
    122         continue;
    123       }
    124     }
    125     ++stream_it;
    126   }
    127   DCHECK(device_found);
    128 
    129   Send(new MediaStreamHostMsg_StopStreamDevice(routing_id(),
    130                                                device_info.device.id));
    131 }
    132 
    133 void MediaStreamDispatcher::EnumerateDevices(
    134     int request_id,
    135     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler,
    136     MediaStreamType type,
    137     const GURL& security_origin,
    138     bool hide_labels_if_no_access) {
    139   DCHECK(main_loop_->BelongsToCurrentThread());
    140   DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
    141          type == MEDIA_DEVICE_VIDEO_CAPTURE ||
    142          type == MEDIA_DEVICE_AUDIO_OUTPUT);
    143   DVLOG(1) << "MediaStreamDispatcher::EnumerateDevices("
    144            << request_id << ")";
    145 
    146   for (RequestList::iterator it = requests_.begin(); it != requests_.end();
    147        ++it) {
    148     DCHECK(!it->IsThisRequest(request_id, event_handler));
    149   }
    150 
    151   requests_.push_back(Request(event_handler, request_id, next_ipc_id_));
    152   Send(new MediaStreamHostMsg_EnumerateDevices(routing_id(),
    153                                                next_ipc_id_++,
    154                                                type,
    155                                                security_origin,
    156                                                hide_labels_if_no_access));
    157 }
    158 
    159 void MediaStreamDispatcher::StopEnumerateDevices(
    160     int request_id,
    161     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler) {
    162   DCHECK(main_loop_->BelongsToCurrentThread());
    163   DVLOG(1) << "MediaStreamDispatcher::StopEnumerateDevices("
    164            << request_id << ")";
    165   for (RequestList::iterator it = requests_.begin(); it != requests_.end();
    166        ++it) {
    167     if (it->IsThisRequest(request_id, event_handler)) {
    168       Send(new MediaStreamHostMsg_CancelEnumerateDevices(routing_id(),
    169                                                          it->ipc_request));
    170       requests_.erase(it);
    171       break;
    172     }
    173   }
    174 }
    175 
    176 void MediaStreamDispatcher::OpenDevice(
    177     int request_id,
    178     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler,
    179     const std::string& device_id,
    180     MediaStreamType type,
    181     const GURL& security_origin) {
    182   DCHECK(main_loop_->BelongsToCurrentThread());
    183   DVLOG(1) << "MediaStreamDispatcher::OpenDevice(" << request_id << ")";
    184 
    185   requests_.push_back(Request(event_handler, request_id, next_ipc_id_));
    186   Send(new MediaStreamHostMsg_OpenDevice(routing_id(),
    187                                          next_ipc_id_++,
    188                                          device_id,
    189                                          type,
    190                                          security_origin));
    191 }
    192 
    193 void MediaStreamDispatcher::CancelOpenDevice(
    194     int request_id,
    195     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler) {
    196   CancelGenerateStream(request_id, event_handler);
    197 }
    198 
    199 void MediaStreamDispatcher::CloseDevice(const std::string& label) {
    200   DCHECK(main_loop_->BelongsToCurrentThread());
    201   DCHECK(!label.empty());
    202   DVLOG(1) << "MediaStreamDispatcher::CloseDevice"
    203            << ", {label = " << label << "}";
    204 
    205   LabelStreamMap::iterator it = label_stream_map_.find(label);
    206   if (it == label_stream_map_.end())
    207     return;
    208   label_stream_map_.erase(it);
    209 
    210   Send(new MediaStreamHostMsg_CloseDevice(routing_id(), label));
    211 }
    212 
    213 bool MediaStreamDispatcher::Send(IPC::Message* message) {
    214   if (!RenderThread::Get()) {
    215     delete message;
    216     return false;
    217   }
    218 
    219   return RenderThread::Get()->Send(message);
    220 }
    221 
    222 bool MediaStreamDispatcher::OnMessageReceived(const IPC::Message& message) {
    223   bool handled = true;
    224   IPC_BEGIN_MESSAGE_MAP(MediaStreamDispatcher, message)
    225     IPC_MESSAGE_HANDLER(MediaStreamMsg_StreamGenerated,
    226                         OnStreamGenerated)
    227     IPC_MESSAGE_HANDLER(MediaStreamMsg_StreamGenerationFailed,
    228                         OnStreamGenerationFailed)
    229     IPC_MESSAGE_HANDLER(MediaStreamMsg_DeviceStopped,
    230                         OnDeviceStopped)
    231     IPC_MESSAGE_HANDLER(MediaStreamMsg_DevicesEnumerated,
    232                         OnDevicesEnumerated)
    233     IPC_MESSAGE_HANDLER(MediaStreamMsg_DeviceOpened,
    234                         OnDeviceOpened)
    235     IPC_MESSAGE_HANDLER(MediaStreamMsg_DeviceOpenFailed,
    236                         OnDeviceOpenFailed)
    237     IPC_MESSAGE_UNHANDLED(handled = false)
    238   IPC_END_MESSAGE_MAP()
    239   return handled;
    240 }
    241 
    242 void MediaStreamDispatcher::OnStreamGenerated(
    243     int request_id,
    244     const std::string& label,
    245     const StreamDeviceInfoArray& audio_array,
    246     const StreamDeviceInfoArray& video_array) {
    247   DCHECK(main_loop_->BelongsToCurrentThread());
    248 
    249   for (RequestList::iterator it = requests_.begin();
    250        it != requests_.end(); ++it) {
    251     Request& request = *it;
    252     if (request.ipc_request == request_id) {
    253       Stream new_stream;
    254       new_stream.handler = request.handler;
    255       new_stream.audio_array = audio_array;
    256       new_stream.video_array = video_array;
    257       label_stream_map_[label] = new_stream;
    258       if (request.handler.get()) {
    259         request.handler->OnStreamGenerated(
    260             request.request_id, label, audio_array, video_array);
    261         DVLOG(1) << "MediaStreamDispatcher::OnStreamGenerated("
    262                  << request.request_id << ", " << label << ")";
    263       }
    264       requests_.erase(it);
    265       break;
    266     }
    267   }
    268 }
    269 
    270 void MediaStreamDispatcher::OnStreamGenerationFailed(
    271     int request_id,
    272     content::MediaStreamRequestResult result) {
    273   DCHECK(main_loop_->BelongsToCurrentThread());
    274   for (RequestList::iterator it = requests_.begin();
    275        it != requests_.end(); ++it) {
    276     Request& request = *it;
    277     if (request.ipc_request == request_id) {
    278       if (request.handler.get()) {
    279         request.handler->OnStreamGenerationFailed(request.request_id, result);
    280         DVLOG(1) << "MediaStreamDispatcher::OnStreamGenerationFailed("
    281                  << request.request_id << ")\n";
    282       }
    283       requests_.erase(it);
    284       break;
    285     }
    286   }
    287 }
    288 
    289 void MediaStreamDispatcher::OnDeviceStopped(
    290     const std::string& label,
    291     const StreamDeviceInfo& device_info) {
    292   DCHECK(main_loop_->BelongsToCurrentThread());
    293   DVLOG(1) << "MediaStreamDispatcher::OnDeviceStopped("
    294            << "{label = " << label << "})"
    295            << ", {device_id = " << device_info.device.id << "})";
    296 
    297   LabelStreamMap::iterator it = label_stream_map_.find(label);
    298   if (it == label_stream_map_.end()) {
    299     // This can happen if a user happen stop a the device from JS at the same
    300     // time as the underlying media device is unplugged from the system.
    301     return;
    302   }
    303   Stream* stream = &it->second;
    304   if (IsAudioInputMediaType(device_info.device.type))
    305     RemoveStreamDeviceFromArray(device_info, &stream->audio_array);
    306   else
    307     RemoveStreamDeviceFromArray(device_info, &stream->video_array);
    308 
    309   if (stream->handler.get())
    310     stream->handler->OnDeviceStopped(label, device_info);
    311 
    312   if (stream->audio_array.empty() && stream->video_array.empty())
    313     label_stream_map_.erase(it);
    314 }
    315 
    316 void MediaStreamDispatcher::OnDevicesEnumerated(
    317     int request_id,
    318     const StreamDeviceInfoArray& device_array) {
    319   DCHECK(main_loop_->BelongsToCurrentThread());
    320   DCHECK_GE(request_id, 0);
    321 
    322   for (RequestList::iterator it = requests_.begin(); it != requests_.end();
    323        ++it) {
    324     if (it->ipc_request == request_id && it->handler.get()) {
    325       it->handler->OnDevicesEnumerated(it->request_id, device_array);
    326       break;
    327     }
    328   }
    329 }
    330 
    331 void MediaStreamDispatcher::OnDeviceOpened(
    332     int request_id,
    333     const std::string& label,
    334     const StreamDeviceInfo& device_info) {
    335   DCHECK(main_loop_->BelongsToCurrentThread());
    336   for (RequestList::iterator it = requests_.begin();
    337        it != requests_.end(); ++it) {
    338     Request& request = *it;
    339     if (request.ipc_request == request_id) {
    340       Stream new_stream;
    341       new_stream.handler = request.handler;
    342       if (IsAudioInputMediaType(device_info.device.type)) {
    343         new_stream.audio_array.push_back(device_info);
    344       } else if (IsVideoMediaType(device_info.device.type)) {
    345         new_stream.video_array.push_back(device_info);
    346       } else {
    347         NOTREACHED();
    348       }
    349       label_stream_map_[label] = new_stream;
    350       if (request.handler.get()) {
    351         request.handler->OnDeviceOpened(request.request_id, label, device_info);
    352         DVLOG(1) << "MediaStreamDispatcher::OnDeviceOpened("
    353                  << request.request_id << ", " << label << ")";
    354       }
    355       requests_.erase(it);
    356       break;
    357     }
    358   }
    359 }
    360 
    361 void MediaStreamDispatcher::OnDeviceOpenFailed(int request_id) {
    362   DCHECK(main_loop_->BelongsToCurrentThread());
    363   for (RequestList::iterator it = requests_.begin();
    364        it != requests_.end(); ++it) {
    365     Request& request = *it;
    366     if (request.ipc_request == request_id) {
    367       if (request.handler.get()) {
    368         request.handler->OnDeviceOpenFailed(request.request_id);
    369         DVLOG(1) << "MediaStreamDispatcher::OnDeviceOpenFailed("
    370                  << request.request_id << ")\n";
    371       }
    372       requests_.erase(it);
    373       break;
    374     }
    375   }
    376 }
    377 
    378 int MediaStreamDispatcher::audio_session_id(const std::string& label,
    379                                             int index) {
    380   LabelStreamMap::iterator it = label_stream_map_.find(label);
    381   if (it == label_stream_map_.end() ||
    382       it->second.audio_array.size() <= static_cast<size_t>(index)) {
    383     return StreamDeviceInfo::kNoId;
    384   }
    385   return it->second.audio_array[index].session_id;
    386 }
    387 
    388 bool MediaStreamDispatcher::IsStream(const std::string& label) {
    389   return label_stream_map_.find(label) != label_stream_map_.end();
    390 }
    391 
    392 int MediaStreamDispatcher::video_session_id(const std::string& label,
    393                                             int index) {
    394   LabelStreamMap::iterator it = label_stream_map_.find(label);
    395   if (it == label_stream_map_.end() ||
    396       it->second.video_array.size() <= static_cast<size_t>(index)) {
    397     return StreamDeviceInfo::kNoId;
    398   }
    399   return it->second.video_array[index].session_id;
    400 }
    401 
    402 }  // namespace content
    403