Tune stillness detector for more responsive headtracking

Bug: 243821894
Test: manual - validated through listening tests

Change-Id: I2b07ac16e790d03b05f2ba0912d92901598d2bd5
diff --git a/media/libheadtracking/HeadTrackingProcessor.cpp b/media/libheadtracking/HeadTrackingProcessor.cpp
index fb44567..ccb75af 100644
--- a/media/libheadtracking/HeadTrackingProcessor.cpp
+++ b/media/libheadtracking/HeadTrackingProcessor.cpp
@@ -88,10 +88,12 @@
     }
 
     void calculate(int64_t timestamp) override {
-        // Handle the screen first, since it might trigger a recentering of the head.
+        bool screenStable = true;
+
+        // Handle the screen first, since it might: trigger a recentering of the head.
         if (mWorldToScreenTimestamp.has_value()) {
             const Pose3f worldToLogicalScreen = mScreenPoseBias.getOutput();
-            bool screenStable = mScreenStillnessDetector.calculate(timestamp);
+            screenStable = mScreenStillnessDetector.calculate(timestamp);
             mModeSelector.setScreenStable(mWorldToScreenTimestamp.value(), screenStable);
             // Whenever the screen is unstable, recenter the head pose.
             if (!screenStable) {
@@ -105,7 +107,8 @@
         if (mWorldToHeadTimestamp.has_value()) {
             Pose3f worldToHead = mHeadPoseBias.getOutput();
             // Auto-recenter.
-            if (mHeadStillnessDetector.calculate(timestamp)) {
+            bool headStable = mHeadStillnessDetector.calculate(timestamp);
+            if (headStable || !screenStable) {
                 recenter(true, false);
                 worldToHead = mHeadPoseBias.getOutput();
             }
diff --git a/media/libheadtracking/StillnessDetector.cpp b/media/libheadtracking/StillnessDetector.cpp
index be7c893..5232084 100644
--- a/media/libheadtracking/StillnessDetector.cpp
+++ b/media/libheadtracking/StillnessDetector.cpp
@@ -26,6 +26,9 @@
     mFifo.clear();
     mWindowFull = false;
     mSuppressionDeadline.reset();
+    // A "true" state indicates stillness is detected (default = true)
+    mCurrentState = true;
+    mPreviousState = true;
 }
 
 void StillnessDetector::setInput(int64_t timestamp, const Pose3f& input) {
@@ -33,7 +36,15 @@
     discardOld(timestamp);
 }
 
+bool StillnessDetector::getPreviousState() const {
+    return mPreviousState;
+}
+
 bool StillnessDetector::calculate(int64_t timestamp) {
+    // Move the current stillness state to the previous state.
+    // This allows us to detect transitions into and out of stillness.
+    mPreviousState = mCurrentState;
+
     discardOld(timestamp);
 
     // Check whether all the poses in the queue are in the proximity of the new one. We want to do
@@ -60,15 +71,17 @@
 
     // If the window has not been full, return the default value.
     if (!mWindowFull) {
-        return mOptions.defaultValue;
+        mCurrentState = mOptions.defaultValue;
     }
-
     // Force "in motion" while the suppression deadline is active.
-    if (mSuppressionDeadline.has_value()) {
-        return false;
+    else if (mSuppressionDeadline.has_value()) {
+        mCurrentState = false;
+    }
+    else {
+        mCurrentState = !moved;
     }
 
-    return !moved;
+    return mCurrentState;
 }
 
 void StillnessDetector::discardOld(int64_t timestamp) {
diff --git a/media/libheadtracking/StillnessDetector.h b/media/libheadtracking/StillnessDetector.h
index ee4b2d8..abd7cc4 100644
--- a/media/libheadtracking/StillnessDetector.h
+++ b/media/libheadtracking/StillnessDetector.h
@@ -80,7 +80,8 @@
     void setInput(int64_t timestamp, const Pose3f& input);
     /** Calculate whether the stream is still at the given timestamp. */
     bool calculate(int64_t timestamp);
-
+    /** Return the stillness state from the previous call to calculate() */
+    bool getPreviousState() const;
   private:
     struct TimestampedPose {
         int64_t timestamp;
@@ -92,6 +93,8 @@
     const float mCosHalfRotationalThreshold;
     std::deque<TimestampedPose> mFifo;
     bool mWindowFull = false;
+    bool mCurrentState = true;
+    bool mPreviousState = true;
     // As soon as motion is detected, this will be set for the time of detection + window duration,
     // and during this time we will always consider outselves in motion without checking. This is
     // used for hyteresis purposes, since because of the approximate method we use for determining
diff --git a/services/audiopolicy/service/SpatializerPoseController.cpp b/services/audiopolicy/service/SpatializerPoseController.cpp
index e012a0b..97ddd4e 100644
--- a/services/audiopolicy/service/SpatializerPoseController.cpp
+++ b/services/audiopolicy/service/SpatializerPoseController.cpp
@@ -65,13 +65,13 @@
 
 // Screen is considered to be unstable (not still) if it has moved significantly within the last
 // time window of this duration.
-constexpr auto kScreenStillnessWindowDuration = 3s;
+constexpr auto kScreenStillnessWindowDuration = 750ms;
 
 // Screen is considered to have moved significantly if translated by this much (in meter, approx).
 constexpr float kScreenStillnessTranslationThreshold = 0.1f;
 
 // Screen is considered to have moved significantly if rotated by this much (in radians, approx).
-constexpr float kScreenStillnessRotationThreshold = 7.0f / 180 * M_PI;
+constexpr float kScreenStillnessRotationThreshold = 15.0f / 180 * M_PI;
 
 // Time units for system clock ticks. This is what the Sensor Framework timestamps represent and
 // what we use for pose filtering.