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 18namespace ppapi { 19namespace proxy { 20 21VideoCaptureResource::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 34VideoCaptureResource::~VideoCaptureResource() { 35} 36 37void 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 65int32_t VideoCaptureResource::EnumerateDevices( 66 const PP_ArrayOutput& output, 67 scoped_refptr<TrackedCallback> callback) { 68 return enumeration_helper_.EnumerateDevices(output, callback); 69} 70 71int32_t VideoCaptureResource::MonitorDeviceChange( 72 PP_MonitorDeviceChangeCallback callback, 73 void* user_data) { 74 return enumeration_helper_.MonitorDeviceChange(callback, user_data); 75} 76 77int32_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 97int32_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 105int32_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 112int32_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 120void 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 132int32_t VideoCaptureResource::EnumerateDevicesSync( 133 const PP_ArrayOutput& devices) { 134 return enumeration_helper_.EnumerateDevicesSync(devices); 135} 136 137void VideoCaptureResource::LastPluginRefWasDeleted() { 138 enumeration_helper_.LastPluginRefWasDeleted(); 139} 140 141void 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 176void 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 194void 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 206void 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 218void 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 228void 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