#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"