blob: 91eb47f6a43f891a6832c0439410a3b273aee477 [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
18#define LOG_TAG "VirtualizerStageController"
19//#define LOG_NDEBUG 0
20#include <utils/Log.h>
21#include <utils/SystemClock.h>
22
23namespace android {
24
25using media::createHeadTrackingProcessor;
26using media::HeadTrackingMode;
27using media::HeadTrackingProcessor;
28using media::Pose3f;
29using media::SensorPoseProvider;
30using media::Twist3f;
31
32using namespace std::chrono_literals;
33
34namespace {
35
36// This is how fast, in m/s, we allow position to shift during rate-limiting.
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -070037constexpr auto kMaxTranslationalVelocity = 2;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070038
39// This is how fast, in rad/s, we allow rotation angle to shift during rate-limiting.
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -070040constexpr auto kMaxRotationalVelocity = 4 * M_PI;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070041
42// This should be set to the typical time scale that the translation sensors used drift in. This
43// means, loosely, for how long we can trust the reading to be "accurate enough". This would
44// determine the time constants used for high-pass filtering those readings. If the value is set
45// too high, we may experience drift. If it is set too low, we may experience poses tending toward
46// identity too fast.
47constexpr auto kTranslationalDriftTimeConstant = 20s;
48
49// This should be set to the typical time scale that the rotation sensors used drift in. This
50// means, loosely, for how long we can trust the reading to be "accurate enough". This would
51// determine the time constants used for high-pass filtering those readings. If the value is set
52// too high, we may experience drift. If it is set too low, we may experience poses tending toward
53// identity too fast.
54constexpr auto kRotationalDriftTimeConstant = 20s;
55
56// This is how far into the future we predict the head pose, using linear extrapolation based on
57// twist (velocity). It should be set to a value that matches the characteristic durations of moving
58// one's head. The higher we set this, the more latency we are able to reduce, but setting this too
59// high will result in high prediction errors whenever the head accelerates (changes velocity).
60constexpr auto kPredictionDuration = 10ms;
61
62// After losing this many consecutive samples from either sensor, we would treat the measurement as
63// stale;
64constexpr auto kMaxLostSamples = 4;
65
66// Time units for system clock ticks. This is what the Sensor Framework timestamps represent and
67// what we use for pose filtering.
68using Ticks = std::chrono::nanoseconds;
69
70// How many ticks in a second.
71constexpr auto kTicksPerSecond = Ticks::period::den;
72
73} // namespace
74
75SpatializerPoseController::SpatializerPoseController(Listener* listener,
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -070076 std::chrono::microseconds sensorPeriod,
77 std::chrono::microseconds maxUpdatePeriod)
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070078 : mListener(listener),
79 mSensorPeriod(sensorPeriod),
80 mPoseProvider(SensorPoseProvider::create("headtracker", this)),
81 mProcessor(createHeadTrackingProcessor(HeadTrackingProcessor::Options{
82 .maxTranslationalVelocity = kMaxTranslationalVelocity / kTicksPerSecond,
83 .maxRotationalVelocity = kMaxRotationalVelocity / kTicksPerSecond,
84 .translationalDriftTimeConstant = Ticks(kTranslationalDriftTimeConstant).count(),
85 .rotationalDriftTimeConstant = Ticks(kRotationalDriftTimeConstant).count(),
86 .freshnessTimeout = Ticks(sensorPeriod * kMaxLostSamples).count(),
87 .predictionDuration = Ticks(kPredictionDuration).count(),
88 })),
89 mThread([this, maxUpdatePeriod] {
90 while (true) {
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -070091 Pose3f headToStage;
92 std::optional<HeadTrackingMode> modeIfChanged;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070093 {
94 std::unique_lock lock(mMutex);
95 mCondVar.wait_for(lock, maxUpdatePeriod,
96 [this] { return mShouldExit || mShouldCalculate; });
97 if (mShouldExit) {
98 ALOGV("Exiting thread");
99 return;
100 }
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700101
102 // Calculate.
103 std::tie(headToStage, modeIfChanged) = calculate_l();
104 }
105
106 // Invoke the callbacks outside the lock.
107 mListener->onHeadToStagePose(headToStage);
108 if (modeIfChanged) {
109 mListener->onActualModeChange(modeIfChanged.value());
110 }
111
112 {
113 std::lock_guard lock(mMutex);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700114 if (!mCalculated) {
115 mCalculated = true;
116 mCondVar.notify_all();
117 }
118 mShouldCalculate = false;
119 }
120 }
121 }) {}
122
123SpatializerPoseController::~SpatializerPoseController() {
124 {
125 std::unique_lock lock(mMutex);
126 mShouldExit = true;
127 mCondVar.notify_all();
128 }
129 mThread.join();
130}
131
132void SpatializerPoseController::setHeadSensor(const ASensor* sensor) {
133 std::lock_guard lock(mMutex);
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700134 // Stop current sensor, if valid and different from the other sensor.
135 if (mHeadSensor != SensorPoseProvider::INVALID_HANDLE && mHeadSensor != mScreenSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700136 mPoseProvider->stopSensor(mHeadSensor);
137 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700138
139 if (sensor != nullptr) {
140 if (ASensor_getHandle(sensor) != mScreenSensor) {
141 // Start new sensor.
142 mHeadSensor = mPoseProvider->startSensor(sensor, mSensorPeriod);
143 } else {
144 // Sensor is already enabled.
145 mHeadSensor = mScreenSensor;
146 }
147 } else {
148 mHeadSensor = SensorPoseProvider::INVALID_HANDLE;
149 }
150
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700151 mProcessor->recenter(true, false);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700152}
153
154void SpatializerPoseController::setScreenSensor(const ASensor* sensor) {
155 std::lock_guard lock(mMutex);
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700156 // Stop current sensor, if valid and different from the other sensor.
157 if (mScreenSensor != SensorPoseProvider::INVALID_HANDLE && mScreenSensor != mHeadSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700158 mPoseProvider->stopSensor(mScreenSensor);
159 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700160
161 if (sensor != nullptr) {
162 if (ASensor_getHandle(sensor) != mHeadSensor) {
163 // Start new sensor.
164 mScreenSensor = mPoseProvider->startSensor(sensor, mSensorPeriod);
165 } else {
166 // Sensor is already enabled.
167 mScreenSensor = mHeadSensor;
168 }
169 } else {
170 mScreenSensor = SensorPoseProvider::INVALID_HANDLE;
171 }
172
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700173 mProcessor->recenter(false, true);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700174}
175
176void SpatializerPoseController::setDesiredMode(HeadTrackingMode mode) {
177 std::lock_guard lock(mMutex);
178 mProcessor->setDesiredMode(mode);
179}
180
181void SpatializerPoseController::setScreenToStagePose(const Pose3f& screenToStage) {
182 std::lock_guard lock(mMutex);
183 mProcessor->setScreenToStagePose(screenToStage);
184}
185
186void SpatializerPoseController::setDisplayOrientation(float physicalToLogicalAngle) {
187 std::lock_guard lock(mMutex);
188 mProcessor->setDisplayOrientation(physicalToLogicalAngle);
189}
190
191void SpatializerPoseController::calculateAsync() {
192 std::lock_guard lock(mMutex);
193 mShouldCalculate = true;
194 mCondVar.notify_all();
195}
196
197void SpatializerPoseController::waitUntilCalculated() {
198 std::unique_lock lock(mMutex);
199 mCondVar.wait(lock, [this] { return mCalculated; });
200}
201
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700202std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>>
203SpatializerPoseController::calculate_l() {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700204 Pose3f headToStage;
205 HeadTrackingMode mode;
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700206 std::optional<media::HeadTrackingMode> modeIfChanged;
207
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700208 mProcessor->calculate(elapsedRealtimeNano());
209 headToStage = mProcessor->getHeadToStagePose();
210 mode = mProcessor->getActualMode();
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700211 if (!mActualMode.has_value() || mActualMode.value() != mode) {
212 mActualMode = mode;
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700213 modeIfChanged = mode;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700214 }
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700215 return std::make_tuple(headToStage, modeIfChanged);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700216}
217
218void SpatializerPoseController::recenter() {
219 std::lock_guard lock(mMutex);
220 mProcessor->recenter();
221}
222
223void SpatializerPoseController::onPose(int64_t timestamp, int32_t sensor, const Pose3f& pose,
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700224 const std::optional<Twist3f>& twist) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700225 std::lock_guard lock(mMutex);
226 if (sensor == mHeadSensor) {
227 mProcessor->setWorldToHeadPose(timestamp, pose, twist.value_or(Twist3f()));
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700228 }
229 if (sensor == mScreenSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700230 mProcessor->setWorldToScreenPose(timestamp, pose);
231 }
232}
233
234} // namespace android