| /* |
| * Copyright 2017 The Chromium OS 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 "common/camera_algorithm_ops_impl.h" |
| |
| #include <utility> |
| #include <vector> |
| |
| #include <base/bind.h> |
| #include <base/files/file.h> |
| #include <base/logging.h> |
| #include <mojo/public/cpp/system/platform_handle.h> |
| |
| #include "cros-camera/common.h" |
| #include "cros-camera/future.h" |
| |
| namespace cros { |
| |
| CameraAlgorithmOpsImpl* CameraAlgorithmOpsImpl::singleton_ = nullptr; |
| |
| CameraAlgorithmOpsImpl::CameraAlgorithmOpsImpl() |
| : binding_(this), cam_algo_(nullptr) { |
| singleton_ = this; |
| } |
| |
| // static |
| CameraAlgorithmOpsImpl* CameraAlgorithmOpsImpl::GetInstance() { |
| static CameraAlgorithmOpsImpl impl; |
| return &impl; |
| } |
| |
| bool CameraAlgorithmOpsImpl::Bind( |
| mojom::CameraAlgorithmOpsRequest request, |
| camera_algorithm_ops_t* cam_algo, |
| scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner, |
| const base::Closure& ipc_lost_handler) { |
| DCHECK(ipc_task_runner->BelongsToCurrentThread()); |
| if (binding_.is_bound()) { |
| LOGF(ERROR) << "Algorithm Ops is already bound"; |
| return false; |
| } |
| DCHECK(!cam_algo_); |
| DCHECK(!ipc_task_runner_); |
| DCHECK(!cb_ptr_.is_bound()); |
| binding_.Bind(std::move(request)); |
| cam_algo_ = cam_algo; |
| ipc_task_runner_ = std::move(ipc_task_runner); |
| binding_.set_connection_error_handler(ipc_lost_handler); |
| return true; |
| } |
| |
| void CameraAlgorithmOpsImpl::Unbind() { |
| DCHECK(ipc_task_runner_->BelongsToCurrentThread()); |
| DCHECK(binding_.is_bound()); |
| DCHECK(cam_algo_); |
| DCHECK(ipc_task_runner_); |
| cb_ptr_.reset(); |
| ipc_task_runner_ = nullptr; |
| cam_algo_ = nullptr; |
| if (binding_.is_bound()) { |
| binding_.Unbind(); |
| } |
| } |
| |
| void CameraAlgorithmOpsImpl::Initialize( |
| mojom::CameraAlgorithmCallbackOpsPtr callback_ops, |
| InitializeCallback callback) { |
| DCHECK(cam_algo_); |
| DCHECK(ipc_task_runner_->BelongsToCurrentThread()); |
| DCHECK(callback_ops.is_bound()); |
| VLOGF_ENTER(); |
| int32_t result = 0; |
| if (cb_ptr_.is_bound()) { |
| LOGF(ERROR) << "Return callback is already registered"; |
| std::move(callback).Run(-EINVAL); |
| return; |
| } |
| CameraAlgorithmOpsImpl::return_callback = |
| CameraAlgorithmOpsImpl::ReturnCallbackForwarder; |
| result = cam_algo_->initialize(this); |
| cb_ptr_ = std::move(callback_ops); |
| std::move(callback).Run(result); |
| VLOGF_EXIT(); |
| } |
| |
| void CameraAlgorithmOpsImpl::RegisterBuffer(mojo::ScopedHandle buffer_fd, |
| RegisterBufferCallback callback) { |
| DCHECK(cam_algo_); |
| DCHECK(ipc_task_runner_->BelongsToCurrentThread()); |
| VLOGF_ENTER(); |
| base::PlatformFile fd; |
| MojoResult mojo_result = mojo::UnwrapPlatformFile(std::move(buffer_fd), &fd); |
| if (mojo_result != MOJO_RESULT_OK) { |
| LOGF(ERROR) << "Failed to unwrap handle: " << mojo_result; |
| std::move(callback).Run(-EBADF); |
| return; |
| } |
| int32_t result = cam_algo_->register_buffer(fd); |
| std::move(callback).Run(result); |
| VLOGF_EXIT(); |
| } |
| |
| void CameraAlgorithmOpsImpl::Request(uint32_t req_id, |
| const std::vector<uint8_t>& req_header, |
| int32_t buffer_handle) { |
| DCHECK(cam_algo_); |
| DCHECK(ipc_task_runner_->BelongsToCurrentThread()); |
| VLOGF_ENTER(); |
| if (!cb_ptr_.is_bound()) { |
| LOGF(ERROR) << "Return callback is not registered yet"; |
| return; |
| } |
| // TODO(b/37434548): This can be removed after libchrome uprev. |
| const std::vector<uint8_t>& header = req_header; |
| cam_algo_->request(req_id, header.data(), header.size(), buffer_handle); |
| VLOGF_EXIT(); |
| } |
| |
| void CameraAlgorithmOpsImpl::DeregisterBuffers( |
| const std::vector<int32_t>& buffer_handles) { |
| DCHECK(cam_algo_); |
| DCHECK(ipc_task_runner_->BelongsToCurrentThread()); |
| VLOGF_ENTER(); |
| // TODO(b/37434548): This can be removed after libchrome uprev. |
| const std::vector<int32_t>& handles = buffer_handles; |
| cam_algo_->deregister_buffers(handles.data(), handles.size()); |
| VLOGF_EXIT(); |
| } |
| |
| // static |
| void CameraAlgorithmOpsImpl::ReturnCallbackForwarder( |
| const camera_algorithm_callback_ops_t* callback_ops, |
| uint32_t req_id, |
| uint32_t status, |
| int32_t buffer_handle) { |
| VLOGF_ENTER(); |
| if (const_cast<CameraAlgorithmOpsImpl*>( |
| static_cast<const CameraAlgorithmOpsImpl*>(callback_ops)) != |
| singleton_) { |
| LOGF(ERROR) << "Invalid callback ops provided"; |
| return; |
| } |
| singleton_->ipc_task_runner_->PostTask( |
| FROM_HERE, |
| base::Bind(&CameraAlgorithmOpsImpl::ReturnCallbackOnIPCThread, |
| base::Unretained(singleton_), req_id, status, buffer_handle)); |
| } |
| |
| void CameraAlgorithmOpsImpl::ReturnCallbackOnIPCThread(uint32_t req_id, |
| uint32_t status, |
| int32_t buffer_handle) { |
| DCHECK(ipc_task_runner_->BelongsToCurrentThread()); |
| VLOGF_ENTER(); |
| if (!cb_ptr_.is_bound()) { |
| LOGF(WARNING) << "Callback is not bound. IPC broken?"; |
| } else { |
| cb_ptr_->Return(req_id, status, buffer_handle); |
| } |
| VLOGF_EXIT(); |
| } |
| |
| } // namespace cros |