xref: /aosp_15_r20/frameworks/av/media/libheadtracking/ModeSelector.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 <android-base/stringprintf.h>
17*ec779b8eSAndroid Build Coastguard Worker 
18*ec779b8eSAndroid Build Coastguard Worker #include "ModeSelector.h"
19*ec779b8eSAndroid Build Coastguard Worker 
20*ec779b8eSAndroid Build Coastguard Worker namespace android {
21*ec779b8eSAndroid Build Coastguard Worker namespace media {
22*ec779b8eSAndroid Build Coastguard Worker using android::base::StringAppendF;
23*ec779b8eSAndroid Build Coastguard Worker 
ModeSelector(const Options & options,HeadTrackingMode initialMode)24*ec779b8eSAndroid Build Coastguard Worker ModeSelector::ModeSelector(const Options& options, HeadTrackingMode initialMode)
25*ec779b8eSAndroid Build Coastguard Worker     : mOptions(options), mDesiredMode(initialMode), mActualMode(initialMode) {}
26*ec779b8eSAndroid Build Coastguard Worker 
setDesiredMode(HeadTrackingMode mode)27*ec779b8eSAndroid Build Coastguard Worker void ModeSelector::setDesiredMode(HeadTrackingMode mode) {
28*ec779b8eSAndroid Build Coastguard Worker     mDesiredMode = mode;
29*ec779b8eSAndroid Build Coastguard Worker }
30*ec779b8eSAndroid Build Coastguard Worker 
setScreenToStagePose(const Pose3f & screenToStage)31*ec779b8eSAndroid Build Coastguard Worker void ModeSelector::setScreenToStagePose(const Pose3f& screenToStage) {
32*ec779b8eSAndroid Build Coastguard Worker     mScreenToStage = screenToStage;
33*ec779b8eSAndroid Build Coastguard Worker }
34*ec779b8eSAndroid Build Coastguard Worker 
setScreenToHeadPose(int64_t timestamp,const std::optional<Pose3f> & screenToHead)35*ec779b8eSAndroid Build Coastguard Worker void ModeSelector::setScreenToHeadPose(int64_t timestamp,
36*ec779b8eSAndroid Build Coastguard Worker                                        const std::optional<Pose3f>& screenToHead) {
37*ec779b8eSAndroid Build Coastguard Worker     mScreenToHead = screenToHead;
38*ec779b8eSAndroid Build Coastguard Worker     mScreenToHeadTimestamp = timestamp;
39*ec779b8eSAndroid Build Coastguard Worker }
40*ec779b8eSAndroid Build Coastguard Worker 
setWorldToHeadPose(int64_t timestamp,const Pose3f & worldToHead)41*ec779b8eSAndroid Build Coastguard Worker void ModeSelector::setWorldToHeadPose(int64_t timestamp, const Pose3f& worldToHead) {
42*ec779b8eSAndroid Build Coastguard Worker     mWorldToHead = worldToHead;
43*ec779b8eSAndroid Build Coastguard Worker     mWorldToHeadTimestamp = timestamp;
44*ec779b8eSAndroid Build Coastguard Worker }
45*ec779b8eSAndroid Build Coastguard Worker 
setScreenStable(int64_t timestamp,bool stable)46*ec779b8eSAndroid Build Coastguard Worker void ModeSelector::setScreenStable(int64_t timestamp, bool stable) {
47*ec779b8eSAndroid Build Coastguard Worker     mScreenStable = stable;
48*ec779b8eSAndroid Build Coastguard Worker     mScreenStableTimestamp = timestamp;
49*ec779b8eSAndroid Build Coastguard Worker }
50*ec779b8eSAndroid Build Coastguard Worker 
calculateActualMode(int64_t timestamp)51*ec779b8eSAndroid Build Coastguard Worker void ModeSelector::calculateActualMode(int64_t timestamp) {
52*ec779b8eSAndroid Build Coastguard Worker     int64_t screenToHeadGap = timestamp - mScreenToHeadTimestamp;
53*ec779b8eSAndroid Build Coastguard Worker     int64_t worldToHeadGap = timestamp - mWorldToHeadTimestamp;
54*ec779b8eSAndroid Build Coastguard Worker     int64_t screenStableGap = timestamp - mScreenStableTimestamp;
55*ec779b8eSAndroid Build Coastguard Worker     bool isValidScreenToHead =
56*ec779b8eSAndroid Build Coastguard Worker             mScreenToHead.has_value() && screenToHeadGap < mOptions.freshnessTimeout;
57*ec779b8eSAndroid Build Coastguard Worker     bool isValidWorldToHead =
58*ec779b8eSAndroid Build Coastguard Worker             mWorldToHead.has_value() && worldToHeadGap < mOptions.freshnessTimeout;
59*ec779b8eSAndroid Build Coastguard Worker     bool isValidScreenStable =
60*ec779b8eSAndroid Build Coastguard Worker             mScreenStable.has_value() && screenStableGap < mOptions.freshnessTimeout;
61*ec779b8eSAndroid Build Coastguard Worker 
62*ec779b8eSAndroid Build Coastguard Worker     HeadTrackingMode mode = mDesiredMode;
63*ec779b8eSAndroid Build Coastguard Worker 
64*ec779b8eSAndroid Build Coastguard Worker     // Optional downgrade from screen-relative to world-relative.
65*ec779b8eSAndroid Build Coastguard Worker     if (mode == HeadTrackingMode::SCREEN_RELATIVE) {
66*ec779b8eSAndroid Build Coastguard Worker         if (!isValidScreenToHead) {
67*ec779b8eSAndroid Build Coastguard Worker             mode = HeadTrackingMode::WORLD_RELATIVE;
68*ec779b8eSAndroid Build Coastguard Worker         }
69*ec779b8eSAndroid Build Coastguard Worker     }
70*ec779b8eSAndroid Build Coastguard Worker 
71*ec779b8eSAndroid Build Coastguard Worker     // Optional downgrade from world-relative to static.
72*ec779b8eSAndroid Build Coastguard Worker     if (mode == HeadTrackingMode::WORLD_RELATIVE) {
73*ec779b8eSAndroid Build Coastguard Worker         if (!isValidWorldToHead || !isValidScreenStable || !mScreenStable.value()) {
74*ec779b8eSAndroid Build Coastguard Worker             mode = HeadTrackingMode::STATIC;
75*ec779b8eSAndroid Build Coastguard Worker         }
76*ec779b8eSAndroid Build Coastguard Worker     }
77*ec779b8eSAndroid Build Coastguard Worker 
78*ec779b8eSAndroid Build Coastguard Worker     if (mode != mActualMode) {
79*ec779b8eSAndroid Build Coastguard Worker         mLocalLog.log(
80*ec779b8eSAndroid Build Coastguard Worker                 "HT mode change from %s to %s, this ts %0.4f ms, lastTs+gap [ScreenToHead %0.4f + "
81*ec779b8eSAndroid Build Coastguard Worker                 "%0.4f, WorldToHead %0.4f + %0.4f, ScreenStable %0.4f + %0.4f] ms",
82*ec779b8eSAndroid Build Coastguard Worker                 media::toString(mActualMode).c_str(), media::toString(mode).c_str(),
83*ec779b8eSAndroid Build Coastguard Worker                 media::nsToFloatMs(timestamp), media::nsToFloatMs(mScreenToHeadTimestamp),
84*ec779b8eSAndroid Build Coastguard Worker                 media::nsToFloatMs(screenToHeadGap), media::nsToFloatMs(mWorldToHeadTimestamp),
85*ec779b8eSAndroid Build Coastguard Worker                 media::nsToFloatMs(worldToHeadGap), media::nsToFloatMs(mScreenStableTimestamp),
86*ec779b8eSAndroid Build Coastguard Worker                 media::nsToFloatMs(screenStableGap));
87*ec779b8eSAndroid Build Coastguard Worker         mActualMode = mode;
88*ec779b8eSAndroid Build Coastguard Worker     }
89*ec779b8eSAndroid Build Coastguard Worker }
90*ec779b8eSAndroid Build Coastguard Worker 
calculate(int64_t timestamp)91*ec779b8eSAndroid Build Coastguard Worker void ModeSelector::calculate(int64_t timestamp) {
92*ec779b8eSAndroid Build Coastguard Worker     calculateActualMode(timestamp);
93*ec779b8eSAndroid Build Coastguard Worker 
94*ec779b8eSAndroid Build Coastguard Worker     switch (mActualMode) {
95*ec779b8eSAndroid Build Coastguard Worker         case HeadTrackingMode::STATIC:
96*ec779b8eSAndroid Build Coastguard Worker             mHeadToStage = mScreenToStage;
97*ec779b8eSAndroid Build Coastguard Worker             break;
98*ec779b8eSAndroid Build Coastguard Worker 
99*ec779b8eSAndroid Build Coastguard Worker         case HeadTrackingMode::WORLD_RELATIVE:
100*ec779b8eSAndroid Build Coastguard Worker             mHeadToStage = mWorldToHead.value().inverse() * mScreenToStage;
101*ec779b8eSAndroid Build Coastguard Worker             break;
102*ec779b8eSAndroid Build Coastguard Worker 
103*ec779b8eSAndroid Build Coastguard Worker         case HeadTrackingMode::SCREEN_RELATIVE:
104*ec779b8eSAndroid Build Coastguard Worker             mHeadToStage = mScreenToHead.value().inverse() * mScreenToStage;
105*ec779b8eSAndroid Build Coastguard Worker             break;
106*ec779b8eSAndroid Build Coastguard Worker     }
107*ec779b8eSAndroid Build Coastguard Worker }
108*ec779b8eSAndroid Build Coastguard Worker 
getHeadToStagePose() const109*ec779b8eSAndroid Build Coastguard Worker Pose3f ModeSelector::getHeadToStagePose() const {
110*ec779b8eSAndroid Build Coastguard Worker     return mHeadToStage;
111*ec779b8eSAndroid Build Coastguard Worker }
112*ec779b8eSAndroid Build Coastguard Worker 
getActualMode() const113*ec779b8eSAndroid Build Coastguard Worker HeadTrackingMode ModeSelector::getActualMode() const {
114*ec779b8eSAndroid Build Coastguard Worker     return mActualMode;
115*ec779b8eSAndroid Build Coastguard Worker }
116*ec779b8eSAndroid Build Coastguard Worker 
toString(unsigned level) const117*ec779b8eSAndroid Build Coastguard Worker std::string ModeSelector::toString(unsigned level) const {
118*ec779b8eSAndroid Build Coastguard Worker     std::string prefixSpace(level, ' ');
119*ec779b8eSAndroid Build Coastguard Worker     std::string ss(prefixSpace);
120*ec779b8eSAndroid Build Coastguard Worker     ss.append("ModeSelector: ScreenToStage ")
121*ec779b8eSAndroid Build Coastguard Worker         .append(mScreenToStage.toString())
122*ec779b8eSAndroid Build Coastguard Worker         .append("\n")
123*ec779b8eSAndroid Build Coastguard Worker         .append(prefixSpace)
124*ec779b8eSAndroid Build Coastguard Worker         .append("Mode change history:\n")
125*ec779b8eSAndroid Build Coastguard Worker         .append(mLocalLog.dumpToString((prefixSpace + " ").c_str(), sMaxLocalLogLine));
126*ec779b8eSAndroid Build Coastguard Worker     return ss;
127*ec779b8eSAndroid Build Coastguard Worker }
128*ec779b8eSAndroid Build Coastguard Worker 
129*ec779b8eSAndroid Build Coastguard Worker }  // namespace media
130*ec779b8eSAndroid Build Coastguard Worker }  // namespace android
131