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(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     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;
     55   }
     56 
     57   ~ScopedRequest() {
     58     if (requested_ && owner_->delegate_) {
     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     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) {}
    102 
    103 PepperDeviceEnumerationHostHelper::~PepperDeviceEnumerationHostHelper() {}
    104 
    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;
    112 }
    113 
    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()
    129 
    130   *handled = false;
    131   return PP_ERROR_FAILED;
    132 }
    133 
    134 int32_t PepperDeviceEnumerationHostHelper::OnEnumerateDevices(
    135     HostMessageContext* context) {
    136   if (enumerate_devices_context_.is_valid())
    137     return PP_ERROR_INPROGRESS;
    138 
    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;
    145 
    146   enumerate_devices_context_ = context->MakeReplyMessageContext();
    147   return PP_OK_COMPLETIONPENDING;
    148 }
    149 
    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)));
    158 
    159   return monitor_->requested() ? PP_OK : PP_ERROR_FAILED;
    160 }
    161 
    162 int32_t PepperDeviceEnumerationHostHelper::OnStopMonitoringDeviceChange(
    163     HostMessageContext* /* context */) {
    164   monitor_.reset(NULL);
    165   return PP_OK;
    166 }
    167 
    168 void PepperDeviceEnumerationHostHelper::OnEnumerateDevicesComplete(
    169     int /* request_id */,
    170     const std::vector<ppapi::DeviceRefData>& devices) {
    171   DCHECK(enumerate_devices_context_.is_valid());
    172 
    173   enumerate_.reset(NULL);
    174 
    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();
    180 }
    181 
    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));
    190 }
    191 
    192 }  // namespace content
    193