• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DeviceEnumerationResourceHelper(PluginResource * owner)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 
~DeviceEnumerationResourceHelper()36 DeviceEnumerationResourceHelper::~DeviceEnumerationResourceHelper() {
37 }
38 
EnumerateDevices(const PP_ArrayOutput & output,scoped_refptr<TrackedCallback> callback)39 int32_t DeviceEnumerationResourceHelper::EnumerateDevices(
40     const PP_ArrayOutput& output,
41     scoped_refptr<TrackedCallback> callback) {
42   if (pending_enumerate_devices_)
43     return PP_ERROR_INPROGRESS;
44 
45   pending_enumerate_devices_ = true;
46   PpapiHostMsg_DeviceEnumeration_EnumerateDevices msg;
47   owner_->Call<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(
48       PluginResource::RENDERER, msg,
49       base::Bind(
50           &DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply,
51           AsWeakPtr(), output, callback));
52   return PP_OK_COMPLETIONPENDING;
53 }
54 
EnumerateDevicesSync(const PP_ArrayOutput & output)55 int32_t DeviceEnumerationResourceHelper::EnumerateDevicesSync(
56     const PP_ArrayOutput& output) {
57   std::vector<DeviceRefData> devices;
58   int32_t result =
59       owner_->SyncCall<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(
60           PluginResource::RENDERER,
61           PpapiHostMsg_DeviceEnumeration_EnumerateDevices(),
62           &devices);
63 
64   if (result == PP_OK)
65     result = WriteToArrayOutput(devices, output);
66 
67   return result;
68 }
69 
MonitorDeviceChange(PP_MonitorDeviceChangeCallback callback,void * user_data)70 int32_t DeviceEnumerationResourceHelper::MonitorDeviceChange(
71     PP_MonitorDeviceChangeCallback callback,
72     void* user_data) {
73   monitor_callback_id_++;
74   monitor_user_data_ = user_data;
75   if (callback) {
76     monitor_callback_.reset(
77         ThreadAwareCallback<PP_MonitorDeviceChangeCallback>::Create(callback));
78     if (!monitor_callback_.get())
79       return PP_ERROR_NO_MESSAGE_LOOP;
80 
81     owner_->Post(PluginResource::RENDERER,
82                  PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange(
83                      monitor_callback_id_));
84   } else {
85     monitor_callback_.reset(NULL);
86 
87     owner_->Post(PluginResource::RENDERER,
88                  PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange());
89   }
90   return PP_OK;
91 }
92 
HandleReply(const ResourceMessageReplyParams & params,const IPC::Message & msg)93 bool DeviceEnumerationResourceHelper::HandleReply(
94     const ResourceMessageReplyParams& params,
95     const IPC::Message& msg) {
96   PPAPI_BEGIN_MESSAGE_MAP(DeviceEnumerationResourceHelper, msg)
97     PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
98         PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange,
99         OnPluginMsgNotifyDeviceChange)
100     PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(return false)
101   PPAPI_END_MESSAGE_MAP()
102 
103   return true;
104 }
105 
LastPluginRefWasDeleted()106 void DeviceEnumerationResourceHelper::LastPluginRefWasDeleted() {
107   // Make sure that no further notifications are sent to the plugin.
108   monitor_callback_id_++;
109   monitor_callback_.reset(NULL);
110   monitor_user_data_ = NULL;
111 
112   // There is no need to do anything with pending callback of
113   // EnumerateDevices(), because OnPluginMsgEnumerateDevicesReply*() will handle
114   // that properly.
115 }
116 
OnPluginMsgEnumerateDevicesReply(const PP_ArrayOutput & output,scoped_refptr<TrackedCallback> callback,const ResourceMessageReplyParams & params,const std::vector<DeviceRefData> & devices)117 void DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply(
118     const PP_ArrayOutput& output,
119     scoped_refptr<TrackedCallback> callback,
120     const ResourceMessageReplyParams& params,
121     const std::vector<DeviceRefData>& devices) {
122   pending_enumerate_devices_ = false;
123 
124   // We shouldn't access |output| if the callback has been called, which is
125   // possible if the last plugin reference to the corresponding resource has
126   // gone away, and the callback has been aborted.
127   if (!TrackedCallback::IsPending(callback))
128     return;
129 
130   int32_t result = params.result();
131   if (result == PP_OK)
132     result = WriteToArrayOutput(devices, output);
133 
134   callback->Run(result);
135 }
136 
OnPluginMsgNotifyDeviceChange(const ResourceMessageReplyParams &,uint32_t callback_id,const std::vector<DeviceRefData> & devices)137 void DeviceEnumerationResourceHelper::OnPluginMsgNotifyDeviceChange(
138     const ResourceMessageReplyParams& /* params */,
139     uint32_t callback_id,
140     const std::vector<DeviceRefData>& devices) {
141   if (monitor_callback_id_ != callback_id) {
142     // A new callback or NULL has been set.
143     return;
144   }
145 
146   CHECK(monitor_callback_.get());
147 
148   scoped_ptr<PP_Resource[]> elements;
149   uint32_t size = devices.size();
150   if (size > 0) {
151     elements.reset(new PP_Resource[size]);
152     for (size_t index = 0; index < size; ++index) {
153       PPB_DeviceRef_Shared* device_object = new PPB_DeviceRef_Shared(
154           OBJECT_IS_PROXY, owner_->pp_instance(), devices[index]);
155       elements[index] = device_object->GetReference();
156     }
157   }
158 
159   monitor_callback_->RunOnTargetThread(monitor_user_data_, size,
160                                        elements.get());
161   for (size_t index = 0; index < size; ++index)
162     PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(elements[index]);
163 }
164 
WriteToArrayOutput(const std::vector<DeviceRefData> & devices,const PP_ArrayOutput & output)165 int32_t DeviceEnumerationResourceHelper::WriteToArrayOutput(
166     const std::vector<DeviceRefData>& devices,
167     const PP_ArrayOutput& output) {
168   ArrayWriter writer(output);
169   if (!writer.is_valid())
170     return PP_ERROR_BADARGUMENT;
171 
172   std::vector<scoped_refptr<Resource> > device_resources;
173   for (size_t i = 0; i < devices.size(); ++i) {
174     device_resources.push_back(new PPB_DeviceRef_Shared(
175         OBJECT_IS_PROXY, owner_->pp_instance(), devices[i]));
176   }
177   if (!writer.StoreResourceVector(device_resources))
178     return PP_ERROR_FAILED;
179 
180   return PP_OK;
181 }
182 
183 }  // namespace proxy
184 }  // namespace ppapi
185