- add sources.
[platform/framework/web/crosswalk.git] / src / ppapi / proxy / device_enumeration_resource_helper.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 "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
25 namespace ppapi {
26 namespace proxy {
27
28 DeviceEnumerationResourceHelper::DeviceEnumerationResourceHelper(
29     PluginResource* owner)
30     : owner_(owner),
31       pending_enumerate_devices_(false),
32       monitor_callback_id_(0),
33       monitor_user_data_(NULL) {
34 }
35
36 DeviceEnumerationResourceHelper::~DeviceEnumerationResourceHelper() {
37 }
38
39 int32_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
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;
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
73 int32_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
88 int32_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
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()
120
121   return true;
122 }
123
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;
129
130   // There is no need to do anything with pending callback of
131   // EnumerateDevices(), because OnPluginMsgEnumerateDevicesReply*() will handle
132   // that properly.
133 }
134
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;
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
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;
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
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.
182     return;
183   }
184
185   CHECK(monitor_callback_.get());
186
187   scoped_ptr<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
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;
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