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/pepper/pepper_media_device_manager.h"
6
7#include "base/logging.h"
8#include "content/renderer/media/media_stream_dispatcher.h"
9#include "content/renderer/render_frame_impl.h"
10#include "ppapi/shared_impl/ppb_device_ref_shared.h"
11
12namespace content {
13
14namespace {
15
16ppapi::DeviceRefData FromStreamDeviceInfo(const StreamDeviceInfo& info) {
17  ppapi::DeviceRefData data;
18  data.id = info.device.id;
19  // Some Flash content can't handle an empty string, so stick a space in to
20  // make them happy. See crbug.com/408404.
21  data.name = info.device.name.empty() ? std::string(" ") : info.device.name;
22  data.type = PepperMediaDeviceManager::FromMediaStreamType(info.device.type);
23  return data;
24}
25
26}  // namespace
27
28base::WeakPtr<PepperMediaDeviceManager>
29PepperMediaDeviceManager::GetForRenderFrame(
30    RenderFrame* render_frame) {
31  PepperMediaDeviceManager* handler =
32      PepperMediaDeviceManager::Get(render_frame);
33  if (!handler)
34    handler = new PepperMediaDeviceManager(render_frame);
35  return handler->AsWeakPtr();
36}
37
38PepperMediaDeviceManager::PepperMediaDeviceManager(RenderFrame* render_frame)
39    : RenderFrameObserver(render_frame),
40      RenderFrameObserverTracker<PepperMediaDeviceManager>(render_frame),
41      next_id_(1) {}
42
43PepperMediaDeviceManager::~PepperMediaDeviceManager() {
44  DCHECK(enumerate_callbacks_.empty());
45  DCHECK(open_callbacks_.empty());
46}
47
48int PepperMediaDeviceManager::EnumerateDevices(
49    PP_DeviceType_Dev type,
50    const GURL& document_url,
51    const EnumerateDevicesCallback& callback) {
52  enumerate_callbacks_[next_id_] = callback;
53  int request_id = next_id_++;
54
55#if defined(ENABLE_WEBRTC)
56  GetMediaStreamDispatcher()->EnumerateDevices(
57      request_id,
58      AsWeakPtr(),
59      PepperMediaDeviceManager::FromPepperDeviceType(type),
60      document_url.GetOrigin());
61#else
62  base::MessageLoop::current()->PostTask(
63      FROM_HERE,
64      base::Bind(&PepperMediaDeviceManager::OnDevicesEnumerated,
65                 AsWeakPtr(),
66                 request_id,
67                 StreamDeviceInfoArray()));
68#endif
69
70  return request_id;
71}
72
73void PepperMediaDeviceManager::StopEnumerateDevices(int request_id) {
74  enumerate_callbacks_.erase(request_id);
75
76#if defined(ENABLE_WEBRTC)
77  // Need to post task since this function might be called inside the callback
78  // of EnumerateDevices.
79  base::MessageLoop::current()->PostTask(
80      FROM_HERE,
81      base::Bind(&PepperMediaDeviceManager::StopEnumerateDevicesDelayed,
82                 AsWeakPtr(),
83                 request_id));
84#endif
85}
86
87void PepperMediaDeviceManager::StopEnumerateDevicesDelayed(int request_id) {
88#if defined(ENABLE_WEBRTC)
89  // This method is being invoked by the message loop at some unknown
90  // point-in-time after StopEnumerateDevices().  Therefore, check that
91  // render_frame() is not NULL, in order to guarantee
92  // GetMediaStreamDispatcher() won't return NULL.
93  if (render_frame())
94    GetMediaStreamDispatcher()->StopEnumerateDevices(request_id, AsWeakPtr());
95#endif
96}
97
98int PepperMediaDeviceManager::OpenDevice(PP_DeviceType_Dev type,
99                                         const std::string& device_id,
100                                         const GURL& document_url,
101                                         const OpenDeviceCallback& callback) {
102  open_callbacks_[next_id_] = callback;
103  int request_id = next_id_++;
104
105#if defined(ENABLE_WEBRTC)
106  GetMediaStreamDispatcher()->OpenDevice(
107      request_id,
108      AsWeakPtr(),
109      device_id,
110      PepperMediaDeviceManager::FromPepperDeviceType(type),
111      document_url.GetOrigin());
112#else
113  base::MessageLoop::current()->PostTask(
114      FROM_HERE,
115      base::Bind(&PepperMediaDeviceManager::OnDeviceOpenFailed,
116                 AsWeakPtr(),
117                 request_id));
118#endif
119
120  return request_id;
121}
122
123void PepperMediaDeviceManager::CancelOpenDevice(int request_id) {
124  open_callbacks_.erase(request_id);
125
126#if defined(ENABLE_WEBRTC)
127  GetMediaStreamDispatcher()->CancelOpenDevice(request_id, AsWeakPtr());
128#endif
129}
130
131void PepperMediaDeviceManager::CloseDevice(const std::string& label) {
132#if defined(ENABLE_WEBRTC)
133  GetMediaStreamDispatcher()->CloseDevice(label);
134#endif
135}
136
137int PepperMediaDeviceManager::GetSessionID(PP_DeviceType_Dev type,
138                                           const std::string& label) {
139#if defined(ENABLE_WEBRTC)
140  switch (type) {
141    case PP_DEVICETYPE_DEV_AUDIOCAPTURE:
142      return GetMediaStreamDispatcher()->audio_session_id(label, 0);
143    case PP_DEVICETYPE_DEV_VIDEOCAPTURE:
144      return GetMediaStreamDispatcher()->video_session_id(label, 0);
145    default:
146      NOTREACHED();
147      return 0;
148  }
149#else
150  return 0;
151#endif
152}
153
154void PepperMediaDeviceManager::OnStreamGenerated(
155    int request_id,
156    const std::string& label,
157    const StreamDeviceInfoArray& audio_device_array,
158    const StreamDeviceInfoArray& video_device_array) {}
159
160void PepperMediaDeviceManager::OnStreamGenerationFailed(
161    int request_id,
162    content::MediaStreamRequestResult result) {}
163
164void PepperMediaDeviceManager::OnDeviceStopped(
165    const std::string& label,
166    const StreamDeviceInfo& device_info) {}
167
168void PepperMediaDeviceManager::OnDevicesEnumerated(
169    int request_id,
170    const StreamDeviceInfoArray& device_array) {
171  EnumerateCallbackMap::iterator iter = enumerate_callbacks_.find(request_id);
172  if (iter == enumerate_callbacks_.end()) {
173    // This might be enumerated result sent before StopEnumerateDevices is
174    // called since EnumerateDevices is persistent request.
175    return;
176  }
177
178  EnumerateDevicesCallback callback = iter->second;
179
180  std::vector<ppapi::DeviceRefData> devices;
181  devices.reserve(device_array.size());
182  for (StreamDeviceInfoArray::const_iterator info = device_array.begin();
183       info != device_array.end();
184       ++info) {
185    devices.push_back(FromStreamDeviceInfo(*info));
186  }
187  callback.Run(request_id, devices);
188}
189
190void PepperMediaDeviceManager::OnDeviceOpened(
191    int request_id,
192    const std::string& label,
193    const StreamDeviceInfo& device_info) {
194  NotifyDeviceOpened(request_id, true, label);
195}
196
197void PepperMediaDeviceManager::OnDeviceOpenFailed(int request_id) {
198  NotifyDeviceOpened(request_id, false, std::string());
199}
200
201// static
202MediaStreamType PepperMediaDeviceManager::FromPepperDeviceType(
203    PP_DeviceType_Dev type) {
204  switch (type) {
205    case PP_DEVICETYPE_DEV_INVALID:
206      return MEDIA_NO_SERVICE;
207    case PP_DEVICETYPE_DEV_AUDIOCAPTURE:
208      return MEDIA_DEVICE_AUDIO_CAPTURE;
209    case PP_DEVICETYPE_DEV_VIDEOCAPTURE:
210      return MEDIA_DEVICE_VIDEO_CAPTURE;
211    default:
212      NOTREACHED();
213      return MEDIA_NO_SERVICE;
214  }
215}
216
217// static
218PP_DeviceType_Dev PepperMediaDeviceManager::FromMediaStreamType(
219    MediaStreamType type) {
220  switch (type) {
221    case MEDIA_NO_SERVICE:
222      return PP_DEVICETYPE_DEV_INVALID;
223    case MEDIA_DEVICE_AUDIO_CAPTURE:
224      return PP_DEVICETYPE_DEV_AUDIOCAPTURE;
225    case MEDIA_DEVICE_VIDEO_CAPTURE:
226      return PP_DEVICETYPE_DEV_VIDEOCAPTURE;
227    default:
228      NOTREACHED();
229      return PP_DEVICETYPE_DEV_INVALID;
230  }
231}
232
233void PepperMediaDeviceManager::NotifyDeviceOpened(int request_id,
234                                                  bool succeeded,
235                                                  const std::string& label) {
236  OpenCallbackMap::iterator iter = open_callbacks_.find(request_id);
237  if (iter == open_callbacks_.end()) {
238    // The callback may have been unregistered.
239    return;
240  }
241
242  OpenDeviceCallback callback = iter->second;
243  open_callbacks_.erase(iter);
244
245  callback.Run(request_id, succeeded, label);
246}
247
248MediaStreamDispatcher* PepperMediaDeviceManager::GetMediaStreamDispatcher()
249    const {
250  DCHECK(render_frame());
251  MediaStreamDispatcher* const dispatcher =
252      static_cast<RenderFrameImpl*>(render_frame())->GetMediaStreamDispatcher();
253  DCHECK(dispatcher);
254  return dispatcher;
255}
256
257}  // namespace content
258