Home | History | Annotate | Download | only in proxy
      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 "ppapi/proxy/device_enumeration_resource_helper.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "ipc/ipc_message.h"
     11 #include "ipc/ipc_message_macros.h"
     12 #include "ppapi/c/pp_array_output.h"
     13 #include "ppapi/c/pp_errors.h"
     14 #include "ppapi/proxy/dispatch_reply_message.h"
     15 #include "ppapi/proxy/plugin_resource.h"
     16 #include "ppapi/proxy/ppapi_messages.h"
     17 #include "ppapi/proxy/resource_message_params.h"
     18 #include "ppapi/shared_impl/array_writer.h"
     19 #include "ppapi/shared_impl/ppapi_globals.h"
     20 #include "ppapi/shared_impl/ppb_device_ref_shared.h"
     21 #include "ppapi/shared_impl/proxy_lock.h"
     22 #include "ppapi/shared_impl/resource_tracker.h"
     23 #include "ppapi/shared_impl/tracked_callback.h"
     24 
     25 namespace ppapi {
     26 namespace proxy {
     27 
     28 DeviceEnumerationResourceHelper::DeviceEnumerationResourceHelper(
     29     PluginResource* owner)
     30     : owner_(owner),
     31       pending_enumerate_devices_(false),
     32       monitor_callback_id_(0),
     33       monitor_user_data_(NULL) {
     34 }
     35 
     36 DeviceEnumerationResourceHelper::~DeviceEnumerationResourceHelper() {
     37 }
     38 
     39 int32_t DeviceEnumerationResourceHelper::EnumerateDevices(
     40     const PP_ArrayOutput& output,
     41     scoped_refptr<TrackedCallback> callback) {
     42   if (pending_enumerate_devices_)
     43     return PP_ERROR_INPROGRESS;
     44 
     45   pending_enumerate_devices_ = true;
     46   PpapiHostMsg_DeviceEnumeration_EnumerateDevices msg;
     47   owner_->Call<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(
     48       PluginResource::RENDERER, msg,
     49       base::Bind(
     50           &DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply,
     51           AsWeakPtr(), output, callback));
     52   return PP_OK_COMPLETIONPENDING;
     53 }
     54 
     55 int32_t DeviceEnumerationResourceHelper::EnumerateDevicesSync(
     56     const PP_ArrayOutput& output) {
     57   std::vector<DeviceRefData> devices;
     58   int32_t result =
     59       owner_->SyncCall<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(
     60           PluginResource::RENDERER,
     61           PpapiHostMsg_DeviceEnumeration_EnumerateDevices(),
     62           &devices);
     63 
     64   if (result == PP_OK)
     65     result = WriteToArrayOutput(devices, output);
     66 
     67   return result;
     68 }
     69 
     70 int32_t DeviceEnumerationResourceHelper::MonitorDeviceChange(
     71     PP_MonitorDeviceChangeCallback callback,
     72     void* user_data) {
     73   monitor_callback_id_++;
     74   monitor_user_data_ = user_data;
     75   if (callback) {
     76     monitor_callback_.reset(
     77         ThreadAwareCallback<PP_MonitorDeviceChangeCallback>::Create(callback));
     78     if (!monitor_callback_.get())
     79       return PP_ERROR_NO_MESSAGE_LOOP;
     80 
     81     owner_->Post(PluginResource::RENDERER,
     82                  PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange(
     83                      monitor_callback_id_));
     84   } else {
     85     monitor_callback_.reset(NULL);
     86 
     87     owner_->Post(PluginResource::RENDERER,
     88                  PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange());
     89   }
     90   return PP_OK;
     91 }
     92 
     93 bool DeviceEnumerationResourceHelper::HandleReply(
     94     const ResourceMessageReplyParams& params,
     95     const IPC::Message& msg) {
     96   PPAPI_BEGIN_MESSAGE_MAP(DeviceEnumerationResourceHelper, msg)
     97     PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
     98         PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange,
     99         OnPluginMsgNotifyDeviceChange)
    100     PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(return false)
    101   PPAPI_END_MESSAGE_MAP()
    102 
    103   return true;
    104 }
    105 
    106 void DeviceEnumerationResourceHelper::LastPluginRefWasDeleted() {
    107   // Make sure that no further notifications are sent to the plugin.
    108   monitor_callback_id_++;
    109   monitor_callback_.reset(NULL);
    110   monitor_user_data_ = NULL;
    111 
    112   // There is no need to do anything with pending callback of
    113   // EnumerateDevices(), because OnPluginMsgEnumerateDevicesReply*() will handle
    114   // that properly.
    115 }
    116 
    117 void DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply(
    118     const PP_ArrayOutput& output,
    119     scoped_refptr<TrackedCallback> callback,
    120     const ResourceMessageReplyParams& params,
    121     const std::vector<DeviceRefData>& devices) {
    122   pending_enumerate_devices_ = false;
    123 
    124   // We shouldn't access |output| if the callback has been called, which is
    125   // possible if the last plugin reference to the corresponding resource has
    126   // gone away, and the callback has been aborted.
    127   if (!TrackedCallback::IsPending(callback))
    128     return;
    129 
    130   int32_t result = params.result();
    131   if (result == PP_OK)
    132     result = WriteToArrayOutput(devices, output);
    133 
    134   callback->Run(result);
    135 }
    136 
    137 void DeviceEnumerationResourceHelper::OnPluginMsgNotifyDeviceChange(
    138     const ResourceMessageReplyParams& /* params */,
    139     uint32_t callback_id,
    140     const std::vector<DeviceRefData>& devices) {
    141   if (monitor_callback_id_ != callback_id) {
    142     // A new callback or NULL has been set.
    143     return;
    144   }
    145 
    146   CHECK(monitor_callback_.get());
    147 
    148   scoped_ptr<PP_Resource[]> elements;
    149   uint32_t size = devices.size();
    150   if (size > 0) {
    151     elements.reset(new PP_Resource[size]);
    152     for (size_t index = 0; index < size; ++index) {
    153       PPB_DeviceRef_Shared* device_object = new PPB_DeviceRef_Shared(
    154           OBJECT_IS_PROXY, owner_->pp_instance(), devices[index]);
    155       elements[index] = device_object->GetReference();
    156     }
    157   }
    158 
    159   monitor_callback_->RunOnTargetThread(monitor_user_data_, size,
    160                                        elements.get());
    161   for (size_t index = 0; index < size; ++index)
    162     PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(elements[index]);
    163 }
    164 
    165 int32_t DeviceEnumerationResourceHelper::WriteToArrayOutput(
    166     const std::vector<DeviceRefData>& devices,
    167     const PP_ArrayOutput& output) {
    168   ArrayWriter writer(output);
    169   if (!writer.is_valid())
    170     return PP_ERROR_BADARGUMENT;
    171 
    172   std::vector<scoped_refptr<Resource> > device_resources;
    173   for (size_t i = 0; i < devices.size(); ++i) {
    174     device_resources.push_back(new PPB_DeviceRef_Shared(
    175         OBJECT_IS_PROXY, owner_->pp_instance(), devices[i]));
    176   }
    177   if (!writer.StoreResourceVector(device_resources))
    178     return PP_ERROR_FAILED;
    179 
    180   return PP_OK;
    181 }
    182 
    183 }  // namespace proxy
    184 }  // namespace ppapi
    185