blob: e012a0b3987daf298c66dc885f033b8f84ea9f60 [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"
Shunkai Yao5a251df2022-07-22 18:42:27 +000017#include <android-base/stringprintf.h>
18#include <chrono>
19#include <cstdint>
20#include <string>
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070021
Ytai Ben-Tsvie9b34952021-09-10 12:48:27 -070022#define LOG_TAG "SpatializerPoseController"
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070023//#define LOG_NDEBUG 0
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -070024#include <sensor/Sensor.h>
Andy Hunga461a002022-05-17 10:36:02 -070025#include <media/MediaMetricsItem.h>
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070026#include <utils/Log.h>
27#include <utils/SystemClock.h>
28
29namespace android {
30
31using media::createHeadTrackingProcessor;
32using media::HeadTrackingMode;
33using media::HeadTrackingProcessor;
34using media::Pose3f;
35using media::SensorPoseProvider;
36using media::Twist3f;
37
38using namespace std::chrono_literals;
39
40namespace {
41
42// This is how fast, in m/s, we allow position to shift during rate-limiting.
Ytai Ben-Tsvic2d28402022-01-14 14:55:16 -080043constexpr float kMaxTranslationalVelocity = 2;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070044
45// This is how fast, in rad/s, we allow rotation angle to shift during rate-limiting.
Ytai Ben-Tsvic2d28402022-01-14 14:55:16 -080046constexpr float kMaxRotationalVelocity = 8;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070047
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070048// This is how far into the future we predict the head pose, using linear extrapolation based on
49// twist (velocity). It should be set to a value that matches the characteristic durations of moving
50// one's head. The higher we set this, the more latency we are able to reduce, but setting this too
51// high will result in high prediction errors whenever the head accelerates (changes velocity).
Ytai Ben-Tsvi3c234b12022-01-31 11:15:17 -080052constexpr auto kPredictionDuration = 50ms;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070053
Ytai Ben-Tsvie2356842022-04-14 11:30:32 -070054// After not getting a pose sample for this long, we would treat the measurement as stale.
55constexpr auto kFreshnessTimeout = 50ms;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070056
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080057// Auto-recenter kicks in after the head has been still for this long.
Ytai Ben-Tsvicdc03062022-01-10 15:57:52 -080058constexpr auto kAutoRecenterWindowDuration = 6s;
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080059
60// Auto-recenter considers head not still if translated by this much (in meters, approx).
61constexpr float kAutoRecenterTranslationThreshold = 0.1f;
62
63// Auto-recenter considers head not still if rotated by this much (in radians, approx).
Ytai Ben-Tsvi237012c2022-02-16 15:54:31 -080064constexpr float kAutoRecenterRotationThreshold = 10.5f / 180 * M_PI;
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080065
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080066// Screen is considered to be unstable (not still) if it has moved significantly within the last
67// time window of this duration.
Ytai Ben-Tsvicdc03062022-01-10 15:57:52 -080068constexpr auto kScreenStillnessWindowDuration = 3s;
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080069
70// Screen is considered to have moved significantly if translated by this much (in meter, approx).
71constexpr float kScreenStillnessTranslationThreshold = 0.1f;
72
73// Screen is considered to have moved significantly if rotated by this much (in radians, approx).
Ytai Ben-Tsvicdc03062022-01-10 15:57:52 -080074constexpr float kScreenStillnessRotationThreshold = 7.0f / 180 * M_PI;
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080075
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070076// Time units for system clock ticks. This is what the Sensor Framework timestamps represent and
77// what we use for pose filtering.
78using Ticks = std::chrono::nanoseconds;
79
80// How many ticks in a second.
81constexpr auto kTicksPerSecond = Ticks::period::den;
82
Andy Hunga461a002022-05-17 10:36:02 -070083std::string getSensorMetricsId(int32_t sensorId) {
84 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_SENSOR).append(std::to_string(sensorId));
85}
86
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070087} // namespace
88
89SpatializerPoseController::SpatializerPoseController(Listener* listener,
Eric Laurente51f80e2022-04-14 10:20:38 +020090 std::chrono::microseconds sensorPeriod,
91 std::optional<std::chrono::microseconds> maxUpdatePeriod)
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070092 : mListener(listener),
93 mSensorPeriod(sensorPeriod),
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070094 mProcessor(createHeadTrackingProcessor(HeadTrackingProcessor::Options{
95 .maxTranslationalVelocity = kMaxTranslationalVelocity / kTicksPerSecond,
96 .maxRotationalVelocity = kMaxRotationalVelocity / kTicksPerSecond,
Ytai Ben-Tsvie2356842022-04-14 11:30:32 -070097 .freshnessTimeout = Ticks(kFreshnessTimeout).count(),
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070098 .predictionDuration = Ticks(kPredictionDuration).count(),
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080099 .autoRecenterWindowDuration = Ticks(kAutoRecenterWindowDuration).count(),
100 .autoRecenterTranslationalThreshold = kAutoRecenterTranslationThreshold,
101 .autoRecenterRotationalThreshold = kAutoRecenterRotationThreshold,
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -0800102 .screenStillnessWindowDuration = Ticks(kScreenStillnessWindowDuration).count(),
103 .screenStillnessTranslationalThreshold = kScreenStillnessTranslationThreshold,
104 .screenStillnessRotationalThreshold = kScreenStillnessRotationThreshold,
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700105 })),
Ytai Ben-Tsvi8b6fe3a2021-09-13 15:55:44 -0700106 mPoseProvider(SensorPoseProvider::create("headtracker", this)),
Keith Mok674f7352022-06-06 21:40:11 +0000107 mThread([this, maxUpdatePeriod] { // It's important that mThread is initialized after
108 // everything else because it runs a member
109 // function that may use any member
110 // of this class.
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700111 while (true) {
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700112 Pose3f headToStage;
113 std::optional<HeadTrackingMode> modeIfChanged;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700114 {
115 std::unique_lock lock(mMutex);
Eric Laurente51f80e2022-04-14 10:20:38 +0200116 if (maxUpdatePeriod.has_value()) {
117 mCondVar.wait_for(lock, maxUpdatePeriod.value(),
118 [this] { return mShouldExit || mShouldCalculate; });
119 } else {
120 mCondVar.wait(lock, [this] { return mShouldExit || mShouldCalculate; });
121 }
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700122 if (mShouldExit) {
123 ALOGV("Exiting thread");
124 return;
125 }
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700126
127 // Calculate.
128 std::tie(headToStage, modeIfChanged) = calculate_l();
129 }
130
131 // Invoke the callbacks outside the lock.
132 mListener->onHeadToStagePose(headToStage);
133 if (modeIfChanged) {
134 mListener->onActualModeChange(modeIfChanged.value());
135 }
136
137 {
138 std::lock_guard lock(mMutex);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700139 if (!mCalculated) {
140 mCalculated = true;
141 mCondVar.notify_all();
142 }
143 mShouldCalculate = false;
144 }
145 }
146 }) {}
147
148SpatializerPoseController::~SpatializerPoseController() {
149 {
150 std::unique_lock lock(mMutex);
151 mShouldExit = true;
152 mCondVar.notify_all();
153 }
154 mThread.join();
155}
156
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700157void SpatializerPoseController::setHeadSensor(int32_t sensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700158 std::lock_guard lock(mMutex);
Andy Hungba2a61a2022-05-20 12:00:28 -0700159 if (sensor == mHeadSensor) return;
160 ALOGV("%s: new sensor:%d mHeadSensor:%d mScreenSensor:%d",
161 __func__, sensor, mHeadSensor, mScreenSensor);
162
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700163 // Stop current sensor, if valid and different from the other sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700164 if (mHeadSensor != INVALID_SENSOR && mHeadSensor != mScreenSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700165 mPoseProvider->stopSensor(mHeadSensor);
Andy Hunga461a002022-05-17 10:36:02 -0700166 mediametrics::LogItem(getSensorMetricsId(mHeadSensor))
167 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
168 .record();
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700169 }
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 != mScreenSensor) {
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700173 // Start new sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700174 mHeadSensor =
175 mPoseProvider->startSensor(sensor, mSensorPeriod) ? sensor : INVALID_SENSOR;
Andy Hunga461a002022-05-17 10:36:02 -0700176 if (mHeadSensor != INVALID_SENSOR) {
177 auto sensor = mPoseProvider->getSensorByHandle(mHeadSensor);
178 std::string stringType = sensor ? sensor->getStringType().c_str() : "";
179 mediametrics::LogItem(getSensorMetricsId(mHeadSensor))
180 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
181 .set(AMEDIAMETRICS_PROP_MODE, AMEDIAMETRICS_PROP_MODE_VALUE_HEAD)
182 .set(AMEDIAMETRICS_PROP_TYPE, stringType)
183 .record();
184 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700185 } else {
186 // Sensor is already enabled.
187 mHeadSensor = mScreenSensor;
188 }
189 } else {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700190 mHeadSensor = INVALID_SENSOR;
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700191 }
192
Andy Hungba2a61a2022-05-20 12:00:28 -0700193 mProcessor->recenter(true /* recenterHead */, false /* recenterScreen */);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700194}
195
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700196void SpatializerPoseController::setScreenSensor(int32_t sensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700197 std::lock_guard lock(mMutex);
Andy Hungba2a61a2022-05-20 12:00:28 -0700198 if (sensor == mScreenSensor) return;
199 ALOGV("%s: new sensor:%d mHeadSensor:%d mScreenSensor:%d",
200 __func__, sensor, mHeadSensor, mScreenSensor);
201
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700202 // Stop current sensor, if valid and different from the other sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700203 if (mScreenSensor != INVALID_SENSOR && mScreenSensor != mHeadSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700204 mPoseProvider->stopSensor(mScreenSensor);
Andy Hunga461a002022-05-17 10:36:02 -0700205 mediametrics::LogItem(getSensorMetricsId(mScreenSensor))
206 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
207 .record();
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700208 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700209
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700210 if (sensor != INVALID_SENSOR) {
211 if (sensor != mHeadSensor) {
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700212 // Start new sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700213 mScreenSensor =
214 mPoseProvider->startSensor(sensor, mSensorPeriod) ? sensor : INVALID_SENSOR;
Andy Hunga461a002022-05-17 10:36:02 -0700215 auto sensor = mPoseProvider->getSensorByHandle(mScreenSensor);
216 std::string stringType = sensor ? sensor->getStringType().c_str() : "";
217 mediametrics::LogItem(getSensorMetricsId(mScreenSensor))
218 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
219 .set(AMEDIAMETRICS_PROP_MODE, AMEDIAMETRICS_PROP_MODE_VALUE_SCREEN)
220 .set(AMEDIAMETRICS_PROP_TYPE, stringType)
221 .record();
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700222 } else {
223 // Sensor is already enabled.
224 mScreenSensor = mHeadSensor;
225 }
226 } else {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700227 mScreenSensor = INVALID_SENSOR;
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700228 }
229
Andy Hungba2a61a2022-05-20 12:00:28 -0700230 mProcessor->recenter(false /* recenterHead */, true /* recenterScreen */);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700231}
232
233void SpatializerPoseController::setDesiredMode(HeadTrackingMode mode) {
234 std::lock_guard lock(mMutex);
235 mProcessor->setDesiredMode(mode);
236}
237
238void SpatializerPoseController::setScreenToStagePose(const Pose3f& screenToStage) {
239 std::lock_guard lock(mMutex);
240 mProcessor->setScreenToStagePose(screenToStage);
241}
242
243void SpatializerPoseController::setDisplayOrientation(float physicalToLogicalAngle) {
244 std::lock_guard lock(mMutex);
245 mProcessor->setDisplayOrientation(physicalToLogicalAngle);
246}
247
248void SpatializerPoseController::calculateAsync() {
249 std::lock_guard lock(mMutex);
250 mShouldCalculate = true;
251 mCondVar.notify_all();
252}
253
254void SpatializerPoseController::waitUntilCalculated() {
255 std::unique_lock lock(mMutex);
256 mCondVar.wait(lock, [this] { return mCalculated; });
257}
258
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700259std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>>
260SpatializerPoseController::calculate_l() {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700261 Pose3f headToStage;
262 HeadTrackingMode mode;
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700263 std::optional<media::HeadTrackingMode> modeIfChanged;
264
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700265 mProcessor->calculate(elapsedRealtimeNano());
266 headToStage = mProcessor->getHeadToStagePose();
267 mode = mProcessor->getActualMode();
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700268 if (!mActualMode.has_value() || mActualMode.value() != mode) {
269 mActualMode = mode;
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700270 modeIfChanged = mode;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700271 }
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700272 return std::make_tuple(headToStage, modeIfChanged);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700273}
274
275void SpatializerPoseController::recenter() {
276 std::lock_guard lock(mMutex);
277 mProcessor->recenter();
278}
279
280void SpatializerPoseController::onPose(int64_t timestamp, int32_t sensor, const Pose3f& pose,
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700281 const std::optional<Twist3f>& twist, bool isNewReference) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700282 std::lock_guard lock(mMutex);
283 if (sensor == mHeadSensor) {
Ytai Ben-Tsvi3c234b12022-01-31 11:15:17 -0800284 mProcessor->setWorldToHeadPose(timestamp, pose,
285 twist.value_or(Twist3f()) / kTicksPerSecond);
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700286 if (isNewReference) {
287 mProcessor->recenter(true, false);
288 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700289 }
290 if (sensor == mScreenSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700291 mProcessor->setWorldToScreenPose(timestamp, pose);
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700292 if (isNewReference) {
293 mProcessor->recenter(false, true);
294 }
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700295 }
296}
297
Shunkai Yao5a251df2022-07-22 18:42:27 +0000298std::string SpatializerPoseController::toString(unsigned level) const {
299 std::string prefixSpace;
300 prefixSpace.append(level, ' ');
301 std::string ss = prefixSpace + "SpatializerPoseController:\n";
302 bool needUnlock = false;
303
304 prefixSpace += ' ';
305 auto now = std::chrono::steady_clock::now();
306 if (!mMutex.try_lock_until(now + media::kSpatializerDumpSysTimeOutInSecond)) {
307 ss.append(prefixSpace).append("try_lock failed, dumpsys maybe INACCURATE!\n");
308 } else {
309 needUnlock = true;
310 }
311
312 ss += prefixSpace;
313 if (mHeadSensor == media::SensorPoseProvider::INVALID_HANDLE) {
314 ss.append("HeadSensor: INVALID\n");
315 } else {
316 base::StringAppendF(&ss, "HeadSensor: 0x%08x\n", mHeadSensor);
317 }
318
319 ss += prefixSpace;
320 if (mScreenSensor == media::SensorPoseProvider::INVALID_HANDLE) {
321 ss += "ScreenSensor: INVALID\n";
322 } else {
323 base::StringAppendF(&ss, "ScreenSensor: 0x%08x\n", mScreenSensor);
324 }
325
326 ss += prefixSpace;
327 if (mActualMode.has_value()) {
328 base::StringAppendF(&ss, "ActualMode: %s", toString(mActualMode.value()).c_str());
329 } else {
330 ss += "ActualMode NOTEXIST\n";
331 }
332
333 if (mProcessor) {
334 ss += mProcessor->toString_l(level + 1);
335 } else {
336 ss.append(prefixSpace.c_str()).append("HeadTrackingProcessor not exist\n");
337 }
338
339 if (mPoseProvider) {
340 ss += mPoseProvider->toString(level + 1);
341 } else {
342 ss.append(prefixSpace.c_str()).append("SensorPoseProvider not exist\n");
343 }
344
345 if (needUnlock) {
346 mMutex.unlock();
347 }
348 // TODO: 233092747 add history sensor info with SimpleLog.
349 return ss;
350}
351
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700352} // namespace android