xref: /aosp_15_r20/frameworks/av/media/libheadtracking/HeadTrackingProcessor.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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 #include <inttypes.h>
17*ec779b8eSAndroid Build Coastguard Worker 
18*ec779b8eSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
19*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/SimpleLog.h>
20*ec779b8eSAndroid Build Coastguard Worker #include "media/HeadTrackingProcessor.h"
21*ec779b8eSAndroid Build Coastguard Worker #include "media/QuaternionUtil.h"
22*ec779b8eSAndroid Build Coastguard Worker 
23*ec779b8eSAndroid Build Coastguard Worker #include "ModeSelector.h"
24*ec779b8eSAndroid Build Coastguard Worker #include "PoseBias.h"
25*ec779b8eSAndroid Build Coastguard Worker #include "PosePredictor.h"
26*ec779b8eSAndroid Build Coastguard Worker #include "ScreenHeadFusion.h"
27*ec779b8eSAndroid Build Coastguard Worker #include "StillnessDetector.h"
28*ec779b8eSAndroid Build Coastguard Worker 
29*ec779b8eSAndroid Build Coastguard Worker namespace android {
30*ec779b8eSAndroid Build Coastguard Worker namespace media {
31*ec779b8eSAndroid Build Coastguard Worker namespace {
32*ec779b8eSAndroid Build Coastguard Worker 
33*ec779b8eSAndroid Build Coastguard Worker using android::base::StringAppendF;
34*ec779b8eSAndroid Build Coastguard Worker using Eigen::Quaternionf;
35*ec779b8eSAndroid Build Coastguard Worker using Eigen::Vector3f;
36*ec779b8eSAndroid Build Coastguard Worker 
37*ec779b8eSAndroid Build Coastguard Worker class HeadTrackingProcessorImpl : public HeadTrackingProcessor {
38*ec779b8eSAndroid Build Coastguard Worker   public:
HeadTrackingProcessorImpl(const Options & options,HeadTrackingMode initialMode)39*ec779b8eSAndroid Build Coastguard Worker     HeadTrackingProcessorImpl(const Options& options, HeadTrackingMode initialMode)
40*ec779b8eSAndroid Build Coastguard Worker         : mOptions(options),
41*ec779b8eSAndroid Build Coastguard Worker           mHeadStillnessDetector(StillnessDetector::Options{
42*ec779b8eSAndroid Build Coastguard Worker                   .defaultValue = false,
43*ec779b8eSAndroid Build Coastguard Worker                   .windowDuration = options.autoRecenterWindowDuration,
44*ec779b8eSAndroid Build Coastguard Worker                   .translationalThreshold = options.autoRecenterTranslationalThreshold,
45*ec779b8eSAndroid Build Coastguard Worker                   .rotationalThreshold = options.autoRecenterRotationalThreshold,
46*ec779b8eSAndroid Build Coastguard Worker           }),
47*ec779b8eSAndroid Build Coastguard Worker           mScreenStillnessDetector(StillnessDetector::Options{
48*ec779b8eSAndroid Build Coastguard Worker                   .defaultValue = true,
49*ec779b8eSAndroid Build Coastguard Worker                   .windowDuration = options.screenStillnessWindowDuration,
50*ec779b8eSAndroid Build Coastguard Worker                   .translationalThreshold = options.screenStillnessTranslationalThreshold,
51*ec779b8eSAndroid Build Coastguard Worker                   .rotationalThreshold = options.screenStillnessRotationalThreshold,
52*ec779b8eSAndroid Build Coastguard Worker           }),
53*ec779b8eSAndroid Build Coastguard Worker           mModeSelector(ModeSelector::Options{.freshnessTimeout = options.freshnessTimeout},
54*ec779b8eSAndroid Build Coastguard Worker                         initialMode),
55*ec779b8eSAndroid Build Coastguard Worker           mRateLimiter(PoseRateLimiter::Options{
56*ec779b8eSAndroid Build Coastguard Worker                   .maxTranslationalVelocity = options.maxTranslationalVelocity,
57*ec779b8eSAndroid Build Coastguard Worker                   .maxRotationalVelocity = options.maxRotationalVelocity}) {}
58*ec779b8eSAndroid Build Coastguard Worker 
setDesiredMode(HeadTrackingMode mode)59*ec779b8eSAndroid Build Coastguard Worker     void setDesiredMode(HeadTrackingMode mode) override { mModeSelector.setDesiredMode(mode); }
60*ec779b8eSAndroid Build Coastguard Worker 
setWorldToHeadPose(int64_t timestamp,const Pose3f & worldToHead,const Twist3f & headTwist)61*ec779b8eSAndroid Build Coastguard Worker     void setWorldToHeadPose(int64_t timestamp, const Pose3f& worldToHead,
62*ec779b8eSAndroid Build Coastguard Worker                             const Twist3f& headTwist) override {
63*ec779b8eSAndroid Build Coastguard Worker         const Pose3f predictedWorldToHead = mPosePredictor.predict(
64*ec779b8eSAndroid Build Coastguard Worker                 timestamp, worldToHead, headTwist, mOptions.predictionDuration);
65*ec779b8eSAndroid Build Coastguard Worker         mHeadPoseBias.setInput(predictedWorldToHead);
66*ec779b8eSAndroid Build Coastguard Worker         mHeadStillnessDetector.setInput(timestamp, predictedWorldToHead);
67*ec779b8eSAndroid Build Coastguard Worker         mWorldToHeadTimestamp = timestamp;
68*ec779b8eSAndroid Build Coastguard Worker     }
69*ec779b8eSAndroid Build Coastguard Worker 
setWorldToScreenPose(int64_t timestamp,const Pose3f & worldToScreen)70*ec779b8eSAndroid Build Coastguard Worker     void setWorldToScreenPose(int64_t timestamp, const Pose3f& worldToScreen) override {
71*ec779b8eSAndroid Build Coastguard Worker         if (mPhysicalToLogicalAngle != mPendingPhysicalToLogicalAngle) {
72*ec779b8eSAndroid Build Coastguard Worker             // We're introducing an artificial discontinuity. Enable the rate limiter.
73*ec779b8eSAndroid Build Coastguard Worker             mRateLimiter.enable();
74*ec779b8eSAndroid Build Coastguard Worker             mPhysicalToLogicalAngle = mPendingPhysicalToLogicalAngle;
75*ec779b8eSAndroid Build Coastguard Worker         }
76*ec779b8eSAndroid Build Coastguard Worker 
77*ec779b8eSAndroid Build Coastguard Worker         Pose3f worldToLogicalScreen = worldToScreen * Pose3f(rotateY(-mPhysicalToLogicalAngle));
78*ec779b8eSAndroid Build Coastguard Worker         mScreenPoseBias.setInput(worldToLogicalScreen);
79*ec779b8eSAndroid Build Coastguard Worker         mScreenStillnessDetector.setInput(timestamp, worldToLogicalScreen);
80*ec779b8eSAndroid Build Coastguard Worker         mWorldToScreenTimestamp = timestamp;
81*ec779b8eSAndroid Build Coastguard Worker     }
82*ec779b8eSAndroid Build Coastguard Worker 
setScreenToStagePose(const Pose3f & screenToStage)83*ec779b8eSAndroid Build Coastguard Worker     void setScreenToStagePose(const Pose3f& screenToStage) override {
84*ec779b8eSAndroid Build Coastguard Worker         mModeSelector.setScreenToStagePose(screenToStage);
85*ec779b8eSAndroid Build Coastguard Worker     }
86*ec779b8eSAndroid Build Coastguard Worker 
setDisplayOrientation(float physicalToLogicalAngle)87*ec779b8eSAndroid Build Coastguard Worker     void setDisplayOrientation(float physicalToLogicalAngle) override {
88*ec779b8eSAndroid Build Coastguard Worker         mPendingPhysicalToLogicalAngle = physicalToLogicalAngle;
89*ec779b8eSAndroid Build Coastguard Worker     }
90*ec779b8eSAndroid Build Coastguard Worker 
calculate(int64_t timestamp)91*ec779b8eSAndroid Build Coastguard Worker     void calculate(int64_t timestamp) override {
92*ec779b8eSAndroid Build Coastguard Worker         bool screenStable = true;
93*ec779b8eSAndroid Build Coastguard Worker 
94*ec779b8eSAndroid Build Coastguard Worker         // Handle the screen first, since it might: trigger a recentering of the head.
95*ec779b8eSAndroid Build Coastguard Worker         if (mWorldToScreenTimestamp.has_value()) {
96*ec779b8eSAndroid Build Coastguard Worker             const Pose3f worldToLogicalScreen = mScreenPoseBias.getOutput();
97*ec779b8eSAndroid Build Coastguard Worker             screenStable = mScreenStillnessDetector.calculate(timestamp);
98*ec779b8eSAndroid Build Coastguard Worker             mModeSelector.setScreenStable(mWorldToScreenTimestamp.value(), screenStable);
99*ec779b8eSAndroid Build Coastguard Worker             // Whenever the screen is unstable, recenter the head pose.
100*ec779b8eSAndroid Build Coastguard Worker             if (!screenStable) {
101*ec779b8eSAndroid Build Coastguard Worker                 recenter(true, false, "calculate: screen movement");
102*ec779b8eSAndroid Build Coastguard Worker             }
103*ec779b8eSAndroid Build Coastguard Worker             mScreenHeadFusion.setWorldToScreenPose(mWorldToScreenTimestamp.value(),
104*ec779b8eSAndroid Build Coastguard Worker                                                    worldToLogicalScreen);
105*ec779b8eSAndroid Build Coastguard Worker         }
106*ec779b8eSAndroid Build Coastguard Worker 
107*ec779b8eSAndroid Build Coastguard Worker         // Handle head.
108*ec779b8eSAndroid Build Coastguard Worker         if (mWorldToHeadTimestamp.has_value()) {
109*ec779b8eSAndroid Build Coastguard Worker             Pose3f worldToHead = mHeadPoseBias.getOutput();
110*ec779b8eSAndroid Build Coastguard Worker             // Auto-recenter.
111*ec779b8eSAndroid Build Coastguard Worker             bool headStable = mHeadStillnessDetector.calculate(timestamp);
112*ec779b8eSAndroid Build Coastguard Worker             if (headStable || !screenStable) {
113*ec779b8eSAndroid Build Coastguard Worker                 recenter(true, false, "calculate: head movement");
114*ec779b8eSAndroid Build Coastguard Worker                 worldToHead = mHeadPoseBias.getOutput();
115*ec779b8eSAndroid Build Coastguard Worker             }
116*ec779b8eSAndroid Build Coastguard Worker 
117*ec779b8eSAndroid Build Coastguard Worker             mScreenHeadFusion.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
118*ec779b8eSAndroid Build Coastguard Worker             mModeSelector.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
119*ec779b8eSAndroid Build Coastguard Worker         }
120*ec779b8eSAndroid Build Coastguard Worker 
121*ec779b8eSAndroid Build Coastguard Worker         auto maybeScreenToHead = mScreenHeadFusion.calculate();
122*ec779b8eSAndroid Build Coastguard Worker         if (maybeScreenToHead.has_value()) {
123*ec779b8eSAndroid Build Coastguard Worker             mModeSelector.setScreenToHeadPose(maybeScreenToHead->timestamp,
124*ec779b8eSAndroid Build Coastguard Worker                                               maybeScreenToHead->pose);
125*ec779b8eSAndroid Build Coastguard Worker         } else {
126*ec779b8eSAndroid Build Coastguard Worker             mModeSelector.setScreenToHeadPose(timestamp, std::nullopt);
127*ec779b8eSAndroid Build Coastguard Worker         }
128*ec779b8eSAndroid Build Coastguard Worker 
129*ec779b8eSAndroid Build Coastguard Worker         HeadTrackingMode prevMode = mModeSelector.getActualMode();
130*ec779b8eSAndroid Build Coastguard Worker         mModeSelector.calculate(timestamp);
131*ec779b8eSAndroid Build Coastguard Worker         if (mModeSelector.getActualMode() != prevMode) {
132*ec779b8eSAndroid Build Coastguard Worker             // Mode has changed, enable rate limiting.
133*ec779b8eSAndroid Build Coastguard Worker             mRateLimiter.enable();
134*ec779b8eSAndroid Build Coastguard Worker         }
135*ec779b8eSAndroid Build Coastguard Worker         mRateLimiter.setTarget(mModeSelector.getHeadToStagePose());
136*ec779b8eSAndroid Build Coastguard Worker         mHeadToStagePose = mRateLimiter.calculatePose(timestamp);
137*ec779b8eSAndroid Build Coastguard Worker     }
138*ec779b8eSAndroid Build Coastguard Worker 
getHeadToStagePose() const139*ec779b8eSAndroid Build Coastguard Worker     Pose3f getHeadToStagePose() const override { return mHeadToStagePose; }
140*ec779b8eSAndroid Build Coastguard Worker 
getActualMode() const141*ec779b8eSAndroid Build Coastguard Worker     HeadTrackingMode getActualMode() const override { return mModeSelector.getActualMode(); }
142*ec779b8eSAndroid Build Coastguard Worker 
recenter(bool recenterHead,bool recenterScreen,std::string source)143*ec779b8eSAndroid Build Coastguard Worker     void recenter(bool recenterHead, bool recenterScreen, std::string source) override {
144*ec779b8eSAndroid Build Coastguard Worker         if (recenterHead) {
145*ec779b8eSAndroid Build Coastguard Worker             mHeadPoseBias.recenter();
146*ec779b8eSAndroid Build Coastguard Worker             mHeadStillnessDetector.reset();
147*ec779b8eSAndroid Build Coastguard Worker             mLocalLog.log("recenter Head from %s", source.c_str());
148*ec779b8eSAndroid Build Coastguard Worker         }
149*ec779b8eSAndroid Build Coastguard Worker         if (recenterScreen) {
150*ec779b8eSAndroid Build Coastguard Worker             mScreenPoseBias.recenter();
151*ec779b8eSAndroid Build Coastguard Worker             mScreenStillnessDetector.reset();
152*ec779b8eSAndroid Build Coastguard Worker             mLocalLog.log("recenter Screen from %s", source.c_str());
153*ec779b8eSAndroid Build Coastguard Worker         }
154*ec779b8eSAndroid Build Coastguard Worker 
155*ec779b8eSAndroid Build Coastguard Worker         // If a sensor being recentered is included in the current mode, apply rate limiting to
156*ec779b8eSAndroid Build Coastguard Worker         // avoid discontinuities.
157*ec779b8eSAndroid Build Coastguard Worker         HeadTrackingMode mode = mModeSelector.getActualMode();
158*ec779b8eSAndroid Build Coastguard Worker         if ((recenterHead && (mode == HeadTrackingMode::WORLD_RELATIVE ||
159*ec779b8eSAndroid Build Coastguard Worker                               mode == HeadTrackingMode::SCREEN_RELATIVE)) ||
160*ec779b8eSAndroid Build Coastguard Worker             (recenterScreen && mode == HeadTrackingMode::SCREEN_RELATIVE)) {
161*ec779b8eSAndroid Build Coastguard Worker             mRateLimiter.enable();
162*ec779b8eSAndroid Build Coastguard Worker         }
163*ec779b8eSAndroid Build Coastguard Worker     }
164*ec779b8eSAndroid Build Coastguard Worker 
setPosePredictorType(PosePredictorType type)165*ec779b8eSAndroid Build Coastguard Worker     void setPosePredictorType(PosePredictorType type) override {
166*ec779b8eSAndroid Build Coastguard Worker         mPosePredictor.setPosePredictorType(type);
167*ec779b8eSAndroid Build Coastguard Worker     }
168*ec779b8eSAndroid Build Coastguard Worker 
toString_l(unsigned level) const169*ec779b8eSAndroid Build Coastguard Worker     std::string toString_l(unsigned level) const override {
170*ec779b8eSAndroid Build Coastguard Worker         std::string prefixSpace(level, ' ');
171*ec779b8eSAndroid Build Coastguard Worker         std::string ss = prefixSpace + "HeadTrackingProcessor:\n";
172*ec779b8eSAndroid Build Coastguard Worker         StringAppendF(&ss, "%s maxTranslationalVelocity: %f meter/second\n", prefixSpace.c_str(),
173*ec779b8eSAndroid Build Coastguard Worker                       mOptions.maxTranslationalVelocity);
174*ec779b8eSAndroid Build Coastguard Worker         StringAppendF(&ss, "%s maxRotationalVelocity: %f rad/second\n", prefixSpace.c_str(),
175*ec779b8eSAndroid Build Coastguard Worker                       mOptions.maxRotationalVelocity);
176*ec779b8eSAndroid Build Coastguard Worker         StringAppendF(&ss, "%s freshnessTimeout: %0.4f ms\n", prefixSpace.c_str(),
177*ec779b8eSAndroid Build Coastguard Worker                       media::nsToFloatMs(mOptions.freshnessTimeout));
178*ec779b8eSAndroid Build Coastguard Worker         StringAppendF(&ss, "%s predictionDuration: %0.4f ms\n", prefixSpace.c_str(),
179*ec779b8eSAndroid Build Coastguard Worker                       media::nsToFloatMs(mOptions.predictionDuration));
180*ec779b8eSAndroid Build Coastguard Worker         StringAppendF(&ss, "%s autoRecenterWindowDuration: %0.4f ms\n", prefixSpace.c_str(),
181*ec779b8eSAndroid Build Coastguard Worker                       media::nsToFloatMs(mOptions.autoRecenterWindowDuration));
182*ec779b8eSAndroid Build Coastguard Worker         StringAppendF(&ss, "%s autoRecenterTranslationalThreshold: %f meter\n", prefixSpace.c_str(),
183*ec779b8eSAndroid Build Coastguard Worker                       mOptions.autoRecenterTranslationalThreshold);
184*ec779b8eSAndroid Build Coastguard Worker         StringAppendF(&ss, "%s autoRecenterRotationalThreshold: %f radians\n", prefixSpace.c_str(),
185*ec779b8eSAndroid Build Coastguard Worker                       mOptions.autoRecenterRotationalThreshold);
186*ec779b8eSAndroid Build Coastguard Worker         StringAppendF(&ss, "%s screenStillnessWindowDuration: %0.4f ms\n", prefixSpace.c_str(),
187*ec779b8eSAndroid Build Coastguard Worker                       media::nsToFloatMs(mOptions.screenStillnessWindowDuration));
188*ec779b8eSAndroid Build Coastguard Worker         StringAppendF(&ss, "%s screenStillnessTranslationalThreshold: %f meter\n",
189*ec779b8eSAndroid Build Coastguard Worker                       prefixSpace.c_str(), mOptions.screenStillnessTranslationalThreshold);
190*ec779b8eSAndroid Build Coastguard Worker         StringAppendF(&ss, "%s screenStillnessRotationalThreshold: %f radians\n",
191*ec779b8eSAndroid Build Coastguard Worker                       prefixSpace.c_str(), mOptions.screenStillnessRotationalThreshold);
192*ec779b8eSAndroid Build Coastguard Worker         ss += mModeSelector.toString(level + 1);
193*ec779b8eSAndroid Build Coastguard Worker         ss += mRateLimiter.toString(level + 1);
194*ec779b8eSAndroid Build Coastguard Worker         ss += mPosePredictor.toString(level + 1);
195*ec779b8eSAndroid Build Coastguard Worker         ss.append(prefixSpace + "ReCenterHistory:\n");
196*ec779b8eSAndroid Build Coastguard Worker         ss += mLocalLog.dumpToString((prefixSpace + " ").c_str(), mMaxLocalLogLine);
197*ec779b8eSAndroid Build Coastguard Worker         return ss;
198*ec779b8eSAndroid Build Coastguard Worker     }
199*ec779b8eSAndroid Build Coastguard Worker 
200*ec779b8eSAndroid Build Coastguard Worker   private:
201*ec779b8eSAndroid Build Coastguard Worker     const Options mOptions;
202*ec779b8eSAndroid Build Coastguard Worker     float mPhysicalToLogicalAngle = 0;
203*ec779b8eSAndroid Build Coastguard Worker     // We store the physical to logical angle as "pending" until the next world-to-screen sample it
204*ec779b8eSAndroid Build Coastguard Worker     // applies to arrives.
205*ec779b8eSAndroid Build Coastguard Worker     float mPendingPhysicalToLogicalAngle = 0;
206*ec779b8eSAndroid Build Coastguard Worker     std::optional<int64_t> mWorldToHeadTimestamp;
207*ec779b8eSAndroid Build Coastguard Worker     std::optional<int64_t> mWorldToScreenTimestamp;
208*ec779b8eSAndroid Build Coastguard Worker     Pose3f mHeadToStagePose;
209*ec779b8eSAndroid Build Coastguard Worker     PoseBias mHeadPoseBias;
210*ec779b8eSAndroid Build Coastguard Worker     PoseBias mScreenPoseBias;
211*ec779b8eSAndroid Build Coastguard Worker     StillnessDetector mHeadStillnessDetector;
212*ec779b8eSAndroid Build Coastguard Worker     StillnessDetector mScreenStillnessDetector;
213*ec779b8eSAndroid Build Coastguard Worker     ScreenHeadFusion mScreenHeadFusion;
214*ec779b8eSAndroid Build Coastguard Worker     ModeSelector mModeSelector;
215*ec779b8eSAndroid Build Coastguard Worker     PoseRateLimiter mRateLimiter;
216*ec779b8eSAndroid Build Coastguard Worker     PosePredictor mPosePredictor;
217*ec779b8eSAndroid Build Coastguard Worker     static constexpr std::size_t mMaxLocalLogLine = 10;
218*ec779b8eSAndroid Build Coastguard Worker     SimpleLog mLocalLog{mMaxLocalLogLine};
219*ec779b8eSAndroid Build Coastguard Worker };
220*ec779b8eSAndroid Build Coastguard Worker 
221*ec779b8eSAndroid Build Coastguard Worker }  // namespace
222*ec779b8eSAndroid Build Coastguard Worker 
createHeadTrackingProcessor(const HeadTrackingProcessor::Options & options,HeadTrackingMode initialMode)223*ec779b8eSAndroid Build Coastguard Worker std::unique_ptr<HeadTrackingProcessor> createHeadTrackingProcessor(
224*ec779b8eSAndroid Build Coastguard Worker         const HeadTrackingProcessor::Options& options, HeadTrackingMode initialMode) {
225*ec779b8eSAndroid Build Coastguard Worker     return std::make_unique<HeadTrackingProcessorImpl>(options, initialMode);
226*ec779b8eSAndroid Build Coastguard Worker }
227*ec779b8eSAndroid Build Coastguard Worker 
toString(HeadTrackingMode mode)228*ec779b8eSAndroid Build Coastguard Worker std::string toString(HeadTrackingMode mode) {
229*ec779b8eSAndroid Build Coastguard Worker     switch (mode) {
230*ec779b8eSAndroid Build Coastguard Worker         case HeadTrackingMode::STATIC:
231*ec779b8eSAndroid Build Coastguard Worker             return "STATIC";
232*ec779b8eSAndroid Build Coastguard Worker         case HeadTrackingMode::WORLD_RELATIVE:
233*ec779b8eSAndroid Build Coastguard Worker             return "WORLD_RELATIVE";
234*ec779b8eSAndroid Build Coastguard Worker         case HeadTrackingMode::SCREEN_RELATIVE:
235*ec779b8eSAndroid Build Coastguard Worker             return "SCREEN_RELATIVE";
236*ec779b8eSAndroid Build Coastguard Worker     }
237*ec779b8eSAndroid Build Coastguard Worker     return "EnumNotImplemented";
238*ec779b8eSAndroid Build Coastguard Worker };
239*ec779b8eSAndroid Build Coastguard Worker 
toString(PosePredictorType posePredictorType)240*ec779b8eSAndroid Build Coastguard Worker std::string toString(PosePredictorType posePredictorType) {
241*ec779b8eSAndroid Build Coastguard Worker     switch (posePredictorType) {
242*ec779b8eSAndroid Build Coastguard Worker         case PosePredictorType::AUTO: return "AUTO";
243*ec779b8eSAndroid Build Coastguard Worker         case PosePredictorType::LAST: return "LAST";
244*ec779b8eSAndroid Build Coastguard Worker         case PosePredictorType::TWIST: return "TWIST";
245*ec779b8eSAndroid Build Coastguard Worker         case PosePredictorType::LEAST_SQUARES: return "LEAST_SQUARES";
246*ec779b8eSAndroid Build Coastguard Worker     }
247*ec779b8eSAndroid Build Coastguard Worker     return "UNKNOWN" + std::to_string((int)posePredictorType);
248*ec779b8eSAndroid Build Coastguard Worker }
249*ec779b8eSAndroid Build Coastguard Worker 
isValidPosePredictorType(PosePredictorType posePredictorType)250*ec779b8eSAndroid Build Coastguard Worker bool isValidPosePredictorType(PosePredictorType posePredictorType) {
251*ec779b8eSAndroid Build Coastguard Worker     switch (posePredictorType) {
252*ec779b8eSAndroid Build Coastguard Worker         case PosePredictorType::AUTO:
253*ec779b8eSAndroid Build Coastguard Worker         case PosePredictorType::LAST:
254*ec779b8eSAndroid Build Coastguard Worker         case PosePredictorType::TWIST:
255*ec779b8eSAndroid Build Coastguard Worker         case PosePredictorType::LEAST_SQUARES:
256*ec779b8eSAndroid Build Coastguard Worker             return true;
257*ec779b8eSAndroid Build Coastguard Worker     }
258*ec779b8eSAndroid Build Coastguard Worker     return false;
259*ec779b8eSAndroid Build Coastguard Worker }
260*ec779b8eSAndroid Build Coastguard Worker 
261*ec779b8eSAndroid Build Coastguard Worker }  // namespace media
262*ec779b8eSAndroid Build Coastguard Worker }  // namespace android
263