• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
20 #include <android-base/stringprintf.h>
21 #include <android/media/BnEffect.h>
22 #include <android/media/BnSpatializer.h>
23 #include <android/media/SpatializationLevel.h>
24 #include <android/media/SpatializationMode.h>
25 #include <android/media/SpatializerHeadTrackingMode.h>
26 #include <audio_utils/SimpleLog.h>
27 #include <math.h>
28 #include <media/AudioEffect.h>
29 #include <media/VectorRecorder.h>
30 #include <media/audiohal/EffectHalInterface.h>
31 #include <media/stagefright/foundation/ALooper.h>
32 #include <system/audio_effects/effect_spatializer.h>
33 #include <string>
34 
35 #include "SpatializerPoseController.h"
36 
37 namespace 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  */
49 class SpatializerPolicyCallback {
50 public:
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  */
91 class Spatializer : public media::BnSpatializer,
92                     public IBinder::DeathRecipient,
93                     private SpatializerPoseController::Listener,
94                     public virtual AudioSystem::SupportedLatencyModesCallback {
95   public:
96     static sp<Spatializer> create(SpatializerPolicyCallback *callback);
97 
98            ~Spatializer() override;
99 
100     /** RefBase */
101     void onFirstRef();
102 
103     /** ISpatializer, see ISpatializer.aidl */
104     binder::Status release() override;
105     binder::Status getSupportedLevels(std::vector<media::SpatializationLevel>* levels) override;
106     binder::Status setLevel(media::SpatializationLevel level) override;
107     binder::Status getLevel(media::SpatializationLevel *level) override;
108     binder::Status isHeadTrackingSupported(bool *supports);
109     binder::Status getSupportedHeadTrackingModes(
110             std::vector<media::SpatializerHeadTrackingMode>* modes) override;
111     binder::Status setDesiredHeadTrackingMode(
112             media::SpatializerHeadTrackingMode mode) override;
113     binder::Status getActualHeadTrackingMode(
114             media::SpatializerHeadTrackingMode* mode) override;
115     binder::Status recenterHeadTracker() override;
116     binder::Status setGlobalTransform(const std::vector<float>& screenToStage) override;
117     binder::Status setHeadSensor(int sensorHandle) override;
118     binder::Status setScreenSensor(int sensorHandle) override;
119     binder::Status setDisplayOrientation(float physicalToLogicalAngle) override;
120     binder::Status setHingeAngle(float hingeAngle) override;
121     binder::Status setFoldState(bool folded) override;
122     binder::Status getSupportedModes(std::vector<media::SpatializationMode>* modes) override;
123     binder::Status registerHeadTrackingCallback(
124         const sp<media::ISpatializerHeadTrackingCallback>& callback) override;
125     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);
128 
129     /** IBinder::DeathRecipient. Listen to the death of the INativeSpatializerCallback. */
130     virtual void binderDied(const wp<IBinder>& who);
131 
132     /** SupportedLatencyModesCallback */
133     void onSupportedLatencyModesChanged(
134             audio_io_handle_t output, const std::vector<audio_latency_mode_t>& modes) override;
135 
136     /** 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 
141     status_t loadEngineConfiguration(sp<EffectHalInterface> effect);
142 
143     /** Level getter for use by local classes. */
getLevel()144     media::SpatializationLevel getLevel() const { std::lock_guard lock(mLock); return mLevel; }
145 
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      */
149     status_t attachOutput(audio_io_handle_t output, size_t numActiveTracks);
150     /** 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. */
getOutput()155     audio_io_handle_t getOutput() const { std::lock_guard lock(mLock); return mOutput; }
156 
157     void updateActiveTracks(size_t numActiveTracks);
158 
159     /** Gets the channel mask, sampling rate and format set for the spatializer input. */
160     audio_config_base_t getAudioInConfig() const;
161 
162     void calculateHeadPose();
163 
164     /** 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 
toString(audio_latency_mode_t mode)169     static std::string toString(audio_latency_mode_t mode) {
170         // We convert to the AIDL type to print (eventually the legacy type will be removed).
171         const auto result = legacy2aidl_audio_latency_mode_t_LatencyMode(mode);
172         return result.has_value() ? media::toString(*result) : "unknown_latency_mode";
173     }
174 
175     // If the Spatializer is not created, we send the status for metrics purposes.
176     // OK:      Spatializer not expected to be created.
177     // NO_INIT: Spatializer creation failed.
178     static void sendEmptyCreateSpatializerMetricWithStatus(status_t status);
179 
180 private:
181     Spatializer(effect_descriptor_t engineDescriptor,
182                      SpatializerPolicyCallback *callback);
183 
184     static void engineCallback(int32_t event, void* user, void *info);
185 
186     // From VirtualizerStageController::Listener
187     void onHeadToStagePose(const media::Pose3f& headToStage) override;
188     void onActualModeChange(media::HeadTrackingMode mode) override;
189 
190     void onHeadToStagePoseMsg(const std::vector<float>& headToStage);
191     void onActualModeChangeMsg(media::HeadTrackingMode mode);
192     void onSupportedLatencyModesChangedMsg(
193             audio_io_handle_t output, std::vector<audio_latency_mode_t>&& modes);
194 
195     static constexpr int kMaxEffectParamValues = 10;
196     /**
197      * Get a parameter from spatializer engine by calling the effect HAL command method directly.
198      * To be used when the engine instance mEngine is not yet created in the effect framework.
199      * When MULTI_VALUES is false, the expected reply is only one value of type T.
200      * When MULTI_VALUES is true, the expected reply is made of a number (of type T) indicating
201      * how many values are returned, followed by this number for values of type T.
202      */
203     template<bool MULTI_VALUES, typename T>
getHalParameter(sp<EffectHalInterface> effect,uint32_t type,std::vector<T> * values)204     status_t getHalParameter(sp<EffectHalInterface> effect, uint32_t type,
205                                           std::vector<T> *values) {
206         static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
207 
208         uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1];
209         uint32_t reply[sizeof(effect_param_t) / sizeof(uint32_t) + 2 + kMaxEffectParamValues];
210 
211         effect_param_t *p = (effect_param_t *)cmd;
212         p->psize = sizeof(uint32_t);
213         if (MULTI_VALUES) {
214             p->vsize = (kMaxEffectParamValues + 1) * sizeof(T);
215         } else {
216             p->vsize = sizeof(T);
217         }
218         *(uint32_t *)p->data = type;
219         uint32_t replySize = sizeof(effect_param_t) + p->psize + p->vsize;
220 
221         status_t status = effect->command(EFFECT_CMD_GET_PARAM,
222                                           sizeof(effect_param_t) + sizeof(uint32_t), cmd,
223                                           &replySize, reply);
224         if (status != NO_ERROR) {
225             return status;
226         }
227         if (p->status != NO_ERROR) {
228             return p->status;
229         }
230         if (replySize <
231                 sizeof(effect_param_t) + sizeof(uint32_t) + (MULTI_VALUES ? 2 : 1) * sizeof(T)) {
232             return BAD_VALUE;
233         }
234 
235         T *params = (T *)((uint8_t *)reply + sizeof(effect_param_t) + sizeof(uint32_t));
236         int numParams = 1;
237         if (MULTI_VALUES) {
238             numParams = (int)*params++;
239         }
240         if (numParams > kMaxEffectParamValues) {
241             return BAD_VALUE;
242         }
243         (*values).clear();
244         std::copy(&params[0], &params[numParams], back_inserter(*values));
245         return NO_ERROR;
246     }
247 
248     /**
249      * Set a parameter to spatializer engine by calling setParameter on mEngine AudioEffect object.
250      * It is possible to pass more than one value of type T according to the parameter type
251      *  according to values vector size.
252      */
253     template<typename T>
setEffectParameter_l(uint32_t type,const std::vector<T> & values)254     status_t setEffectParameter_l(uint32_t type, const std::vector<T>& values) REQUIRES(mLock) {
255         static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
256 
257         uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1 + values.size()];
258         effect_param_t *p = (effect_param_t *)cmd;
259         p->psize = sizeof(uint32_t);
260         p->vsize = sizeof(T) * values.size();
261         *(uint32_t *)p->data = type;
262         memcpy((uint32_t *)p->data + 1, values.data(), sizeof(T) * values.size());
263 
264         status_t status = mEngine->setParameter(p);
265         if (status != NO_ERROR) {
266             return status;
267         }
268         if (p->status != NO_ERROR) {
269             return p->status;
270         }
271         return NO_ERROR;
272     }
273 
274     /**
275      * Get a parameter from spatializer engine by calling getParameter on AudioEffect object.
276      * It is possible to read more than one value of type T according to the parameter type
277      * by specifying values vector size.
278      */
279     template<typename T>
getEffectParameter_l(uint32_t type,std::vector<T> * values)280     status_t getEffectParameter_l(uint32_t type, std::vector<T> *values) REQUIRES(mLock) {
281         static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
282 
283         uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1 + values->size()];
284         effect_param_t *p = (effect_param_t *)cmd;
285         p->psize = sizeof(uint32_t);
286         p->vsize = sizeof(T) * values->size();
287         *(uint32_t *)p->data = type;
288 
289         status_t status = mEngine->getParameter(p);
290 
291         if (status != NO_ERROR) {
292             return status;
293         }
294         if (p->status != NO_ERROR) {
295             return p->status;
296         }
297 
298         int numValues = std::min(p->vsize / sizeof(T), values->size());
299         (*values).clear();
300         T *retValues = (T *)((uint8_t *)p->data + sizeof(uint32_t));
301         std::copy(&retValues[0], &retValues[numValues], back_inserter(*values));
302 
303         return NO_ERROR;
304     }
305 
306     void postFramesProcessedMsg(int frames);
307 
308     /**
309      * Checks if head and screen sensors must be actively monitored based on
310      * spatializer state and playback activity and configures the pose controller
311      * accordingly.
312      */
313     void checkSensorsState_l() REQUIRES(mLock);
314 
315     /**
316      * Checks if the head pose controller should be created or destroyed according
317      * to desired head tracking mode.
318      */
319     void checkPoseController_l() REQUIRES(mLock);
320 
321     /**
322      * Checks if the spatializer effect should be enabled based on
323      * playback activity and requested level.
324      */
325     void checkEngineState_l() REQUIRES(mLock);
326 
327     /**
328      * Reset head tracking mode and recenter pose in engine: Called when the head tracking
329      * is disabled.
330      */
331     void resetEngineHeadPose_l() REQUIRES(mLock);
332 
333     /** Effect engine descriptor */
334     const effect_descriptor_t mEngineDescriptor;
335     /** Callback interface to parent audio policy service */
336     SpatializerPolicyCallback* const mPolicyCallback;
337 
338     /** Currently there is only one version of the spatializer running */
339     static constexpr const char* kDefaultMetricsId =
340             AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "0";
341     const std::string mMetricsId = kDefaultMetricsId;
342 
343     /** Mutex protecting internal state */
344     mutable std::mutex mLock;
345 
346     /** Client AudioEffect for the engine */
347     sp<AudioEffect> mEngine GUARDED_BY(mLock);
348     /** Output stream the spatializer mixer thread is attached to */
349     audio_io_handle_t mOutput GUARDED_BY(mLock) = AUDIO_IO_HANDLE_NONE;
350 
351     /** Callback interface to the client (AudioService) controlling this`Spatializer */
352     sp<media::INativeSpatializerCallback> mSpatializerCallback GUARDED_BY(mLock);
353 
354     /** Callback interface for head tracking */
355     sp<media::ISpatializerHeadTrackingCallback> mHeadTrackingCallback GUARDED_BY(mLock);
356 
357     /** Requested spatialization level */
358     media::SpatializationLevel mLevel GUARDED_BY(mLock) = media::SpatializationLevel::NONE;
359 
360     /** Control logic for head-tracking, etc. */
361     std::shared_ptr<SpatializerPoseController> mPoseController GUARDED_BY(mLock);
362 
363     /** Last requested head tracking mode */
364     media::HeadTrackingMode mDesiredHeadTrackingMode GUARDED_BY(mLock)
365             = media::HeadTrackingMode::STATIC;
366 
367     /** Last-reported actual head-tracking mode. */
368     media::SpatializerHeadTrackingMode mActualHeadTrackingMode GUARDED_BY(mLock)
369             = media::SpatializerHeadTrackingMode::DISABLED;
370 
371     /** Selected Head pose sensor */
372     int32_t mHeadSensor GUARDED_BY(mLock) = SpatializerPoseController::INVALID_SENSOR;
373 
374     /** Selected Screen pose sensor */
375     int32_t mScreenSensor GUARDED_BY(mLock) = SpatializerPoseController::INVALID_SENSOR;
376 
377     /** Last display orientation received */
378     float mDisplayOrientation GUARDED_BY(mLock) = 0.f;  // aligned to natural up orientation.
379 
380     /** Last folded state */
381     bool mFoldedState GUARDED_BY(mLock) = false;  // foldable: true means folded.
382 
383     /** Last hinge angle */
384     float mHingeAngle GUARDED_BY(mLock) = 0.f;  // foldable: 0.f is closed, M_PI flat open.
385 
386     std::vector<media::SpatializationLevel> mLevels;
387     std::vector<media::SpatializerHeadTrackingMode> mHeadTrackingModes;
388     std::vector<media::SpatializationMode> mSpatializationModes;
389     std::vector<audio_channel_mask_t> mChannelMasks;
390     bool mSupportsHeadTracking;
391 
392     // Looper thread for mEngine callbacks
393     class EngineCallbackHandler;
394 
395     sp<ALooper> mLooper;
396     sp<EngineCallbackHandler> mHandler;
397 
398     size_t mNumActiveTracks GUARDED_BY(mLock) = 0;
399     std::vector<audio_latency_mode_t> mSupportedLatencyModes GUARDED_BY(mLock);
400 
401     static const std::vector<const char*> sHeadPoseKeys;
402 
403     // Local log for command messages.
404     static constexpr int mMaxLocalLogLine = 10;
405     SimpleLog mLocalLog{mMaxLocalLogLine};
406 
407     /**
408      * @brief Calculate and record sensor data.
409      * Dump to local log with max/average pose angle every mPoseRecordThreshold.
410      */
411     // Record one log line per second (up to mMaxLocalLogLine) to capture most recent sensor data.
GUARDED_BY(mLock)412     media::VectorRecorder mPoseRecorder GUARDED_BY(mLock) {
413         6 /* vectorSize */, std::chrono::seconds(1), mMaxLocalLogLine, { 3 } /* delimiterIdx */};
414     // Record one log line per minute (up to mMaxLocalLogLine) to capture durable sensor data.
GUARDED_BY(mLock)415     media::VectorRecorder mPoseDurableRecorder  GUARDED_BY(mLock) {
416         6 /* vectorSize */, std::chrono::minutes(1), mMaxLocalLogLine, { 3 } /* delimiterIdx */};
417 };  // Spatializer
418 
419 }; // namespace android
420 
421 #endif // ANDROID_MEDIA_SPATIALIZER_H
422