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     if (!owner_->document_url_.is_valid())
     38       return;
     39 
     40     requested_ = true;
     41 
     42     // Note that the callback passed into
     43     // PepperDeviceEnumerationHostHelper::Delegate::EnumerateDevices() may be
     44     // called synchronously. In that case, |request_id_| hasn't been updated
     45     // when the callback is called. Moreover, |callback| may destroy this
     46     // object. So we don't pass in |callback| directly. Instead, we use
     47     // EnumerateDevicesCallbackBody() to ensure that we always call |callback|
     48     // asynchronously.
     49     sync_call_ = true;
     50     request_id_ = owner_->delegate_->EnumerateDevices(
     51         owner_->device_type_,
     52         owner_->document_url_,
     53         base::Bind(&ScopedRequest::EnumerateDevicesCallbackBody, AsWeakPtr()));
     54     sync_call_ = false;
     55   }
     56 
     57   ~ScopedRequest() {
     58     if (requested_) {
     59       owner_->delegate_->StopEnumerateDevices(request_id_);
     60     }
     61   }
     62 
     63   bool requested() const { return requested_; }
     64 
     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.
     80     }
     81   }
     82 
     83   PepperDeviceEnumerationHostHelper* owner_;
     84   PepperDeviceEnumerationHostHelper::Delegate::EnumerateDevicesCallback
     85       callback_;
     86   bool requested_;
     87   int request_id_;
     88   bool sync_call_;
     89 
     90   DISALLOW_COPY_AND_ASSIGN(ScopedRequest);
     91 };
     92 
     93 PepperDeviceEnumerationHostHelper::PepperDeviceEnumerationHostHelper(
     94     ppapi::host::ResourceHost* resource_host,
     95     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) {
    102 }
    103 
    104 PepperDeviceEnumerationHostHelper::~PepperDeviceEnumerationHostHelper() {
    105 }
    106 
    107 bool PepperDeviceEnumerationHostHelper::HandleResourceMessage(
    108     const IPC::Message& msg,
    109     HostMessageContext* context,
    110     int32_t* result) {
    111   bool return_value = false;
    112   *result = InternalHandleResourceMessage(msg, context, &return_value);
    113   return return_value;
    114 }
    115 
    116 int32_t PepperDeviceEnumerationHostHelper::InternalHandleResourceMessage(
    117     const IPC::Message& msg,
    118     HostMessageContext* context,
    119     bool* handled) {
    120   *handled = true;
    121   IPC_BEGIN_MESSAGE_MAP(PepperDeviceEnumerationHostHelper, msg)
    122     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
    123         PpapiHostMsg_DeviceEnumeration_EnumerateDevices, OnEnumerateDevices)
    124     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
    125         PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange,
    126         OnMonitorDeviceChange)
    127     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
    128         PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange,
    129         OnStopMonitoringDeviceChange)
    130   IPC_END_MESSAGE_MAP()
    131 
    132   *handled = false;
    133   return PP_ERROR_FAILED;
    134 }
    135 
    136 int32_t PepperDeviceEnumerationHostHelper::OnEnumerateDevices(
    137     HostMessageContext* context) {
    138   if (enumerate_devices_context_)
    139     return PP_ERROR_INPROGRESS;
    140 
    141   enumerate_.reset(new ScopedRequest(
    142       this,
    143       base::Bind(&PepperDeviceEnumerationHostHelper::OnEnumerateDevicesComplete,
    144                  base::Unretained(this))));
    145   if (!enumerate_->requested())
    146     return PP_ERROR_FAILED;
    147 
    148   enumerate_devices_context_.reset(
    149       new ppapi::host::ReplyMessageContext(context->MakeReplyMessageContext()));
    150   return PP_OK_COMPLETIONPENDING;
    151 }
    152 
    153 int32_t PepperDeviceEnumerationHostHelper::OnMonitorDeviceChange(
    154     HostMessageContext* /* context */,
    155     uint32_t callback_id) {
    156   monitor_.reset(new ScopedRequest(
    157       this,
    158       base::Bind(&PepperDeviceEnumerationHostHelper::OnNotifyDeviceChange,
    159                  base::Unretained(this), callback_id)));
    160 
    161   return monitor_->requested() ? PP_OK : PP_ERROR_FAILED;
    162 }
    163 
    164 int32_t PepperDeviceEnumerationHostHelper::OnStopMonitoringDeviceChange(
    165     HostMessageContext* /* context */) {
    166   monitor_.reset(NULL);
    167   return PP_OK;
    168 }
    169 
    170 void PepperDeviceEnumerationHostHelper::OnEnumerateDevicesComplete(
    171     int /* request_id */,
    172     const std::vector<ppapi::DeviceRefData>& devices) {
    173   DCHECK(enumerate_devices_context_.get());
    174 
    175   enumerate_.reset(NULL);
    176 
    177   enumerate_devices_context_->params.set_result(PP_OK);
    178   resource_host_->host()->SendReply(
    179       *enumerate_devices_context_,
    180       PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply(devices));
    181   enumerate_devices_context_.reset();
    182 }
    183 
    184 void PepperDeviceEnumerationHostHelper::OnNotifyDeviceChange(
    185     uint32_t callback_id,
    186     int /* request_id */,
    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           devices));
    193 }
    194 
    195 }  // namespace content
    196