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