- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / pepper / pepper_device_enumeration_host_helper.cc
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.
29   ScopedRequest(
30       PepperDeviceEnumerationHostHelper* owner,
31       const Delegate::EnumerateDevicesCallback& callback)
32       : owner_(owner),
33         callback_(callback),
34         requested_(false),
35         request_id_(0),
36         sync_call_(false) {
37     requested_ = true;
38
39     // Note that the callback passed into
40     // PepperDeviceEnumerationHostHelper::Delegate::EnumerateDevices() may be
41     // called synchronously. In that case, |request_id_| hasn't been updated
42     // when the callback is called. Moreover, |callback| may destroy this
43     // object. So we don't pass in |callback| directly. Instead, we use
44     // EnumerateDevicesCallbackBody() to ensure that we always call |callback|
45     // asynchronously.
46     sync_call_ = true;
47     request_id_ = owner_->delegate_->EnumerateDevices(
48         owner_->device_type_,
49         base::Bind(&ScopedRequest::EnumerateDevicesCallbackBody, AsWeakPtr()));
50     sync_call_ = false;
51   }
52
53   ~ScopedRequest() {
54     if (requested_) {
55       owner_->delegate_->StopEnumerateDevices(request_id_);
56     }
57   }
58
59   bool requested() const { return requested_; }
60
61  private:
62   void EnumerateDevicesCallbackBody(
63       int request_id,
64       bool succeeded,
65       const std::vector<ppapi::DeviceRefData>& devices) {
66     if (sync_call_) {
67       base::MessageLoop::current()->PostTask(
68           FROM_HERE,
69           base::Bind(&ScopedRequest::EnumerateDevicesCallbackBody,
70                      AsWeakPtr(),
71                      request_id,
72                      succeeded,
73                      devices));
74     } else {
75       DCHECK_EQ(request_id_, request_id);
76       callback_.Run(request_id, succeeded, devices);
77       // This object may have been destroyed at this point.
78     }
79   }
80
81   PepperDeviceEnumerationHostHelper* owner_;
82   PepperDeviceEnumerationHostHelper::Delegate::EnumerateDevicesCallback
83       callback_;
84   bool requested_;
85   int request_id_;
86   bool sync_call_;
87
88   DISALLOW_COPY_AND_ASSIGN(ScopedRequest);
89 };
90
91 PepperDeviceEnumerationHostHelper::PepperDeviceEnumerationHostHelper(
92     ppapi::host::ResourceHost* resource_host,
93     Delegate* delegate,
94     PP_DeviceType_Dev device_type)
95     : resource_host_(resource_host),
96       delegate_(delegate),
97       device_type_(device_type) {
98 }
99
100 PepperDeviceEnumerationHostHelper::~PepperDeviceEnumerationHostHelper() {
101 }
102
103 bool PepperDeviceEnumerationHostHelper::HandleResourceMessage(
104     const IPC::Message& msg,
105     HostMessageContext* context,
106     int32_t* result) {
107   bool return_value = false;
108   *result = InternalHandleResourceMessage(msg, context, &return_value);
109   return return_value;
110 }
111
112 int32_t PepperDeviceEnumerationHostHelper::InternalHandleResourceMessage(
113     const IPC::Message& msg,
114     HostMessageContext* context,
115     bool* handled) {
116   *handled = true;
117   IPC_BEGIN_MESSAGE_MAP(PepperDeviceEnumerationHostHelper, msg)
118     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
119         PpapiHostMsg_DeviceEnumeration_EnumerateDevices, OnEnumerateDevices)
120     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
121         PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange,
122         OnMonitorDeviceChange)
123     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
124         PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange,
125         OnStopMonitoringDeviceChange)
126   IPC_END_MESSAGE_MAP()
127
128   *handled = false;
129   return PP_ERROR_FAILED;
130 }
131
132 int32_t PepperDeviceEnumerationHostHelper::OnEnumerateDevices(
133     HostMessageContext* context) {
134   if (enumerate_devices_context_)
135     return PP_ERROR_INPROGRESS;
136
137   enumerate_.reset(new ScopedRequest(
138       this,
139       base::Bind(&PepperDeviceEnumerationHostHelper::OnEnumerateDevicesComplete,
140                  base::Unretained(this))));
141   if (!enumerate_->requested())
142     return PP_ERROR_FAILED;
143
144   enumerate_devices_context_.reset(
145       new ppapi::host::ReplyMessageContext(context->MakeReplyMessageContext()));
146   return PP_OK_COMPLETIONPENDING;
147 }
148
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), callback_id)));
156
157   return monitor_->requested() ? PP_OK : PP_ERROR_FAILED;
158 }
159
160 int32_t PepperDeviceEnumerationHostHelper::OnStopMonitoringDeviceChange(
161     HostMessageContext* /* context */) {
162   monitor_.reset(NULL);
163   return PP_OK;
164 }
165
166 void PepperDeviceEnumerationHostHelper::OnEnumerateDevicesComplete(
167     int /* request_id */,
168     bool succeeded,
169     const std::vector<ppapi::DeviceRefData>& devices) {
170   DCHECK(enumerate_devices_context_.get());
171
172   enumerate_.reset(NULL);
173
174   enumerate_devices_context_->params.set_result(
175       succeeded ? PP_OK : PP_ERROR_FAILED);
176   resource_host_->host()->SendReply(
177       *enumerate_devices_context_,
178       PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply(
179           succeeded ? devices : std::vector<ppapi::DeviceRefData>()));
180   enumerate_devices_context_.reset();
181 }
182
183 void PepperDeviceEnumerationHostHelper::OnNotifyDeviceChange(
184     uint32_t callback_id,
185     int /* request_id */,
186     bool succeeded,
187     const std::vector<ppapi::DeviceRefData>& devices) {
188   resource_host_->host()->SendUnsolicitedReply(
189       resource_host_->pp_resource(),
190       PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
191           callback_id,
192           succeeded ? devices : std::vector<ppapi::DeviceRefData>()));
193 }
194
195 }  // namespace content