| #define LOG_TAG "PoseClient" | |
| #include <dvr/dvr_shared_buffers.h> | |
| #include <dvr/pose_client.h> | |
| #include <stdint.h> | |
| #include <log/log.h> | |
| #include <pdx/client.h> | |
| #include <pdx/default_transport/client_channel_factory.h> | |
| #include <pdx/file_handle.h> | |
| #include <private/dvr/buffer_hub_client.h> | |
| #include <private/dvr/buffer_hub_queue_client.h> | |
| #include <private/dvr/display_client.h> | |
| #include <private/dvr/pose-ipc.h> | |
| #include <private/dvr/shared_buffer_helpers.h> | |
| using android::dvr::ConsumerQueue; | |
| using android::pdx::LocalHandle; | |
| using android::pdx::LocalChannelHandle; | |
| using android::pdx::Status; | |
| using android::pdx::Transaction; | |
| namespace android { | |
| namespace dvr { | |
| namespace { | |
| typedef CPUMappedBroadcastRing<DvrPoseRing> SensorPoseRing; | |
| constexpr static int32_t MAX_CONTROLLERS = 2; | |
| } // namespace | |
| // PoseClient is a remote interface to the pose service in sensord. | |
| class PoseClient : public pdx::ClientBase<PoseClient> { | |
| public: | |
| ~PoseClient() override {} | |
| // Casts C handle into an instance of this class. | |
| static PoseClient* FromC(DvrPoseClient* client) { | |
| return reinterpret_cast<PoseClient*>(client); | |
| } | |
| // Polls the pose service for the current state and stores it in *state. | |
| // Returns zero on success, a negative error code otherwise. | |
| int Poll(DvrPose* state) { | |
| // Allocate the helper class to access the sensor pose buffer. | |
| if (sensor_pose_buffer_ == nullptr) { | |
| sensor_pose_buffer_ = std::make_unique<SensorPoseRing>( | |
| DvrGlobalBuffers::kSensorPoseBuffer, CPUUsageMode::READ_RARELY); | |
| } | |
| if (state) { | |
| if (sensor_pose_buffer_->GetNewest(state)) { | |
| return 0; | |
| } else { | |
| return -EAGAIN; | |
| } | |
| } | |
| return -EINVAL; | |
| } | |
| int GetPose(uint32_t vsync_count, DvrPoseAsync* out_pose) { | |
| const auto vsync_buffer = GetVsyncBuffer(); | |
| if (vsync_buffer) { | |
| *out_pose = | |
| vsync_buffer | |
| ->vsync_poses[vsync_count & DvrVsyncPoseBuffer::kIndexMask]; | |
| return 0; | |
| } else { | |
| return -EAGAIN; | |
| } | |
| } | |
| uint32_t GetVsyncCount() { | |
| const auto vsync_buffer = GetVsyncBuffer(); | |
| if (vsync_buffer) { | |
| return vsync_buffer->vsync_count; | |
| } | |
| return 0; | |
| } | |
| int GetControllerPose(int32_t controller_id, uint32_t vsync_count, | |
| DvrPoseAsync* out_pose) { | |
| if (controller_id < 0 || controller_id >= MAX_CONTROLLERS) { | |
| return -EINVAL; | |
| } | |
| if (!controllers_[controller_id].mapped_pose_buffer) { | |
| int ret = GetControllerRingBuffer(controller_id); | |
| if (ret < 0) | |
| return ret; | |
| } | |
| *out_pose = | |
| controllers_[controller_id] | |
| .mapped_pose_buffer[vsync_count & DvrVsyncPoseBuffer::kIndexMask]; | |
| return 0; | |
| } | |
| int LogController(bool enable) { | |
| Transaction trans{*this}; | |
| Status<int> status = trans.Send<int>(DVR_POSE_LOG_CONTROLLER, &enable, | |
| sizeof(enable), nullptr, 0); | |
| ALOGE_IF(!status, "Pose LogController() failed because: %s", | |
| status.GetErrorMessage().c_str()); | |
| return ReturnStatusOrError(status); | |
| } | |
| // Freezes the pose to the provided state. Future poll operations will return | |
| // this state until a different state is frozen or SetMode() is called with a | |
| // different mode. | |
| // Returns zero on success, a negative error code otherwise. | |
| int Freeze(const DvrPose& frozen_state) { | |
| Transaction trans{*this}; | |
| Status<int> status = trans.Send<int>(DVR_POSE_FREEZE, &frozen_state, | |
| sizeof(frozen_state), nullptr, 0); | |
| ALOGE_IF(!status, "Pose Freeze() failed because: %s\n", | |
| status.GetErrorMessage().c_str()); | |
| return ReturnStatusOrError(status); | |
| } | |
| // Sets the data mode for the pose service. | |
| int SetMode(DvrPoseMode mode) { | |
| Transaction trans{*this}; | |
| Status<int> status = | |
| trans.Send<int>(DVR_POSE_SET_MODE, &mode, sizeof(mode), nullptr, 0); | |
| ALOGE_IF(!status, "Pose SetPoseMode() failed because: %s", | |
| status.GetErrorMessage().c_str()); | |
| return ReturnStatusOrError(status); | |
| } | |
| // Gets the data mode for the pose service. | |
| int GetMode(DvrPoseMode* out_mode) { | |
| int mode; | |
| Transaction trans{*this}; | |
| Status<int> status = | |
| trans.Send<int>(DVR_POSE_GET_MODE, nullptr, 0, &mode, sizeof(mode)); | |
| ALOGE_IF(!status, "Pose GetPoseMode() failed because: %s", | |
| status.GetErrorMessage().c_str()); | |
| if (status) | |
| *out_mode = DvrPoseMode(mode); | |
| return ReturnStatusOrError(status); | |
| } | |
| int GetTangoReaderHandle(uint64_t data_type, ConsumerQueue** queue_out) { | |
| // Get buffer. | |
| Transaction trans{*this}; | |
| Status<LocalChannelHandle> status = trans.Send<LocalChannelHandle>( | |
| DVR_POSE_GET_TANGO_READER, &data_type, sizeof(data_type), nullptr, 0); | |
| if (!status) { | |
| ALOGE("PoseClient GetTangoReaderHandle() failed because: %s", | |
| status.GetErrorMessage().c_str()); | |
| *queue_out = nullptr; | |
| return -status.error(); | |
| } | |
| std::unique_ptr<ConsumerQueue> consumer_queue = | |
| ConsumerQueue::Import(status.take()); | |
| *queue_out = consumer_queue.release(); | |
| return 0; | |
| } | |
| int DataCapture(const DvrPoseDataCaptureRequest* request) { | |
| Transaction trans{*this}; | |
| Status<int> status = trans.Send<int>(DVR_POSE_DATA_CAPTURE, request, | |
| sizeof(*request), nullptr, 0); | |
| ALOGE_IF(!status, "PoseClient DataCapture() failed because: %s\n", | |
| status.GetErrorMessage().c_str()); | |
| return ReturnStatusOrError(status); | |
| } | |
| int DataReaderDestroy(uint64_t data_type) { | |
| Transaction trans{*this}; | |
| Status<int> status = trans.Send<int>(DVR_POSE_TANGO_READER_DESTROY, | |
| &data_type, sizeof(data_type), nullptr, | |
| 0); | |
| ALOGE_IF(!status, "PoseClient DataReaderDestroy() failed because: %s\n", | |
| status.GetErrorMessage().c_str()); | |
| return ReturnStatusOrError(status); | |
| } | |
| // Enables or disables all pose processing from sensors | |
| int EnableSensors(bool enabled) { | |
| Transaction trans{*this}; | |
| Status<int> status = trans.Send<int>(DVR_POSE_SENSORS_ENABLE, &enabled, | |
| sizeof(enabled), nullptr, 0); | |
| ALOGE_IF(!status, "Pose EnableSensors() failed because: %s\n", | |
| status.GetErrorMessage().c_str()); | |
| return ReturnStatusOrError(status); | |
| } | |
| int GetRingBuffer(DvrPoseRingBufferInfo* out_info) { | |
| // First time mapping the buffer? | |
| const auto vsync_buffer = GetVsyncBuffer(); | |
| if (vsync_buffer) { | |
| if (out_info) { | |
| out_info->min_future_count = DvrVsyncPoseBuffer::kMinFutureCount; | |
| out_info->total_count = DvrVsyncPoseBuffer::kSize; | |
| out_info->buffer = vsync_buffer->vsync_poses; | |
| } | |
| return -EINVAL; | |
| } | |
| return -EAGAIN; | |
| } | |
| int GetControllerRingBuffer(int32_t controller_id) { | |
| if (controller_id < 0 || controller_id >= MAX_CONTROLLERS) { | |
| return -EINVAL; | |
| } | |
| ControllerClientState& client_state = controllers_[controller_id]; | |
| if (client_state.pose_buffer.get()) { | |
| return 0; | |
| } | |
| Transaction trans{*this}; | |
| Status<LocalChannelHandle> status = trans.Send<LocalChannelHandle>( | |
| DVR_POSE_GET_CONTROLLER_RING_BUFFER, &controller_id, | |
| sizeof(controller_id), nullptr, 0); | |
| if (!status) { | |
| return -status.error(); | |
| } | |
| auto buffer = BufferConsumer::Import(status.take()); | |
| if (!buffer) { | |
| ALOGE("Pose failed to import ring buffer"); | |
| return -EIO; | |
| } | |
| constexpr size_t size = DvrVsyncPoseBuffer::kSize * sizeof(DvrPoseAsync); | |
| void* addr = nullptr; | |
| int ret = buffer->GetBlobReadOnlyPointer(size, &addr); | |
| if (ret < 0 || !addr) { | |
| ALOGE("Pose failed to map ring buffer: ret:%d, addr:%p", ret, addr); | |
| return -EIO; | |
| } | |
| client_state.pose_buffer.swap(buffer); | |
| client_state.mapped_pose_buffer = static_cast<const DvrPoseAsync*>(addr); | |
| ALOGI( | |
| "Mapped controller %d pose data translation %f,%f,%f quat %f,%f,%f,%f", | |
| controller_id, client_state.mapped_pose_buffer[0].position[0], | |
| client_state.mapped_pose_buffer[0].position[1], | |
| client_state.mapped_pose_buffer[0].position[2], | |
| client_state.mapped_pose_buffer[0].orientation[0], | |
| client_state.mapped_pose_buffer[0].orientation[1], | |
| client_state.mapped_pose_buffer[0].orientation[2], | |
| client_state.mapped_pose_buffer[0].orientation[3]); | |
| return 0; | |
| } | |
| private: | |
| friend BASE; | |
| // Set up a channel to the pose service. | |
| PoseClient() | |
| : BASE(pdx::default_transport::ClientChannelFactory::Create( | |
| DVR_POSE_SERVICE_CLIENT)) { | |
| // TODO(eieio): Cache the pose and make timeout 0 so that the API doesn't | |
| // block while waiting for the pose service to come back up. | |
| EnableAutoReconnect(kInfiniteTimeout); | |
| } | |
| PoseClient(const PoseClient&) = delete; | |
| PoseClient& operator=(const PoseClient&) = delete; | |
| const DvrVsyncPoseBuffer* GetVsyncBuffer() { | |
| if (mapped_vsync_pose_buffer_ == nullptr) { | |
| if (vsync_pose_buffer_ == nullptr) { | |
| // The constructor tries mapping it so we do not need TryMapping after. | |
| vsync_pose_buffer_ = std::make_unique<CPUMappedBuffer>( | |
| DvrGlobalBuffers::kVsyncPoseBuffer, CPUUsageMode::READ_OFTEN); | |
| } else if (vsync_pose_buffer_->IsMapped() == false) { | |
| vsync_pose_buffer_->TryMapping(); | |
| } | |
| if (vsync_pose_buffer_->IsMapped()) { | |
| mapped_vsync_pose_buffer_ = | |
| static_cast<DvrVsyncPoseBuffer*>(vsync_pose_buffer_->Address()); | |
| } | |
| } | |
| return mapped_vsync_pose_buffer_; | |
| } | |
| // The vsync pose buffer if already mapped. | |
| std::unique_ptr<CPUMappedBuffer> vsync_pose_buffer_; | |
| // The direct sensor pose buffer. | |
| std::unique_ptr<SensorPoseRing> sensor_pose_buffer_; | |
| const DvrVsyncPoseBuffer* mapped_vsync_pose_buffer_ = nullptr; | |
| struct ControllerClientState { | |
| std::unique_ptr<BufferConsumer> pose_buffer; | |
| const DvrPoseAsync* mapped_pose_buffer = nullptr; | |
| }; | |
| ControllerClientState controllers_[MAX_CONTROLLERS]; | |
| }; | |
| int dvrPoseClientGetDataReaderHandle(DvrPoseClient* client, uint64_t type, | |
| ConsumerQueue** queue_out) { | |
| return PoseClient::FromC(client)->GetTangoReaderHandle(type, queue_out); | |
| } | |
| } // namespace dvr | |
| } // namespace android | |
| using android::dvr::PoseClient; | |
| extern "C" { | |
| DvrPoseClient* dvrPoseClientCreate() { | |
| auto* client = PoseClient::Create().release(); | |
| return reinterpret_cast<DvrPoseClient*>(client); | |
| } | |
| void dvrPoseClientDestroy(DvrPoseClient* client) { | |
| delete PoseClient::FromC(client); | |
| } | |
| int dvrPoseClientGet(DvrPoseClient* client, uint32_t vsync_count, | |
| DvrPoseAsync* out_pose) { | |
| return PoseClient::FromC(client)->GetPose(vsync_count, out_pose); | |
| } | |
| uint32_t dvrPoseClientGetVsyncCount(DvrPoseClient* client) { | |
| return PoseClient::FromC(client)->GetVsyncCount(); | |
| } | |
| int dvrPoseClientGetController(DvrPoseClient* client, int32_t controller_id, | |
| uint32_t vsync_count, DvrPoseAsync* out_pose) { | |
| return PoseClient::FromC(client)->GetControllerPose(controller_id, | |
| vsync_count, out_pose); | |
| } | |
| int dvrPoseClientLogController(DvrPoseClient* client, bool enable) { | |
| return PoseClient::FromC(client)->LogController(enable); | |
| } | |
| int dvrPoseClientPoll(DvrPoseClient* client, DvrPose* state) { | |
| return PoseClient::FromC(client)->Poll(state); | |
| } | |
| int dvrPoseClientFreeze(DvrPoseClient* client, const DvrPose* frozen_state) { | |
| return PoseClient::FromC(client)->Freeze(*frozen_state); | |
| } | |
| int dvrPoseClientModeSet(DvrPoseClient* client, DvrPoseMode mode) { | |
| return PoseClient::FromC(client)->SetMode(mode); | |
| } | |
| int dvrPoseClientModeGet(DvrPoseClient* client, DvrPoseMode* mode) { | |
| return PoseClient::FromC(client)->GetMode(mode); | |
| } | |
| int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled) { | |
| return PoseClient::FromC(client)->EnableSensors(enabled); | |
| } | |
| int dvrPoseClientDataCapture(DvrPoseClient* client, | |
| const DvrPoseDataCaptureRequest* request) { | |
| return PoseClient::FromC(client)->DataCapture(request); | |
| } | |
| int dvrPoseClientDataReaderDestroy(DvrPoseClient* client, uint64_t data_type) { | |
| return PoseClient::FromC(client)->DataReaderDestroy(data_type); | |
| } | |
| } // extern "C" |