blob: 5e9a0e16998c2270bb4dddcc70dcb4fd6d2005d0 [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.
Shunkai Yaoa56279c2022-08-31 19:22:06 +000055// The max connection interval is 50ms, and HT sensor event interval can differ depending on the
56// sampling rate, scheduling, sensor eventQ FIFO etc. 120 (2 * 50 + 20) ms seems reasonable for now.
57constexpr auto kFreshnessTimeout = 120ms;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070058
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080059// Auto-recenter kicks in after the head has been still for this long.
Ytai Ben-Tsvicdc03062022-01-10 15:57:52 -080060constexpr auto kAutoRecenterWindowDuration = 6s;
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080061
62// Auto-recenter considers head not still if translated by this much (in meters, approx).
63constexpr float kAutoRecenterTranslationThreshold = 0.1f;
64
65// Auto-recenter considers head not still if rotated by this much (in radians, approx).
Ytai Ben-Tsvi237012c2022-02-16 15:54:31 -080066constexpr float kAutoRecenterRotationThreshold = 10.5f / 180 * M_PI;
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080067
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080068// Screen is considered to be unstable (not still) if it has moved significantly within the last
69// time window of this duration.
Ytai Ben-Tsvicdc03062022-01-10 15:57:52 -080070constexpr auto kScreenStillnessWindowDuration = 3s;
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080071
72// Screen is considered to have moved significantly if translated by this much (in meter, approx).
73constexpr float kScreenStillnessTranslationThreshold = 0.1f;
74
75// Screen is considered to have moved significantly if rotated by this much (in radians, approx).
Ytai Ben-Tsvicdc03062022-01-10 15:57:52 -080076constexpr float kScreenStillnessRotationThreshold = 7.0f / 180 * M_PI;
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080077
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070078// Time units for system clock ticks. This is what the Sensor Framework timestamps represent and
79// what we use for pose filtering.
80using Ticks = std::chrono::nanoseconds;
81
82// How many ticks in a second.
83constexpr auto kTicksPerSecond = Ticks::period::den;
84
Andy Hunga461a002022-05-17 10:36:02 -070085std::string getSensorMetricsId(int32_t sensorId) {
86 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_SENSOR).append(std::to_string(sensorId));
87}
88
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070089} // namespace
90
91SpatializerPoseController::SpatializerPoseController(Listener* listener,
Eric Laurente51f80e2022-04-14 10:20:38 +020092 std::chrono::microseconds sensorPeriod,
93 std::optional<std::chrono::microseconds> maxUpdatePeriod)
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070094 : mListener(listener),
95 mSensorPeriod(sensorPeriod),
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070096 mProcessor(createHeadTrackingProcessor(HeadTrackingProcessor::Options{
97 .maxTranslationalVelocity = kMaxTranslationalVelocity / kTicksPerSecond,
98 .maxRotationalVelocity = kMaxRotationalVelocity / kTicksPerSecond,
Ytai Ben-Tsvie2356842022-04-14 11:30:32 -070099 .freshnessTimeout = Ticks(kFreshnessTimeout).count(),
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700100 .predictionDuration = Ticks(kPredictionDuration).count(),
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -0800101 .autoRecenterWindowDuration = Ticks(kAutoRecenterWindowDuration).count(),
102 .autoRecenterTranslationalThreshold = kAutoRecenterTranslationThreshold,
103 .autoRecenterRotationalThreshold = kAutoRecenterRotationThreshold,
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -0800104 .screenStillnessWindowDuration = Ticks(kScreenStillnessWindowDuration).count(),
105 .screenStillnessTranslationalThreshold = kScreenStillnessTranslationThreshold,
106 .screenStillnessRotationalThreshold = kScreenStillnessRotationThreshold,
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700107 })),
Ytai Ben-Tsvi8b6fe3a2021-09-13 15:55:44 -0700108 mPoseProvider(SensorPoseProvider::create("headtracker", this)),
Keith Mok674f7352022-06-06 21:40:11 +0000109 mThread([this, maxUpdatePeriod] { // It's important that mThread is initialized after
110 // everything else because it runs a member
111 // function that may use any member
112 // of this class.
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700113 while (true) {
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700114 Pose3f headToStage;
115 std::optional<HeadTrackingMode> modeIfChanged;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700116 {
117 std::unique_lock lock(mMutex);
Eric Laurente51f80e2022-04-14 10:20:38 +0200118 if (maxUpdatePeriod.has_value()) {
119 mCondVar.wait_for(lock, maxUpdatePeriod.value(),
120 [this] { return mShouldExit || mShouldCalculate; });
121 } else {
122 mCondVar.wait(lock, [this] { return mShouldExit || mShouldCalculate; });
123 }
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700124 if (mShouldExit) {
125 ALOGV("Exiting thread");
126 return;
127 }
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700128
129 // Calculate.
130 std::tie(headToStage, modeIfChanged) = calculate_l();
131 }
132
133 // Invoke the callbacks outside the lock.
134 mListener->onHeadToStagePose(headToStage);
135 if (modeIfChanged) {
136 mListener->onActualModeChange(modeIfChanged.value());
137 }
138
139 {
140 std::lock_guard lock(mMutex);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700141 if (!mCalculated) {
142 mCalculated = true;
143 mCondVar.notify_all();
144 }
145 mShouldCalculate = false;
146 }
147 }
148 }) {}
149
150SpatializerPoseController::~SpatializerPoseController() {
151 {
152 std::unique_lock lock(mMutex);
153 mShouldExit = true;
154 mCondVar.notify_all();
155 }
156 mThread.join();
157}
158
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700159void SpatializerPoseController::setHeadSensor(int32_t sensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700160 std::lock_guard lock(mMutex);
Andy Hungba2a61a2022-05-20 12:00:28 -0700161 if (sensor == mHeadSensor) return;
162 ALOGV("%s: new sensor:%d mHeadSensor:%d mScreenSensor:%d",
163 __func__, sensor, mHeadSensor, mScreenSensor);
164
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700165 // Stop current sensor, if valid and different from the other sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700166 if (mHeadSensor != INVALID_SENSOR && mHeadSensor != mScreenSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700167 mPoseProvider->stopSensor(mHeadSensor);
Andy Hunga461a002022-05-17 10:36:02 -0700168 mediametrics::LogItem(getSensorMetricsId(mHeadSensor))
169 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
170 .record();
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700171 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700172
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700173 if (sensor != INVALID_SENSOR) {
174 if (sensor != mScreenSensor) {
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700175 // Start new sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700176 mHeadSensor =
177 mPoseProvider->startSensor(sensor, mSensorPeriod) ? sensor : INVALID_SENSOR;
Andy Hunga461a002022-05-17 10:36:02 -0700178 if (mHeadSensor != INVALID_SENSOR) {
179 auto sensor = mPoseProvider->getSensorByHandle(mHeadSensor);
180 std::string stringType = sensor ? sensor->getStringType().c_str() : "";
181 mediametrics::LogItem(getSensorMetricsId(mHeadSensor))
182 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
183 .set(AMEDIAMETRICS_PROP_MODE, AMEDIAMETRICS_PROP_MODE_VALUE_HEAD)
184 .set(AMEDIAMETRICS_PROP_TYPE, stringType)
185 .record();
186 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700187 } else {
188 // Sensor is already enabled.
189 mHeadSensor = mScreenSensor;
190 }
191 } else {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700192 mHeadSensor = INVALID_SENSOR;
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700193 }
194
Andy Hungba2a61a2022-05-20 12:00:28 -0700195 mProcessor->recenter(true /* recenterHead */, false /* recenterScreen */);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700196}
197
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700198void SpatializerPoseController::setScreenSensor(int32_t sensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700199 std::lock_guard lock(mMutex);
Andy Hungba2a61a2022-05-20 12:00:28 -0700200 if (sensor == mScreenSensor) return;
201 ALOGV("%s: new sensor:%d mHeadSensor:%d mScreenSensor:%d",
202 __func__, sensor, mHeadSensor, mScreenSensor);
203
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700204 // Stop current sensor, if valid and different from the other sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700205 if (mScreenSensor != INVALID_SENSOR && mScreenSensor != mHeadSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700206 mPoseProvider->stopSensor(mScreenSensor);
Andy Hunga461a002022-05-17 10:36:02 -0700207 mediametrics::LogItem(getSensorMetricsId(mScreenSensor))
208 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
209 .record();
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700210 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700211
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700212 if (sensor != INVALID_SENSOR) {
213 if (sensor != mHeadSensor) {
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700214 // Start new sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700215 mScreenSensor =
216 mPoseProvider->startSensor(sensor, mSensorPeriod) ? sensor : INVALID_SENSOR;
Andy Hunga461a002022-05-17 10:36:02 -0700217 auto sensor = mPoseProvider->getSensorByHandle(mScreenSensor);
218 std::string stringType = sensor ? sensor->getStringType().c_str() : "";
219 mediametrics::LogItem(getSensorMetricsId(mScreenSensor))
220 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
221 .set(AMEDIAMETRICS_PROP_MODE, AMEDIAMETRICS_PROP_MODE_VALUE_SCREEN)
222 .set(AMEDIAMETRICS_PROP_TYPE, stringType)
223 .record();
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700224 } else {
225 // Sensor is already enabled.
226 mScreenSensor = mHeadSensor;
227 }
228 } else {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700229 mScreenSensor = INVALID_SENSOR;
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700230 }
231
Andy Hungba2a61a2022-05-20 12:00:28 -0700232 mProcessor->recenter(false /* recenterHead */, true /* recenterScreen */);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700233}
234
235void SpatializerPoseController::setDesiredMode(HeadTrackingMode mode) {
236 std::lock_guard lock(mMutex);
237 mProcessor->setDesiredMode(mode);
238}
239
240void SpatializerPoseController::setScreenToStagePose(const Pose3f& screenToStage) {
241 std::lock_guard lock(mMutex);
242 mProcessor->setScreenToStagePose(screenToStage);
243}
244
245void SpatializerPoseController::setDisplayOrientation(float physicalToLogicalAngle) {
246 std::lock_guard lock(mMutex);
247 mProcessor->setDisplayOrientation(physicalToLogicalAngle);
248}
249
250void SpatializerPoseController::calculateAsync() {
251 std::lock_guard lock(mMutex);
252 mShouldCalculate = true;
253 mCondVar.notify_all();
254}
255
256void SpatializerPoseController::waitUntilCalculated() {
257 std::unique_lock lock(mMutex);
258 mCondVar.wait(lock, [this] { return mCalculated; });
259}
260
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700261std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>>
262SpatializerPoseController::calculate_l() {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700263 Pose3f headToStage;
264 HeadTrackingMode mode;
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700265 std::optional<media::HeadTrackingMode> modeIfChanged;
266
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700267 mProcessor->calculate(elapsedRealtimeNano());
268 headToStage = mProcessor->getHeadToStagePose();
269 mode = mProcessor->getActualMode();
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700270 if (!mActualMode.has_value() || mActualMode.value() != mode) {
271 mActualMode = mode;
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700272 modeIfChanged = mode;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700273 }
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700274 return std::make_tuple(headToStage, modeIfChanged);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700275}
276
277void SpatializerPoseController::recenter() {
278 std::lock_guard lock(mMutex);
279 mProcessor->recenter();
280}
281
282void SpatializerPoseController::onPose(int64_t timestamp, int32_t sensor, const Pose3f& pose,
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700283 const std::optional<Twist3f>& twist, bool isNewReference) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700284 std::lock_guard lock(mMutex);
285 if (sensor == mHeadSensor) {
Ytai Ben-Tsvi3c234b12022-01-31 11:15:17 -0800286 mProcessor->setWorldToHeadPose(timestamp, pose,
287 twist.value_or(Twist3f()) / kTicksPerSecond);
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700288 if (isNewReference) {
289 mProcessor->recenter(true, false);
290 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700291 }
292 if (sensor == mScreenSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700293 mProcessor->setWorldToScreenPose(timestamp, pose);
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700294 if (isNewReference) {
295 mProcessor->recenter(false, true);
296 }
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700297 }
298}
299
Shunkai Yao5a251df2022-07-22 18:42:27 +0000300std::string SpatializerPoseController::toString(unsigned level) const {
301 std::string prefixSpace;
302 prefixSpace.append(level, ' ');
303 std::string ss = prefixSpace + "SpatializerPoseController:\n";
304 bool needUnlock = false;
305
306 prefixSpace += ' ';
307 auto now = std::chrono::steady_clock::now();
308 if (!mMutex.try_lock_until(now + media::kSpatializerDumpSysTimeOutInSecond)) {
309 ss.append(prefixSpace).append("try_lock failed, dumpsys maybe INACCURATE!\n");
310 } else {
311 needUnlock = true;
312 }
313
314 ss += prefixSpace;
Shunkai Yao51379452022-08-30 03:14:50 +0000315 if (mHeadSensor == INVALID_SENSOR) {
316 ss += "HeadSensor: INVALID\n";
Shunkai Yao5a251df2022-07-22 18:42:27 +0000317 } else {
318 base::StringAppendF(&ss, "HeadSensor: 0x%08x\n", mHeadSensor);
319 }
320
321 ss += prefixSpace;
Shunkai Yao51379452022-08-30 03:14:50 +0000322 if (mScreenSensor == INVALID_SENSOR) {
Shunkai Yao5a251df2022-07-22 18:42:27 +0000323 ss += "ScreenSensor: INVALID\n";
324 } else {
325 base::StringAppendF(&ss, "ScreenSensor: 0x%08x\n", mScreenSensor);
326 }
327
328 ss += prefixSpace;
329 if (mActualMode.has_value()) {
Shunkai Yao51379452022-08-30 03:14:50 +0000330 base::StringAppendF(&ss, "ActualMode: %s\n", media::toString(mActualMode.value()).c_str());
Shunkai Yao5a251df2022-07-22 18:42:27 +0000331 } else {
332 ss += "ActualMode NOTEXIST\n";
333 }
334
335 if (mProcessor) {
336 ss += mProcessor->toString_l(level + 1);
337 } else {
338 ss.append(prefixSpace.c_str()).append("HeadTrackingProcessor not exist\n");
339 }
340
341 if (mPoseProvider) {
342 ss += mPoseProvider->toString(level + 1);
343 } else {
344 ss.append(prefixSpace.c_str()).append("SensorPoseProvider not exist\n");
345 }
346
347 if (needUnlock) {
348 mMutex.unlock();
349 }
350 // TODO: 233092747 add history sensor info with SimpleLog.
351 return ss;
352}
353
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700354} // namespace android