| /* |
| * Copyright 2016 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 "hal_adapter/camera_hal_adapter.h" |
| |
| #include <fcntl.h> |
| |
| #include <deque> |
| #include <utility> |
| |
| #include <base/bind.h> |
| #include <base/bind_helpers.h> |
| #include <base/logging.h> |
| #include <base/posix/eintr_wrapper.h> |
| #include <mojo/edk/embedder/embedder.h> |
| #include <mojo/edk/embedder/platform_channel_utils_posix.h> |
| #include <mojo/edk/embedder/platform_handle_vector.h> |
| #include <mojo/edk/embedder/scoped_platform_handle.h> |
| |
| #include "hal_adapter/arc_camera3_mojo_utils.h" |
| #include "hal_adapter/camera_device_adapter.h" |
| #include "hal_adapter/camera_module_callbacks_delegate.h" |
| #include "hal_adapter/camera_module_delegate.h" |
| |
| namespace arc { |
| |
| CameraHalAdapter::CameraHalAdapter(camera_module_t* camera_module, |
| int socket_fd, |
| base::Closure quit_cb) |
| : camera_module_(camera_module), |
| socket_fd_(socket_fd), |
| ipc_thread_("Mojo IPC thread") { |
| VLOG(2) << "CameraHalAdapter::CameraHalAdapter"; |
| mojo::edk::Init(); |
| if (!ipc_thread_.StartWithOptions( |
| base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) { |
| LOG(ERROR) << "Mojo IPC thread failed to start"; |
| return; |
| } |
| mojo::edk::InitIPCSupport(this, ipc_thread_.task_runner()); |
| module_delegate_.reset(new CameraModuleDelegate(this, quit_cb)); |
| } |
| |
| CameraHalAdapter::~CameraHalAdapter() { |
| VLOG(2) << "CameraHalAdapter::~CameraHalAdapter"; |
| mojo::edk::ShutdownIPCSupport(); |
| } |
| |
| bool CameraHalAdapter::Start() { |
| if (!socket_fd_.is_valid()) { |
| LOG(ERROR) << "Invalid socket fd: " << socket_fd_.get(); |
| return false; |
| } |
| mojo::edk::ScopedPlatformHandle handle( |
| mojo::edk::PlatformHandle(socket_fd_.release())); |
| |
| // Make socket non-blocking. |
| int flags = HANDLE_EINTR(fcntl(handle.get().handle, F_GETFL)); |
| if (flags == -1) { |
| PLOG(ERROR) << "fcntl(F_GETFL)"; |
| return false; |
| } |
| if (HANDLE_EINTR(fcntl(handle.get().handle, F_SETFL, flags | O_NONBLOCK)) == |
| -1) { |
| PLOG(ERROR) << "fcntl(F_SETFL) failed to enable O_NONBLOCK"; |
| return false; |
| } |
| |
| char buf[1] = {}; |
| std::deque<mojo::edk::PlatformHandle> platform_handles; |
| mojo::edk::PlatformChannelRecvmsg(handle.get(), buf, sizeof(buf), |
| &platform_handles, true); |
| if (platform_handles.size() != 1) { |
| LOG(ERROR) << "Unexpected number of handles received, expected 1: " |
| << platform_handles.size(); |
| return false; |
| } |
| mojo::edk::ScopedPlatformHandle parent_pipe(platform_handles.back()); |
| platform_handles.pop_back(); |
| if (!parent_pipe.is_valid()) { |
| LOG(ERROR) << "Invalid parent pipe"; |
| return false; |
| } |
| mojo::edk::SetParentPipeHandle(std::move(parent_pipe)); |
| |
| char token[64] = {0}; |
| mojo::edk::PlatformChannelRecvmsg(handle.get(), token, sizeof(token), |
| &platform_handles, true); |
| VLOG(2) << "Got token: " << token; |
| mojo::ScopedMessagePipeHandle child_pipe = |
| mojo::edk::CreateChildMessagePipe(std::string(token)); |
| |
| module_delegate_->Bind(std::move(child_pipe)); |
| |
| VLOG(2) << "CameraHalAdapter started"; |
| return true; |
| } |
| |
| // Callback interface for camera_module_t APIs. |
| |
| mojom::OpenDeviceResultPtr CameraHalAdapter::OpenDevice(int32_t device_id) { |
| VLOG(2) << "CameraHalAdapter::OpenDevice"; |
| mojom::OpenDeviceResultPtr result = mojom::OpenDeviceResult::New(); |
| |
| if (device_adapters_.find(device_id) != device_adapters_.end()) { |
| LOG(WARNING) << "Multiple calls to OpenDevice on device " << device_id; |
| result->set_error(0); |
| return result; |
| } |
| camera3_device_t* camera_device; |
| char name[16]; |
| snprintf(name, sizeof(name), "%d", device_id); |
| int32_t ret = camera_module_->common.methods->open( |
| &camera_module_->common, name, |
| reinterpret_cast<hw_device_t**>(&camera_device)); |
| if (ret) { |
| result->set_error(ret); |
| } else { |
| device_adapters_[device_id].reset(new CameraDeviceAdapter(camera_device)); |
| mojom::Camera3DeviceOpsPtr device_ops = |
| device_adapters_.at(device_id)->GetDeviceOpsPtr(); |
| result->set_device_ops(std::move(device_ops)); |
| } |
| return result; |
| } |
| |
| int32_t CameraHalAdapter::CloseDevice(int32_t device_id) { |
| VLOG(2) << "CameraHalAdapter::CloseDevice"; |
| if (device_adapters_.find(device_id) == device_adapters_.end()) { |
| LOG(ERROR) << "Failed to close camera device " << device_id |
| << ": device is not opened"; |
| return -ENODEV; |
| } |
| int32_t result = device_adapters_.at(device_id)->Close(); |
| device_adapters_.erase(device_id); |
| return result; |
| } |
| |
| int32_t CameraHalAdapter::GetNumberOfCameras() { |
| VLOG(2) << "CameraHalAdapter::GetNumberOfCameras"; |
| return camera_module_->get_number_of_cameras(); |
| } |
| |
| mojom::GetCameraInfoResultPtr CameraHalAdapter::GetCameraInfo( |
| int32_t device_id) { |
| VLOG(2) << "CameraHalAdapter::GetCameraInfo"; |
| mojom::GetCameraInfoResultPtr result = mojom::GetCameraInfoResult::New(); |
| |
| camera_info_t info; |
| int32_t ret = camera_module_->get_camera_info(device_id, &info); |
| if (ret) { |
| result->set_error(ret); |
| return result; |
| } |
| |
| if (VLOG_IS_ON(2)) { |
| dump_camera_metadata(info.static_camera_characteristics, 2, 3); |
| } |
| |
| mojom::CameraInfoPtr info_ptr = mojom::CameraInfo::New(); |
| info_ptr->facing = info.facing; |
| info_ptr->orientation = info.orientation; |
| info_ptr->device_version = info.device_version; |
| mojo::ScopedDataPipeProducerHandle producer_handle; |
| mojo::ScopedDataPipeConsumerHandle consumer_handle; |
| ret = internal::SerializeCameraMetadata(&producer_handle, &consumer_handle, |
| info.static_camera_characteristics); |
| if (ret) { |
| LOG(ERROR) << "Failed to send camera metadata in GetCameraInfo"; |
| // The returned error code is -EIO but HAL need -EINVAL. |
| result->set_error(-EINVAL); |
| return result; |
| } |
| info_ptr->metadata_handle = std::move(consumer_handle); |
| |
| result->set_info(std::move(info_ptr)); |
| return result; |
| } |
| |
| int32_t CameraHalAdapter::SetCallbacks( |
| mojom::CameraModuleCallbacksPtr callbacks) { |
| VLOG(2) << "CameraHalAdapter::SetCallbacks"; |
| callbacks_delegate_.reset( |
| new CameraModuleCallbacksDelegate(callbacks.PassInterface())); |
| return camera_module_->set_callbacks(callbacks_delegate_.get()); |
| } |
| |
| } // namespace arc |