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 "content/common/media/media_stream_messages.h"
      9 #include "content/renderer/media/media_stream_dispatcher_eventhandler.h"
     10 #include "content/renderer/render_thread_impl.h"
     11 #include "media/audio/audio_parameters.h"
     12 #include "third_party/WebKit/public/web/WebUserGestureIndicator.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(RenderFrame* render_frame)
     65     : RenderFrameObserver(render_frame),
     66       next_ipc_id_(0) {
     67 }
     68 
     69 MediaStreamDispatcher::~MediaStreamDispatcher() {}
     70 
     71 void MediaStreamDispatcher::GenerateStream(
     72     int request_id,
     73     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler,
     74     const StreamOptions& components,
     75     const GURL& security_origin) {
     76   DCHECK(thread_checker_.CalledOnValidThread());
     77   DVLOG(1) << "MediaStreamDispatcher::GenerateStream(" << request_id << ")";
     78 
     79   requests_.push_back(Request(event_handler, request_id, next_ipc_id_));
     80   Send(new MediaStreamHostMsg_GenerateStream(
     81       routing_id(), next_ipc_id_++, components, security_origin,
     82       blink::WebUserGestureIndicator::isProcessingUserGesture()));
     83 }
     84 
     85 void MediaStreamDispatcher::CancelGenerateStream(
     86     int request_id,
     87     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler) {
     88   DCHECK(thread_checker_.CalledOnValidThread());
     89   DVLOG(1) << "MediaStreamDispatcher::CancelGenerateStream"
     90            << ", {request_id = " << request_id << "}";
     91 
     92   RequestList::iterator it = requests_.begin();
     93   for (; it != requests_.end(); ++it) {
     94     if (it->IsThisRequest(request_id, event_handler)) {
     95       int ipc_request = it->ipc_request;
     96       requests_.erase(it);
     97       Send(new MediaStreamHostMsg_CancelGenerateStream(routing_id(),
     98                                                        ipc_request));
     99       break;
    100     }
    101   }
    102 }
    103 
    104 void MediaStreamDispatcher::StopStreamDevice(
    105     const StreamDeviceInfo& device_info) {
    106   DCHECK(thread_checker_.CalledOnValidThread());
    107   DVLOG(1) << "MediaStreamDispatcher::StopStreamDevice"
    108            << ", {device_id = " << device_info.device.id << "}";
    109   // Remove |device_info| from all streams in |label_stream_map_|.
    110   bool device_found = false;
    111   LabelStreamMap::iterator stream_it = label_stream_map_.begin();
    112   while (stream_it != label_stream_map_.end()) {
    113     StreamDeviceInfoArray& audio_array = stream_it->second.audio_array;
    114     StreamDeviceInfoArray& video_array = stream_it->second.video_array;
    115 
    116     if (RemoveStreamDeviceFromArray(device_info, &audio_array) ||
    117         RemoveStreamDeviceFromArray(device_info, &video_array)) {
    118       device_found = true;
    119       if (audio_array.empty() && video_array.empty()) {
    120         label_stream_map_.erase(stream_it++);
    121         continue;
    122       }
    123     }
    124     ++stream_it;
    125   }
    126   DCHECK(device_found);
    127 
    128   Send(new MediaStreamHostMsg_StopStreamDevice(routing_id(),
    129                                                device_info.device.id));
    130 }
    131 
    132 void MediaStreamDispatcher::EnumerateDevices(
    133     int request_id,
    134     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler,
    135     MediaStreamType type,
    136     const GURL& security_origin) {
    137   DCHECK(thread_checker_.CalledOnValidThread());
    138   DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
    139          type == MEDIA_DEVICE_VIDEO_CAPTURE ||
    140          type == MEDIA_DEVICE_AUDIO_OUTPUT);
    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(thread_checker_.CalledOnValidThread());
    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(thread_checker_.CalledOnValidThread());
    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(thread_checker_.CalledOnValidThread());
    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 void MediaStreamDispatcher::OnDestruct() {
    211   // Do not self-destruct. UserMediaClientImpl owns |this|.
    212 }
    213 
    214 bool MediaStreamDispatcher::Send(IPC::Message* message) {
    215   if (!RenderThread::Get()) {
    216     delete message;
    217     return false;
    218   }
    219 
    220   return RenderThread::Get()->Send(message);
    221 }
    222 
    223 bool MediaStreamDispatcher::OnMessageReceived(const IPC::Message& message) {
    224   bool handled = true;
    225   IPC_BEGIN_MESSAGE_MAP(MediaStreamDispatcher, message)
    226     IPC_MESSAGE_HANDLER(MediaStreamMsg_StreamGenerated,
    227                         OnStreamGenerated)
    228     IPC_MESSAGE_HANDLER(MediaStreamMsg_StreamGenerationFailed,
    229                         OnStreamGenerationFailed)
    230     IPC_MESSAGE_HANDLER(MediaStreamMsg_DeviceStopped,
    231                         OnDeviceStopped)
    232     IPC_MESSAGE_HANDLER(MediaStreamMsg_DevicesEnumerated,
    233                         OnDevicesEnumerated)
    234     IPC_MESSAGE_HANDLER(MediaStreamMsg_DeviceOpened,
    235                         OnDeviceOpened)
    236     IPC_MESSAGE_HANDLER(MediaStreamMsg_DeviceOpenFailed,
    237                         OnDeviceOpenFailed)
    238     IPC_MESSAGE_UNHANDLED(handled = false)
    239   IPC_END_MESSAGE_MAP()
    240   return handled;
    241 }
    242 
    243 void MediaStreamDispatcher::OnStreamGenerated(
    244     int request_id,
    245     const std::string& label,
    246     const StreamDeviceInfoArray& audio_array,
    247     const StreamDeviceInfoArray& video_array) {
    248   DCHECK(thread_checker_.CalledOnValidThread());
    249 
    250   for (RequestList::iterator it = requests_.begin();
    251        it != requests_.end(); ++it) {
    252     Request& request = *it;
    253     if (request.ipc_request == request_id) {
    254       Stream new_stream;
    255       new_stream.handler = request.handler;
    256       new_stream.audio_array = audio_array;
    257       new_stream.video_array = video_array;
    258       label_stream_map_[label] = new_stream;
    259       if (request.handler.get()) {
    260         request.handler->OnStreamGenerated(
    261             request.request_id, label, audio_array, video_array);
    262         DVLOG(1) << "MediaStreamDispatcher::OnStreamGenerated("
    263                  << request.request_id << ", " << label << ")";
    264       }
    265       requests_.erase(it);
    266       break;
    267     }
    268   }
    269 }
    270 
    271 void MediaStreamDispatcher::OnStreamGenerationFailed(
    272     int request_id,
    273     content::MediaStreamRequestResult result) {
    274   DCHECK(thread_checker_.CalledOnValidThread());
    275   for (RequestList::iterator it = requests_.begin();
    276        it != requests_.end(); ++it) {
    277     Request& request = *it;
    278     if (request.ipc_request == request_id) {
    279       if (request.handler.get()) {
    280         request.handler->OnStreamGenerationFailed(request.request_id, result);
    281         DVLOG(1) << "MediaStreamDispatcher::OnStreamGenerationFailed("
    282                  << request.request_id << ")\n";
    283       }
    284       requests_.erase(it);
    285       break;
    286     }
    287   }
    288 }
    289 
    290 void MediaStreamDispatcher::OnDeviceStopped(
    291     const std::string& label,
    292     const StreamDeviceInfo& device_info) {
    293   DCHECK(thread_checker_.CalledOnValidThread());
    294   DVLOG(1) << "MediaStreamDispatcher::OnDeviceStopped("
    295            << "{label = " << label << "})"
    296            << ", {device_id = " << device_info.device.id << "})";
    297 
    298   LabelStreamMap::iterator it = label_stream_map_.find(label);
    299   if (it == label_stream_map_.end()) {
    300     // This can happen if a user happen stop a the device from JS at the same
    301     // time as the underlying media device is unplugged from the system.
    302     return;
    303   }
    304   Stream* stream = &it->second;
    305   if (IsAudioInputMediaType(device_info.device.type))
    306     RemoveStreamDeviceFromArray(device_info, &stream->audio_array);
    307   else
    308     RemoveStreamDeviceFromArray(device_info, &stream->video_array);
    309 
    310   if (stream->handler.get())
    311     stream->handler->OnDeviceStopped(label, device_info);
    312 
    313   if (stream->audio_array.empty() && stream->video_array.empty())
    314     label_stream_map_.erase(it);
    315 }
    316 
    317 void MediaStreamDispatcher::OnDevicesEnumerated(
    318     int request_id,
    319     const StreamDeviceInfoArray& device_array) {
    320   DCHECK(thread_checker_.CalledOnValidThread());
    321   DCHECK_GE(request_id, 0);
    322 
    323   for (RequestList::iterator it = requests_.begin(); it != requests_.end();
    324        ++it) {
    325     if (it->ipc_request == request_id && it->handler.get()) {
    326       it->handler->OnDevicesEnumerated(it->request_id, device_array);
    327       break;
    328     }
    329   }
    330 }
    331 
    332 void MediaStreamDispatcher::OnDeviceOpened(
    333     int request_id,
    334     const std::string& label,
    335     const StreamDeviceInfo& device_info) {
    336   DCHECK(thread_checker_.CalledOnValidThread());
    337   for (RequestList::iterator it = requests_.begin();
    338        it != requests_.end(); ++it) {
    339     Request& request = *it;
    340     if (request.ipc_request == request_id) {
    341       Stream new_stream;
    342       new_stream.handler = request.handler;
    343       if (IsAudioInputMediaType(device_info.device.type)) {
    344         new_stream.audio_array.push_back(device_info);
    345       } else if (IsVideoMediaType(device_info.device.type)) {
    346         new_stream.video_array.push_back(device_info);
    347       } else {
    348         NOTREACHED();
    349       }
    350       label_stream_map_[label] = new_stream;
    351       if (request.handler.get()) {
    352         request.handler->OnDeviceOpened(request.request_id, label, device_info);
    353         DVLOG(1) << "MediaStreamDispatcher::OnDeviceOpened("
    354                  << request.request_id << ", " << label << ")";
    355       }
    356       requests_.erase(it);
    357       break;
    358     }
    359   }
    360 }
    361 
    362 void MediaStreamDispatcher::OnDeviceOpenFailed(int request_id) {
    363   DCHECK(thread_checker_.CalledOnValidThread());
    364   for (RequestList::iterator it = requests_.begin();
    365        it != requests_.end(); ++it) {
    366     Request& request = *it;
    367     if (request.ipc_request == request_id) {
    368       if (request.handler.get()) {
    369         request.handler->OnDeviceOpenFailed(request.request_id);
    370         DVLOG(1) << "MediaStreamDispatcher::OnDeviceOpenFailed("
    371                  << request.request_id << ")\n";
    372       }
    373       requests_.erase(it);
    374       break;
    375     }
    376   }
    377 }
    378 
    379 int MediaStreamDispatcher::audio_session_id(const std::string& label,
    380                                             int index) {
    381   DCHECK(thread_checker_.CalledOnValidThread());
    382   LabelStreamMap::iterator it = label_stream_map_.find(label);
    383   if (it == label_stream_map_.end() ||
    384       it->second.audio_array.size() <= static_cast<size_t>(index)) {
    385     return StreamDeviceInfo::kNoId;
    386   }
    387   return it->second.audio_array[index].session_id;
    388 }
    389 
    390 bool MediaStreamDispatcher::IsStream(const std::string& label) {
    391   DCHECK(thread_checker_.CalledOnValidThread());
    392   return label_stream_map_.find(label) != label_stream_map_.end();
    393 }
    394 
    395 int MediaStreamDispatcher::video_session_id(const std::string& label,
    396                                             int index) {
    397   DCHECK(thread_checker_.CalledOnValidThread());
    398   LabelStreamMap::iterator it = label_stream_map_.find(label);
    399   if (it == label_stream_map_.end() ||
    400       it->second.video_array.size() <= static_cast<size_t>(index)) {
    401     return StreamDeviceInfo::kNoId;
    402   }
    403   return it->second.video_array[index].session_id;
    404 }
    405 
    406 bool MediaStreamDispatcher::IsAudioDuckingActive() const {
    407   DCHECK(thread_checker_.CalledOnValidThread());
    408   LabelStreamMap::const_iterator stream_it = label_stream_map_.begin();
    409   while (stream_it != label_stream_map_.end()) {
    410     const StreamDeviceInfoArray& audio_array = stream_it->second.audio_array;
    411     for (StreamDeviceInfoArray::const_iterator device_it = audio_array.begin();
    412          device_it != audio_array.end(); ++device_it) {
    413       if (device_it->device.input.effects & media::AudioParameters::DUCKING)
    414         return true;
    415     }
    416     ++stream_it;
    417   }
    418   return false;
    419 }
    420 
    421 }  // namespace content
    422