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