| #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/display_client.h> |
| #include <private/dvr/pose-ipc.h> |
| #include <private/dvr/shared_buffer_helpers.h> |
| |
| 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); |
| } |
| |
| // 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]; |
| }; |
| |
| } // 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); |
| } |
| |
| } // extern "C" |