Switch to static mode and recenter whenever screen moves
This logic intends to solve issues related to using head-tracking
while moving (e.g. being in a moving vehicle of walking).
We do so by switching to static mode and recentering whenever we
detect a significant motion of the screen.
Test: Manual verification via the SpatialAudioDemo app.
Test: atest --host libheadtracking-test
Change-Id: Iae5090c5a315d31ff89ada8d8a13694ea68ccf8e
diff --git a/media/libheadtracking/HeadTrackingProcessor.cpp b/media/libheadtracking/HeadTrackingProcessor.cpp
index dd2244a..257ee42 100644
--- a/media/libheadtracking/HeadTrackingProcessor.cpp
+++ b/media/libheadtracking/HeadTrackingProcessor.cpp
@@ -46,6 +46,11 @@
.translationalThreshold = options.autoRecenterTranslationalThreshold,
.rotationalThreshold = options.autoRecenterRotationalThreshold,
}),
+ mScreenStillnessDetector(StillnessDetector::Options{
+ .windowDuration = options.screenStillnessWindowDuration,
+ .translationalThreshold = options.screenStillnessTranslationalThreshold,
+ .rotationalThreshold = options.screenStillnessRotationalThreshold,
+ }),
mModeSelector(ModeSelector::Options{.freshnessTimeout = options.freshnessTimeout},
initialMode),
mRateLimiter(PoseRateLimiter::Options{
@@ -83,6 +88,22 @@
}
void calculate(int64_t timestamp) override {
+ // Handle the screen first, since it might trigger a recentering of the head.
+ if (mWorldToScreenTimestamp.has_value()) {
+ const Pose3f worldToLogicalScreen = mScreenPoseDriftCompensator.getOutput();
+ mScreenStillnessDetector.setInput(mWorldToScreenTimestamp.value(),
+ worldToLogicalScreen);
+ bool screenStable = mScreenStillnessDetector.calculate(timestamp);
+ mModeSelector.setScreenStable(mWorldToScreenTimestamp.value(), screenStable);
+ // Whenever the screen is unstable, recenter the head pose.
+ if (!screenStable) {
+ recenter(true, false);
+ }
+ mScreenHeadFusion.setWorldToScreenPose(mWorldToScreenTimestamp.value(),
+ worldToLogicalScreen);
+ }
+
+ // Handle head.
if (mWorldToHeadTimestamp.has_value()) {
Pose3f worldToHead = mHeadPoseDriftCompensator.getOutput();
mHeadStillnessDetector.setInput(mWorldToHeadTimestamp.value(), worldToHead);
@@ -96,12 +117,6 @@
mModeSelector.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
}
- if (mWorldToScreenTimestamp.has_value()) {
- const Pose3f worldToLogicalScreen = mScreenPoseDriftCompensator.getOutput();
- mScreenHeadFusion.setWorldToScreenPose(mWorldToScreenTimestamp.value(),
- worldToLogicalScreen);
- }
-
auto maybeScreenToHead = mScreenHeadFusion.calculate();
if (maybeScreenToHead.has_value()) {
mModeSelector.setScreenToHeadPose(maybeScreenToHead->timestamp,
@@ -131,6 +146,7 @@
}
if (recenterScreen) {
mScreenPoseDriftCompensator.recenter();
+ mScreenStillnessDetector.reset();
}
// If a sensor being recentered is included in the current mode, apply rate limiting to
@@ -155,6 +171,7 @@
PoseDriftCompensator mHeadPoseDriftCompensator;
PoseDriftCompensator mScreenPoseDriftCompensator;
StillnessDetector mHeadStillnessDetector;
+ StillnessDetector mScreenStillnessDetector;
ScreenHeadFusion mScreenHeadFusion;
ModeSelector mModeSelector;
PoseRateLimiter mRateLimiter;