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_view_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  data.name = info.device.name;
20  data.type = PepperMediaDeviceManager::FromMediaStreamType(info.device.type);
21  return data;
22}
23
24}  // namespace
25
26PepperMediaDeviceManager* PepperMediaDeviceManager::GetForRenderView(
27    RenderView* render_view) {
28  PepperMediaDeviceManager* handler =
29      PepperMediaDeviceManager::Get(render_view);
30  if (!handler)
31    handler = new PepperMediaDeviceManager(render_view);
32  return handler;
33}
34
35PepperMediaDeviceManager::PepperMediaDeviceManager(RenderView* render_view)
36    : RenderViewObserver(render_view),
37      RenderViewObserverTracker<PepperMediaDeviceManager>(render_view),
38      next_id_(1) {}
39
40PepperMediaDeviceManager::~PepperMediaDeviceManager() {
41  DCHECK(enumerate_callbacks_.empty());
42  DCHECK(open_callbacks_.empty());
43}
44
45int PepperMediaDeviceManager::EnumerateDevices(
46    PP_DeviceType_Dev type,
47    const GURL& document_url,
48    const EnumerateDevicesCallback& callback) {
49  enumerate_callbacks_[next_id_] = callback;
50  int request_id = next_id_++;
51
52#if defined(ENABLE_WEBRTC)
53  GetRenderViewImpl()->media_stream_dispatcher()->EnumerateDevices(
54      request_id,
55      AsWeakPtr(),
56      PepperMediaDeviceManager::FromPepperDeviceType(type),
57      document_url.GetOrigin(),
58      false);
59#else
60  base::MessageLoop::current()->PostTask(
61      FROM_HERE,
62      base::Bind(&PepperMediaDeviceManager::OnDevicesEnumerated,
63                 AsWeakPtr(),
64                 request_id,
65                 StreamDeviceInfoArray()));
66#endif
67
68  return request_id;
69}
70
71void PepperMediaDeviceManager::StopEnumerateDevices(int request_id) {
72  enumerate_callbacks_.erase(request_id);
73
74#if defined(ENABLE_WEBRTC)
75  // Need to post task since this function might be called inside the callback
76  // of EnumerateDevices.
77  base::MessageLoop::current()->PostTask(
78      FROM_HERE,
79      base::Bind(&MediaStreamDispatcher::StopEnumerateDevices,
80                 GetRenderViewImpl()->media_stream_dispatcher()->AsWeakPtr(),
81                 request_id,
82                 AsWeakPtr()));
83#endif
84}
85
86int PepperMediaDeviceManager::OpenDevice(PP_DeviceType_Dev type,
87                                         const std::string& device_id,
88                                         const GURL& document_url,
89                                         const OpenDeviceCallback& callback) {
90  open_callbacks_[next_id_] = callback;
91  int request_id = next_id_++;
92
93#if defined(ENABLE_WEBRTC)
94  GetRenderViewImpl()->media_stream_dispatcher()->OpenDevice(
95      request_id,
96      AsWeakPtr(),
97      device_id,
98      PepperMediaDeviceManager::FromPepperDeviceType(type),
99      document_url.GetOrigin());
100#else
101  base::MessageLoop::current()->PostTask(
102      FROM_HERE,
103      base::Bind(&PepperMediaDeviceManager::OnDeviceOpenFailed,
104                 AsWeakPtr(),
105                 request_id));
106#endif
107
108  return request_id;
109}
110
111void PepperMediaDeviceManager::CancelOpenDevice(int request_id) {
112  open_callbacks_.erase(request_id);
113
114#if defined(ENABLE_WEBRTC)
115  GetRenderViewImpl()->media_stream_dispatcher()->CancelOpenDevice(request_id,
116                                                                   AsWeakPtr());
117#endif
118}
119
120void PepperMediaDeviceManager::CloseDevice(const std::string& label) {
121#if defined(ENABLE_WEBRTC)
122  GetRenderViewImpl()->media_stream_dispatcher()->CloseDevice(label);
123#endif
124}
125
126int PepperMediaDeviceManager::GetSessionID(PP_DeviceType_Dev type,
127                                           const std::string& label) {
128#if defined(ENABLE_WEBRTC)
129  switch (type) {
130    case PP_DEVICETYPE_DEV_AUDIOCAPTURE:
131      return GetRenderViewImpl()->media_stream_dispatcher()->audio_session_id(
132          label, 0);
133    case PP_DEVICETYPE_DEV_VIDEOCAPTURE:
134      return GetRenderViewImpl()->media_stream_dispatcher()->video_session_id(
135          label, 0);
136    default:
137      NOTREACHED();
138      return 0;
139  }
140#else
141  return 0;
142#endif
143}
144
145void PepperMediaDeviceManager::OnStreamGenerated(
146    int request_id,
147    const std::string& label,
148    const StreamDeviceInfoArray& audio_device_array,
149    const StreamDeviceInfoArray& video_device_array) {}
150
151void PepperMediaDeviceManager::OnStreamGenerationFailed(
152    int request_id,
153    content::MediaStreamRequestResult result) {}
154
155void PepperMediaDeviceManager::OnDeviceStopped(
156    const std::string& label,
157    const StreamDeviceInfo& device_info) {}
158
159void PepperMediaDeviceManager::OnDevicesEnumerated(
160    int request_id,
161    const StreamDeviceInfoArray& device_array) {
162  EnumerateCallbackMap::iterator iter = enumerate_callbacks_.find(request_id);
163  if (iter == enumerate_callbacks_.end()) {
164    // This might be enumerated result sent before StopEnumerateDevices is
165    // called since EnumerateDevices is persistent request.
166    return;
167  }
168
169  EnumerateDevicesCallback callback = iter->second;
170
171  std::vector<ppapi::DeviceRefData> devices;
172  devices.reserve(device_array.size());
173  for (StreamDeviceInfoArray::const_iterator info = device_array.begin();
174       info != device_array.end();
175       ++info) {
176    devices.push_back(FromStreamDeviceInfo(*info));
177  }
178  callback.Run(request_id, devices);
179}
180
181void PepperMediaDeviceManager::OnDeviceOpened(
182    int request_id,
183    const std::string& label,
184    const StreamDeviceInfo& device_info) {
185  NotifyDeviceOpened(request_id, true, label);
186}
187
188void PepperMediaDeviceManager::OnDeviceOpenFailed(int request_id) {
189  NotifyDeviceOpened(request_id, false, std::string());
190}
191
192// static
193MediaStreamType PepperMediaDeviceManager::FromPepperDeviceType(
194    PP_DeviceType_Dev type) {
195  switch (type) {
196    case PP_DEVICETYPE_DEV_INVALID:
197      return MEDIA_NO_SERVICE;
198    case PP_DEVICETYPE_DEV_AUDIOCAPTURE:
199      return MEDIA_DEVICE_AUDIO_CAPTURE;
200    case PP_DEVICETYPE_DEV_VIDEOCAPTURE:
201      return MEDIA_DEVICE_VIDEO_CAPTURE;
202    default:
203      NOTREACHED();
204      return MEDIA_NO_SERVICE;
205  }
206}
207
208// static
209PP_DeviceType_Dev PepperMediaDeviceManager::FromMediaStreamType(
210    MediaStreamType type) {
211  switch (type) {
212    case MEDIA_NO_SERVICE:
213      return PP_DEVICETYPE_DEV_INVALID;
214    case MEDIA_DEVICE_AUDIO_CAPTURE:
215      return PP_DEVICETYPE_DEV_AUDIOCAPTURE;
216    case MEDIA_DEVICE_VIDEO_CAPTURE:
217      return PP_DEVICETYPE_DEV_VIDEOCAPTURE;
218    default:
219      NOTREACHED();
220      return PP_DEVICETYPE_DEV_INVALID;
221  }
222}
223
224void PepperMediaDeviceManager::NotifyDeviceOpened(int request_id,
225                                                  bool succeeded,
226                                                  const std::string& label) {
227  OpenCallbackMap::iterator iter = open_callbacks_.find(request_id);
228  if (iter == open_callbacks_.end()) {
229    // The callback may have been unregistered.
230    return;
231  }
232
233  OpenDeviceCallback callback = iter->second;
234  open_callbacks_.erase(iter);
235
236  callback.Run(request_id, succeeded, label);
237}
238
239RenderViewImpl* PepperMediaDeviceManager::GetRenderViewImpl() {
240  return static_cast<RenderViewImpl*>(render_view());
241}
242
243}  // namespace content
244