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 // A request is identified by pair (request_id, handler), or ipc_request.
     18 // There could be multiple clients making requests and each has its own
     19 // request_id sequence.
     20 // The ipc_request is garanteed to be unique when it's created in
     21 // MediaStreamDispatcher.
     22 struct MediaStreamDispatcher::Request {
     23   Request(const base::WeakPtr<MediaStreamDispatcherEventHandler>& handler,
     24           int request_id,
     25           int ipc_request)
     26       : handler(handler),
     27         request_id(request_id),
     28         ipc_request(ipc_request) {
     29   }
     30   bool IsThisRequest(
     31       int request_id1,
     32       const base::WeakPtr<MediaStreamDispatcherEventHandler>& handler1) {
     33     return (request_id1 == request_id && handler1.get() == handler.get());
     34   }
     35   base::WeakPtr<MediaStreamDispatcherEventHandler> handler;
     36   int request_id;
     37   int ipc_request;
     38 };
     39 
     40 struct MediaStreamDispatcher::Stream {
     41   Stream() {}
     42   ~Stream() {}
     43   base::WeakPtr<MediaStreamDispatcherEventHandler> handler;
     44   StreamDeviceInfoArray audio_array;
     45   StreamDeviceInfoArray video_array;
     46 };
     47 
     48 MediaStreamDispatcher::EnumerationRequest::EnumerationRequest(
     49     const base::WeakPtr<MediaStreamDispatcherEventHandler>& handler,
     50     int request_id)
     51     : handler(handler),
     52       request_id(request_id) {
     53 }
     54 
     55 MediaStreamDispatcher::EnumerationRequest::~EnumerationRequest() {}
     56 
     57 bool MediaStreamDispatcher::EnumerationRequest::IsThisRequest(
     58     int request_id1,
     59     const base::WeakPtr<MediaStreamDispatcherEventHandler>& handler1) {
     60   return (request_id1 == request_id && handler1.get() == handler.get());
     61 }
     62 
     63 MediaStreamDispatcher::EnumerationState::EnumerationState()
     64     : ipc_id(-1) {
     65 }
     66 
     67 MediaStreamDispatcher::EnumerationState::~EnumerationState() {}
     68 
     69 struct MediaStreamDispatcher::EnumerationState::CachedDevices {
     70   CachedDevices(const std::string& label,
     71                 const StreamDeviceInfoArray& device_array)
     72       : label(label),
     73         devices(device_array) {
     74   }
     75   ~CachedDevices() {}
     76 
     77   std::string label;
     78   StreamDeviceInfoArray devices;
     79 };
     80 
     81 MediaStreamDispatcher::MediaStreamDispatcher(RenderViewImpl* render_view)
     82     : RenderViewObserver(render_view),
     83       main_loop_(base::MessageLoopProxy::current()),
     84       next_ipc_id_(0) {
     85 }
     86 
     87 MediaStreamDispatcher::~MediaStreamDispatcher() {}
     88 
     89 void MediaStreamDispatcher::GenerateStream(
     90     int request_id,
     91     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler,
     92     const StreamOptions& components,
     93     const GURL& security_origin) {
     94   DCHECK(main_loop_->BelongsToCurrentThread());
     95   DVLOG(1) << "MediaStreamDispatcher::GenerateStream(" << request_id << ")";
     96 
     97   requests_.push_back(Request(event_handler, request_id, next_ipc_id_));
     98   Send(new MediaStreamHostMsg_GenerateStream(routing_id(),
     99                                              next_ipc_id_++,
    100                                              components,
    101                                              security_origin));
    102 }
    103 
    104 void MediaStreamDispatcher::CancelGenerateStream(
    105     int request_id,
    106     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler) {
    107   DCHECK(main_loop_->BelongsToCurrentThread());
    108   DVLOG(1) << "MediaStreamDispatcher::CancelGenerateStream"
    109            << ", {request_id = " << request_id << "}";
    110 
    111   RequestList::iterator it = requests_.begin();
    112   for (; it != requests_.end(); ++it) {
    113     if (it->IsThisRequest(request_id, event_handler)) {
    114       int ipc_request = it->ipc_request;
    115       requests_.erase(it);
    116       Send(new MediaStreamHostMsg_CancelGenerateStream(routing_id(),
    117                                                        ipc_request));
    118       break;
    119     }
    120   }
    121 }
    122 
    123 void MediaStreamDispatcher::StopStream(const std::string& label) {
    124   DCHECK(main_loop_->BelongsToCurrentThread());
    125   DVLOG(1) << "MediaStreamDispatcher::StopStream"
    126            << ", {label = " << label << "}";
    127 
    128   LabelStreamMap::iterator it = label_stream_map_.find(label);
    129   if (it == label_stream_map_.end())
    130     return;
    131 
    132   Send(new MediaStreamHostMsg_StopGeneratedStream(routing_id(), label));
    133   label_stream_map_.erase(it);
    134 }
    135 
    136 void MediaStreamDispatcher::EnumerateDevices(
    137     int request_id,
    138     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler,
    139     MediaStreamType type,
    140     const GURL& security_origin) {
    141   DCHECK(main_loop_->BelongsToCurrentThread());
    142   DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
    143          type == MEDIA_DEVICE_VIDEO_CAPTURE);
    144   DVLOG(1) << "MediaStreamDispatcher::EnumerateDevices("
    145            << request_id << ")";
    146 
    147   EnumerationState* state =
    148       (type == MEDIA_DEVICE_AUDIO_CAPTURE ?
    149        &audio_enumeration_state_ : &video_enumeration_state_);
    150   state->requests.push_back(EnumerationRequest(event_handler, request_id));
    151 
    152   if (state->cached_devices) {
    153     event_handler->OnDevicesEnumerated(
    154         request_id, state->cached_devices->devices);
    155   } else if (state->ipc_id < 0) {
    156     Send(new MediaStreamHostMsg_EnumerateDevices(routing_id(),
    157                                                  next_ipc_id_,
    158                                                  type,
    159                                                  security_origin));
    160     state->ipc_id = next_ipc_id_++;
    161   }
    162 }
    163 
    164 void MediaStreamDispatcher::StopEnumerateDevices(
    165     int request_id,
    166     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler) {
    167   DCHECK(main_loop_->BelongsToCurrentThread());
    168   DVLOG(1) << "MediaStreamDispatcher::StopEnumerateDevices("
    169            << request_id << ")";
    170 
    171   // Remove the request.
    172   RemoveEnumerationRequest(
    173       request_id, event_handler, &audio_enumeration_state_);
    174   RemoveEnumerationRequest(
    175       request_id, event_handler, &video_enumeration_state_);
    176 }
    177 
    178 void MediaStreamDispatcher::RemoveEnumerationRequest(
    179     int request_id,
    180     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler,
    181     EnumerationState* state) {
    182   EnumerationRequestList* requests = &state->requests;
    183   for (EnumerationRequestList::iterator it = requests->begin();
    184        it != requests->end(); ++it) {
    185     if (it->IsThisRequest(request_id, event_handler)) {
    186       requests->erase(it);
    187       if (requests->empty() && state->cached_devices) {
    188         // No more request and has a label, try to stop the label
    189         // and invalidate the state.
    190         Send(new MediaStreamHostMsg_StopGeneratedStream(
    191             routing_id(), state->cached_devices->label));
    192         state->ipc_id = -1;
    193         state->cached_devices.reset();
    194       }
    195       return;
    196     }
    197   }
    198 }
    199 
    200 void MediaStreamDispatcher::OpenDevice(
    201     int request_id,
    202     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler,
    203     const std::string& device_id,
    204     MediaStreamType type,
    205     const GURL& security_origin) {
    206   DCHECK(main_loop_->BelongsToCurrentThread());
    207   DVLOG(1) << "MediaStreamDispatcher::OpenDevice(" << request_id << ")";
    208 
    209   requests_.push_back(Request(event_handler, request_id, next_ipc_id_));
    210   Send(new MediaStreamHostMsg_OpenDevice(routing_id(),
    211                                          next_ipc_id_++,
    212                                          device_id,
    213                                          type,
    214                                          security_origin));
    215 }
    216 
    217 void MediaStreamDispatcher::CancelOpenDevice(
    218     int request_id,
    219     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler) {
    220   CancelGenerateStream(request_id, event_handler);
    221 }
    222 
    223 void MediaStreamDispatcher::CloseDevice(const std::string& label) {
    224   DCHECK(main_loop_->BelongsToCurrentThread());
    225   DVLOG(1) << "MediaStreamDispatcher::CloseDevice"
    226            << ", {label = " << label << "}";
    227 
    228   StopStream(label);
    229 }
    230 
    231 bool MediaStreamDispatcher::Send(IPC::Message* message) {
    232   if (!RenderThread::Get()) {
    233     delete message;
    234     return false;
    235   }
    236 
    237   return RenderThread::Get()->Send(message);
    238 }
    239 
    240 bool MediaStreamDispatcher::OnMessageReceived(const IPC::Message& message) {
    241   bool handled = true;
    242   IPC_BEGIN_MESSAGE_MAP(MediaStreamDispatcher, message)
    243     IPC_MESSAGE_HANDLER(MediaStreamMsg_StreamGenerated,
    244                         OnStreamGenerated)
    245     IPC_MESSAGE_HANDLER(MediaStreamMsg_StreamGenerationFailed,
    246                         OnStreamGenerationFailed)
    247     IPC_MESSAGE_HANDLER(MediaStreamMsg_StopGeneratedStream,
    248                         OnStopGeneratedStream)
    249     IPC_MESSAGE_HANDLER(MediaStreamMsg_DevicesEnumerated,
    250                         OnDevicesEnumerated)
    251     IPC_MESSAGE_HANDLER(MediaStreamMsg_DevicesEnumerationFailed,
    252                         OnDevicesEnumerationFailed)
    253     IPC_MESSAGE_HANDLER(MediaStreamMsg_DeviceOpened,
    254                         OnDeviceOpened)
    255     IPC_MESSAGE_HANDLER(MediaStreamMsg_DeviceOpenFailed,
    256                         OnDeviceOpenFailed)
    257     IPC_MESSAGE_UNHANDLED(handled = false)
    258   IPC_END_MESSAGE_MAP()
    259   return handled;
    260 }
    261 
    262 void MediaStreamDispatcher::OnStreamGenerated(
    263     int request_id,
    264     const std::string& label,
    265     const StreamDeviceInfoArray& audio_array,
    266     const StreamDeviceInfoArray& video_array) {
    267   DCHECK(main_loop_->BelongsToCurrentThread());
    268 
    269   for (RequestList::iterator it = requests_.begin();
    270        it != requests_.end(); ++it) {
    271     Request& request = *it;
    272     if (request.ipc_request == request_id) {
    273       Stream new_stream;
    274       new_stream.handler = request.handler;
    275       new_stream.audio_array = audio_array;
    276       new_stream.video_array = video_array;
    277       label_stream_map_[label] = new_stream;
    278       if (request.handler.get()) {
    279         request.handler->OnStreamGenerated(
    280             request.request_id, label, audio_array, video_array);
    281         DVLOG(1) << "MediaStreamDispatcher::OnStreamGenerated("
    282                  << request.request_id << ", " << label << ")";
    283       }
    284       requests_.erase(it);
    285       break;
    286     }
    287   }
    288 }
    289 
    290 void MediaStreamDispatcher::OnStreamGenerationFailed(int request_id) {
    291   DCHECK(main_loop_->BelongsToCurrentThread());
    292   for (RequestList::iterator it = requests_.begin();
    293        it != requests_.end(); ++it) {
    294     Request& request = *it;
    295     if (request.ipc_request == request_id) {
    296       if (request.handler.get()) {
    297         request.handler->OnStreamGenerationFailed(request.request_id);
    298         DVLOG(1) << "MediaStreamDispatcher::OnStreamGenerationFailed("
    299                  << request.request_id << ")\n";
    300       }
    301       requests_.erase(it);
    302       break;
    303     }
    304   }
    305 }
    306 
    307 void MediaStreamDispatcher::OnStopGeneratedStream(const std::string& label) {
    308   DCHECK(main_loop_->BelongsToCurrentThread());
    309   LabelStreamMap::iterator it = label_stream_map_.find(label);
    310   if (it == label_stream_map_.end())
    311     return;
    312 
    313   if (it->second.handler.get()) {
    314     it->second.handler->OnStopGeneratedStream(label);
    315     DVLOG(1) << "MediaStreamDispatcher::OnStopGeneratedStream("
    316              << label << ")\n";
    317   }
    318   label_stream_map_.erase(it);
    319 }
    320 
    321 void MediaStreamDispatcher::OnDevicesEnumerated(
    322     int request_id,
    323     const std::string& label,
    324     const StreamDeviceInfoArray& device_array) {
    325   DCHECK(main_loop_->BelongsToCurrentThread());
    326   DCHECK_GE(request_id, 0);
    327 
    328   EnumerationState* state;
    329   if (request_id == audio_enumeration_state_.ipc_id) {
    330     state = &audio_enumeration_state_;
    331   } else if (request_id == video_enumeration_state_.ipc_id) {
    332     state = &video_enumeration_state_;
    333   } else {
    334     // This could happen when requester has stopped enumeration while some
    335     // enumerated response is on the way. Have to stop the |label| because
    336     // this might be the first enumerated device list is received. This also
    337     // lead to same label being stopped multiple times.
    338     Send(new MediaStreamHostMsg_StopGeneratedStream(routing_id(), label));
    339     return;
    340   }
    341 
    342   DCHECK(!label.empty());
    343   state->cached_devices.reset(new EnumerationState::CachedDevices(
    344       label, device_array));
    345 
    346   for (EnumerationRequestList::iterator it = state->requests.begin();
    347        it != state->requests.end(); ++it) {
    348     if (it->handler.get()) {
    349       it->handler->OnDevicesEnumerated(it->request_id, device_array);
    350       DVLOG(1) << "MediaStreamDispatcher::OnDevicesEnumerated("
    351                << it->request_id << ")";
    352     }
    353   }
    354 }
    355 
    356 void MediaStreamDispatcher::OnDevicesEnumerationFailed(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->OnDevicesEnumerationFailed(request.request_id);
    364         DVLOG(1) << "MediaStreamDispatcher::OnDevicesEnumerationFailed("
    365                  << request.request_id << ")\n";
    366       }
    367       requests_.erase(it);
    368       break;
    369     }
    370   }
    371 }
    372 
    373 void MediaStreamDispatcher::OnDeviceOpened(
    374     int request_id,
    375     const std::string& label,
    376     const StreamDeviceInfo& device_info) {
    377   DCHECK(main_loop_->BelongsToCurrentThread());
    378   for (RequestList::iterator it = requests_.begin();
    379        it != requests_.end(); ++it) {
    380     Request& request = *it;
    381     if (request.ipc_request == request_id) {
    382       Stream new_stream;
    383       new_stream.handler = request.handler;
    384       if (IsAudioMediaType(device_info.device.type)) {
    385         new_stream.audio_array.push_back(device_info);
    386       } else if (IsVideoMediaType(device_info.device.type)) {
    387         new_stream.video_array.push_back(device_info);
    388       } else {
    389         NOTREACHED();
    390       }
    391       label_stream_map_[label] = new_stream;
    392       if (request.handler.get()) {
    393         request.handler->OnDeviceOpened(request.request_id, label, device_info);
    394         DVLOG(1) << "MediaStreamDispatcher::OnDeviceOpened("
    395                  << request.request_id << ", " << label << ")";
    396       }
    397       requests_.erase(it);
    398       break;
    399     }
    400   }
    401 }
    402 
    403 void MediaStreamDispatcher::OnDeviceOpenFailed(int request_id) {
    404   DCHECK(main_loop_->BelongsToCurrentThread());
    405   for (RequestList::iterator it = requests_.begin();
    406        it != requests_.end(); ++it) {
    407     Request& request = *it;
    408     if (request.ipc_request == request_id) {
    409       if (request.handler.get()) {
    410         request.handler->OnDeviceOpenFailed(request.request_id);
    411         DVLOG(1) << "MediaStreamDispatcher::OnDeviceOpenFailed("
    412                  << request.request_id << ")\n";
    413       }
    414       requests_.erase(it);
    415       break;
    416     }
    417   }
    418 }
    419 
    420 int MediaStreamDispatcher::audio_session_id(const std::string& label,
    421                                             int index) {
    422   LabelStreamMap::iterator it = label_stream_map_.find(label);
    423   if (it == label_stream_map_.end())
    424     return StreamDeviceInfo::kNoId;
    425 
    426   DCHECK_GT(it->second.audio_array.size(), static_cast<size_t>(index));
    427   return it->second.audio_array[index].session_id;
    428 }
    429 
    430 bool MediaStreamDispatcher::IsStream(const std::string& label) {
    431   return label_stream_map_.find(label) != label_stream_map_.end();
    432 }
    433 
    434 int MediaStreamDispatcher::video_session_id(const std::string& label,
    435                                             int index) {
    436   LabelStreamMap::iterator it = label_stream_map_.find(label);
    437   if (it == label_stream_map_.end())
    438     return StreamDeviceInfo::kNoId;
    439 
    440   DCHECK_GT(it->second.video_array.size(), static_cast<size_t>(index));
    441   return it->second.video_array[index].session_id;
    442 }
    443 
    444 }  // namespace content
    445