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::EnumerateDevices0_2(
     40     PP_Resource* devices,
     41     scoped_refptr<TrackedCallback> callback) {
     42   if (pending_enumerate_devices_)
     43     return PP_ERROR_INPROGRESS;
     44   if (!devices)
     45     return PP_ERROR_BADARGUMENT;
     46 
     47   pending_enumerate_devices_ = true;
     48   PpapiHostMsg_DeviceEnumeration_EnumerateDevices msg;
     49   owner_->Call<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(
     50       PluginResource::RENDERER, msg,
     51       base::Bind(
     52           &DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply0_2,
     53           AsWeakPtr(), devices, callback));
     54   return PP_OK_COMPLETIONPENDING;
     55 }
     56 
     57 int32_t DeviceEnumerationResourceHelper::EnumerateDevices(
     58     const PP_ArrayOutput& output,
     59     scoped_refptr<TrackedCallback> callback) {
     60   if (pending_enumerate_devices_)
     61     return PP_ERROR_INPROGRESS;
     62 
     63   pending_enumerate_devices_ = true;
     64   PpapiHostMsg_DeviceEnumeration_EnumerateDevices msg;
     65   owner_->Call<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(
     66       PluginResource::RENDERER, msg,
     67       base::Bind(
     68           &DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply,
     69           AsWeakPtr(), output, callback));
     70   return PP_OK_COMPLETIONPENDING;
     71 }
     72 
     73 int32_t DeviceEnumerationResourceHelper::EnumerateDevicesSync(
     74     const PP_ArrayOutput& output) {
     75   std::vector<DeviceRefData> devices;
     76   int32_t result =
     77       owner_->SyncCall<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(
     78           PluginResource::RENDERER,
     79           PpapiHostMsg_DeviceEnumeration_EnumerateDevices(),
     80           &devices);
     81 
     82   if (result == PP_OK)
     83     result = WriteToArrayOutput(devices, output);
     84 
     85   return result;
     86 }
     87 
     88 int32_t DeviceEnumerationResourceHelper::MonitorDeviceChange(
     89     PP_MonitorDeviceChangeCallback callback,
     90     void* user_data) {
     91   monitor_callback_id_++;
     92   monitor_user_data_ = user_data;
     93   if (callback) {
     94     monitor_callback_.reset(
     95         ThreadAwareCallback<PP_MonitorDeviceChangeCallback>::Create(callback));
     96     if (!monitor_callback_.get())
     97       return PP_ERROR_NO_MESSAGE_LOOP;
     98 
     99     owner_->Post(PluginResource::RENDERER,
    100                  PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange(
    101                      monitor_callback_id_));
    102   } else {
    103     monitor_callback_.reset(NULL);
    104 
    105     owner_->Post(PluginResource::RENDERER,
    106                  PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange());
    107   }
    108   return PP_OK;
    109 }
    110 
    111 bool DeviceEnumerationResourceHelper::HandleReply(
    112     const ResourceMessageReplyParams& params,
    113     const IPC::Message& msg) {
    114   IPC_BEGIN_MESSAGE_MAP(DeviceEnumerationResourceHelper, msg)
    115     PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
    116         PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange,
    117         OnPluginMsgNotifyDeviceChange)
    118     PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(return false)
    119   IPC_END_MESSAGE_MAP()
    120 
    121   return true;
    122 }
    123 
    124 void DeviceEnumerationResourceHelper::LastPluginRefWasDeleted() {
    125   // Make sure that no further notifications are sent to the plugin.
    126   monitor_callback_id_++;
    127   monitor_callback_.reset(NULL);
    128   monitor_user_data_ = NULL;
    129 
    130   // There is no need to do anything with pending callback of
    131   // EnumerateDevices(), because OnPluginMsgEnumerateDevicesReply*() will handle
    132   // that properly.
    133 }
    134 
    135 void DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply0_2(
    136     PP_Resource* devices_resource,
    137     scoped_refptr<TrackedCallback> callback,
    138     const ResourceMessageReplyParams& params,
    139     const std::vector<DeviceRefData>& devices) {
    140   pending_enumerate_devices_ = false;
    141 
    142   // We shouldn't access |devices_resource| if the callback has been called,
    143   // which is possible if the last plugin reference to the corresponding
    144   // resource has gone away, and the callback has been aborted.
    145   if (!TrackedCallback::IsPending(callback))
    146     return;
    147 
    148   if (params.result() == PP_OK) {
    149     *devices_resource = PPB_DeviceRef_Shared::CreateResourceArray(
    150         OBJECT_IS_PROXY, owner_->pp_instance(), devices);
    151   }
    152 
    153   callback->Run(params.result());
    154 }
    155 
    156 void DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply(
    157     const PP_ArrayOutput& output,
    158     scoped_refptr<TrackedCallback> callback,
    159     const ResourceMessageReplyParams& params,
    160     const std::vector<DeviceRefData>& devices) {
    161   pending_enumerate_devices_ = false;
    162 
    163   // We shouldn't access |output| if the callback has been called, which is
    164   // possible if the last plugin reference to the corresponding resource has
    165   // gone away, and the callback has been aborted.
    166   if (!TrackedCallback::IsPending(callback))
    167     return;
    168 
    169   int32_t result = params.result();
    170   if (result == PP_OK)
    171     result = WriteToArrayOutput(devices, output);
    172 
    173   callback->Run(result);
    174 }
    175 
    176 void DeviceEnumerationResourceHelper::OnPluginMsgNotifyDeviceChange(
    177     const ResourceMessageReplyParams& /* params */,
    178     uint32_t callback_id,
    179     const std::vector<DeviceRefData>& devices) {
    180   if (monitor_callback_id_ != callback_id) {
    181     // A new callback or NULL has been set.
    182     return;
    183   }
    184 
    185   CHECK(monitor_callback_.get());
    186 
    187   scoped_ptr<PP_Resource[]> elements;
    188   uint32_t size = devices.size();
    189   if (size > 0) {
    190     elements.reset(new PP_Resource[size]);
    191     for (size_t index = 0; index < size; ++index) {
    192       PPB_DeviceRef_Shared* device_object = new PPB_DeviceRef_Shared(
    193           OBJECT_IS_PROXY, owner_->pp_instance(), devices[index]);
    194       elements[index] = device_object->GetReference();
    195     }
    196   }
    197 
    198   monitor_callback_->RunOnTargetThread(monitor_user_data_, size,
    199                                        elements.get());
    200   for (size_t index = 0; index < size; ++index)
    201     PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(elements[index]);
    202 }
    203 
    204 int32_t DeviceEnumerationResourceHelper::WriteToArrayOutput(
    205     const std::vector<DeviceRefData>& devices,
    206     const PP_ArrayOutput& output) {
    207   ArrayWriter writer(output);
    208   if (!writer.is_valid())
    209     return PP_ERROR_BADARGUMENT;
    210 
    211   std::vector<scoped_refptr<Resource> > device_resources;
    212   for (size_t i = 0; i < devices.size(); ++i) {
    213     device_resources.push_back(new PPB_DeviceRef_Shared(
    214         OBJECT_IS_PROXY, owner_->pp_instance(), devices[i]));
    215   }
    216   if (!writer.StoreResourceVector(device_resources))
    217     return PP_ERROR_FAILED;
    218 
    219   return PP_OK;
    220 }
    221 
    222 }  // namespace proxy
    223 }  // namespace ppapi
    224