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.
5 #include "ppapi/proxy/device_enumeration_resource_helper.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"
28 DeviceEnumerationResourceHelper::DeviceEnumerationResourceHelper(
29 PluginResource* owner)
31 pending_enumerate_devices_(false),
32 monitor_callback_id_(0),
33 monitor_user_data_(NULL) {
36 DeviceEnumerationResourceHelper::~DeviceEnumerationResourceHelper() {
39 int32_t DeviceEnumerationResourceHelper::EnumerateDevices0_2(
41 scoped_refptr<TrackedCallback> callback) {
42 if (pending_enumerate_devices_)
43 return PP_ERROR_INPROGRESS;
45 return PP_ERROR_BADARGUMENT;
47 pending_enumerate_devices_ = true;
48 PpapiHostMsg_DeviceEnumeration_EnumerateDevices msg;
49 owner_->Call<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(
50 PluginResource::RENDERER, msg,
52 &DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply0_2,
53 AsWeakPtr(), devices, callback));
54 return PP_OK_COMPLETIONPENDING;
57 int32_t DeviceEnumerationResourceHelper::EnumerateDevices(
58 const PP_ArrayOutput& output,
59 scoped_refptr<TrackedCallback> callback) {
60 if (pending_enumerate_devices_)
61 return PP_ERROR_INPROGRESS;
63 pending_enumerate_devices_ = true;
64 PpapiHostMsg_DeviceEnumeration_EnumerateDevices msg;
65 owner_->Call<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(
66 PluginResource::RENDERER, msg,
68 &DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply,
69 AsWeakPtr(), output, callback));
70 return PP_OK_COMPLETIONPENDING;
73 int32_t DeviceEnumerationResourceHelper::EnumerateDevicesSync(
74 const PP_ArrayOutput& output) {
75 std::vector<DeviceRefData> devices;
77 owner_->SyncCall<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(
78 PluginResource::RENDERER,
79 PpapiHostMsg_DeviceEnumeration_EnumerateDevices(),
83 result = WriteToArrayOutput(devices, output);
88 int32_t DeviceEnumerationResourceHelper::MonitorDeviceChange(
89 PP_MonitorDeviceChangeCallback callback,
91 monitor_callback_id_++;
92 monitor_user_data_ = user_data;
94 monitor_callback_.reset(
95 ThreadAwareCallback<PP_MonitorDeviceChangeCallback>::Create(callback));
96 if (!monitor_callback_.get())
97 return PP_ERROR_NO_MESSAGE_LOOP;
99 owner_->Post(PluginResource::RENDERER,
100 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange(
101 monitor_callback_id_));
103 monitor_callback_.reset(NULL);
105 owner_->Post(PluginResource::RENDERER,
106 PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange());
111 bool 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()
124 void 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;
130 // There is no need to do anything with pending callback of
131 // EnumerateDevices(), because OnPluginMsgEnumerateDevicesReply*() will handle
135 void 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;
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))
148 if (params.result() == PP_OK) {
149 *devices_resource = PPB_DeviceRef_Shared::CreateResourceArray(
150 OBJECT_IS_PROXY, owner_->pp_instance(), devices);
153 callback->Run(params.result());
156 void 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;
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))
169 int32_t result = params.result();
171 result = WriteToArrayOutput(devices, output);
173 callback->Run(result);
176 void 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.
185 CHECK(monitor_callback_.get());
187 scoped_ptr<PP_Resource[]> elements;
188 uint32_t size = devices.size();
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();
198 monitor_callback_->RunOnTargetThread(monitor_user_data_, size,
200 for (size_t index = 0; index < size; ++index)
201 PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(elements[index]);
204 int32_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;
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]));
216 if (!writer.StoreResourceVector(device_resources))
217 return PP_ERROR_FAILED;