blob: ccbbf66799438cc968255e1bcadb6ace78c415f7 [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 Yaoafc0c2e2022-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>
Mikhail Naganovf53e1822022-12-18 02:48:14 +000026#include <android/media/audio/common/AudioLatencyMode.h>
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +000027#include <audio_utils/SimpleLog.h>
28#include <math.h>
29#include <media/AudioEffect.h>
Eric Laurent2be8b292021-08-23 09:44:33 -070030#include <media/audiohal/EffectHalInterface.h>
Eric Laurent8a4259f2021-09-14 16:04:00 +020031#include <media/stagefright/foundation/ALooper.h>
Eric Laurent1c5e2e32021-08-18 18:50:28 +020032#include <system/audio_effects/effect_spatializer.h>
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +000033#include <string>
Eric Laurent6d607012021-07-05 11:54:40 +020034
Eric Laurent2be8b292021-08-23 09:44:33 -070035#include "SpatializerPoseController.h"
Eric Laurent6d607012021-07-05 11:54:40 +020036
37namespace android {
38
39
40// ----------------------------------------------------------------------------
41
42/**
43 * A callback interface from the Spatializer object or its parent AudioPolicyService.
44 * This is implemented by the audio policy service hosting the Spatializer to perform
45 * actions needed when a state change inside the Spatializer requires some audio system
46 * changes that cannot be performed by the Spatializer. For instance opening or closing a
47 * spatializer output stream when the spatializer is enabled or disabled
48 */
49class SpatializerPolicyCallback {
50public:
51 /** Called when a stage change occurs that requires the parent audio policy service to take
52 * some action.
53 */
54 virtual void onCheckSpatializer() = 0;
55
56 virtual ~SpatializerPolicyCallback() = default;
57};
58/**
59 * The Spatializer class implements all functional controlling the multichannel spatializer
60 * with head tracking implementation in the native audio service: audio policy and audio flinger.
61 * It presents an AIDL interface available to the java audio service to discover the availability
62 * of the feature and options, control its state and register an active head tracking sensor.
63 * It maintains the current state of the platform spatializer and applies the stored parameters
64 * when the spatializer engine is created and enabled.
65 * Based on the requested spatializer level, it will request the creation of a specialized output
66 * mixer to the audio policy service which will in turn notify the Spatializer of the output
67 * stream on which a spatializer engine should be created, configured and enabled.
68 * The spatializer also hosts the head tracking management logic. This logic receives the
69 * desired head tracking mode and selected head tracking sensor, registers a sensor event listener
70 * and derives the compounded head pose information to the spatializer engine.
71 *
72 * Workflow:
73 * - Initialization: when the audio policy service starts, it checks if a spatializer effect
74 * engine exists and if the audio policy manager reports a dedicated spatializer output profile.
75 * If both conditions are met, a Spatializer object is created
76 * - Capabilities discovery: AudioService will call AudioSystem::canBeSpatialized() and if true,
77 * acquire an ISpatializer interface with AudioSystem::getSpatializer(). This interface
78 * will be used to query the implementation capabilities and configure the spatializer.
79 * - Enabling: when ISpatializer::setLevel() sets a level different from NONE the spatializer
80 * is considered enabled. The audio policy callback onCheckSpatializer() is called. This
81 * triggers a request to audio policy manager to open a spatialization output stream and a
82 * spatializer mixer is created in audio flinger. When an output is returned by audio policy
83 * manager, Spatializer::attachOutput() is called which creates and enables the spatializer
84 * stage engine on the specified output.
85 * - Disabling: when the spatialization level is set to NONE, the spatializer is considered
86 * disabled. The audio policy callback onCheckSpatializer() is called. This triggers a call
87 * to Spatializer::detachOutput() and the spatializer engine is released. Then a request is
88 * made to audio policy manager to release and close the spatializer output stream and the
89 * spatializer mixer thread is destroyed.
90 */
Eric Laurent2be8b292021-08-23 09:44:33 -070091class Spatializer : public media::BnSpatializer,
Atneya Nair20e6cc82022-05-17 20:12:37 -040092 public AudioEffect::IAudioEffectCallback,
Eric Laurent2be8b292021-08-23 09:44:33 -070093 public IBinder::DeathRecipient,
Eric Laurentee398ad2022-05-03 18:19:35 +020094 private SpatializerPoseController::Listener,
95 public virtual AudioSystem::SupportedLatencyModesCallback {
Eric Laurent2be8b292021-08-23 09:44:33 -070096 public:
Eric Laurent6d607012021-07-05 11:54:40 +020097 static sp<Spatializer> create(SpatializerPolicyCallback *callback);
98
99 ~Spatializer() override;
100
Eric Laurent8a4259f2021-09-14 16:04:00 +0200101 /** RefBase */
102 void onFirstRef();
103
Eric Laurent6d607012021-07-05 11:54:40 +0200104 /** ISpatializer, see ISpatializer.aidl */
105 binder::Status release() override;
106 binder::Status getSupportedLevels(std::vector<media::SpatializationLevel>* levels) override;
107 binder::Status setLevel(media::SpatializationLevel level) override;
108 binder::Status getLevel(media::SpatializationLevel *level) override;
Eric Laurentc87402b2021-09-17 16:49:42 +0200109 binder::Status isHeadTrackingSupported(bool *supports);
Eric Laurent6d607012021-07-05 11:54:40 +0200110 binder::Status getSupportedHeadTrackingModes(
Ytai Ben-Tsvia16a9df2021-08-05 08:57:06 -0700111 std::vector<media::SpatializerHeadTrackingMode>* modes) override;
112 binder::Status setDesiredHeadTrackingMode(
113 media::SpatializerHeadTrackingMode mode) override;
114 binder::Status getActualHeadTrackingMode(
115 media::SpatializerHeadTrackingMode* mode) override;
116 binder::Status recenterHeadTracker() override;
Eric Laurent6d607012021-07-05 11:54:40 +0200117 binder::Status setGlobalTransform(const std::vector<float>& screenToStage) override;
Eric Laurent2be8b292021-08-23 09:44:33 -0700118 binder::Status setHeadSensor(int sensorHandle) override;
119 binder::Status setScreenSensor(int sensorHandle) override;
120 binder::Status setDisplayOrientation(float physicalToLogicalAngle) override;
121 binder::Status setHingeAngle(float hingeAngle) override;
122 binder::Status getSupportedModes(std::vector<media::SpatializationMode>* modes) override;
Eric Laurent67816e32021-09-16 15:18:40 +0200123 binder::Status registerHeadTrackingCallback(
124 const sp<media::ISpatializerHeadTrackingCallback>& callback) override;
Eric Laurentc87402b2021-09-17 16:49:42 +0200125 binder::Status setParameter(int key, const std::vector<unsigned char>& value) override;
126 binder::Status getParameter(int key, std::vector<unsigned char> *value) override;
127 binder::Status getOutput(int *output);
Eric Laurent6d607012021-07-05 11:54:40 +0200128
129 /** IBinder::DeathRecipient. Listen to the death of the INativeSpatializerCallback. */
130 virtual void binderDied(const wp<IBinder>& who);
131
Eric Laurentee398ad2022-05-03 18:19:35 +0200132 /** SupportedLatencyModesCallback */
133 void onSupportedLatencyModesChanged(
134 audio_io_handle_t output, const std::vector<audio_latency_mode_t>& modes) override;
135
Eric Laurent6d607012021-07-05 11:54:40 +0200136 /** Registers a INativeSpatializerCallback when a client is attached to this Spatializer
137 * by audio policy service.
138 */
139 status_t registerCallback(const sp<media::INativeSpatializerCallback>& callback);
140
Eric Laurent2be8b292021-08-23 09:44:33 -0700141 status_t loadEngineConfiguration(sp<EffectHalInterface> effect);
142
Eric Laurent6d607012021-07-05 11:54:40 +0200143 /** Level getter for use by local classes. */
Eric Laurent2be8b292021-08-23 09:44:33 -0700144 media::SpatializationLevel getLevel() const { std::lock_guard lock(mLock); return mLevel; }
Eric Laurent6d607012021-07-05 11:54:40 +0200145
146 /** Called by audio policy service when the special output mixer dedicated to spatialization
147 * is opened and the spatializer engine must be created.
148 */
Eric Laurent15903592022-02-24 20:44:36 +0100149 status_t attachOutput(audio_io_handle_t output, size_t numActiveTracks);
Eric Laurent6d607012021-07-05 11:54:40 +0200150 /** Called by audio policy service when the special output mixer dedicated to spatialization
151 * is closed and the spatializer engine must be release.
152 */
153 audio_io_handle_t detachOutput();
154 /** Returns the output stream the spatializer is attached to. */
Eric Laurent2be8b292021-08-23 09:44:33 -0700155 audio_io_handle_t getOutput() const { std::lock_guard lock(mLock); return mOutput; }
Eric Laurent6d607012021-07-05 11:54:40 +0200156
Eric Laurent15903592022-02-24 20:44:36 +0100157 void updateActiveTracks(size_t numActiveTracks);
158
Eric Laurent6d607012021-07-05 11:54:40 +0200159 /** Gets the channel mask, sampling rate and format set for the spatializer input. */
Eric Laurent2be8b292021-08-23 09:44:33 -0700160 audio_config_base_t getAudioInConfig() const;
Eric Laurent6d607012021-07-05 11:54:40 +0200161
Eric Laurent8a4259f2021-09-14 16:04:00 +0200162 void calculateHeadPose();
163
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000164 /** Convert fields in Spatializer and sub-modules to a string. Disable thread-safety-analysis
165 * here because we want to dump mutex guarded members even try_lock failed to provide as much
166 * information as possible for debugging purpose. */
167 std::string toString(unsigned level) const NO_THREAD_SAFETY_ANALYSIS;
168
169 static std::string toString(audio_latency_mode_t mode) {
Andy Hung4bd53e72022-11-17 17:21:45 -0800170 // We convert to the AIDL type to print (eventually the legacy type will be removed).
Mikhail Naganovf53e1822022-12-18 02:48:14 +0000171 const auto result = legacy2aidl_audio_latency_mode_t_AudioLatencyMode(mode);
172 return result.has_value() ?
173 media::audio::common::toString(*result) : "unknown_latency_mode";
Andy Hung4bd53e72022-11-17 17:21:45 -0800174 }
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000175
176 /**
177 * Format head to stage vector to a string, [0.00, 0.00, 0.00, -1.29, -0.50, 15.27].
178 */
179 template <typename T>
180 static std::string toString(const std::vector<T>& vec, bool radianToDegree = false) {
181 if (vec.size() == 0) {
182 return "[]";
183 }
184
185 std::string ss = "[";
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000186 for (auto f = vec.begin(); f != vec.end(); ++f) {
187 if (f != vec.begin()) {
188 ss .append(", ");
189 }
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000190 if (radianToDegree) {
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000191 base::StringAppendF(&ss, "%0.2f", HeadToStagePoseRecorder::getDegreeWithRadian(*f));
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000192 } else {
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000193 base::StringAppendF(&ss, "%f", *f);
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000194 }
195 }
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000196 ss.append("]");
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000197 return ss;
198 };
199
Andy Hung8aa43c02022-09-13 18:53:06 -0700200 // If the Spatializer is not created, we send the status for metrics purposes.
201 // OK: Spatializer not expected to be created.
202 // NO_INIT: Spatializer creation failed.
203 static void sendEmptyCreateSpatializerMetricWithStatus(status_t status);
204
Eric Laurent6d607012021-07-05 11:54:40 +0200205private:
Eric Laurent6d607012021-07-05 11:54:40 +0200206 Spatializer(effect_descriptor_t engineDescriptor,
207 SpatializerPolicyCallback *callback);
208
Eric Laurent6d607012021-07-05 11:54:40 +0200209 static void engineCallback(int32_t event, void* user, void *info);
210
Eric Laurent2be8b292021-08-23 09:44:33 -0700211 // From VirtualizerStageController::Listener
212 void onHeadToStagePose(const media::Pose3f& headToStage) override;
213 void onActualModeChange(media::HeadTrackingMode mode) override;
214
Eric Laurent8a4259f2021-09-14 16:04:00 +0200215 void onHeadToStagePoseMsg(const std::vector<float>& headToStage);
216 void onActualModeChangeMsg(media::HeadTrackingMode mode);
Eric Laurent9c04de92022-07-20 13:49:47 +0200217 void onSupportedLatencyModesChangedMsg(
218 audio_io_handle_t output, std::vector<audio_latency_mode_t>&& modes);
Eric Laurent8a4259f2021-09-14 16:04:00 +0200219
Eric Laurent2be8b292021-08-23 09:44:33 -0700220 static constexpr int kMaxEffectParamValues = 10;
221 /**
222 * Get a parameter from spatializer engine by calling the effect HAL command method directly.
223 * To be used when the engine instance mEngine is not yet created in the effect framework.
224 * When MULTI_VALUES is false, the expected reply is only one value of type T.
225 * When MULTI_VALUES is true, the expected reply is made of a number (of type T) indicating
226 * how many values are returned, followed by this number for values of type T.
227 */
228 template<bool MULTI_VALUES, typename T>
229 status_t getHalParameter(sp<EffectHalInterface> effect, uint32_t type,
230 std::vector<T> *values) {
231 static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
232
233 uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1];
234 uint32_t reply[sizeof(effect_param_t) / sizeof(uint32_t) + 2 + kMaxEffectParamValues];
235
236 effect_param_t *p = (effect_param_t *)cmd;
237 p->psize = sizeof(uint32_t);
238 if (MULTI_VALUES) {
239 p->vsize = (kMaxEffectParamValues + 1) * sizeof(T);
240 } else {
241 p->vsize = sizeof(T);
242 }
243 *(uint32_t *)p->data = type;
244 uint32_t replySize = sizeof(effect_param_t) + p->psize + p->vsize;
245
246 status_t status = effect->command(EFFECT_CMD_GET_PARAM,
247 sizeof(effect_param_t) + sizeof(uint32_t), cmd,
248 &replySize, reply);
249 if (status != NO_ERROR) {
250 return status;
251 }
252 if (p->status != NO_ERROR) {
253 return p->status;
254 }
255 if (replySize <
256 sizeof(effect_param_t) + sizeof(uint32_t) + (MULTI_VALUES ? 2 : 1) * sizeof(T)) {
257 return BAD_VALUE;
258 }
259
260 T *params = (T *)((uint8_t *)reply + sizeof(effect_param_t) + sizeof(uint32_t));
261 int numParams = 1;
262 if (MULTI_VALUES) {
263 numParams = (int)*params++;
264 }
265 if (numParams > kMaxEffectParamValues) {
266 return BAD_VALUE;
267 }
Eric Laurentc87402b2021-09-17 16:49:42 +0200268 (*values).clear();
Eric Laurent2be8b292021-08-23 09:44:33 -0700269 std::copy(&params[0], &params[numParams], back_inserter(*values));
270 return NO_ERROR;
271 }
272
273 /**
274 * Set a parameter to spatializer engine by calling setParameter on mEngine AudioEffect object.
275 * It is possible to pass more than one value of type T according to the parameter type
276 * according to values vector size.
277 */
278 template<typename T>
279 status_t setEffectParameter_l(uint32_t type, const std::vector<T>& values) REQUIRES(mLock) {
280 static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
281
282 uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1 + values.size()];
283 effect_param_t *p = (effect_param_t *)cmd;
284 p->psize = sizeof(uint32_t);
285 p->vsize = sizeof(T) * values.size();
286 *(uint32_t *)p->data = type;
287 memcpy((uint32_t *)p->data + 1, values.data(), sizeof(T) * values.size());
288
Eric Laurentc87402b2021-09-17 16:49:42 +0200289 status_t status = mEngine->setParameter(p);
290 if (status != NO_ERROR) {
291 return status;
292 }
293 if (p->status != NO_ERROR) {
294 return p->status;
295 }
296 return NO_ERROR;
297 }
298
299 /**
300 * Get a parameter from spatializer engine by calling getParameter on AudioEffect object.
301 * It is possible to read more than one value of type T according to the parameter type
302 * by specifying values vector size.
303 */
304 template<typename T>
305 status_t getEffectParameter_l(uint32_t type, std::vector<T> *values) REQUIRES(mLock) {
306 static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
307
308 uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1 + values->size()];
309 effect_param_t *p = (effect_param_t *)cmd;
310 p->psize = sizeof(uint32_t);
311 p->vsize = sizeof(T) * values->size();
312 *(uint32_t *)p->data = type;
313
314 status_t status = mEngine->getParameter(p);
315
316 if (status != NO_ERROR) {
317 return status;
318 }
319 if (p->status != NO_ERROR) {
320 return p->status;
321 }
322
323 int numValues = std::min(p->vsize / sizeof(T), values->size());
324 (*values).clear();
325 T *retValues = (T *)((uint8_t *)p->data + sizeof(uint32_t));
326 std::copy(&retValues[0], &retValues[numValues], back_inserter(*values));
327
328 return NO_ERROR;
Eric Laurent2be8b292021-08-23 09:44:33 -0700329 }
330
Atneya Nair20e6cc82022-05-17 20:12:37 -0400331 virtual void onFramesProcessed(int32_t framesProcessed) override;
Eric Laurent8a4259f2021-09-14 16:04:00 +0200332
Eric Laurent9249d342022-03-18 11:55:56 +0100333 /**
334 * Checks if head and screen sensors must be actively monitored based on
335 * spatializer state and playback activity and configures the pose controller
336 * accordingly.
337 */
338 void checkSensorsState_l() REQUIRES(mLock);
Eric Laurent15903592022-02-24 20:44:36 +0100339
Eric Laurent7ea0d1b2022-04-01 14:23:44 +0200340 /**
Eric Laurent11094172022-04-05 18:27:42 +0200341 * Checks if the head pose controller should be created or destroyed according
342 * to desired head tracking mode.
343 */
344 void checkPoseController_l() REQUIRES(mLock);
345
346 /**
Eric Laurent7ea0d1b2022-04-01 14:23:44 +0200347 * Checks if the spatializer effect should be enabled based on
348 * playback activity and requested level.
349 */
350 void checkEngineState_l() REQUIRES(mLock);
351
Eric Laurentbdecc052022-10-21 11:28:32 +0200352 /**
353 * Reset head tracking mode and recenter pose in engine: Called when the head tracking
354 * is disabled.
355 */
356 void resetEngineHeadPose_l() REQUIRES(mLock);
357
Eric Laurent6d607012021-07-05 11:54:40 +0200358 /** Effect engine descriptor */
359 const effect_descriptor_t mEngineDescriptor;
360 /** Callback interface to parent audio policy service */
Andy Hunga461a002022-05-17 10:36:02 -0700361 SpatializerPolicyCallback* const mPolicyCallback;
362
363 /** Currently there is only one version of the spatializer running */
Andy Hung8aa43c02022-09-13 18:53:06 -0700364 static constexpr const char* kDefaultMetricsId =
365 AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "0";
366 const std::string mMetricsId = kDefaultMetricsId;
Eric Laurent6d607012021-07-05 11:54:40 +0200367
368 /** Mutex protecting internal state */
Eric Laurent2be8b292021-08-23 09:44:33 -0700369 mutable std::mutex mLock;
Eric Laurent6d607012021-07-05 11:54:40 +0200370
371 /** Client AudioEffect for the engine */
372 sp<AudioEffect> mEngine GUARDED_BY(mLock);
373 /** Output stream the spatializer mixer thread is attached to */
374 audio_io_handle_t mOutput GUARDED_BY(mLock) = AUDIO_IO_HANDLE_NONE;
Eric Laurent6d607012021-07-05 11:54:40 +0200375
376 /** Callback interface to the client (AudioService) controlling this`Spatializer */
377 sp<media::INativeSpatializerCallback> mSpatializerCallback GUARDED_BY(mLock);
378
Eric Laurent67816e32021-09-16 15:18:40 +0200379 /** Callback interface for head tracking */
380 sp<media::ISpatializerHeadTrackingCallback> mHeadTrackingCallback GUARDED_BY(mLock);
381
Eric Laurent6d607012021-07-05 11:54:40 +0200382 /** Requested spatialization level */
383 media::SpatializationLevel mLevel GUARDED_BY(mLock) = media::SpatializationLevel::NONE;
Eric Laurent6d607012021-07-05 11:54:40 +0200384
Eric Laurent2be8b292021-08-23 09:44:33 -0700385 /** Control logic for head-tracking, etc. */
386 std::shared_ptr<SpatializerPoseController> mPoseController GUARDED_BY(mLock);
387
388 /** Last requested head tracking mode */
389 media::HeadTrackingMode mDesiredHeadTrackingMode GUARDED_BY(mLock)
390 = media::HeadTrackingMode::STATIC;
391
392 /** Last-reported actual head-tracking mode. */
393 media::SpatializerHeadTrackingMode mActualHeadTrackingMode GUARDED_BY(mLock)
394 = media::SpatializerHeadTrackingMode::DISABLED;
395
396 /** Selected Head pose sensor */
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700397 int32_t mHeadSensor GUARDED_BY(mLock) = SpatializerPoseController::INVALID_SENSOR;
Eric Laurent2be8b292021-08-23 09:44:33 -0700398
399 /** Selected Screen pose sensor */
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700400 int32_t mScreenSensor GUARDED_BY(mLock) = SpatializerPoseController::INVALID_SENSOR;
Eric Laurent2be8b292021-08-23 09:44:33 -0700401
402 /** Last display orientation received */
403 static constexpr float kDisplayOrientationInvalid = 1000;
404 float mDisplayOrientation GUARDED_BY(mLock) = kDisplayOrientationInvalid;
405
406 std::vector<media::SpatializationLevel> mLevels;
Andy Hunga461a002022-05-17 10:36:02 -0700407 std::vector<media::SpatializerHeadTrackingMode> mHeadTrackingModes;
Eric Laurent2be8b292021-08-23 09:44:33 -0700408 std::vector<media::SpatializationMode> mSpatializationModes;
409 std::vector<audio_channel_mask_t> mChannelMasks;
410 bool mSupportsHeadTracking;
Eric Laurent8a4259f2021-09-14 16:04:00 +0200411
412 // Looper thread for mEngine callbacks
413 class EngineCallbackHandler;
414
415 sp<ALooper> mLooper;
416 sp<EngineCallbackHandler> mHandler;
417
Eric Laurent15903592022-02-24 20:44:36 +0100418 size_t mNumActiveTracks GUARDED_BY(mLock) = 0;
Eric Laurentee398ad2022-05-03 18:19:35 +0200419 std::vector<audio_latency_mode_t> mSupportedLatencyModes GUARDED_BY(mLock);
Eric Laurent15903592022-02-24 20:44:36 +0100420
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000421 static const std::vector<const char*> sHeadPoseKeys;
Eric Laurent6d607012021-07-05 11:54:40 +0200422
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000423 // Local log for command messages.
424 static constexpr int mMaxLocalLogLine = 10;
425 SimpleLog mLocalLog{mMaxLocalLogLine};
426
427 /**
428 * @brief Calculate and record sensor data.
429 * Dump to local log with max/average pose angle every mPoseRecordThreshold.
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000430 */
431 class HeadToStagePoseRecorder {
432 public:
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000433 HeadToStagePoseRecorder(std::chrono::duration<double> threshold, int maxLogLine)
434 : mPoseRecordThreshold(threshold), mPoseRecordLog(maxLogLine) {
435 resetRecord();
436 }
437
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000438 /** Convert recorded sensor data to string with level indentation */
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000439 std::string toString(unsigned level) const;
440
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000441 /**
442 * @brief Calculate sensor data, record into local log when it is time.
443 *
444 * @param headToStage The vector from Pose3f::toVector().
445 */
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000446 void record(const std::vector<float>& headToStage);
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000447
448 static constexpr float getDegreeWithRadian(const float radian) {
449 float radianToDegreeRatio = (180 / PI);
450 return (radian * radianToDegreeRatio);
451 }
452
453 private:
454 static constexpr float PI = M_PI;
455 /**
456 * Pose recorder time threshold to record sensor data in local log.
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000457 * Sensor data will be recorded into log at least every mPoseRecordThreshold.
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000458 */
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000459 std::chrono::duration<double> mPoseRecordThreshold;
460 // Number of seconds pass since last record.
461 std::chrono::duration<double> mNumOfSecondsSinceLastRecord;
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000462 /**
463 * According to frameworks/av/media/libheadtracking/include/media/Pose.h
464 * "The vector will have exactly 6 elements, where the first three are a translation vector
465 * and the last three are a rotation vector."
466 */
467 static constexpr size_t mPoseVectorSize = 6;
468 /**
469 * Timestamp of last sensor data record in local log.
470 */
471 std::chrono::time_point<std::chrono::steady_clock> mFirstSampleTimestamp;
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000472 /**
473 * Number of sensor samples received since last record, sample rate is ~100Hz which produce
474 * ~6k samples/minute.
475 */
476 uint32_t mNumOfSampleSinceLastRecord = 0;
477 /* The sum of pose angle represented by radian since last dump, div
478 * mNumOfSampleSinceLastRecord to get arithmetic mean. Largest possible value: 2PI * 100Hz *
479 * mPoseRecordThreshold.
480 */
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000481 std::vector<double> mPoseRadianSum;
482 std::vector<float> mMaxPoseAngle;
483 std::vector<float> mMinPoseAngle;
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000484 // Local log for history sensor data.
485 SimpleLog mPoseRecordLog{mMaxLocalLogLine};
486
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000487 bool shouldRecordLog() {
488 mNumOfSecondsSinceLastRecord = std::chrono::duration_cast<std::chrono::seconds>(
489 std::chrono::steady_clock::now() - mFirstSampleTimestamp);
490 return mNumOfSecondsSinceLastRecord >= mPoseRecordThreshold;
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000491 }
492
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000493 void resetRecord() {
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000494 mPoseRadianSum.assign(mPoseVectorSize, 0);
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000495 mMaxPoseAngle.assign(mPoseVectorSize, -PI);
496 mMinPoseAngle.assign(mPoseVectorSize, PI);
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000497 mNumOfSampleSinceLastRecord = 0;
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000498 mNumOfSecondsSinceLastRecord = std::chrono::seconds(0);
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000499 }
500
501 // Add each sample to sum and only calculate when record.
502 void poseSumToAverage() {
503 if (mNumOfSampleSinceLastRecord == 0) return;
504 for (auto& p : mPoseRadianSum) {
505 const float reciprocal = 1.f / mNumOfSampleSinceLastRecord;
506 p *= reciprocal;
507 }
508 }
509 }; // HeadToStagePoseRecorder
Shunkai Yaodc8f52d2022-08-25 00:44:04 +0000510
511 // Record one log line per second (up to mMaxLocalLogLine) to capture most recent sensor data.
512 HeadToStagePoseRecorder mPoseRecorder GUARDED_BY(mLock) =
513 HeadToStagePoseRecorder(std::chrono::seconds(1), mMaxLocalLogLine);
514 // Record one log line per minute (up to mMaxLocalLogLine) to capture durable sensor data.
515 HeadToStagePoseRecorder mPoseDurableRecorder GUARDED_BY(mLock) =
516 HeadToStagePoseRecorder(std::chrono::minutes(1), mMaxLocalLogLine);
Shunkai Yaoafc0c2e2022-07-22 18:42:27 +0000517}; // Spatializer
Eric Laurent6d607012021-07-05 11:54:40 +0200518
519}; // namespace android
520
521#endif // ANDROID_MEDIA_SPATIALIZER_H