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/video_capture_resource.h" 6 7 #include "ppapi/c/dev/ppp_video_capture_dev.h" 8 #include "ppapi/proxy/dispatch_reply_message.h" 9 #include "ppapi/proxy/plugin_dispatcher.h" 10 #include "ppapi/proxy/plugin_globals.h" 11 #include "ppapi/proxy/plugin_resource_tracker.h" 12 #include "ppapi/proxy/ppapi_messages.h" 13 #include "ppapi/proxy/ppb_buffer_proxy.h" 14 #include "ppapi/proxy/resource_message_params.h" 15 #include "ppapi/shared_impl/proxy_lock.h" 16 #include "ppapi/shared_impl/tracked_callback.h" 17 18 namespace ppapi { 19 namespace proxy { 20 21 VideoCaptureResource::VideoCaptureResource( 22 Connection connection, 23 PP_Instance instance, 24 PluginDispatcher* dispatcher) 25 : PluginResource(connection, instance), 26 open_state_(BEFORE_OPEN), 27 enumeration_helper_(this) { 28 SendCreate(RENDERER, PpapiHostMsg_VideoCapture_Create()); 29 30 ppp_video_capture_impl_ = static_cast<const PPP_VideoCapture_Dev*>( 31 dispatcher->local_get_interface()(PPP_VIDEO_CAPTURE_DEV_INTERFACE)); 32 } 33 34 VideoCaptureResource::~VideoCaptureResource() { 35 } 36 37 void VideoCaptureResource::OnReplyReceived( 38 const ResourceMessageReplyParams& params, 39 const IPC::Message& msg) { 40 if (enumeration_helper_.HandleReply(params, msg)) 41 return; 42 43 if (params.sequence()) { 44 PluginResource::OnReplyReceived(params, msg); 45 return; 46 } 47 48 IPC_BEGIN_MESSAGE_MAP(VideoCaptureResource, msg) 49 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( 50 PpapiPluginMsg_VideoCapture_OnDeviceInfo, 51 OnPluginMsgOnDeviceInfo) 52 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( 53 PpapiPluginMsg_VideoCapture_OnStatus, 54 OnPluginMsgOnStatus) 55 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( 56 PpapiPluginMsg_VideoCapture_OnError, 57 OnPluginMsgOnError) 58 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( 59 PpapiPluginMsg_VideoCapture_OnBufferReady, 60 OnPluginMsgOnBufferReady) 61 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(NOTREACHED()) 62 IPC_END_MESSAGE_MAP() 63 } 64 65 int32_t VideoCaptureResource::EnumerateDevices0_2( 66 PP_Resource* devices, 67 scoped_refptr<TrackedCallback> callback) { 68 return enumeration_helper_.EnumerateDevices0_2(devices, callback); 69 } 70 71 int32_t VideoCaptureResource::EnumerateDevices( 72 const PP_ArrayOutput& output, 73 scoped_refptr<TrackedCallback> callback) { 74 return enumeration_helper_.EnumerateDevices(output, callback); 75 } 76 77 int32_t VideoCaptureResource::MonitorDeviceChange( 78 PP_MonitorDeviceChangeCallback callback, 79 void* user_data) { 80 return enumeration_helper_.MonitorDeviceChange(callback, user_data); 81 } 82 83 int32_t VideoCaptureResource::Open( 84 const std::string& device_id, 85 const PP_VideoCaptureDeviceInfo_Dev& requested_info, 86 uint32_t buffer_count, 87 scoped_refptr<TrackedCallback> callback) { 88 if (open_state_ != BEFORE_OPEN) 89 return PP_ERROR_FAILED; 90 91 if (TrackedCallback::IsPending(open_callback_)) 92 return PP_ERROR_INPROGRESS; 93 94 open_callback_ = callback; 95 96 Call<PpapiPluginMsg_VideoCapture_OpenReply>( 97 RENDERER, 98 PpapiHostMsg_VideoCapture_Open(device_id, requested_info, buffer_count), 99 base::Bind(&VideoCaptureResource::OnPluginMsgOpenReply, this)); 100 return PP_OK_COMPLETIONPENDING; 101 } 102 103 int32_t VideoCaptureResource::StartCapture() { 104 if (open_state_ != OPENED) 105 return PP_ERROR_FAILED; 106 107 Post(RENDERER, PpapiHostMsg_VideoCapture_StartCapture()); 108 return PP_OK; 109 } 110 111 int32_t VideoCaptureResource::ReuseBuffer(uint32_t buffer) { 112 if (buffer >= buffer_in_use_.size() || !buffer_in_use_[buffer]) 113 return PP_ERROR_BADARGUMENT; 114 Post(RENDERER, PpapiHostMsg_VideoCapture_ReuseBuffer(buffer)); 115 return PP_OK; 116 } 117 118 int32_t VideoCaptureResource::StopCapture() { 119 if (open_state_ != OPENED) 120 return PP_ERROR_FAILED; 121 122 Post(RENDERER, PpapiHostMsg_VideoCapture_StopCapture()); 123 return PP_OK; 124 } 125 126 void VideoCaptureResource::Close() { 127 if (open_state_ == CLOSED) 128 return; 129 130 Post(RENDERER, PpapiHostMsg_VideoCapture_Close()); 131 132 open_state_ = CLOSED; 133 134 if (TrackedCallback::IsPending(open_callback_)) 135 open_callback_->PostAbort(); 136 } 137 138 int32_t VideoCaptureResource::EnumerateDevicesSync( 139 const PP_ArrayOutput& devices) { 140 return enumeration_helper_.EnumerateDevicesSync(devices); 141 } 142 143 void VideoCaptureResource::LastPluginRefWasDeleted() { 144 enumeration_helper_.LastPluginRefWasDeleted(); 145 } 146 147 void VideoCaptureResource::OnPluginMsgOnDeviceInfo( 148 const ResourceMessageReplyParams& params, 149 const struct PP_VideoCaptureDeviceInfo_Dev& info, 150 const std::vector<HostResource>& buffers, 151 uint32_t buffer_size) { 152 if (!ppp_video_capture_impl_) 153 return; 154 155 std::vector<base::SharedMemoryHandle> handles; 156 params.TakeAllSharedMemoryHandles(&handles); 157 CHECK(handles.size() == buffers.size()); 158 159 PluginResourceTracker* tracker = 160 PluginGlobals::Get()->plugin_resource_tracker(); 161 scoped_ptr<PP_Resource[]> resources(new PP_Resource[buffers.size()]); 162 for (size_t i = 0; i < buffers.size(); ++i) { 163 // We assume that the browser created a new set of resources. 164 DCHECK(!tracker->PluginResourceForHostResource(buffers[i])); 165 resources[i] = ppapi::proxy::PPB_Buffer_Proxy::AddProxyResource( 166 buffers[i], handles[i], buffer_size); 167 } 168 169 buffer_in_use_ = std::vector<bool>(buffers.size()); 170 171 CallWhileUnlocked(ppp_video_capture_impl_->OnDeviceInfo, 172 pp_instance(), 173 pp_resource(), 174 &info, 175 static_cast<uint32_t>(buffers.size()), 176 const_cast<const PP_Resource*>(resources.get())); 177 178 for (size_t i = 0; i < buffers.size(); ++i) 179 tracker->ReleaseResource(resources[i]); 180 } 181 182 void VideoCaptureResource::OnPluginMsgOnStatus( 183 const ResourceMessageReplyParams& params, 184 uint32_t status) { 185 switch (status) { 186 case PP_VIDEO_CAPTURE_STATUS_STARTING: 187 case PP_VIDEO_CAPTURE_STATUS_STOPPING: 188 // Those states are not sent by the browser. 189 NOTREACHED(); 190 break; 191 } 192 if (ppp_video_capture_impl_) { 193 CallWhileUnlocked(ppp_video_capture_impl_->OnStatus, 194 pp_instance(), 195 pp_resource(), 196 status); 197 } 198 } 199 200 void VideoCaptureResource::OnPluginMsgOnError( 201 const ResourceMessageReplyParams& params, 202 uint32_t error_code) { 203 open_state_ = CLOSED; 204 if (ppp_video_capture_impl_) { 205 CallWhileUnlocked(ppp_video_capture_impl_->OnError, 206 pp_instance(), 207 pp_resource(), 208 error_code); 209 } 210 } 211 212 void VideoCaptureResource::OnPluginMsgOnBufferReady( 213 const ResourceMessageReplyParams& params, 214 uint32_t buffer) { 215 SetBufferInUse(buffer); 216 if (ppp_video_capture_impl_) { 217 CallWhileUnlocked(ppp_video_capture_impl_->OnBufferReady, 218 pp_instance(), 219 pp_resource(), 220 buffer); 221 } 222 } 223 224 void VideoCaptureResource::OnPluginMsgOpenReply( 225 const ResourceMessageReplyParams& params) { 226 if (open_state_ == BEFORE_OPEN && params.result() == PP_OK) 227 open_state_ = OPENED; 228 229 // The callback may have been aborted by Close(). 230 if (TrackedCallback::IsPending(open_callback_)) 231 open_callback_->Run(params.result()); 232 } 233 234 void VideoCaptureResource::SetBufferInUse(uint32_t buffer_index) { 235 CHECK(buffer_index < buffer_in_use_.size()); 236 buffer_in_use_[buffer_index] = true; 237 } 238 239 } // namespace proxy 240 } // namespace ppapi 241