| #define LOG_TAG "PoseClient" |
| #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/pose-ipc.h> |
| #include <private/dvr/pose_client_internal.h> |
| #include <private/dvr/sensor_constants.h> |
| |
| using android::pdx::LocalHandle; |
| using android::pdx::LocalChannelHandle; |
| using android::pdx::Status; |
| using android::pdx::Transaction; |
| |
| #define arraysize(x) (static_cast<int32_t>(std::extent<decltype(x)>::value)) |
| |
| namespace android { |
| namespace dvr { |
| |
| // 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(DvrPose* 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(DvrPoseState* state) { |
| Transaction trans{*this}; |
| Status<int> status = |
| trans.Send<int>(DVR_POSE_POLL, nullptr, 0, state, sizeof(*state)); |
| ALOGE_IF(!status, "Pose poll() failed because: %s\n", |
| status.GetErrorMessage().c_str()); |
| return ReturnStatusOrError(status); |
| } |
| |
| int GetPose(uint32_t vsync_count, DvrPoseAsync* out_pose) { |
| if (!mapped_pose_buffer_) { |
| int ret = GetRingBuffer(nullptr); |
| if (ret < 0) |
| return ret; |
| } |
| *out_pose = |
| mapped_pose_buffer_->ring[vsync_count & kPoseAsyncBufferIndexMask]; |
| return 0; |
| } |
| |
| uint32_t GetVsyncCount() { |
| if (!mapped_pose_buffer_) { |
| int ret = GetRingBuffer(nullptr); |
| if (ret < 0) |
| return 0; |
| } |
| return mapped_pose_buffer_->vsync_count; |
| } |
| |
| int GetControllerPose(int32_t controller_id, uint32_t vsync_count, |
| DvrPoseAsync* out_pose) { |
| if (controller_id < 0 || controller_id >= arraysize(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 & kPoseAsyncBufferIndexMask]; |
| 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 DvrPoseState& 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 GetRingBuffer(DvrPoseRingBufferInfo* out_info) { |
| if (pose_buffer_.get()) { |
| if (out_info) { |
| GetPoseRingBufferInfo(out_info); |
| } |
| return 0; |
| } |
| |
| Transaction trans{*this}; |
| Status<LocalChannelHandle> status = |
| trans.Send<LocalChannelHandle>(DVR_POSE_GET_RING_BUFFER); |
| if (!status) { |
| ALOGE("Pose GetRingBuffer() failed because: %s", |
| status.GetErrorMessage().c_str()); |
| return -status.error(); |
| } |
| |
| auto buffer = BufferConsumer::Import(status.take()); |
| if (!buffer) { |
| ALOGE("Pose failed to import ring buffer"); |
| return -EIO; |
| } |
| void* addr = nullptr; |
| int ret = buffer->GetBlobReadOnlyPointer(sizeof(DvrPoseRingBuffer), &addr); |
| if (ret < 0 || !addr) { |
| ALOGE("Pose failed to map ring buffer: ret:%d, addr:%p", ret, addr); |
| return -EIO; |
| } |
| pose_buffer_.swap(buffer); |
| mapped_pose_buffer_ = static_cast<const DvrPoseRingBuffer*>(addr); |
| ALOGI("Mapped pose data translation %f,%f,%f quat %f,%f,%f,%f", |
| mapped_pose_buffer_->ring[0].translation[0], |
| mapped_pose_buffer_->ring[0].translation[1], |
| mapped_pose_buffer_->ring[0].translation[2], |
| mapped_pose_buffer_->ring[0].orientation[0], |
| mapped_pose_buffer_->ring[0].orientation[1], |
| mapped_pose_buffer_->ring[0].orientation[2], |
| mapped_pose_buffer_->ring[0].orientation[3]); |
| if (out_info) { |
| GetPoseRingBufferInfo(out_info); |
| } |
| return 0; |
| } |
| |
| int GetControllerRingBuffer(int32_t controller_id) { |
| if (controller_id < 0 || controller_id >= arraysize(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 = kPoseAsyncBufferTotalCount * 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].translation[0], |
| client_state.mapped_pose_buffer[0].translation[1], |
| client_state.mapped_pose_buffer[0].translation[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; |
| } |
| |
| int NotifyVsync(uint32_t vsync_count, int64_t display_timestamp, |
| int64_t display_period_ns, |
| int64_t right_eye_photon_offset_ns) { |
| const struct iovec data[] = { |
| {.iov_base = &vsync_count, .iov_len = sizeof(vsync_count)}, |
| {.iov_base = &display_timestamp, .iov_len = sizeof(display_timestamp)}, |
| {.iov_base = &display_period_ns, .iov_len = sizeof(display_period_ns)}, |
| {.iov_base = &right_eye_photon_offset_ns, |
| .iov_len = sizeof(right_eye_photon_offset_ns)}, |
| }; |
| Transaction trans{*this}; |
| Status<int> status = |
| trans.SendVector<int>(DVR_POSE_NOTIFY_VSYNC, data, nullptr); |
| ALOGE_IF(!status, "Pose NotifyVsync() failed because: %s\n", |
| status.GetErrorMessage().c_str()); |
| return ReturnStatusOrError(status); |
| } |
| |
| int GetRingBufferFd(LocalHandle* fd) { |
| int ret = GetRingBuffer(nullptr); |
| if (ret < 0) |
| return ret; |
| *fd = pose_buffer_->GetBlobFd(); |
| 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; |
| |
| void GetPoseRingBufferInfo(DvrPoseRingBufferInfo* out_info) const { |
| out_info->min_future_count = kPoseAsyncBufferMinFutureCount; |
| out_info->total_count = kPoseAsyncBufferTotalCount; |
| out_info->buffer = mapped_pose_buffer_->ring; |
| } |
| |
| std::unique_ptr<BufferConsumer> pose_buffer_; |
| const DvrPoseRingBuffer* mapped_pose_buffer_ = nullptr; |
| |
| struct ControllerClientState { |
| std::unique_ptr<BufferConsumer> pose_buffer; |
| const DvrPoseAsync* mapped_pose_buffer = nullptr; |
| }; |
| ControllerClientState controllers_[2]; |
| }; |
| |
| } // namespace dvr |
| } // namespace android |
| |
| using android::dvr::PoseClient; |
| |
| struct DvrPose {}; |
| |
| extern "C" { |
| |
| DvrPose* dvrPoseCreate() { |
| PoseClient* client = PoseClient::Create().release(); |
| return reinterpret_cast<DvrPose*>(client); |
| } |
| |
| void dvrPoseDestroy(DvrPose* client) { delete PoseClient::FromC(client); } |
| |
| int dvrPoseGet(DvrPose* client, uint32_t vsync_count, DvrPoseAsync* out_pose) { |
| return PoseClient::FromC(client)->GetPose(vsync_count, out_pose); |
| } |
| |
| uint32_t dvrPoseGetVsyncCount(DvrPose* client) { |
| return PoseClient::FromC(client)->GetVsyncCount(); |
| } |
| |
| int dvrPoseGetController(DvrPose* client, int32_t controller_id, |
| uint32_t vsync_count, DvrPoseAsync* out_pose) { |
| return PoseClient::FromC(client)->GetControllerPose(controller_id, |
| vsync_count, out_pose); |
| } |
| |
| int dvrPoseLogController(DvrPose* client, bool enable) { |
| return PoseClient::FromC(client)->LogController(enable); |
| } |
| |
| int dvrPosePoll(DvrPose* client, DvrPoseState* state) { |
| return PoseClient::FromC(client)->Poll(state); |
| } |
| |
| int dvrPoseFreeze(DvrPose* client, const DvrPoseState* frozen_state) { |
| return PoseClient::FromC(client)->Freeze(*frozen_state); |
| } |
| |
| int dvrPoseSetMode(DvrPose* client, DvrPoseMode mode) { |
| return PoseClient::FromC(client)->SetMode(mode); |
| } |
| |
| int dvrPoseGetMode(DvrPose* client, DvrPoseMode* mode) { |
| return PoseClient::FromC(client)->GetMode(mode); |
| } |
| |
| int dvrPoseGetRingBuffer(DvrPose* client, DvrPoseRingBufferInfo* out_info) { |
| return PoseClient::FromC(client)->GetRingBuffer(out_info); |
| } |
| |
| int privateDvrPoseNotifyVsync(DvrPose* client, uint32_t vsync_count, |
| int64_t display_timestamp, |
| int64_t display_period_ns, |
| int64_t right_eye_photon_offset_ns) { |
| return PoseClient::FromC(client)->NotifyVsync(vsync_count, display_timestamp, |
| display_period_ns, |
| right_eye_photon_offset_ns); |
| } |
| |
| int privateDvrPoseGetRingBufferFd(DvrPose* client, LocalHandle* fd) { |
| return PoseClient::FromC(client)->GetRingBufferFd(fd); |
| } |
| |
| } // extern "C" |