device_enumeration_resource_helper.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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 "ppapi/proxy/device_enumeration_resource_helper.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "base/memory/scoped_ptr.h"
10#include "ipc/ipc_message.h"
11#include "ipc/ipc_message_macros.h"
12#include "ppapi/c/pp_array_output.h"
13#include "ppapi/c/pp_errors.h"
14#include "ppapi/proxy/dispatch_reply_message.h"
15#include "ppapi/proxy/plugin_resource.h"
16#include "ppapi/proxy/ppapi_messages.h"
17#include "ppapi/proxy/resource_message_params.h"
18#include "ppapi/shared_impl/array_writer.h"
19#include "ppapi/shared_impl/ppapi_globals.h"
20#include "ppapi/shared_impl/ppb_device_ref_shared.h"
21#include "ppapi/shared_impl/proxy_lock.h"
22#include "ppapi/shared_impl/resource_tracker.h"
23#include "ppapi/shared_impl/tracked_callback.h"
24
25namespace ppapi {
26namespace proxy {
27
28DeviceEnumerationResourceHelper::DeviceEnumerationResourceHelper(
29    PluginResource* owner)
30    : owner_(owner),
31      pending_enumerate_devices_(false),
32      monitor_callback_id_(0),
33      monitor_user_data_(NULL) {
34}
35
36DeviceEnumerationResourceHelper::~DeviceEnumerationResourceHelper() {
37}
38
39int32_t DeviceEnumerationResourceHelper::EnumerateDevices0_2(
40    PP_Resource* devices,
41    scoped_refptr<TrackedCallback> callback) {
42  if (pending_enumerate_devices_)
43    return PP_ERROR_INPROGRESS;
44  if (!devices)
45    return PP_ERROR_BADARGUMENT;
46
47  pending_enumerate_devices_ = true;
48  PpapiHostMsg_DeviceEnumeration_EnumerateDevices msg;
49  owner_->Call<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(
50      PluginResource::RENDERER, msg,
51      base::Bind(
52          &DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply0_2,
53          AsWeakPtr(), devices, callback));
54  return PP_OK_COMPLETIONPENDING;
55}
56
57int32_t DeviceEnumerationResourceHelper::EnumerateDevices(
58    const PP_ArrayOutput& output,
59    scoped_refptr<TrackedCallback> callback) {
60  if (pending_enumerate_devices_)
61    return PP_ERROR_INPROGRESS;
62
63  pending_enumerate_devices_ = true;
64  PpapiHostMsg_DeviceEnumeration_EnumerateDevices msg;
65  owner_->Call<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(
66      PluginResource::RENDERER, msg,
67      base::Bind(
68          &DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply,
69          AsWeakPtr(), output, callback));
70  return PP_OK_COMPLETIONPENDING;
71}
72
73int32_t DeviceEnumerationResourceHelper::EnumerateDevicesSync(
74    const PP_ArrayOutput& output) {
75  std::vector<DeviceRefData> devices;
76  int32_t result =
77      owner_->SyncCall<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(
78          PluginResource::RENDERER,
79          PpapiHostMsg_DeviceEnumeration_EnumerateDevices(),
80          &devices);
81
82  if (result == PP_OK)
83    result = WriteToArrayOutput(devices, output);
84
85  return result;
86}
87
88int32_t DeviceEnumerationResourceHelper::MonitorDeviceChange(
89    PP_MonitorDeviceChangeCallback callback,
90    void* user_data) {
91  monitor_callback_id_++;
92  monitor_user_data_ = user_data;
93  if (callback) {
94    monitor_callback_.reset(
95        ThreadAwareCallback<PP_MonitorDeviceChangeCallback>::Create(callback));
96    if (!monitor_callback_.get())
97      return PP_ERROR_NO_MESSAGE_LOOP;
98
99    owner_->Post(PluginResource::RENDERER,
100                 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange(
101                     monitor_callback_id_));
102  } else {
103    monitor_callback_.reset(NULL);
104
105    owner_->Post(PluginResource::RENDERER,
106                 PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange());
107  }
108  return PP_OK;
109}
110
111bool DeviceEnumerationResourceHelper::HandleReply(
112    const ResourceMessageReplyParams& params,
113    const IPC::Message& msg) {
114  IPC_BEGIN_MESSAGE_MAP(DeviceEnumerationResourceHelper, msg)
115    PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
116        PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange,
117        OnPluginMsgNotifyDeviceChange)
118    PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(return false)
119  IPC_END_MESSAGE_MAP()
120
121  return true;
122}
123
124void DeviceEnumerationResourceHelper::LastPluginRefWasDeleted() {
125  // Make sure that no further notifications are sent to the plugin.
126  monitor_callback_id_++;
127  monitor_callback_.reset(NULL);
128  monitor_user_data_ = NULL;
129
130  // There is no need to do anything with pending callback of
131  // EnumerateDevices(), because OnPluginMsgEnumerateDevicesReply*() will handle
132  // that properly.
133}
134
135void DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply0_2(
136    PP_Resource* devices_resource,
137    scoped_refptr<TrackedCallback> callback,
138    const ResourceMessageReplyParams& params,
139    const std::vector<DeviceRefData>& devices) {
140  pending_enumerate_devices_ = false;
141
142  // We shouldn't access |devices_resource| if the callback has been called,
143  // which is possible if the last plugin reference to the corresponding
144  // resource has gone away, and the callback has been aborted.
145  if (!TrackedCallback::IsPending(callback))
146    return;
147
148  if (params.result() == PP_OK) {
149    *devices_resource = PPB_DeviceRef_Shared::CreateResourceArray(
150        OBJECT_IS_PROXY, owner_->pp_instance(), devices);
151  }
152
153  callback->Run(params.result());
154}
155
156void DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply(
157    const PP_ArrayOutput& output,
158    scoped_refptr<TrackedCallback> callback,
159    const ResourceMessageReplyParams& params,
160    const std::vector<DeviceRefData>& devices) {
161  pending_enumerate_devices_ = false;
162
163  // We shouldn't access |output| if the callback has been called, which is
164  // possible if the last plugin reference to the corresponding resource has
165  // gone away, and the callback has been aborted.
166  if (!TrackedCallback::IsPending(callback))
167    return;
168
169  int32_t result = params.result();
170  if (result == PP_OK)
171    result = WriteToArrayOutput(devices, output);
172
173  callback->Run(result);
174}
175
176void DeviceEnumerationResourceHelper::OnPluginMsgNotifyDeviceChange(
177    const ResourceMessageReplyParams& /* params */,
178    uint32_t callback_id,
179    const std::vector<DeviceRefData>& devices) {
180  if (monitor_callback_id_ != callback_id) {
181    // A new callback or NULL has been set.
182    return;
183  }
184
185  CHECK(monitor_callback_.get());
186
187  scoped_array<PP_Resource> elements;
188  uint32_t size = devices.size();
189  if (size > 0) {
190    elements.reset(new PP_Resource[size]);
191    for (size_t index = 0; index < size; ++index) {
192      PPB_DeviceRef_Shared* device_object = new PPB_DeviceRef_Shared(
193          OBJECT_IS_PROXY, owner_->pp_instance(), devices[index]);
194      elements[index] = device_object->GetReference();
195    }
196  }
197
198  monitor_callback_->RunOnTargetThread(monitor_user_data_, size,
199                                       elements.get());
200  for (size_t index = 0; index < size; ++index)
201    PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(elements[index]);
202}
203
204int32_t DeviceEnumerationResourceHelper::WriteToArrayOutput(
205    const std::vector<DeviceRefData>& devices,
206    const PP_ArrayOutput& output) {
207  ArrayWriter writer(output);
208  if (!writer.is_valid())
209    return PP_ERROR_BADARGUMENT;
210
211  std::vector<scoped_refptr<Resource> > device_resources;
212  for (size_t i = 0; i < devices.size(); ++i) {
213    device_resources.push_back(new PPB_DeviceRef_Shared(
214        OBJECT_IS_PROXY, owner_->pp_instance(), devices[i]));
215  }
216  if (!writer.StoreResourceVector(device_resources))
217    return PP_ERROR_FAILED;
218
219  return PP_OK;
220}
221
222}  // namespace proxy
223}  // namespace ppapi
224