Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / media_stream_dispatcher.cc
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