blob: fb445677ede300513228adf5eeebde69dad3eb4d [file] [log] [blame]
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -07001/*
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 */
Shunkai Yao59b27bc2022-07-22 18:42:27 +000016#include <inttypes.h>
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070017
Shunkai Yao59b27bc2022-07-22 18:42:27 +000018#include <android-base/stringprintf.h>
19#include <audio_utils/SimpleLog.h>
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070020#include "media/HeadTrackingProcessor.h"
21
22#include "ModeSelector.h"
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -080023#include "PoseBias.h"
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070024#include "QuaternionUtil.h"
25#include "ScreenHeadFusion.h"
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080026#include "StillnessDetector.h"
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070027
28namespace android {
29namespace media {
30namespace {
31
Shunkai Yao59b27bc2022-07-22 18:42:27 +000032using android::base::StringAppendF;
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070033using Eigen::Quaternionf;
34using Eigen::Vector3f;
35
36class HeadTrackingProcessorImpl : public HeadTrackingProcessor {
37 public:
38 HeadTrackingProcessorImpl(const Options& options, HeadTrackingMode initialMode)
39 : mOptions(options),
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080040 mHeadStillnessDetector(StillnessDetector::Options{
Ytai Ben-Tsvi4cb1e482022-01-06 11:22:05 -080041 .defaultValue = false,
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080042 .windowDuration = options.autoRecenterWindowDuration,
43 .translationalThreshold = options.autoRecenterTranslationalThreshold,
44 .rotationalThreshold = options.autoRecenterRotationalThreshold,
45 }),
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080046 mScreenStillnessDetector(StillnessDetector::Options{
Ytai Ben-Tsvi4cb1e482022-01-06 11:22:05 -080047 .defaultValue = true,
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080048 .windowDuration = options.screenStillnessWindowDuration,
49 .translationalThreshold = options.screenStillnessTranslationalThreshold,
50 .rotationalThreshold = options.screenStillnessRotationalThreshold,
51 }),
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070052 mModeSelector(ModeSelector::Options{.freshnessTimeout = options.freshnessTimeout},
53 initialMode),
54 mRateLimiter(PoseRateLimiter::Options{
55 .maxTranslationalVelocity = options.maxTranslationalVelocity,
56 .maxRotationalVelocity = options.maxRotationalVelocity}) {}
57
58 void setDesiredMode(HeadTrackingMode mode) override { mModeSelector.setDesiredMode(mode); }
59
60 void setWorldToHeadPose(int64_t timestamp, const Pose3f& worldToHead,
61 const Twist3f& headTwist) override {
62 Pose3f predictedWorldToHead =
63 worldToHead * integrate(headTwist, mOptions.predictionDuration);
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -080064 mHeadPoseBias.setInput(predictedWorldToHead);
Ytai Ben-Tsvi5e6c0f32022-01-19 08:20:39 -080065 mHeadStillnessDetector.setInput(timestamp, predictedWorldToHead);
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070066 mWorldToHeadTimestamp = timestamp;
67 }
68
69 void setWorldToScreenPose(int64_t timestamp, const Pose3f& worldToScreen) override {
Ytai Ben-Tsvi7901bdd2021-09-08 16:11:07 -070070 if (mPhysicalToLogicalAngle != mPendingPhysicalToLogicalAngle) {
71 // We're introducing an artificial discontinuity. Enable the rate limiter.
72 mRateLimiter.enable();
73 mPhysicalToLogicalAngle = mPendingPhysicalToLogicalAngle;
74 }
75
Ytai Ben-Tsvi5e6c0f32022-01-19 08:20:39 -080076 Pose3f worldToLogicalScreen = worldToScreen * Pose3f(rotateY(-mPhysicalToLogicalAngle));
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -080077 mScreenPoseBias.setInput(worldToLogicalScreen);
Ytai Ben-Tsvi5e6c0f32022-01-19 08:20:39 -080078 mScreenStillnessDetector.setInput(timestamp, worldToLogicalScreen);
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070079 mWorldToScreenTimestamp = timestamp;
80 }
81
82 void setScreenToStagePose(const Pose3f& screenToStage) override {
83 mModeSelector.setScreenToStagePose(screenToStage);
84 }
85
86 void setDisplayOrientation(float physicalToLogicalAngle) override {
Ytai Ben-Tsvi7901bdd2021-09-08 16:11:07 -070087 mPendingPhysicalToLogicalAngle = physicalToLogicalAngle;
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070088 }
89
90 void calculate(int64_t timestamp) override {
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080091 // Handle the screen first, since it might trigger a recentering of the head.
92 if (mWorldToScreenTimestamp.has_value()) {
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -080093 const Pose3f worldToLogicalScreen = mScreenPoseBias.getOutput();
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080094 bool screenStable = mScreenStillnessDetector.calculate(timestamp);
95 mModeSelector.setScreenStable(mWorldToScreenTimestamp.value(), screenStable);
96 // Whenever the screen is unstable, recenter the head pose.
97 if (!screenStable) {
98 recenter(true, false);
99 }
100 mScreenHeadFusion.setWorldToScreenPose(mWorldToScreenTimestamp.value(),
101 worldToLogicalScreen);
102 }
103
104 // Handle head.
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700105 if (mWorldToHeadTimestamp.has_value()) {
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -0800106 Pose3f worldToHead = mHeadPoseBias.getOutput();
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -0800107 // Auto-recenter.
108 if (mHeadStillnessDetector.calculate(timestamp)) {
109 recenter(true, false);
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -0800110 worldToHead = mHeadPoseBias.getOutput();
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -0800111 }
112
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700113 mScreenHeadFusion.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
114 mModeSelector.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
115 }
116
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700117 auto maybeScreenToHead = mScreenHeadFusion.calculate();
118 if (maybeScreenToHead.has_value()) {
119 mModeSelector.setScreenToHeadPose(maybeScreenToHead->timestamp,
120 maybeScreenToHead->pose);
121 } else {
122 mModeSelector.setScreenToHeadPose(timestamp, std::nullopt);
123 }
124
125 HeadTrackingMode prevMode = mModeSelector.getActualMode();
126 mModeSelector.calculate(timestamp);
127 if (mModeSelector.getActualMode() != prevMode) {
128 // Mode has changed, enable rate limiting.
129 mRateLimiter.enable();
130 }
131 mRateLimiter.setTarget(mModeSelector.getHeadToStagePose());
132 mHeadToStagePose = mRateLimiter.calculatePose(timestamp);
133 }
134
135 Pose3f getHeadToStagePose() const override { return mHeadToStagePose; }
136
137 HeadTrackingMode getActualMode() const override { return mModeSelector.getActualMode(); }
138
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700139 void recenter(bool recenterHead, bool recenterScreen) override {
140 if (recenterHead) {
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -0800141 mHeadPoseBias.recenter();
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -0800142 mHeadStillnessDetector.reset();
Shunkai Yao59b27bc2022-07-22 18:42:27 +0000143 mLocalLog.log("recenter Head");
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700144 }
145 if (recenterScreen) {
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -0800146 mScreenPoseBias.recenter();
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -0800147 mScreenStillnessDetector.reset();
Shunkai Yao59b27bc2022-07-22 18:42:27 +0000148 mLocalLog.log("recenter Screen");
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700149 }
150
151 // If a sensor being recentered is included in the current mode, apply rate limiting to
152 // avoid discontinuities.
153 HeadTrackingMode mode = mModeSelector.getActualMode();
154 if ((recenterHead && (mode == HeadTrackingMode::WORLD_RELATIVE ||
155 mode == HeadTrackingMode::SCREEN_RELATIVE)) ||
156 (recenterScreen && mode == HeadTrackingMode::SCREEN_RELATIVE)) {
157 mRateLimiter.enable();
158 }
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700159 }
160
Shunkai Yao59b27bc2022-07-22 18:42:27 +0000161 std::string toString_l(unsigned level) const override {
162 std::string prefixSpace(level, ' ');
163 std::string ss = prefixSpace + "HeadTrackingProcessor:\n";
164 StringAppendF(&ss, "%smaxTranslationalVelocity: %f\n", prefixSpace.c_str(),
165 mOptions.maxTranslationalVelocity);
166 StringAppendF(&ss, "%smaxRotationalVelocity: %f\n", prefixSpace.c_str(),
167 mOptions.maxRotationalVelocity);
168 StringAppendF(&ss, "%sfreshnessTimeout: %" PRId64 "\n", prefixSpace.c_str(),
169 mOptions.freshnessTimeout);
170 StringAppendF(&ss, "%spredictionDuration: %f\n", prefixSpace.c_str(),
171 mOptions.predictionDuration);
172 StringAppendF(&ss, "%sautoRecenterWindowDuration: %" PRId64 "\n", prefixSpace.c_str(),
173 mOptions.autoRecenterWindowDuration);
174 StringAppendF(&ss, "%sautoRecenterTranslationalThreshold: %f\n", prefixSpace.c_str(),
175 mOptions.autoRecenterTranslationalThreshold);
176 StringAppendF(&ss, "%sautoRecenterRotationalThreshold: %f\n", prefixSpace.c_str(),
177 mOptions.autoRecenterRotationalThreshold);
178 StringAppendF(&ss, "%sscreenStillnessWindowDuration: %" PRId64 "\n", prefixSpace.c_str(),
179 mOptions.screenStillnessWindowDuration);
180 StringAppendF(&ss, "%sscreenStillnessTranslationalThreshold: %f\n", prefixSpace.c_str(),
181 mOptions.screenStillnessTranslationalThreshold);
182 StringAppendF(&ss, "%sscreenStillnessRotationalThreshold: %f\n", prefixSpace.c_str(),
183 mOptions.screenStillnessRotationalThreshold);
184 ss.append(prefixSpace + "ReCenterHistory:\n");
185 ss += mLocalLog.dumpToString((prefixSpace + " ").c_str(), mMaxLocalLogLine);
186 // TODO: 233092747 add string from PoseRateLimiter/PoseRateLimiter etc...
187 return ss;
188 }
189
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700190 private:
191 const Options mOptions;
192 float mPhysicalToLogicalAngle = 0;
Ytai Ben-Tsvi7901bdd2021-09-08 16:11:07 -0700193 // We store the physical to logical angle as "pending" until the next world-to-screen sample it
194 // applies to arrives.
195 float mPendingPhysicalToLogicalAngle = 0;
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700196 std::optional<int64_t> mWorldToHeadTimestamp;
197 std::optional<int64_t> mWorldToScreenTimestamp;
198 Pose3f mHeadToStagePose;
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -0800199 PoseBias mHeadPoseBias;
200 PoseBias mScreenPoseBias;
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -0800201 StillnessDetector mHeadStillnessDetector;
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -0800202 StillnessDetector mScreenStillnessDetector;
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700203 ScreenHeadFusion mScreenHeadFusion;
204 ModeSelector mModeSelector;
205 PoseRateLimiter mRateLimiter;
Shunkai Yao59b27bc2022-07-22 18:42:27 +0000206 static constexpr std::size_t mMaxLocalLogLine = 10;
207 SimpleLog mLocalLog{mMaxLocalLogLine};
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700208};
209
210} // namespace
211
Ytai Ben-Tsviedbab3d2021-08-16 11:27:52 -0700212std::unique_ptr<HeadTrackingProcessor> createHeadTrackingProcessor(
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700213 const HeadTrackingProcessor::Options& options, HeadTrackingMode initialMode) {
214 return std::make_unique<HeadTrackingProcessorImpl>(options, initialMode);
215}
216
217} // namespace media
218} // namespace android