1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/pepper/pepper_device_enumeration_host_helper.h"
8 #include "base/check.h"
9 #include "base/location.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/task/single_thread_task_runner.h"
12 #include "base/threading/thread_task_runner_handle.h"
13 #include "ipc/ipc_message.h"
14 #include "ppapi/c/pp_errors.h"
15 #include "ppapi/host/dispatch_host_message.h"
16 #include "ppapi/host/host_message_context.h"
17 #include "ppapi/host/ppapi_host.h"
18 #include "ppapi/host/resource_host.h"
19 #include "ppapi/proxy/ppapi_messages.h"
20 #include "ppapi/shared_impl/ppb_device_ref_shared.h"
22 using ppapi::host::HostMessageContext;
26 // Makes sure that StopEnumerateDevices() is called for each EnumerateDevices().
27 class PepperDeviceEnumerationHostHelper::ScopedEnumerationRequest
28 : public base::SupportsWeakPtr<ScopedEnumerationRequest> {
30 // |owner| must outlive this object.
31 ScopedEnumerationRequest(PepperDeviceEnumerationHostHelper* owner,
32 Delegate::DevicesOnceCallback callback)
33 : callback_(std::move(callback)), requested_(false), sync_call_(false) {
34 if (!owner->delegate_) {
35 // If no delegate, return an empty list of devices.
36 base::ThreadTaskRunnerHandle::Get()->PostTask(
39 &ScopedEnumerationRequest::EnumerateDevicesCallbackBody,
40 AsWeakPtr(), std::vector<ppapi::DeviceRefData>()));
46 // Note that the callback passed into
47 // PepperDeviceEnumerationHostHelper::Delegate::EnumerateDevices() may be
48 // called synchronously. In that case, |callback| may destroy this
49 // object. So we don't pass in |callback| directly. Instead, we use
50 // EnumerateDevicesCallbackBody() to ensure that we always call |callback|
53 owner->delegate_->EnumerateDevices(
55 base::BindOnce(&ScopedEnumerationRequest::EnumerateDevicesCallbackBody,
60 ScopedEnumerationRequest(const ScopedEnumerationRequest&) = delete;
61 ScopedEnumerationRequest& operator=(const ScopedEnumerationRequest&) = delete;
63 bool requested() const { return requested_; }
66 void EnumerateDevicesCallbackBody(
67 const std::vector<ppapi::DeviceRefData>& devices) {
69 base::ThreadTaskRunnerHandle::Get()->PostTask(
72 &ScopedEnumerationRequest::EnumerateDevicesCallbackBody,
73 AsWeakPtr(), devices));
75 std::move(callback_).Run(devices);
76 // This object may have been destroyed at this point.
80 PepperDeviceEnumerationHostHelper::Delegate::DevicesOnceCallback callback_;
85 // Makes sure that StopMonitoringDevices() is called for each
86 // StartMonitoringDevices().
87 class PepperDeviceEnumerationHostHelper::ScopedMonitoringRequest
88 : public base::SupportsWeakPtr<ScopedMonitoringRequest> {
90 // |owner| must outlive this object.
91 ScopedMonitoringRequest(PepperDeviceEnumerationHostHelper* owner,
92 Delegate::DevicesCallback callback)
94 callback_(std::move(callback)),
96 subscription_id_(0u) {
98 if (!owner->delegate_) {
104 // |callback| is never called synchronously by StartMonitoringDevices(),
105 // so it is OK to pass it directly, even if |callback| destroys |this|.
106 subscription_id_ = owner_->delegate_->StartMonitoringDevices(
107 owner_->device_type_, callback_);
110 ScopedMonitoringRequest(const ScopedMonitoringRequest&) = delete;
111 ScopedMonitoringRequest& operator=(const ScopedMonitoringRequest&) = delete;
113 ~ScopedMonitoringRequest() {
114 if (requested_ && owner_->delegate_) {
115 owner_->delegate_->StopMonitoringDevices(owner_->device_type_,
120 bool requested() const { return requested_; }
123 PepperDeviceEnumerationHostHelper* const owner_;
124 PepperDeviceEnumerationHostHelper::Delegate::DevicesCallback callback_;
126 size_t subscription_id_;
129 PepperDeviceEnumerationHostHelper::PepperDeviceEnumerationHostHelper(
130 ppapi::host::ResourceHost* resource_host,
131 base::WeakPtr<Delegate> delegate,
132 PP_DeviceType_Dev device_type,
133 const GURL& document_url)
134 : resource_host_(resource_host),
136 device_type_(device_type) {}
138 PepperDeviceEnumerationHostHelper::~PepperDeviceEnumerationHostHelper() {}
140 bool PepperDeviceEnumerationHostHelper::HandleResourceMessage(
141 const IPC::Message& msg,
142 HostMessageContext* context,
144 bool return_value = false;
145 *result = InternalHandleResourceMessage(msg, context, &return_value);
149 int32_t PepperDeviceEnumerationHostHelper::InternalHandleResourceMessage(
150 const IPC::Message& msg,
151 HostMessageContext* context,
154 PPAPI_BEGIN_MESSAGE_MAP(PepperDeviceEnumerationHostHelper, msg)
155 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
156 PpapiHostMsg_DeviceEnumeration_EnumerateDevices, OnEnumerateDevices)
157 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
158 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange,
159 OnMonitorDeviceChange)
160 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
161 PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange,
162 OnStopMonitoringDeviceChange)
163 PPAPI_END_MESSAGE_MAP()
166 LOG(ERROR) << "Cannot handle internal resource message";
167 return PP_ERROR_FAILED;
170 int32_t PepperDeviceEnumerationHostHelper::OnEnumerateDevices(
171 HostMessageContext* context) {
172 if (enumerate_devices_context_.is_valid()) {
173 LOG(ERROR) << "Invalid enumerate devices context";
174 return PP_ERROR_INPROGRESS;
177 enumerate_ = std::make_unique<ScopedEnumerationRequest>(
178 this, base::BindOnce(
179 &PepperDeviceEnumerationHostHelper::OnEnumerateDevicesComplete,
180 base::Unretained(this)));
181 if (!enumerate_->requested()) {
182 LOG(ERROR) << "Cannot request enumerate";
183 return PP_ERROR_FAILED;
186 enumerate_devices_context_ = context->MakeReplyMessageContext();
187 return PP_OK_COMPLETIONPENDING;
190 int32_t PepperDeviceEnumerationHostHelper::OnMonitorDeviceChange(
191 HostMessageContext* /* context */,
192 uint32_t callback_id) {
193 monitor_ = std::make_unique<ScopedMonitoringRequest>(
194 this, base::BindRepeating(
195 &PepperDeviceEnumerationHostHelper::OnNotifyDeviceChange,
196 base::Unretained(this), callback_id));
198 return monitor_->requested() ? PP_OK : PP_ERROR_FAILED;
201 int32_t PepperDeviceEnumerationHostHelper::OnStopMonitoringDeviceChange(
202 HostMessageContext* /* context */) {
203 monitor_.reset(nullptr);
207 void PepperDeviceEnumerationHostHelper::OnEnumerateDevicesComplete(
208 const std::vector<ppapi::DeviceRefData>& devices) {
209 DCHECK(enumerate_devices_context_.is_valid());
211 enumerate_.reset(nullptr);
213 enumerate_devices_context_.params.set_result(PP_OK);
214 resource_host_->host()->SendReply(
215 enumerate_devices_context_,
216 PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply(devices));
217 enumerate_devices_context_ = ppapi::host::ReplyMessageContext();
220 void PepperDeviceEnumerationHostHelper::OnNotifyDeviceChange(
221 uint32_t callback_id,
222 const std::vector<ppapi::DeviceRefData>& devices) {
223 resource_host_->host()->SendUnsolicitedReply(
224 resource_host_->pp_resource(),
225 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(callback_id,
229 } // namespace content