blob: df2b2157a2d4d419f424f9d6cbdc3ff8c21149df [file] [log] [blame]
Eric Laurent6d607012021-07-05 11:54:40 +02001/*
2 * Copyright (C) 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
17#ifndef ANDROID_MEDIA_SPATIALIZER_H
18#define ANDROID_MEDIA_SPATIALIZER_H
19
Shunkai Yao59b27bc2022-07-22 18:42:27 +000020#include <android-base/stringprintf.h>
Eric Laurent6d607012021-07-05 11:54:40 +020021#include <android/media/BnEffect.h>
22#include <android/media/BnSpatializer.h>
Eric Laurent6d607012021-07-05 11:54:40 +020023#include <android/media/SpatializationLevel.h>
Eric Laurent2be8b292021-08-23 09:44:33 -070024#include <android/media/SpatializationMode.h>
25#include <android/media/SpatializerHeadTrackingMode.h>
Shunkai Yao59b27bc2022-07-22 18:42:27 +000026#include <audio_utils/SimpleLog.h>
27#include <math.h>
28#include <media/AudioEffect.h>
Eric Laurent2be8b292021-08-23 09:44:33 -070029#include <media/audiohal/EffectHalInterface.h>
Eric Laurent8a4259f2021-09-14 16:04:00 +020030#include <media/stagefright/foundation/ALooper.h>
Eric Laurent1c5e2e32021-08-18 18:50:28 +020031#include <system/audio_effects/effect_spatializer.h>
Shunkai Yao59b27bc2022-07-22 18:42:27 +000032#include <string>
Eric Laurent6d607012021-07-05 11:54:40 +020033
Eric Laurent2be8b292021-08-23 09:44:33 -070034#include "SpatializerPoseController.h"
Eric Laurent6d607012021-07-05 11:54:40 +020035
36namespace android {
37
38
39// ----------------------------------------------------------------------------
40
41/**
42 * A callback interface from the Spatializer object or its parent AudioPolicyService.
43 * This is implemented by the audio policy service hosting the Spatializer to perform
44 * actions needed when a state change inside the Spatializer requires some audio system
45 * changes that cannot be performed by the Spatializer. For instance opening or closing a
46 * spatializer output stream when the spatializer is enabled or disabled
47 */
48class SpatializerPolicyCallback {
49public:
50 /** Called when a stage change occurs that requires the parent audio policy service to take
51 * some action.
52 */
53 virtual void onCheckSpatializer() = 0;
54
55 virtual ~SpatializerPolicyCallback() = default;
56};
57/**
58 * The Spatializer class implements all functional controlling the multichannel spatializer
59 * with head tracking implementation in the native audio service: audio policy and audio flinger.
60 * It presents an AIDL interface available to the java audio service to discover the availability
61 * of the feature and options, control its state and register an active head tracking sensor.
62 * It maintains the current state of the platform spatializer and applies the stored parameters
63 * when the spatializer engine is created and enabled.
64 * Based on the requested spatializer level, it will request the creation of a specialized output
65 * mixer to the audio policy service which will in turn notify the Spatializer of the output
66 * stream on which a spatializer engine should be created, configured and enabled.
67 * The spatializer also hosts the head tracking management logic. This logic receives the
68 * desired head tracking mode and selected head tracking sensor, registers a sensor event listener
69 * and derives the compounded head pose information to the spatializer engine.
70 *
71 * Workflow:
72 * - Initialization: when the audio policy service starts, it checks if a spatializer effect
73 * engine exists and if the audio policy manager reports a dedicated spatializer output profile.
74 * If both conditions are met, a Spatializer object is created
75 * - Capabilities discovery: AudioService will call AudioSystem::canBeSpatialized() and if true,
76 * acquire an ISpatializer interface with AudioSystem::getSpatializer(). This interface
77 * will be used to query the implementation capabilities and configure the spatializer.
78 * - Enabling: when ISpatializer::setLevel() sets a level different from NONE the spatializer
79 * is considered enabled. The audio policy callback onCheckSpatializer() is called. This
80 * triggers a request to audio policy manager to open a spatialization output stream and a
81 * spatializer mixer is created in audio flinger. When an output is returned by audio policy
82 * manager, Spatializer::attachOutput() is called which creates and enables the spatializer
83 * stage engine on the specified output.
84 * - Disabling: when the spatialization level is set to NONE, the spatializer is considered
85 * disabled. The audio policy callback onCheckSpatializer() is called. This triggers a call
86 * to Spatializer::detachOutput() and the spatializer engine is released. Then a request is
87 * made to audio policy manager to release and close the spatializer output stream and the
88 * spatializer mixer thread is destroyed.
89 */
Eric Laurent2be8b292021-08-23 09:44:33 -070090class Spatializer : public media::BnSpatializer,
91 public IBinder::DeathRecipient,
Eric Laurentee398ad2022-05-03 18:19:35 +020092 private SpatializerPoseController::Listener,
93 public virtual AudioSystem::SupportedLatencyModesCallback {
Eric Laurent2be8b292021-08-23 09:44:33 -070094 public:
Eric Laurent6d607012021-07-05 11:54:40 +020095 static sp<Spatializer> create(SpatializerPolicyCallback *callback);
96
97 ~Spatializer() override;
98
Eric Laurent8a4259f2021-09-14 16:04:00 +020099 /** RefBase */
100 void onFirstRef();
101
Eric Laurent6d607012021-07-05 11:54:40 +0200102 /** ISpatializer, see ISpatializer.aidl */
103 binder::Status release() override;
104 binder::Status getSupportedLevels(std::vector<media::SpatializationLevel>* levels) override;
105 binder::Status setLevel(media::SpatializationLevel level) override;
106 binder::Status getLevel(media::SpatializationLevel *level) override;
Eric Laurentc87402b2021-09-17 16:49:42 +0200107 binder::Status isHeadTrackingSupported(bool *supports);
Eric Laurent6d607012021-07-05 11:54:40 +0200108 binder::Status getSupportedHeadTrackingModes(
Ytai Ben-Tsvia16a9df2021-08-05 08:57:06 -0700109 std::vector<media::SpatializerHeadTrackingMode>* modes) override;
110 binder::Status setDesiredHeadTrackingMode(
111 media::SpatializerHeadTrackingMode mode) override;
112 binder::Status getActualHeadTrackingMode(
113 media::SpatializerHeadTrackingMode* mode) override;
114 binder::Status recenterHeadTracker() override;
Eric Laurent6d607012021-07-05 11:54:40 +0200115 binder::Status setGlobalTransform(const std::vector<float>& screenToStage) override;
Eric Laurent2be8b292021-08-23 09:44:33 -0700116 binder::Status setHeadSensor(int sensorHandle) override;
117 binder::Status setScreenSensor(int sensorHandle) override;
118 binder::Status setDisplayOrientation(float physicalToLogicalAngle) override;
119 binder::Status setHingeAngle(float hingeAngle) override;
120 binder::Status getSupportedModes(std::vector<media::SpatializationMode>* modes) override;
Eric Laurent67816e32021-09-16 15:18:40 +0200121 binder::Status registerHeadTrackingCallback(
122 const sp<media::ISpatializerHeadTrackingCallback>& callback) override;
Eric Laurentc87402b2021-09-17 16:49:42 +0200123 binder::Status setParameter(int key, const std::vector<unsigned char>& value) override;
124 binder::Status getParameter(int key, std::vector<unsigned char> *value) override;
125 binder::Status getOutput(int *output);
Eric Laurent6d607012021-07-05 11:54:40 +0200126
127 /** IBinder::DeathRecipient. Listen to the death of the INativeSpatializerCallback. */
128 virtual void binderDied(const wp<IBinder>& who);
129
Eric Laurentee398ad2022-05-03 18:19:35 +0200130 /** SupportedLatencyModesCallback */
131 void onSupportedLatencyModesChanged(
132 audio_io_handle_t output, const std::vector<audio_latency_mode_t>& modes) override;
133
Eric Laurent6d607012021-07-05 11:54:40 +0200134 /** Registers a INativeSpatializerCallback when a client is attached to this Spatializer
135 * by audio policy service.
136 */
137 status_t registerCallback(const sp<media::INativeSpatializerCallback>& callback);
138
Eric Laurent2be8b292021-08-23 09:44:33 -0700139 status_t loadEngineConfiguration(sp<EffectHalInterface> effect);
140
Eric Laurent6d607012021-07-05 11:54:40 +0200141 /** Level getter for use by local classes. */
Eric Laurent2be8b292021-08-23 09:44:33 -0700142 media::SpatializationLevel getLevel() const { std::lock_guard lock(mLock); return mLevel; }
Eric Laurent6d607012021-07-05 11:54:40 +0200143
144 /** Called by audio policy service when the special output mixer dedicated to spatialization
145 * is opened and the spatializer engine must be created.
146 */
Eric Laurent15903592022-02-24 20:44:36 +0100147 status_t attachOutput(audio_io_handle_t output, size_t numActiveTracks);
Eric Laurent6d607012021-07-05 11:54:40 +0200148 /** Called by audio policy service when the special output mixer dedicated to spatialization
149 * is closed and the spatializer engine must be release.
150 */
151 audio_io_handle_t detachOutput();
152 /** Returns the output stream the spatializer is attached to. */
Eric Laurent2be8b292021-08-23 09:44:33 -0700153 audio_io_handle_t getOutput() const { std::lock_guard lock(mLock); return mOutput; }
Eric Laurent6d607012021-07-05 11:54:40 +0200154
Eric Laurent15903592022-02-24 20:44:36 +0100155 void updateActiveTracks(size_t numActiveTracks);
156
Eric Laurent6d607012021-07-05 11:54:40 +0200157 /** Gets the channel mask, sampling rate and format set for the spatializer input. */
Eric Laurent2be8b292021-08-23 09:44:33 -0700158 audio_config_base_t getAudioInConfig() const;
Eric Laurent6d607012021-07-05 11:54:40 +0200159
Eric Laurent8a4259f2021-09-14 16:04:00 +0200160 void calculateHeadPose();
161
Shunkai Yao59b27bc2022-07-22 18:42:27 +0000162 /** Convert fields in Spatializer and sub-modules to a string. Disable thread-safety-analysis
163 * here because we want to dump mutex guarded members even try_lock failed to provide as much
164 * information as possible for debugging purpose. */
165 std::string toString(unsigned level) const NO_THREAD_SAFETY_ANALYSIS;
166
167 static std::string toString(audio_latency_mode_t mode) {
168 switch (mode) {
169 case AUDIO_LATENCY_MODE_FREE:
170 return "LATENCY_MODE_FREE";
171 case AUDIO_LATENCY_MODE_LOW:
172 return "LATENCY_MODE_LOW";
173 }
174 return "EnumNotImplemented";
175 };
176
177 /**
178 * Format head to stage vector to a string, [0.00, 0.00, 0.00, -1.29, -0.50, 15.27].
179 */
180 template <typename T>
181 static std::string toString(const std::vector<T>& vec, bool radianToDegree = false) {
182 if (vec.size() == 0) {
183 return "[]";
184 }
185
186 std::string ss = "[";
187 for (const auto& f : vec) {
188 if (radianToDegree) {
189 base::StringAppendF(&ss, "%0.2f, ",
190 HeadToStagePoseRecorder::getDegreeWithRadian(f));
191 } else {
192 base::StringAppendF(&ss, "%f, ", f);
193 }
194 }
195 ss.replace(ss.end() - 2, ss.end(), "]");
196 return ss;
197 };
198
Eric Laurent6d607012021-07-05 11:54:40 +0200199private:
Eric Laurent6d607012021-07-05 11:54:40 +0200200 Spatializer(effect_descriptor_t engineDescriptor,
201 SpatializerPolicyCallback *callback);
202
Eric Laurent6d607012021-07-05 11:54:40 +0200203 static void engineCallback(int32_t event, void* user, void *info);
204
Eric Laurent2be8b292021-08-23 09:44:33 -0700205 // From VirtualizerStageController::Listener
206 void onHeadToStagePose(const media::Pose3f& headToStage) override;
207 void onActualModeChange(media::HeadTrackingMode mode) override;
208
Eric Laurent8a4259f2021-09-14 16:04:00 +0200209 void onHeadToStagePoseMsg(const std::vector<float>& headToStage);
210 void onActualModeChangeMsg(media::HeadTrackingMode mode);
Eric Laurent9c04de92022-07-20 13:49:47 +0200211 void onSupportedLatencyModesChangedMsg(
212 audio_io_handle_t output, std::vector<audio_latency_mode_t>&& modes);
Eric Laurent8a4259f2021-09-14 16:04:00 +0200213
Eric Laurent2be8b292021-08-23 09:44:33 -0700214 static constexpr int kMaxEffectParamValues = 10;
215 /**
216 * Get a parameter from spatializer engine by calling the effect HAL command method directly.
217 * To be used when the engine instance mEngine is not yet created in the effect framework.
218 * When MULTI_VALUES is false, the expected reply is only one value of type T.
219 * When MULTI_VALUES is true, the expected reply is made of a number (of type T) indicating
220 * how many values are returned, followed by this number for values of type T.
221 */
222 template<bool MULTI_VALUES, typename T>
223 status_t getHalParameter(sp<EffectHalInterface> effect, uint32_t type,
224 std::vector<T> *values) {
225 static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
226
227 uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1];
228 uint32_t reply[sizeof(effect_param_t) / sizeof(uint32_t) + 2 + kMaxEffectParamValues];
229
230 effect_param_t *p = (effect_param_t *)cmd;
231 p->psize = sizeof(uint32_t);
232 if (MULTI_VALUES) {
233 p->vsize = (kMaxEffectParamValues + 1) * sizeof(T);
234 } else {
235 p->vsize = sizeof(T);
236 }
237 *(uint32_t *)p->data = type;
238 uint32_t replySize = sizeof(effect_param_t) + p->psize + p->vsize;
239
240 status_t status = effect->command(EFFECT_CMD_GET_PARAM,
241 sizeof(effect_param_t) + sizeof(uint32_t), cmd,
242 &replySize, reply);
243 if (status != NO_ERROR) {
244 return status;
245 }
246 if (p->status != NO_ERROR) {
247 return p->status;
248 }
249 if (replySize <
250 sizeof(effect_param_t) + sizeof(uint32_t) + (MULTI_VALUES ? 2 : 1) * sizeof(T)) {
251 return BAD_VALUE;
252 }
253
254 T *params = (T *)((uint8_t *)reply + sizeof(effect_param_t) + sizeof(uint32_t));
255 int numParams = 1;
256 if (MULTI_VALUES) {
257 numParams = (int)*params++;
258 }
259 if (numParams > kMaxEffectParamValues) {
260 return BAD_VALUE;
261 }
Eric Laurentc87402b2021-09-17 16:49:42 +0200262 (*values).clear();
Eric Laurent2be8b292021-08-23 09:44:33 -0700263 std::copy(&params[0], &params[numParams], back_inserter(*values));
264 return NO_ERROR;
265 }
266
267 /**
268 * Set a parameter to spatializer engine by calling setParameter on mEngine AudioEffect object.
269 * It is possible to pass more than one value of type T according to the parameter type
270 * according to values vector size.
271 */
272 template<typename T>
273 status_t setEffectParameter_l(uint32_t type, const std::vector<T>& values) REQUIRES(mLock) {
274 static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
275
276 uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1 + values.size()];
277 effect_param_t *p = (effect_param_t *)cmd;
278 p->psize = sizeof(uint32_t);
279 p->vsize = sizeof(T) * values.size();
280 *(uint32_t *)p->data = type;
281 memcpy((uint32_t *)p->data + 1, values.data(), sizeof(T) * values.size());
282
Eric Laurentc87402b2021-09-17 16:49:42 +0200283 status_t status = mEngine->setParameter(p);
284 if (status != NO_ERROR) {
285 return status;
286 }
287 if (p->status != NO_ERROR) {
288 return p->status;
289 }
290 return NO_ERROR;
291 }
292
293 /**
294 * Get a parameter from spatializer engine by calling getParameter on AudioEffect object.
295 * It is possible to read more than one value of type T according to the parameter type
296 * by specifying values vector size.
297 */
298 template<typename T>
299 status_t getEffectParameter_l(uint32_t type, std::vector<T> *values) REQUIRES(mLock) {
300 static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
301
302 uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1 + values->size()];
303 effect_param_t *p = (effect_param_t *)cmd;
304 p->psize = sizeof(uint32_t);
305 p->vsize = sizeof(T) * values->size();
306 *(uint32_t *)p->data = type;
307
308 status_t status = mEngine->getParameter(p);
309
310 if (status != NO_ERROR) {
311 return status;
312 }
313 if (p->status != NO_ERROR) {
314 return p->status;
315 }
316
317 int numValues = std::min(p->vsize / sizeof(T), values->size());
318 (*values).clear();
319 T *retValues = (T *)((uint8_t *)p->data + sizeof(uint32_t));
320 std::copy(&retValues[0], &retValues[numValues], back_inserter(*values));
321
322 return NO_ERROR;
Eric Laurent2be8b292021-08-23 09:44:33 -0700323 }
324
Eric Laurent8a4259f2021-09-14 16:04:00 +0200325 void postFramesProcessedMsg(int frames);
326
Eric Laurent9249d342022-03-18 11:55:56 +0100327 /**
328 * Checks if head and screen sensors must be actively monitored based on
329 * spatializer state and playback activity and configures the pose controller
330 * accordingly.
331 */
332 void checkSensorsState_l() REQUIRES(mLock);
Eric Laurent15903592022-02-24 20:44:36 +0100333
Eric Laurent7ea0d1b2022-04-01 14:23:44 +0200334 /**
Eric Laurent11094172022-04-05 18:27:42 +0200335 * Checks if the head pose controller should be created or destroyed according
336 * to desired head tracking mode.
337 */
338 void checkPoseController_l() REQUIRES(mLock);
339
340 /**
Eric Laurent7ea0d1b2022-04-01 14:23:44 +0200341 * Checks if the spatializer effect should be enabled based on
342 * playback activity and requested level.
343 */
344 void checkEngineState_l() REQUIRES(mLock);
345
Eric Laurent6d607012021-07-05 11:54:40 +0200346 /** Effect engine descriptor */
347 const effect_descriptor_t mEngineDescriptor;
348 /** Callback interface to parent audio policy service */
Andy Hunga461a002022-05-17 10:36:02 -0700349 SpatializerPolicyCallback* const mPolicyCallback;
350
351 /** Currently there is only one version of the spatializer running */
352 const std::string mMetricsId = AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "0";
Eric Laurent6d607012021-07-05 11:54:40 +0200353
354 /** Mutex protecting internal state */
Eric Laurent2be8b292021-08-23 09:44:33 -0700355 mutable std::mutex mLock;
Eric Laurent6d607012021-07-05 11:54:40 +0200356
357 /** Client AudioEffect for the engine */
358 sp<AudioEffect> mEngine GUARDED_BY(mLock);
359 /** Output stream the spatializer mixer thread is attached to */
360 audio_io_handle_t mOutput GUARDED_BY(mLock) = AUDIO_IO_HANDLE_NONE;
Eric Laurent6d607012021-07-05 11:54:40 +0200361
362 /** Callback interface to the client (AudioService) controlling this`Spatializer */
363 sp<media::INativeSpatializerCallback> mSpatializerCallback GUARDED_BY(mLock);
364
Eric Laurent67816e32021-09-16 15:18:40 +0200365 /** Callback interface for head tracking */
366 sp<media::ISpatializerHeadTrackingCallback> mHeadTrackingCallback GUARDED_BY(mLock);
367
Eric Laurent6d607012021-07-05 11:54:40 +0200368 /** Requested spatialization level */
369 media::SpatializationLevel mLevel GUARDED_BY(mLock) = media::SpatializationLevel::NONE;
Eric Laurent6d607012021-07-05 11:54:40 +0200370
Eric Laurent2be8b292021-08-23 09:44:33 -0700371 /** Control logic for head-tracking, etc. */
372 std::shared_ptr<SpatializerPoseController> mPoseController GUARDED_BY(mLock);
373
374 /** Last requested head tracking mode */
375 media::HeadTrackingMode mDesiredHeadTrackingMode GUARDED_BY(mLock)
376 = media::HeadTrackingMode::STATIC;
377
378 /** Last-reported actual head-tracking mode. */
379 media::SpatializerHeadTrackingMode mActualHeadTrackingMode GUARDED_BY(mLock)
380 = media::SpatializerHeadTrackingMode::DISABLED;
381
382 /** Selected Head pose sensor */
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700383 int32_t mHeadSensor GUARDED_BY(mLock) = SpatializerPoseController::INVALID_SENSOR;
Eric Laurent2be8b292021-08-23 09:44:33 -0700384
385 /** Selected Screen pose sensor */
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700386 int32_t mScreenSensor GUARDED_BY(mLock) = SpatializerPoseController::INVALID_SENSOR;
Eric Laurent2be8b292021-08-23 09:44:33 -0700387
388 /** Last display orientation received */
389 static constexpr float kDisplayOrientationInvalid = 1000;
390 float mDisplayOrientation GUARDED_BY(mLock) = kDisplayOrientationInvalid;
391
392 std::vector<media::SpatializationLevel> mLevels;
Andy Hunga461a002022-05-17 10:36:02 -0700393 std::vector<media::SpatializerHeadTrackingMode> mHeadTrackingModes;
Eric Laurent2be8b292021-08-23 09:44:33 -0700394 std::vector<media::SpatializationMode> mSpatializationModes;
395 std::vector<audio_channel_mask_t> mChannelMasks;
396 bool mSupportsHeadTracking;
Eric Laurent8a4259f2021-09-14 16:04:00 +0200397
398 // Looper thread for mEngine callbacks
399 class EngineCallbackHandler;
400
401 sp<ALooper> mLooper;
402 sp<EngineCallbackHandler> mHandler;
403
Eric Laurent15903592022-02-24 20:44:36 +0100404 size_t mNumActiveTracks GUARDED_BY(mLock) = 0;
Eric Laurentee398ad2022-05-03 18:19:35 +0200405 std::vector<audio_latency_mode_t> mSupportedLatencyModes GUARDED_BY(mLock);
Eric Laurent15903592022-02-24 20:44:36 +0100406
Shunkai Yao59b27bc2022-07-22 18:42:27 +0000407 static const std::vector<const char*> sHeadPoseKeys;
Eric Laurent6d607012021-07-05 11:54:40 +0200408
Shunkai Yao59b27bc2022-07-22 18:42:27 +0000409 // Local log for command messages.
410 static constexpr int mMaxLocalLogLine = 10;
411 SimpleLog mLocalLog{mMaxLocalLogLine};
412
413 /**
414 * @brief Calculate and record sensor data.
415 * Dump to local log with max/average pose angle every mPoseRecordThreshold.
416 * TODO: log azimuth/elevation angles obtained for debugging actual orientation.
417 */
418 class HeadToStagePoseRecorder {
419 public:
420 /** Convert recorded sensor data to string with level indentation */
421 std::string toString_l(unsigned level) const;
422 /**
423 * @brief Calculate sensor data, record into local log when it is time.
424 *
425 * @param headToStage The vector from Pose3f::toVector().
426 */
427 void record_l(const std::vector<float>& headToStage);
428
429 static constexpr float getDegreeWithRadian(const float radian) {
430 float radianToDegreeRatio = (180 / PI);
431 return (radian * radianToDegreeRatio);
432 }
433
434 private:
435 static constexpr float PI = M_PI;
436 /**
437 * Pose recorder time threshold to record sensor data in local log.
438 * Sensor data will be recorded at least every mPoseRecordThreshold.
439 */
440 // TODO: add another history log to record longer period of sensor data.
441 static constexpr std::chrono::duration<double> mPoseRecordThreshold =
442 std::chrono::seconds(1);
443 /**
444 * According to frameworks/av/media/libheadtracking/include/media/Pose.h
445 * "The vector will have exactly 6 elements, where the first three are a translation vector
446 * and the last three are a rotation vector."
447 */
448 static constexpr size_t mPoseVectorSize = 6;
449 /**
450 * Timestamp of last sensor data record in local log.
451 */
452 std::chrono::time_point<std::chrono::steady_clock> mFirstSampleTimestamp;
453 // Last pose recorded, vector obtained from Pose3f::toVector().
454 std::vector<float> mLastPoseRecorded{mPoseVectorSize};
455 /**
456 * Number of sensor samples received since last record, sample rate is ~100Hz which produce
457 * ~6k samples/minute.
458 */
459 uint32_t mNumOfSampleSinceLastRecord = 0;
460 /* The sum of pose angle represented by radian since last dump, div
461 * mNumOfSampleSinceLastRecord to get arithmetic mean. Largest possible value: 2PI * 100Hz *
462 * mPoseRecordThreshold.
463 */
464 std::vector<double> mPoseRadianSum{mPoseVectorSize};
465 std::vector<float> mMaxPoseAngle{mPoseVectorSize};
466 std::vector<float> mMinPoseAngle{mPoseVectorSize};
467 // Local log for history sensor data.
468 SimpleLog mPoseRecordLog{mMaxLocalLogLine};
469
470 bool shouldRecordLog() const {
471 return std::chrono::duration_cast<std::chrono::seconds>(
472 std::chrono::steady_clock::now() - mFirstSampleTimestamp) >=
473 mPoseRecordThreshold;
474 }
475
476 void resetRecord(const std::vector<float>& headToStage) {
477 mPoseRadianSum.assign(mPoseVectorSize, 0);
478 mMaxPoseAngle.assign(mPoseVectorSize, 0);
479 mMinPoseAngle.assign(mPoseVectorSize, 0);
480 mNumOfSampleSinceLastRecord = 0;
481 mLastPoseRecorded = headToStage;
482 }
483
484 // Add each sample to sum and only calculate when record.
485 void poseSumToAverage() {
486 if (mNumOfSampleSinceLastRecord == 0) return;
487 for (auto& p : mPoseRadianSum) {
488 const float reciprocal = 1.f / mNumOfSampleSinceLastRecord;
489 p *= reciprocal;
490 }
491 }
492 }; // HeadToStagePoseRecorder
493 HeadToStagePoseRecorder mPoseRecorder;
494}; // Spatializer
Eric Laurent6d607012021-07-05 11:54:40 +0200495
496}; // namespace android
497
498#endif // ANDROID_MEDIA_SPATIALIZER_H