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::EnumerateDevices(
40 const PP_ArrayOutput
& output
,
41 scoped_refptr
<TrackedCallback
> callback
) {
42 if (pending_enumerate_devices_
)
43 return PP_ERROR_INPROGRESS
;
45 pending_enumerate_devices_
= true;
46 PpapiHostMsg_DeviceEnumeration_EnumerateDevices msg
;
47 owner_
->Call
<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply
>(
48 PluginResource::RENDERER
, msg
,
50 &DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply
,
51 AsWeakPtr(), output
, callback
));
52 return PP_OK_COMPLETIONPENDING
;
55 int32_t DeviceEnumerationResourceHelper::EnumerateDevicesSync(
56 const PP_ArrayOutput
& output
) {
57 std::vector
<DeviceRefData
> devices
;
59 owner_
->SyncCall
<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply
>(
60 PluginResource::RENDERER
,
61 PpapiHostMsg_DeviceEnumeration_EnumerateDevices(),
65 result
= WriteToArrayOutput(devices
, output
);
70 int32_t DeviceEnumerationResourceHelper::MonitorDeviceChange(
71 PP_MonitorDeviceChangeCallback callback
,
73 monitor_callback_id_
++;
74 monitor_user_data_
= user_data
;
76 monitor_callback_
.reset(
77 ThreadAwareCallback
<PP_MonitorDeviceChangeCallback
>::Create(callback
));
78 if (!monitor_callback_
.get())
79 return PP_ERROR_NO_MESSAGE_LOOP
;
81 owner_
->Post(PluginResource::RENDERER
,
82 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange(
83 monitor_callback_id_
));
85 monitor_callback_
.reset(NULL
);
87 owner_
->Post(PluginResource::RENDERER
,
88 PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange());
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()
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
;
112 // There is no need to do anything with pending callback of
113 // EnumerateDevices(), because OnPluginMsgEnumerateDevicesReply*() will handle
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;
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
))
130 int32_t result
= params
.result();
132 result
= WriteToArrayOutput(devices
, output
);
134 callback
->Run(result
);
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.
146 CHECK(monitor_callback_
.get());
148 scoped_ptr
<PP_Resource
[]> elements
;
149 uint32_t size
= static_cast<uint32_t>(devices
.size());
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();
159 monitor_callback_
->RunOnTargetThread(monitor_user_data_
, size
,
161 for (size_t index
= 0; index
< size
; ++index
)
162 PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(elements
[index
]);
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
;
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
]));
177 if (!writer
.StoreResourceVector(device_resources
))
178 return PP_ERROR_FAILED
;