Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / renderer / pepper / pepper_device_enumeration_host_helper.cc
blobedc0840bb92a4c4307b7bc50bc717ae6b5813391
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 "content/renderer/pepper/pepper_device_enumeration_host_helper.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/memory/weak_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "ipc/ipc_message.h"
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/host/dispatch_host_message.h"
14 #include "ppapi/host/host_message_context.h"
15 #include "ppapi/host/ppapi_host.h"
16 #include "ppapi/host/resource_host.h"
17 #include "ppapi/proxy/ppapi_messages.h"
18 #include "ppapi/shared_impl/ppb_device_ref_shared.h"
20 using ppapi::host::HostMessageContext;
22 namespace content {
24 // Makes sure that StopEnumerateDevices() is called for each EnumerateDevices().
25 class PepperDeviceEnumerationHostHelper::ScopedRequest
26 : public base::SupportsWeakPtr<ScopedRequest> {
27 public:
28 // |owner| must outlive this object.
29 ScopedRequest(PepperDeviceEnumerationHostHelper* owner,
30 const Delegate::EnumerateDevicesCallback& callback)
31 : owner_(owner),
32 callback_(callback),
33 requested_(false),
34 request_id_(0),
35 sync_call_(false) {
36 if (!owner_->document_url_.is_valid())
37 return;
39 requested_ = true;
41 // Note that the callback passed into
42 // PepperDeviceEnumerationHostHelper::Delegate::EnumerateDevices() may be
43 // called synchronously. In that case, |request_id_| hasn't been updated
44 // when the callback is called. Moreover, |callback| may destroy this
45 // object. So we don't pass in |callback| directly. Instead, we use
46 // EnumerateDevicesCallbackBody() to ensure that we always call |callback|
47 // asynchronously.
48 sync_call_ = true;
49 DCHECK(owner_->delegate_);
50 request_id_ = owner_->delegate_->EnumerateDevices(
51 owner_->device_type_,
52 owner_->document_url_,
53 base::Bind(&ScopedRequest::EnumerateDevicesCallbackBody, AsWeakPtr()));
54 sync_call_ = false;
57 ~ScopedRequest() {
58 if (requested_ && owner_->delegate_) {
59 owner_->delegate_->StopEnumerateDevices(request_id_);
63 bool requested() const { return requested_; }
65 private:
66 void EnumerateDevicesCallbackBody(
67 int request_id,
68 const std::vector<ppapi::DeviceRefData>& devices) {
69 if (sync_call_) {
70 base::MessageLoop::current()->PostTask(
71 FROM_HERE,
72 base::Bind(&ScopedRequest::EnumerateDevicesCallbackBody,
73 AsWeakPtr(),
74 request_id,
75 devices));
76 } else {
77 DCHECK_EQ(request_id_, request_id);
78 callback_.Run(request_id, devices);
79 // This object may have been destroyed at this point.
83 PepperDeviceEnumerationHostHelper* owner_;
84 PepperDeviceEnumerationHostHelper::Delegate::EnumerateDevicesCallback
85 callback_;
86 bool requested_;
87 int request_id_;
88 bool sync_call_;
90 DISALLOW_COPY_AND_ASSIGN(ScopedRequest);
93 PepperDeviceEnumerationHostHelper::PepperDeviceEnumerationHostHelper(
94 ppapi::host::ResourceHost* resource_host,
95 base::WeakPtr<Delegate> delegate,
96 PP_DeviceType_Dev device_type,
97 const GURL& document_url)
98 : resource_host_(resource_host),
99 delegate_(delegate),
100 device_type_(device_type),
101 document_url_(document_url) {}
103 PepperDeviceEnumerationHostHelper::~PepperDeviceEnumerationHostHelper() {}
105 bool PepperDeviceEnumerationHostHelper::HandleResourceMessage(
106 const IPC::Message& msg,
107 HostMessageContext* context,
108 int32_t* result) {
109 bool return_value = false;
110 *result = InternalHandleResourceMessage(msg, context, &return_value);
111 return return_value;
114 int32_t PepperDeviceEnumerationHostHelper::InternalHandleResourceMessage(
115 const IPC::Message& msg,
116 HostMessageContext* context,
117 bool* handled) {
118 *handled = true;
119 PPAPI_BEGIN_MESSAGE_MAP(PepperDeviceEnumerationHostHelper, msg)
120 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
121 PpapiHostMsg_DeviceEnumeration_EnumerateDevices, OnEnumerateDevices)
122 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
123 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange,
124 OnMonitorDeviceChange)
125 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
126 PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange,
127 OnStopMonitoringDeviceChange)
128 PPAPI_END_MESSAGE_MAP()
130 *handled = false;
131 return PP_ERROR_FAILED;
134 int32_t PepperDeviceEnumerationHostHelper::OnEnumerateDevices(
135 HostMessageContext* context) {
136 if (enumerate_devices_context_.is_valid())
137 return PP_ERROR_INPROGRESS;
139 enumerate_.reset(new ScopedRequest(
140 this,
141 base::Bind(&PepperDeviceEnumerationHostHelper::OnEnumerateDevicesComplete,
142 base::Unretained(this))));
143 if (!enumerate_->requested())
144 return PP_ERROR_FAILED;
146 enumerate_devices_context_ = context->MakeReplyMessageContext();
147 return PP_OK_COMPLETIONPENDING;
150 int32_t PepperDeviceEnumerationHostHelper::OnMonitorDeviceChange(
151 HostMessageContext* /* context */,
152 uint32_t callback_id) {
153 monitor_.reset(new ScopedRequest(
154 this,
155 base::Bind(&PepperDeviceEnumerationHostHelper::OnNotifyDeviceChange,
156 base::Unretained(this),
157 callback_id)));
159 return monitor_->requested() ? PP_OK : PP_ERROR_FAILED;
162 int32_t PepperDeviceEnumerationHostHelper::OnStopMonitoringDeviceChange(
163 HostMessageContext* /* context */) {
164 monitor_.reset(NULL);
165 return PP_OK;
168 void PepperDeviceEnumerationHostHelper::OnEnumerateDevicesComplete(
169 int /* request_id */,
170 const std::vector<ppapi::DeviceRefData>& devices) {
171 DCHECK(enumerate_devices_context_.is_valid());
173 enumerate_.reset(NULL);
175 enumerate_devices_context_.params.set_result(PP_OK);
176 resource_host_->host()->SendReply(
177 enumerate_devices_context_,
178 PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply(devices));
179 enumerate_devices_context_ = ppapi::host::ReplyMessageContext();
182 void PepperDeviceEnumerationHostHelper::OnNotifyDeviceChange(
183 uint32_t callback_id,
184 int /* request_id */,
185 const std::vector<ppapi::DeviceRefData>& devices) {
186 resource_host_->host()->SendUnsolicitedReply(
187 resource_host_->pp_resource(),
188 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(callback_id,
189 devices));
192 } // namespace content