blob: 23bcd77575e88d0094a5e7d2f56378de57f096bb [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>
Andy Hunga461a002022-05-17 10:36:02 -070021#include <media/MediaMetricsItem.h>
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070022#include <utils/Log.h>
23#include <utils/SystemClock.h>
24
25namespace android {
26
27using media::createHeadTrackingProcessor;
28using media::HeadTrackingMode;
29using media::HeadTrackingProcessor;
30using media::Pose3f;
31using media::SensorPoseProvider;
32using media::Twist3f;
33
34using namespace std::chrono_literals;
35
36namespace {
37
38// This is how fast, in m/s, we allow position to shift during rate-limiting.
Ytai Ben-Tsvic2d28402022-01-14 14:55:16 -080039constexpr float kMaxTranslationalVelocity = 2;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070040
41// This is how fast, in rad/s, we allow rotation angle to shift during rate-limiting.
Ytai Ben-Tsvic2d28402022-01-14 14:55:16 -080042constexpr float kMaxRotationalVelocity = 8;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070043
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070044// This is how far into the future we predict the head pose, using linear extrapolation based on
45// twist (velocity). It should be set to a value that matches the characteristic durations of moving
46// one's head. The higher we set this, the more latency we are able to reduce, but setting this too
47// high will result in high prediction errors whenever the head accelerates (changes velocity).
Ytai Ben-Tsvi3c234b12022-01-31 11:15:17 -080048constexpr auto kPredictionDuration = 50ms;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070049
Ytai Ben-Tsvie2356842022-04-14 11:30:32 -070050// After not getting a pose sample for this long, we would treat the measurement as stale.
51constexpr auto kFreshnessTimeout = 50ms;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070052
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080053// Auto-recenter kicks in after the head has been still for this long.
Ytai Ben-Tsvicdc03062022-01-10 15:57:52 -080054constexpr auto kAutoRecenterWindowDuration = 6s;
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080055
56// Auto-recenter considers head not still if translated by this much (in meters, approx).
57constexpr float kAutoRecenterTranslationThreshold = 0.1f;
58
59// Auto-recenter considers head not still if rotated by this much (in radians, approx).
Ytai Ben-Tsvi237012c2022-02-16 15:54:31 -080060constexpr float kAutoRecenterRotationThreshold = 10.5f / 180 * M_PI;
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080061
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080062// Screen is considered to be unstable (not still) if it has moved significantly within the last
63// time window of this duration.
Ytai Ben-Tsvicdc03062022-01-10 15:57:52 -080064constexpr auto kScreenStillnessWindowDuration = 3s;
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080065
66// Screen is considered to have moved significantly if translated by this much (in meter, approx).
67constexpr float kScreenStillnessTranslationThreshold = 0.1f;
68
69// Screen is considered to have moved significantly if rotated by this much (in radians, approx).
Ytai Ben-Tsvicdc03062022-01-10 15:57:52 -080070constexpr float kScreenStillnessRotationThreshold = 7.0f / 180 * M_PI;
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080071
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070072// Time units for system clock ticks. This is what the Sensor Framework timestamps represent and
73// what we use for pose filtering.
74using Ticks = std::chrono::nanoseconds;
75
76// How many ticks in a second.
77constexpr auto kTicksPerSecond = Ticks::period::den;
78
Andy Hunga461a002022-05-17 10:36:02 -070079std::string getSensorMetricsId(int32_t sensorId) {
80 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_SENSOR).append(std::to_string(sensorId));
81}
82
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070083} // namespace
84
85SpatializerPoseController::SpatializerPoseController(Listener* listener,
Eric Laurente51f80e2022-04-14 10:20:38 +020086 std::chrono::microseconds sensorPeriod,
87 std::optional<std::chrono::microseconds> maxUpdatePeriod)
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070088 : mListener(listener),
89 mSensorPeriod(sensorPeriod),
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070090 mProcessor(createHeadTrackingProcessor(HeadTrackingProcessor::Options{
91 .maxTranslationalVelocity = kMaxTranslationalVelocity / kTicksPerSecond,
92 .maxRotationalVelocity = kMaxRotationalVelocity / kTicksPerSecond,
Ytai Ben-Tsvie2356842022-04-14 11:30:32 -070093 .freshnessTimeout = Ticks(kFreshnessTimeout).count(),
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070094 .predictionDuration = Ticks(kPredictionDuration).count(),
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080095 .autoRecenterWindowDuration = Ticks(kAutoRecenterWindowDuration).count(),
96 .autoRecenterTranslationalThreshold = kAutoRecenterTranslationThreshold,
97 .autoRecenterRotationalThreshold = kAutoRecenterRotationThreshold,
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080098 .screenStillnessWindowDuration = Ticks(kScreenStillnessWindowDuration).count(),
99 .screenStillnessTranslationalThreshold = kScreenStillnessTranslationThreshold,
100 .screenStillnessRotationalThreshold = kScreenStillnessRotationThreshold,
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700101 })),
Ytai Ben-Tsvi8b6fe3a2021-09-13 15:55:44 -0700102 mPoseProvider(SensorPoseProvider::create("headtracker", this)),
Keith Mok674f7352022-06-06 21:40:11 +0000103 mThread([this, maxUpdatePeriod] { // It's important that mThread is initialized after
104 // everything else because it runs a member
105 // function that may use any member
106 // of this class.
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700107 while (true) {
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700108 Pose3f headToStage;
109 std::optional<HeadTrackingMode> modeIfChanged;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700110 {
111 std::unique_lock lock(mMutex);
Eric Laurente51f80e2022-04-14 10:20:38 +0200112 if (maxUpdatePeriod.has_value()) {
113 mCondVar.wait_for(lock, maxUpdatePeriod.value(),
114 [this] { return mShouldExit || mShouldCalculate; });
115 } else {
116 mCondVar.wait(lock, [this] { return mShouldExit || mShouldCalculate; });
117 }
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700118 if (mShouldExit) {
119 ALOGV("Exiting thread");
120 return;
121 }
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700122
123 // Calculate.
124 std::tie(headToStage, modeIfChanged) = calculate_l();
125 }
126
127 // Invoke the callbacks outside the lock.
128 mListener->onHeadToStagePose(headToStage);
129 if (modeIfChanged) {
130 mListener->onActualModeChange(modeIfChanged.value());
131 }
132
133 {
134 std::lock_guard lock(mMutex);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700135 if (!mCalculated) {
136 mCalculated = true;
137 mCondVar.notify_all();
138 }
139 mShouldCalculate = false;
140 }
141 }
142 }) {}
143
144SpatializerPoseController::~SpatializerPoseController() {
145 {
146 std::unique_lock lock(mMutex);
147 mShouldExit = true;
148 mCondVar.notify_all();
149 }
150 mThread.join();
151}
152
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700153void SpatializerPoseController::setHeadSensor(int32_t sensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700154 std::lock_guard lock(mMutex);
Andy Hungba2a61a2022-05-20 12:00:28 -0700155 if (sensor == mHeadSensor) return;
156 ALOGV("%s: new sensor:%d mHeadSensor:%d mScreenSensor:%d",
157 __func__, sensor, mHeadSensor, mScreenSensor);
158
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700159 // Stop current sensor, if valid and different from the other sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700160 if (mHeadSensor != INVALID_SENSOR && mHeadSensor != mScreenSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700161 mPoseProvider->stopSensor(mHeadSensor);
Andy Hunga461a002022-05-17 10:36:02 -0700162 mediametrics::LogItem(getSensorMetricsId(mHeadSensor))
163 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
164 .record();
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700165 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700166
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700167 if (sensor != INVALID_SENSOR) {
168 if (sensor != mScreenSensor) {
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700169 // Start new sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700170 mHeadSensor =
171 mPoseProvider->startSensor(sensor, mSensorPeriod) ? sensor : INVALID_SENSOR;
Andy Hunga461a002022-05-17 10:36:02 -0700172 if (mHeadSensor != INVALID_SENSOR) {
173 auto sensor = mPoseProvider->getSensorByHandle(mHeadSensor);
174 std::string stringType = sensor ? sensor->getStringType().c_str() : "";
175 mediametrics::LogItem(getSensorMetricsId(mHeadSensor))
176 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
177 .set(AMEDIAMETRICS_PROP_MODE, AMEDIAMETRICS_PROP_MODE_VALUE_HEAD)
178 .set(AMEDIAMETRICS_PROP_TYPE, stringType)
179 .record();
180 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700181 } else {
182 // Sensor is already enabled.
183 mHeadSensor = mScreenSensor;
184 }
185 } else {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700186 mHeadSensor = INVALID_SENSOR;
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700187 }
188
Andy Hungba2a61a2022-05-20 12:00:28 -0700189 mProcessor->recenter(true /* recenterHead */, false /* recenterScreen */);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700190}
191
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700192void SpatializerPoseController::setScreenSensor(int32_t sensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700193 std::lock_guard lock(mMutex);
Andy Hungba2a61a2022-05-20 12:00:28 -0700194 if (sensor == mScreenSensor) return;
195 ALOGV("%s: new sensor:%d mHeadSensor:%d mScreenSensor:%d",
196 __func__, sensor, mHeadSensor, mScreenSensor);
197
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700198 // Stop current sensor, if valid and different from the other sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700199 if (mScreenSensor != INVALID_SENSOR && mScreenSensor != mHeadSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700200 mPoseProvider->stopSensor(mScreenSensor);
Andy Hunga461a002022-05-17 10:36:02 -0700201 mediametrics::LogItem(getSensorMetricsId(mScreenSensor))
202 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
203 .record();
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700204 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700205
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700206 if (sensor != INVALID_SENSOR) {
207 if (sensor != mHeadSensor) {
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700208 // Start new sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700209 mScreenSensor =
210 mPoseProvider->startSensor(sensor, mSensorPeriod) ? sensor : INVALID_SENSOR;
Andy Hunga461a002022-05-17 10:36:02 -0700211 auto sensor = mPoseProvider->getSensorByHandle(mScreenSensor);
212 std::string stringType = sensor ? sensor->getStringType().c_str() : "";
213 mediametrics::LogItem(getSensorMetricsId(mScreenSensor))
214 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
215 .set(AMEDIAMETRICS_PROP_MODE, AMEDIAMETRICS_PROP_MODE_VALUE_SCREEN)
216 .set(AMEDIAMETRICS_PROP_TYPE, stringType)
217 .record();
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700218 } else {
219 // Sensor is already enabled.
220 mScreenSensor = mHeadSensor;
221 }
222 } else {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700223 mScreenSensor = INVALID_SENSOR;
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700224 }
225
Andy Hungba2a61a2022-05-20 12:00:28 -0700226 mProcessor->recenter(false /* recenterHead */, true /* recenterScreen */);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700227}
228
229void SpatializerPoseController::setDesiredMode(HeadTrackingMode mode) {
230 std::lock_guard lock(mMutex);
231 mProcessor->setDesiredMode(mode);
232}
233
234void SpatializerPoseController::setScreenToStagePose(const Pose3f& screenToStage) {
235 std::lock_guard lock(mMutex);
236 mProcessor->setScreenToStagePose(screenToStage);
237}
238
239void SpatializerPoseController::setDisplayOrientation(float physicalToLogicalAngle) {
240 std::lock_guard lock(mMutex);
241 mProcessor->setDisplayOrientation(physicalToLogicalAngle);
242}
243
244void SpatializerPoseController::calculateAsync() {
245 std::lock_guard lock(mMutex);
246 mShouldCalculate = true;
247 mCondVar.notify_all();
248}
249
250void SpatializerPoseController::waitUntilCalculated() {
251 std::unique_lock lock(mMutex);
252 mCondVar.wait(lock, [this] { return mCalculated; });
253}
254
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700255std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>>
256SpatializerPoseController::calculate_l() {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700257 Pose3f headToStage;
258 HeadTrackingMode mode;
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700259 std::optional<media::HeadTrackingMode> modeIfChanged;
260
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700261 mProcessor->calculate(elapsedRealtimeNano());
262 headToStage = mProcessor->getHeadToStagePose();
263 mode = mProcessor->getActualMode();
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700264 if (!mActualMode.has_value() || mActualMode.value() != mode) {
265 mActualMode = mode;
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700266 modeIfChanged = mode;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700267 }
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700268 return std::make_tuple(headToStage, modeIfChanged);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700269}
270
271void SpatializerPoseController::recenter() {
272 std::lock_guard lock(mMutex);
273 mProcessor->recenter();
274}
275
276void SpatializerPoseController::onPose(int64_t timestamp, int32_t sensor, const Pose3f& pose,
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700277 const std::optional<Twist3f>& twist, bool isNewReference) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700278 std::lock_guard lock(mMutex);
279 if (sensor == mHeadSensor) {
Ytai Ben-Tsvi3c234b12022-01-31 11:15:17 -0800280 mProcessor->setWorldToHeadPose(timestamp, pose,
281 twist.value_or(Twist3f()) / kTicksPerSecond);
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700282 if (isNewReference) {
283 mProcessor->recenter(true, false);
284 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700285 }
286 if (sensor == mScreenSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700287 mProcessor->setWorldToScreenPose(timestamp, pose);
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700288 if (isNewReference) {
289 mProcessor->recenter(false, true);
290 }
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700291 }
292}
293
294} // namespace android