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