1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #pragma once 17 18 #include <chrono> 19 #include <condition_variable> 20 #include <limits> 21 #include <memory> 22 #include <mutex> 23 #include <thread> 24 25 #include <media/HeadTrackingProcessor.h> 26 #include <media/SensorPoseProvider.h> 27 28 namespace android { 29 30 /** 31 * This class encapsulates the logic for pose processing, intended for driving a spatializer effect. 32 * This includes integration with the Sensor sub-system for retrieving sensor data, doing all the 33 * necessary processing, etc. 34 * 35 * Calculations happen on a dedicated thread and published to the client via the Listener interface. 36 * A calculation may be triggered in one of two ways: 37 * - By calling calculateAsync() - calculation will be kicked off in the background. 38 * - By setting a timeout in the ctor, a calculation will be triggered after the timeout elapsed 39 * from the last calculateAsync() call. 40 * 41 * This class is thread-safe. 42 */ 43 class SpatializerPoseController : private media::SensorPoseProvider::Listener { 44 public: 45 static constexpr int32_t INVALID_SENSOR = media::SensorPoseProvider::INVALID_HANDLE; 46 47 /** 48 * Listener interface for getting pose and mode updates. 49 * Methods will always be invoked from a designated thread. 50 */ 51 class Listener { 52 public: 53 virtual ~Listener() = default; 54 55 virtual void onHeadToStagePose(const media::Pose3f&) = 0; 56 virtual void onActualModeChange(media::HeadTrackingMode) = 0; 57 }; 58 59 /** 60 * Ctor. 61 * sensorPeriod determines how often to receive updates from the sensors (input rate). 62 * maxUpdatePeriod determines how often to produce an output when calculateAsync() isn't 63 * invoked. 64 */ 65 SpatializerPoseController(Listener* listener, std::chrono::microseconds sensorPeriod, 66 std::chrono::microseconds maxUpdatePeriod); 67 68 /** Dtor. */ 69 ~SpatializerPoseController(); 70 71 /** 72 * Set the sensor that is to be used for head-tracking. 73 * INVALID_SENSOR can be used to disable head-tracking. 74 */ 75 void setHeadSensor(int32_t sensor); 76 77 /** 78 * Set the sensor that is to be used for screen-tracking. 79 * INVALID_SENSOR can be used to disable screen-tracking. 80 */ 81 void setScreenSensor(int32_t sensor); 82 83 /** Sets the desired head-tracking mode. */ 84 void setDesiredMode(media::HeadTrackingMode mode); 85 86 /** 87 * Set the screen-to-stage pose, used in all modes. 88 */ 89 void setScreenToStagePose(const media::Pose3f& screenToStage); 90 91 /** 92 * Sets the display orientation. 93 * Orientation is expressed in the angle of rotation from the physical "up" side of the screen 94 * to the logical "up" side of the content displayed the screen. Counterclockwise angles, as 95 * viewed while facing the screen are positive. 96 */ 97 void setDisplayOrientation(float physicalToLogicalAngle); 98 99 /** 100 * This causes the current poses for both the head and screen to be considered "center". 101 */ 102 void recenter(); 103 104 /** 105 * This call triggers the recalculation of the output and the invocation of the relevant 106 * callbacks. This call is async and the callbacks will be triggered shortly after. 107 */ 108 void calculateAsync(); 109 110 /** 111 * Blocks until calculation and invocation of the respective callbacks has happened at least 112 * once. Do not call from within callbacks. 113 */ 114 void waitUntilCalculated(); 115 116 private: 117 mutable std::mutex mMutex; 118 Listener* const mListener; 119 const std::chrono::microseconds mSensorPeriod; 120 // Order matters for the following two members to ensure correct destruction. 121 std::unique_ptr<media::HeadTrackingProcessor> mProcessor; 122 std::unique_ptr<media::SensorPoseProvider> mPoseProvider; 123 int32_t mHeadSensor = media::SensorPoseProvider::INVALID_HANDLE; 124 int32_t mScreenSensor = media::SensorPoseProvider::INVALID_HANDLE; 125 std::optional<media::HeadTrackingMode> mActualMode; 126 std::thread mThread; 127 std::condition_variable mCondVar; 128 bool mShouldCalculate = true; 129 bool mShouldExit = false; 130 bool mCalculated = false; 131 132 void onPose(int64_t timestamp, int32_t sensor, const media::Pose3f& pose, 133 const std::optional<media::Twist3f>& twist, bool isNewReference) override; 134 135 /** 136 * Calculates the new outputs and updates internal state. Must be called with the lock held. 137 * Returns values that should be passed to the respective callbacks. 138 */ 139 std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>> calculate_l(); 140 }; 141 142 } // namespace android 143