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 PPAPI_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 PPAPI_END_MESSAGE_MAP() 63 } 64 65 int32_t VideoCaptureResource::EnumerateDevices( 66 const PP_ArrayOutput& output, 67 scoped_refptr<TrackedCallback> callback) { 68 return enumeration_helper_.EnumerateDevices(output, callback); 69 } 70 71 int32_t VideoCaptureResource::MonitorDeviceChange( 72 PP_MonitorDeviceChangeCallback callback, 73 void* user_data) { 74 return enumeration_helper_.MonitorDeviceChange(callback, user_data); 75 } 76 77 int32_t VideoCaptureResource::Open( 78 const std::string& device_id, 79 const PP_VideoCaptureDeviceInfo_Dev& requested_info, 80 uint32_t buffer_count, 81 scoped_refptr<TrackedCallback> callback) { 82 if (open_state_ != BEFORE_OPEN) 83 return PP_ERROR_FAILED; 84 85 if (TrackedCallback::IsPending(open_callback_)) 86 return PP_ERROR_INPROGRESS; 87 88 open_callback_ = callback; 89 90 Call<PpapiPluginMsg_VideoCapture_OpenReply>( 91 RENDERER, 92 PpapiHostMsg_VideoCapture_Open(device_id, requested_info, buffer_count), 93 base::Bind(&VideoCaptureResource::OnPluginMsgOpenReply, this)); 94 return PP_OK_COMPLETIONPENDING; 95 } 96 97 int32_t VideoCaptureResource::StartCapture() { 98 if (open_state_ != OPENED) 99 return PP_ERROR_FAILED; 100 101 Post(RENDERER, PpapiHostMsg_VideoCapture_StartCapture()); 102 return PP_OK; 103 } 104 105 int32_t VideoCaptureResource::ReuseBuffer(uint32_t buffer) { 106 if (buffer >= buffer_in_use_.size() || !buffer_in_use_[buffer]) 107 return PP_ERROR_BADARGUMENT; 108 Post(RENDERER, PpapiHostMsg_VideoCapture_ReuseBuffer(buffer)); 109 return PP_OK; 110 } 111 112 int32_t VideoCaptureResource::StopCapture() { 113 if (open_state_ != OPENED) 114 return PP_ERROR_FAILED; 115 116 Post(RENDERER, PpapiHostMsg_VideoCapture_StopCapture()); 117 return PP_OK; 118 } 119 120 void VideoCaptureResource::Close() { 121 if (open_state_ == CLOSED) 122 return; 123 124 Post(RENDERER, PpapiHostMsg_VideoCapture_Close()); 125 126 open_state_ = CLOSED; 127 128 if (TrackedCallback::IsPending(open_callback_)) 129 open_callback_->PostAbort(); 130 } 131 132 int32_t VideoCaptureResource::EnumerateDevicesSync( 133 const PP_ArrayOutput& devices) { 134 return enumeration_helper_.EnumerateDevicesSync(devices); 135 } 136 137 void VideoCaptureResource::LastPluginRefWasDeleted() { 138 enumeration_helper_.LastPluginRefWasDeleted(); 139 } 140 141 void VideoCaptureResource::OnPluginMsgOnDeviceInfo( 142 const ResourceMessageReplyParams& params, 143 const struct PP_VideoCaptureDeviceInfo_Dev& info, 144 const std::vector<HostResource>& buffers, 145 uint32_t buffer_size) { 146 if (!ppp_video_capture_impl_) 147 return; 148 149 std::vector<base::SharedMemoryHandle> handles; 150 params.TakeAllSharedMemoryHandles(&handles); 151 CHECK(handles.size() == buffers.size()); 152 153 PluginResourceTracker* tracker = 154 PluginGlobals::Get()->plugin_resource_tracker(); 155 scoped_ptr<PP_Resource[]> resources(new PP_Resource[buffers.size()]); 156 for (size_t i = 0; i < buffers.size(); ++i) { 157 // We assume that the browser created a new set of resources. 158 DCHECK(!tracker->PluginResourceForHostResource(buffers[i])); 159 resources[i] = ppapi::proxy::PPB_Buffer_Proxy::AddProxyResource( 160 buffers[i], handles[i], buffer_size); 161 } 162 163 buffer_in_use_ = std::vector<bool>(buffers.size()); 164 165 CallWhileUnlocked(ppp_video_capture_impl_->OnDeviceInfo, 166 pp_instance(), 167 pp_resource(), 168 &info, 169 buffers.size(), 170 resources.get()); 171 172 for (size_t i = 0; i < buffers.size(); ++i) 173 tracker->ReleaseResource(resources[i]); 174 } 175 176 void VideoCaptureResource::OnPluginMsgOnStatus( 177 const ResourceMessageReplyParams& params, 178 uint32_t status) { 179 switch (status) { 180 case PP_VIDEO_CAPTURE_STATUS_STARTING: 181 case PP_VIDEO_CAPTURE_STATUS_STOPPING: 182 // Those states are not sent by the browser. 183 NOTREACHED(); 184 break; 185 } 186 if (ppp_video_capture_impl_) { 187 CallWhileUnlocked(ppp_video_capture_impl_->OnStatus, 188 pp_instance(), 189 pp_resource(), 190 status); 191 } 192 } 193 194 void VideoCaptureResource::OnPluginMsgOnError( 195 const ResourceMessageReplyParams& params, 196 uint32_t error_code) { 197 open_state_ = CLOSED; 198 if (ppp_video_capture_impl_) { 199 CallWhileUnlocked(ppp_video_capture_impl_->OnError, 200 pp_instance(), 201 pp_resource(), 202 error_code); 203 } 204 } 205 206 void VideoCaptureResource::OnPluginMsgOnBufferReady( 207 const ResourceMessageReplyParams& params, 208 uint32_t buffer) { 209 SetBufferInUse(buffer); 210 if (ppp_video_capture_impl_) { 211 CallWhileUnlocked(ppp_video_capture_impl_->OnBufferReady, 212 pp_instance(), 213 pp_resource(), 214 buffer); 215 } 216 } 217 218 void VideoCaptureResource::OnPluginMsgOpenReply( 219 const ResourceMessageReplyParams& params) { 220 if (open_state_ == BEFORE_OPEN && params.result() == PP_OK) 221 open_state_ = OPENED; 222 223 // The callback may have been aborted by Close(). 224 if (TrackedCallback::IsPending(open_callback_)) 225 open_callback_->Run(params.result()); 226 } 227 228 void VideoCaptureResource::SetBufferInUse(uint32_t buffer_index) { 229 CHECK(buffer_index < buffer_in_use_.size()); 230 buffer_in_use_[buffer_index] = true; 231 } 232 233 } // namespace proxy 234 } // namespace ppapi 235