• 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 "content/renderer/pepper/pepper_device_enumeration_host_helper.h"
6 
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"
19 
20 using ppapi::host::HostMessageContext;
21 
22 namespace content {
23 
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.
ScopedRequest(PepperDeviceEnumerationHostHelper * owner,const Delegate::EnumerateDevicesCallback & callback)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;
38 
39     requested_ = true;
40 
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     request_id_ = owner_->delegate_->EnumerateDevices(
50         owner_->device_type_,
51         owner_->document_url_,
52         base::Bind(&ScopedRequest::EnumerateDevicesCallbackBody, AsWeakPtr()));
53     sync_call_ = false;
54   }
55 
~ScopedRequest()56   ~ScopedRequest() {
57     if (requested_) {
58       owner_->delegate_->StopEnumerateDevices(request_id_);
59     }
60   }
61 
requested() const62   bool requested() const { return requested_; }
63 
64  private:
EnumerateDevicesCallbackBody(int request_id,const std::vector<ppapi::DeviceRefData> & devices)65   void EnumerateDevicesCallbackBody(
66       int request_id,
67       const std::vector<ppapi::DeviceRefData>& devices) {
68     if (sync_call_) {
69       base::MessageLoop::current()->PostTask(
70           FROM_HERE,
71           base::Bind(&ScopedRequest::EnumerateDevicesCallbackBody,
72                      AsWeakPtr(),
73                      request_id,
74                      devices));
75     } else {
76       DCHECK_EQ(request_id_, request_id);
77       callback_.Run(request_id, devices);
78       // This object may have been destroyed at this point.
79     }
80   }
81 
82   PepperDeviceEnumerationHostHelper* owner_;
83   PepperDeviceEnumerationHostHelper::Delegate::EnumerateDevicesCallback
84       callback_;
85   bool requested_;
86   int request_id_;
87   bool sync_call_;
88 
89   DISALLOW_COPY_AND_ASSIGN(ScopedRequest);
90 };
91 
PepperDeviceEnumerationHostHelper(ppapi::host::ResourceHost * resource_host,Delegate * delegate,PP_DeviceType_Dev device_type,const GURL & document_url)92 PepperDeviceEnumerationHostHelper::PepperDeviceEnumerationHostHelper(
93     ppapi::host::ResourceHost* resource_host,
94     Delegate* delegate,
95     PP_DeviceType_Dev device_type,
96     const GURL& document_url)
97     : resource_host_(resource_host),
98       delegate_(delegate),
99       device_type_(device_type),
100       document_url_(document_url) {}
101 
~PepperDeviceEnumerationHostHelper()102 PepperDeviceEnumerationHostHelper::~PepperDeviceEnumerationHostHelper() {}
103 
HandleResourceMessage(const IPC::Message & msg,HostMessageContext * context,int32_t * result)104 bool PepperDeviceEnumerationHostHelper::HandleResourceMessage(
105     const IPC::Message& msg,
106     HostMessageContext* context,
107     int32_t* result) {
108   bool return_value = false;
109   *result = InternalHandleResourceMessage(msg, context, &return_value);
110   return return_value;
111 }
112 
InternalHandleResourceMessage(const IPC::Message & msg,HostMessageContext * context,bool * handled)113 int32_t PepperDeviceEnumerationHostHelper::InternalHandleResourceMessage(
114     const IPC::Message& msg,
115     HostMessageContext* context,
116     bool* handled) {
117   *handled = true;
118   PPAPI_BEGIN_MESSAGE_MAP(PepperDeviceEnumerationHostHelper, msg)
119     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
120         PpapiHostMsg_DeviceEnumeration_EnumerateDevices, OnEnumerateDevices)
121     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
122         PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange,
123         OnMonitorDeviceChange)
124     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
125         PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange,
126         OnStopMonitoringDeviceChange)
127   PPAPI_END_MESSAGE_MAP()
128 
129   *handled = false;
130   return PP_ERROR_FAILED;
131 }
132 
OnEnumerateDevices(HostMessageContext * context)133 int32_t PepperDeviceEnumerationHostHelper::OnEnumerateDevices(
134     HostMessageContext* context) {
135   if (enumerate_devices_context_.is_valid())
136     return PP_ERROR_INPROGRESS;
137 
138   enumerate_.reset(new ScopedRequest(
139       this,
140       base::Bind(&PepperDeviceEnumerationHostHelper::OnEnumerateDevicesComplete,
141                  base::Unretained(this))));
142   if (!enumerate_->requested())
143     return PP_ERROR_FAILED;
144 
145   enumerate_devices_context_ = context->MakeReplyMessageContext();
146   return PP_OK_COMPLETIONPENDING;
147 }
148 
OnMonitorDeviceChange(HostMessageContext *,uint32_t callback_id)149 int32_t PepperDeviceEnumerationHostHelper::OnMonitorDeviceChange(
150     HostMessageContext* /* context */,
151     uint32_t callback_id) {
152   monitor_.reset(new ScopedRequest(
153       this,
154       base::Bind(&PepperDeviceEnumerationHostHelper::OnNotifyDeviceChange,
155                  base::Unretained(this),
156                  callback_id)));
157 
158   return monitor_->requested() ? PP_OK : PP_ERROR_FAILED;
159 }
160 
OnStopMonitoringDeviceChange(HostMessageContext *)161 int32_t PepperDeviceEnumerationHostHelper::OnStopMonitoringDeviceChange(
162     HostMessageContext* /* context */) {
163   monitor_.reset(NULL);
164   return PP_OK;
165 }
166 
OnEnumerateDevicesComplete(int,const std::vector<ppapi::DeviceRefData> & devices)167 void PepperDeviceEnumerationHostHelper::OnEnumerateDevicesComplete(
168     int /* request_id */,
169     const std::vector<ppapi::DeviceRefData>& devices) {
170   DCHECK(enumerate_devices_context_.is_valid());
171 
172   enumerate_.reset(NULL);
173 
174   enumerate_devices_context_.params.set_result(PP_OK);
175   resource_host_->host()->SendReply(
176       enumerate_devices_context_,
177       PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply(devices));
178   enumerate_devices_context_ = ppapi::host::ReplyMessageContext();
179 }
180 
OnNotifyDeviceChange(uint32_t callback_id,int,const std::vector<ppapi::DeviceRefData> & devices)181 void PepperDeviceEnumerationHostHelper::OnNotifyDeviceChange(
182     uint32_t callback_id,
183     int /* request_id */,
184     const std::vector<ppapi::DeviceRefData>& devices) {
185   resource_host_->host()->SendUnsolicitedReply(
186       resource_host_->pp_resource(),
187       PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(callback_id,
188                                                           devices));
189 }
190 
191 }  // namespace content
192