// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ppapi/proxy/video_capture_resource.h" #include "ppapi/c/dev/ppp_video_capture_dev.h" #include "ppapi/proxy/dispatch_reply_message.h" #include "ppapi/proxy/plugin_dispatcher.h" #include "ppapi/proxy/plugin_globals.h" #include "ppapi/proxy/plugin_resource_tracker.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/ppb_buffer_proxy.h" #include "ppapi/proxy/resource_message_params.h" #include "ppapi/shared_impl/proxy_lock.h" #include "ppapi/shared_impl/tracked_callback.h" namespace ppapi { namespace proxy { VideoCaptureResource::VideoCaptureResource( Connection connection, PP_Instance instance, PluginDispatcher* dispatcher) : PluginResource(connection, instance), open_state_(BEFORE_OPEN), enumeration_helper_(this) { SendCreate(RENDERER, PpapiHostMsg_VideoCapture_Create()); ppp_video_capture_impl_ = static_cast( dispatcher->local_get_interface()(PPP_VIDEO_CAPTURE_DEV_INTERFACE)); } VideoCaptureResource::~VideoCaptureResource() { } void VideoCaptureResource::OnReplyReceived( const ResourceMessageReplyParams& params, const IPC::Message& msg) { if (enumeration_helper_.HandleReply(params, msg)) return; if (params.sequence()) { PluginResource::OnReplyReceived(params, msg); return; } IPC_BEGIN_MESSAGE_MAP(VideoCaptureResource, msg) PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( PpapiPluginMsg_VideoCapture_OnDeviceInfo, OnPluginMsgOnDeviceInfo) PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( PpapiPluginMsg_VideoCapture_OnStatus, OnPluginMsgOnStatus) PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( PpapiPluginMsg_VideoCapture_OnError, OnPluginMsgOnError) PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( PpapiPluginMsg_VideoCapture_OnBufferReady, OnPluginMsgOnBufferReady) PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(NOTREACHED()) IPC_END_MESSAGE_MAP() } int32_t VideoCaptureResource::EnumerateDevices( const PP_ArrayOutput& output, scoped_refptr callback) { return enumeration_helper_.EnumerateDevices(output, callback); } int32_t VideoCaptureResource::MonitorDeviceChange( PP_MonitorDeviceChangeCallback callback, void* user_data) { return enumeration_helper_.MonitorDeviceChange(callback, user_data); } int32_t VideoCaptureResource::Open( const std::string& device_id, const PP_VideoCaptureDeviceInfo_Dev& requested_info, uint32_t buffer_count, scoped_refptr callback) { if (open_state_ != BEFORE_OPEN) return PP_ERROR_FAILED; if (TrackedCallback::IsPending(open_callback_)) return PP_ERROR_INPROGRESS; open_callback_ = callback; Call( RENDERER, PpapiHostMsg_VideoCapture_Open(device_id, requested_info, buffer_count), base::Bind(&VideoCaptureResource::OnPluginMsgOpenReply, this)); return PP_OK_COMPLETIONPENDING; } int32_t VideoCaptureResource::StartCapture() { if (open_state_ != OPENED) return PP_ERROR_FAILED; Post(RENDERER, PpapiHostMsg_VideoCapture_StartCapture()); return PP_OK; } int32_t VideoCaptureResource::ReuseBuffer(uint32_t buffer) { if (buffer >= buffer_in_use_.size() || !buffer_in_use_[buffer]) return PP_ERROR_BADARGUMENT; Post(RENDERER, PpapiHostMsg_VideoCapture_ReuseBuffer(buffer)); return PP_OK; } int32_t VideoCaptureResource::StopCapture() { if (open_state_ != OPENED) return PP_ERROR_FAILED; Post(RENDERER, PpapiHostMsg_VideoCapture_StopCapture()); return PP_OK; } void VideoCaptureResource::Close() { if (open_state_ == CLOSED) return; Post(RENDERER, PpapiHostMsg_VideoCapture_Close()); open_state_ = CLOSED; if (TrackedCallback::IsPending(open_callback_)) open_callback_->PostAbort(); } int32_t VideoCaptureResource::EnumerateDevicesSync( const PP_ArrayOutput& devices) { return enumeration_helper_.EnumerateDevicesSync(devices); } void VideoCaptureResource::LastPluginRefWasDeleted() { enumeration_helper_.LastPluginRefWasDeleted(); } void VideoCaptureResource::OnPluginMsgOnDeviceInfo( const ResourceMessageReplyParams& params, const struct PP_VideoCaptureDeviceInfo_Dev& info, const std::vector& buffers, uint32_t buffer_size) { if (!ppp_video_capture_impl_) return; std::vector handles; params.TakeAllSharedMemoryHandles(&handles); CHECK(handles.size() == buffers.size()); PluginResourceTracker* tracker = PluginGlobals::Get()->plugin_resource_tracker(); scoped_ptr resources(new PP_Resource[buffers.size()]); for (size_t i = 0; i < buffers.size(); ++i) { // We assume that the browser created a new set of resources. DCHECK(!tracker->PluginResourceForHostResource(buffers[i])); resources[i] = ppapi::proxy::PPB_Buffer_Proxy::AddProxyResource( buffers[i], handles[i], buffer_size); } buffer_in_use_ = std::vector(buffers.size()); CallWhileUnlocked(ppp_video_capture_impl_->OnDeviceInfo, pp_instance(), pp_resource(), &info, static_cast(buffers.size()), const_cast(resources.get())); for (size_t i = 0; i < buffers.size(); ++i) tracker->ReleaseResource(resources[i]); } void VideoCaptureResource::OnPluginMsgOnStatus( const ResourceMessageReplyParams& params, uint32_t status) { switch (status) { case PP_VIDEO_CAPTURE_STATUS_STARTING: case PP_VIDEO_CAPTURE_STATUS_STOPPING: // Those states are not sent by the browser. NOTREACHED(); break; } if (ppp_video_capture_impl_) { CallWhileUnlocked(ppp_video_capture_impl_->OnStatus, pp_instance(), pp_resource(), status); } } void VideoCaptureResource::OnPluginMsgOnError( const ResourceMessageReplyParams& params, uint32_t error_code) { open_state_ = CLOSED; if (ppp_video_capture_impl_) { CallWhileUnlocked(ppp_video_capture_impl_->OnError, pp_instance(), pp_resource(), error_code); } } void VideoCaptureResource::OnPluginMsgOnBufferReady( const ResourceMessageReplyParams& params, uint32_t buffer) { SetBufferInUse(buffer); if (ppp_video_capture_impl_) { CallWhileUnlocked(ppp_video_capture_impl_->OnBufferReady, pp_instance(), pp_resource(), buffer); } } void VideoCaptureResource::OnPluginMsgOpenReply( const ResourceMessageReplyParams& params) { if (open_state_ == BEFORE_OPEN && params.result() == PP_OK) open_state_ = OPENED; // The callback may have been aborted by Close(). if (TrackedCallback::IsPending(open_callback_)) open_callback_->Run(params.result()); } void VideoCaptureResource::SetBufferInUse(uint32_t buffer_index) { CHECK(buffer_index < buffer_in_use_.size()); buffer_in_use_[buffer_index] = true; } } // namespace proxy } // namespace ppapi