blob: ce076dd43b7a82f1bf0be63787afcf9810befa8d [file] [log] [blame]
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -07001/*
2 * Copyright 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 */
16#include "SpatializerPoseController.h"
17
Ytai Ben-Tsvie9b34952021-09-10 12:48:27 -070018#define LOG_TAG "SpatializerPoseController"
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070019//#define LOG_NDEBUG 0
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -070020#include <sensor/Sensor.h>
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070021#include <utils/Log.h>
22#include <utils/SystemClock.h>
23
24namespace android {
25
26using media::createHeadTrackingProcessor;
27using media::HeadTrackingMode;
28using media::HeadTrackingProcessor;
29using media::Pose3f;
30using media::SensorPoseProvider;
31using media::Twist3f;
32
33using namespace std::chrono_literals;
34
35namespace {
36
37// This is how fast, in m/s, we allow position to shift during rate-limiting.
Ytai Ben-Tsvic2d28402022-01-14 14:55:16 -080038constexpr float kMaxTranslationalVelocity = 2;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070039
40// This is how fast, in rad/s, we allow rotation angle to shift during rate-limiting.
Ytai Ben-Tsvic2d28402022-01-14 14:55:16 -080041constexpr float kMaxRotationalVelocity = 8;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070042
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070043// This is how far into the future we predict the head pose, using linear extrapolation based on
44// twist (velocity). It should be set to a value that matches the characteristic durations of moving
45// one's head. The higher we set this, the more latency we are able to reduce, but setting this too
46// high will result in high prediction errors whenever the head accelerates (changes velocity).
Ytai Ben-Tsvi3c234b12022-01-31 11:15:17 -080047constexpr auto kPredictionDuration = 50ms;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070048
Ytai Ben-Tsvie2356842022-04-14 11:30:32 -070049// After not getting a pose sample for this long, we would treat the measurement as stale.
50constexpr auto kFreshnessTimeout = 50ms;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070051
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080052// Auto-recenter kicks in after the head has been still for this long.
Ytai Ben-Tsvicdc03062022-01-10 15:57:52 -080053constexpr auto kAutoRecenterWindowDuration = 6s;
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080054
55// Auto-recenter considers head not still if translated by this much (in meters, approx).
56constexpr float kAutoRecenterTranslationThreshold = 0.1f;
57
58// Auto-recenter considers head not still if rotated by this much (in radians, approx).
Ytai Ben-Tsvi237012c2022-02-16 15:54:31 -080059constexpr float kAutoRecenterRotationThreshold = 10.5f / 180 * M_PI;
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080060
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080061// Screen is considered to be unstable (not still) if it has moved significantly within the last
62// time window of this duration.
Ytai Ben-Tsvicdc03062022-01-10 15:57:52 -080063constexpr auto kScreenStillnessWindowDuration = 3s;
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080064
65// Screen is considered to have moved significantly if translated by this much (in meter, approx).
66constexpr float kScreenStillnessTranslationThreshold = 0.1f;
67
68// Screen is considered to have moved significantly if rotated by this much (in radians, approx).
Ytai Ben-Tsvicdc03062022-01-10 15:57:52 -080069constexpr float kScreenStillnessRotationThreshold = 7.0f / 180 * M_PI;
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080070
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070071// Time units for system clock ticks. This is what the Sensor Framework timestamps represent and
72// what we use for pose filtering.
73using Ticks = std::chrono::nanoseconds;
74
75// How many ticks in a second.
76constexpr auto kTicksPerSecond = Ticks::period::den;
77
78} // namespace
79
80SpatializerPoseController::SpatializerPoseController(Listener* listener,
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -070081 std::chrono::microseconds sensorPeriod,
82 std::chrono::microseconds maxUpdatePeriod)
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070083 : mListener(listener),
84 mSensorPeriod(sensorPeriod),
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070085 mProcessor(createHeadTrackingProcessor(HeadTrackingProcessor::Options{
86 .maxTranslationalVelocity = kMaxTranslationalVelocity / kTicksPerSecond,
87 .maxRotationalVelocity = kMaxRotationalVelocity / kTicksPerSecond,
Ytai Ben-Tsvie2356842022-04-14 11:30:32 -070088 .freshnessTimeout = Ticks(kFreshnessTimeout).count(),
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070089 .predictionDuration = Ticks(kPredictionDuration).count(),
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080090 .autoRecenterWindowDuration = Ticks(kAutoRecenterWindowDuration).count(),
91 .autoRecenterTranslationalThreshold = kAutoRecenterTranslationThreshold,
92 .autoRecenterRotationalThreshold = kAutoRecenterRotationThreshold,
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080093 .screenStillnessWindowDuration = Ticks(kScreenStillnessWindowDuration).count(),
94 .screenStillnessTranslationalThreshold = kScreenStillnessTranslationThreshold,
95 .screenStillnessRotationalThreshold = kScreenStillnessRotationThreshold,
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070096 })),
Ytai Ben-Tsvi8b6fe3a2021-09-13 15:55:44 -070097 mPoseProvider(SensorPoseProvider::create("headtracker", this)),
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070098 mThread([this, maxUpdatePeriod] {
99 while (true) {
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700100 Pose3f headToStage;
101 std::optional<HeadTrackingMode> modeIfChanged;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700102 {
103 std::unique_lock lock(mMutex);
104 mCondVar.wait_for(lock, maxUpdatePeriod,
105 [this] { return mShouldExit || mShouldCalculate; });
106 if (mShouldExit) {
107 ALOGV("Exiting thread");
108 return;
109 }
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700110
111 // Calculate.
112 std::tie(headToStage, modeIfChanged) = calculate_l();
113 }
114
115 // Invoke the callbacks outside the lock.
116 mListener->onHeadToStagePose(headToStage);
117 if (modeIfChanged) {
118 mListener->onActualModeChange(modeIfChanged.value());
119 }
120
121 {
122 std::lock_guard lock(mMutex);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700123 if (!mCalculated) {
124 mCalculated = true;
125 mCondVar.notify_all();
126 }
127 mShouldCalculate = false;
128 }
129 }
130 }) {}
131
132SpatializerPoseController::~SpatializerPoseController() {
133 {
134 std::unique_lock lock(mMutex);
135 mShouldExit = true;
136 mCondVar.notify_all();
137 }
138 mThread.join();
139}
140
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700141void SpatializerPoseController::setHeadSensor(int32_t sensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700142 std::lock_guard lock(mMutex);
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700143 // Stop current sensor, if valid and different from the other sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700144 if (mHeadSensor != INVALID_SENSOR && mHeadSensor != mScreenSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700145 mPoseProvider->stopSensor(mHeadSensor);
146 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700147
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700148 if (sensor != INVALID_SENSOR) {
149 if (sensor != mScreenSensor) {
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700150 // Start new sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700151 mHeadSensor =
152 mPoseProvider->startSensor(sensor, mSensorPeriod) ? sensor : INVALID_SENSOR;
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700153 } else {
154 // Sensor is already enabled.
155 mHeadSensor = mScreenSensor;
156 }
157 } else {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700158 mHeadSensor = INVALID_SENSOR;
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700159 }
160
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700161 mProcessor->recenter(true, false);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700162}
163
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700164void SpatializerPoseController::setScreenSensor(int32_t sensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700165 std::lock_guard lock(mMutex);
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700166 // Stop current sensor, if valid and different from the other sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700167 if (mScreenSensor != INVALID_SENSOR && mScreenSensor != mHeadSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700168 mPoseProvider->stopSensor(mScreenSensor);
169 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700170
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700171 if (sensor != INVALID_SENSOR) {
172 if (sensor != mHeadSensor) {
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700173 // Start new sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700174 mScreenSensor =
175 mPoseProvider->startSensor(sensor, mSensorPeriod) ? sensor : INVALID_SENSOR;
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700176 } else {
177 // Sensor is already enabled.
178 mScreenSensor = mHeadSensor;
179 }
180 } else {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700181 mScreenSensor = INVALID_SENSOR;
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700182 }
183
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700184 mProcessor->recenter(false, true);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700185}
186
187void SpatializerPoseController::setDesiredMode(HeadTrackingMode mode) {
188 std::lock_guard lock(mMutex);
189 mProcessor->setDesiredMode(mode);
190}
191
192void SpatializerPoseController::setScreenToStagePose(const Pose3f& screenToStage) {
193 std::lock_guard lock(mMutex);
194 mProcessor->setScreenToStagePose(screenToStage);
195}
196
197void SpatializerPoseController::setDisplayOrientation(float physicalToLogicalAngle) {
198 std::lock_guard lock(mMutex);
199 mProcessor->setDisplayOrientation(physicalToLogicalAngle);
200}
201
202void SpatializerPoseController::calculateAsync() {
203 std::lock_guard lock(mMutex);
204 mShouldCalculate = true;
205 mCondVar.notify_all();
206}
207
208void SpatializerPoseController::waitUntilCalculated() {
209 std::unique_lock lock(mMutex);
210 mCondVar.wait(lock, [this] { return mCalculated; });
211}
212
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700213std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>>
214SpatializerPoseController::calculate_l() {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700215 Pose3f headToStage;
216 HeadTrackingMode mode;
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700217 std::optional<media::HeadTrackingMode> modeIfChanged;
218
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700219 mProcessor->calculate(elapsedRealtimeNano());
220 headToStage = mProcessor->getHeadToStagePose();
221 mode = mProcessor->getActualMode();
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700222 if (!mActualMode.has_value() || mActualMode.value() != mode) {
223 mActualMode = mode;
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700224 modeIfChanged = mode;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700225 }
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700226 return std::make_tuple(headToStage, modeIfChanged);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700227}
228
229void SpatializerPoseController::recenter() {
230 std::lock_guard lock(mMutex);
231 mProcessor->recenter();
232}
233
234void SpatializerPoseController::onPose(int64_t timestamp, int32_t sensor, const Pose3f& pose,
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700235 const std::optional<Twist3f>& twist, bool isNewReference) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700236 std::lock_guard lock(mMutex);
237 if (sensor == mHeadSensor) {
Ytai Ben-Tsvi3c234b12022-01-31 11:15:17 -0800238 mProcessor->setWorldToHeadPose(timestamp, pose,
239 twist.value_or(Twist3f()) / kTicksPerSecond);
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700240 if (isNewReference) {
241 mProcessor->recenter(true, false);
242 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700243 }
244 if (sensor == mScreenSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700245 mProcessor->setWorldToScreenPose(timestamp, pose);
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700246 if (isNewReference) {
247 mProcessor->recenter(false, true);
248 }
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700249 }
250}
251
252} // namespace android