Home | History | Annotate | Download | only in pepper
      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
    196