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 25namespace ppapi { 26namespace proxy { 27 28DeviceEnumerationResourceHelper::DeviceEnumerationResourceHelper( 29 PluginResource* owner) 30 : owner_(owner), 31 pending_enumerate_devices_(false), 32 monitor_callback_id_(0), 33 monitor_user_data_(NULL) { 34} 35 36DeviceEnumerationResourceHelper::~DeviceEnumerationResourceHelper() { 37} 38 39int32_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 55int32_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 70int32_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 93bool 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 106void 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 117void 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 137void 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 165int32_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