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