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 #include <media/VectorRecorder.h> 28 29 namespace android { 30 31 /** 32 * This class encapsulates the logic for pose processing, intended for driving a spatializer effect. 33 * This includes integration with the Sensor sub-system for retrieving sensor data, doing all the 34 * necessary processing, etc. 35 * 36 * Calculations happen on a dedicated thread and published to the client via the Listener interface. 37 * A calculation may be triggered in one of two ways: 38 * - By calling calculateAsync() - calculation will be kicked off in the background. 39 * - By setting a timeout in the ctor, a calculation will be triggered after the timeout elapsed 40 * from the last calculateAsync() call. 41 * 42 * This class is thread-safe. 43 */ 44 class SpatializerPoseController : private media::SensorPoseProvider::Listener { 45 public: 46 static constexpr int32_t INVALID_SENSOR = media::SensorPoseProvider::INVALID_HANDLE; 47 48 /** 49 * Listener interface for getting pose and mode updates. 50 * Methods will always be invoked from a designated thread. 51 */ 52 class Listener { 53 public: 54 virtual ~Listener() = default; 55 56 virtual void onHeadToStagePose(const media::Pose3f&) = 0; 57 virtual void onActualModeChange(media::HeadTrackingMode) = 0; 58 }; 59 60 /** 61 * Ctor. 62 * sensorPeriod determines how often to receive updates from the sensors (input rate). 63 * maxUpdatePeriod determines how often to produce an output when calculateAsync() isn't 64 * invoked; passing nullopt means an output is never produced. 65 */ 66 SpatializerPoseController(Listener* listener, std::chrono::microseconds sensorPeriod, 67 std::optional<std::chrono::microseconds> maxUpdatePeriod); 68 69 /** Dtor. */ 70 ~SpatializerPoseController(); 71 72 /** 73 * Set the sensor that is to be used for head-tracking. 74 * INVALID_SENSOR can be used to disable head-tracking. 75 */ 76 void setHeadSensor(int32_t sensor); 77 78 /** 79 * Set the sensor that is to be used for screen-tracking. 80 * INVALID_SENSOR can be used to disable screen-tracking. 81 */ 82 void setScreenSensor(int32_t sensor); 83 84 /** Sets the desired head-tracking mode. */ 85 void setDesiredMode(media::HeadTrackingMode mode); 86 87 /** 88 * Set the screen-to-stage pose, used in all modes. 89 */ 90 void setScreenToStagePose(const media::Pose3f& screenToStage); 91 92 /** 93 * Sets the display orientation. 94 * Orientation is expressed in the angle of rotation from the physical "up" side of the screen 95 * to the logical "up" side of the content displayed the screen. Counterclockwise angles, as 96 * viewed while facing the screen are positive. 97 */ 98 void setDisplayOrientation(float physicalToLogicalAngle); 99 100 /** 101 * This causes the current poses for both the head and screen to be considered "center". 102 */ 103 void recenter(); 104 105 /** 106 * This call triggers the recalculation of the output and the invocation of the relevant 107 * callbacks. This call is async and the callbacks will be triggered shortly after. 108 */ 109 void calculateAsync(); 110 111 /** 112 * Blocks until calculation and invocation of the respective callbacks has happened at least 113 * once. Do not call from within callbacks. 114 */ 115 void waitUntilCalculated(); 116 117 // convert fields to a printable string 118 std::string toString(unsigned level) const; 119 120 private: 121 mutable std::timed_mutex mMutex; 122 Listener* const mListener; 123 const std::chrono::microseconds mSensorPeriod; 124 std::unique_ptr<media::HeadTrackingProcessor> mProcessor; 125 int32_t mHeadSensor = media::SensorPoseProvider::INVALID_HANDLE; 126 int32_t mScreenSensor = media::SensorPoseProvider::INVALID_HANDLE; 127 std::optional<media::HeadTrackingMode> mActualMode; 128 std::condition_variable_any mCondVar; 129 bool mShouldCalculate = true; 130 bool mShouldExit = false; 131 bool mCalculated = false; 132 133 media::VectorRecorder mHeadSensorRecorder{ 134 8 /* vectorSize */, std::chrono::seconds(1), 10 /* maxLogLine */, 135 { 3, 6, 7 } /* delimiterIdx */}; 136 media::VectorRecorder mHeadSensorDurableRecorder{ 137 8 /* vectorSize */, std::chrono::minutes(1), 10 /* maxLogLine */, 138 { 3, 6, 7 } /* delimiterIdx */}; 139 140 media::VectorRecorder mScreenSensorRecorder{ 141 4 /* vectorSize */, std::chrono::seconds(1), 10 /* maxLogLine */, 142 { 3 } /* delimiterIdx */}; 143 media::VectorRecorder mScreenSensorDurableRecorder{ 144 4 /* vectorSize */, std::chrono::minutes(1), 10 /* maxLogLine */, 145 { 3 } /* delimiterIdx */}; 146 147 // Next to last variable as releasing this stops the callbacks 148 std::unique_ptr<media::SensorPoseProvider> mPoseProvider; 149 150 // It's important that mThread is the last variable in this class 151 // since we starts mThread in initializer list 152 std::thread mThread; 153 154 void onPose(int64_t timestamp, int32_t sensor, const media::Pose3f& pose, 155 const std::optional<media::Twist3f>& twist, bool isNewReference) override; 156 157 /** 158 * Calculates the new outputs and updates internal state. Must be called with the lock held. 159 * Returns values that should be passed to the respective callbacks. 160 */ 161 std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>> calculate_l(); 162 }; 163 164 } // namespace android 165