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/media/BnEffect.h>
21 #include <android/media/BnSpatializer.h>
22 #include <android/media/SpatializationLevel.h>
23 #include <android/media/SpatializationMode.h>
24 #include <android/media/SpatializerHeadTrackingMode.h>
25 #include <media/audiohal/EffectHalInterface.h>
26 #include <media/stagefright/foundation/ALooper.h>
27 #include <media/AudioEffect.h>
28 #include <system/audio_effects/effect_spatializer.h>
29 
30 #include "SpatializerPoseController.h"
31 
32 namespace android {
33 
34 
35 // ----------------------------------------------------------------------------
36 
37 /**
38  * A callback interface from the Spatializer object or its parent AudioPolicyService.
39  * This is implemented by the audio policy service hosting the Spatializer to perform
40  * actions needed when a state change inside the Spatializer requires some audio system
41  * changes that cannot be performed by the Spatializer. For instance opening or closing a
42  * spatializer output stream when the spatializer is enabled or disabled
43  */
44 class SpatializerPolicyCallback {
45 public:
46     /** Called when a stage change occurs that requires the parent audio policy service to take
47      * some action.
48      */
49     virtual void onCheckSpatializer() = 0;
50 
51     virtual ~SpatializerPolicyCallback() = default;
52 };
53 /**
54  * The Spatializer class implements all functional controlling the multichannel spatializer
55  * with head tracking implementation in the native audio service: audio policy and audio flinger.
56  * It presents an AIDL interface available to the java audio service to discover the availability
57  * of the feature and options, control its state and register an active head tracking sensor.
58  * It maintains the current state of the platform spatializer and applies the stored parameters
59  * when the spatializer engine is created and enabled.
60  * Based on the requested spatializer level, it will request the creation of a specialized output
61  * mixer to the audio policy service which will in turn notify the Spatializer of the output
62  * stream on which a spatializer engine should be created, configured and enabled.
63  * The spatializer also hosts the head tracking management logic. This logic receives the
64  * desired head tracking mode and selected head tracking sensor, registers a sensor event listener
65  * and derives the compounded head pose information to the spatializer engine.
66  *
67  * Workflow:
68  * - Initialization: when the audio policy service starts, it checks if a spatializer effect
69  * engine exists and if the audio policy manager reports a dedicated spatializer output profile.
70  * If both conditions are met, a Spatializer object is created
71  * - Capabilities discovery: AudioService will call AudioSystem::canBeSpatialized() and if true,
72  * acquire an ISpatializer interface with AudioSystem::getSpatializer(). This interface
73  * will be used to query the implementation capabilities and configure the spatializer.
74  * - Enabling: when ISpatializer::setLevel() sets a level different from NONE the spatializer
75  * is considered enabled. The audio policy callback onCheckSpatializer() is called. This
76  * triggers a request to audio policy manager to open a spatialization output stream and a
77  * spatializer mixer is created in audio flinger. When an output is returned by audio policy
78  * manager, Spatializer::attachOutput() is called which creates and enables the spatializer
79  * stage engine on the specified output.
80  * - Disabling: when the spatialization level is set to NONE, the spatializer is considered
81  * disabled. The audio policy callback onCheckSpatializer() is called. This triggers a call
82  * to Spatializer::detachOutput() and the spatializer engine is released. Then a request is
83  * made to audio policy manager to release and close the spatializer output stream and the
84  * spatializer mixer thread is destroyed.
85  */
86 class Spatializer : public media::BnSpatializer,
87                     public IBinder::DeathRecipient,
88                     private SpatializerPoseController::Listener {
89   public:
90     static sp<Spatializer> create(SpatializerPolicyCallback *callback);
91 
92            ~Spatializer() override;
93 
94     /** RefBase */
95     void onFirstRef();
96 
97     /** ISpatializer, see ISpatializer.aidl */
98     binder::Status release() override;
99     binder::Status getSupportedLevels(std::vector<media::SpatializationLevel>* levels) override;
100     binder::Status setLevel(media::SpatializationLevel level) override;
101     binder::Status getLevel(media::SpatializationLevel *level) override;
102     binder::Status isHeadTrackingSupported(bool *supports);
103     binder::Status getSupportedHeadTrackingModes(
104             std::vector<media::SpatializerHeadTrackingMode>* modes) override;
105     binder::Status setDesiredHeadTrackingMode(
106             media::SpatializerHeadTrackingMode mode) override;
107     binder::Status getActualHeadTrackingMode(
108             media::SpatializerHeadTrackingMode* mode) override;
109     binder::Status recenterHeadTracker() override;
110     binder::Status setGlobalTransform(const std::vector<float>& screenToStage) override;
111     binder::Status setHeadSensor(int sensorHandle) override;
112     binder::Status setScreenSensor(int sensorHandle) override;
113     binder::Status setDisplayOrientation(float physicalToLogicalAngle) override;
114     binder::Status setHingeAngle(float hingeAngle) override;
115     binder::Status getSupportedModes(std::vector<media::SpatializationMode>* modes) override;
116     binder::Status registerHeadTrackingCallback(
117         const sp<media::ISpatializerHeadTrackingCallback>& callback) override;
118     binder::Status setParameter(int key, const std::vector<unsigned char>& value) override;
119     binder::Status getParameter(int key, std::vector<unsigned char> *value) override;
120     binder::Status getOutput(int *output);
121 
122     /** IBinder::DeathRecipient. Listen to the death of the INativeSpatializerCallback. */
123     virtual void binderDied(const wp<IBinder>& who);
124 
125     /** Registers a INativeSpatializerCallback when a client is attached to this Spatializer
126      * by audio policy service.
127      */
128     status_t registerCallback(const sp<media::INativeSpatializerCallback>& callback);
129 
130     status_t loadEngineConfiguration(sp<EffectHalInterface> effect);
131 
132     /** Level getter for use by local classes. */
getLevel()133     media::SpatializationLevel getLevel() const { std::lock_guard lock(mLock); return mLevel; }
134 
135     /** Called by audio policy service when the special output mixer dedicated to spatialization
136      * is opened and the spatializer engine must be created.
137      */
138     status_t attachOutput(audio_io_handle_t output);
139     /** Called by audio policy service when the special output mixer dedicated to spatialization
140      * is closed and the spatializer engine must be release.
141      */
142     audio_io_handle_t detachOutput();
143     /** Returns the output stream the spatializer is attached to. */
getOutput()144     audio_io_handle_t getOutput() const { std::lock_guard lock(mLock); return mOutput; }
145 
146     /** Gets the channel mask, sampling rate and format set for the spatializer input. */
147     audio_config_base_t getAudioInConfig() const;
148 
149     void calculateHeadPose();
150 
151 private:
152     Spatializer(effect_descriptor_t engineDescriptor,
153                      SpatializerPolicyCallback *callback);
154 
155     static void engineCallback(int32_t event, void* user, void *info);
156 
157     // From VirtualizerStageController::Listener
158     void onHeadToStagePose(const media::Pose3f& headToStage) override;
159     void onActualModeChange(media::HeadTrackingMode mode) override;
160 
161     void onHeadToStagePoseMsg(const std::vector<float>& headToStage);
162     void onActualModeChangeMsg(media::HeadTrackingMode mode);
163 
164     static constexpr int kMaxEffectParamValues = 10;
165     /**
166      * Get a parameter from spatializer engine by calling the effect HAL command method directly.
167      * To be used when the engine instance mEngine is not yet created in the effect framework.
168      * When MULTI_VALUES is false, the expected reply is only one value of type T.
169      * When MULTI_VALUES is true, the expected reply is made of a number (of type T) indicating
170      * how many values are returned, followed by this number for values of type T.
171      */
172     template<bool MULTI_VALUES, typename T>
getHalParameter(sp<EffectHalInterface> effect,uint32_t type,std::vector<T> * values)173     status_t getHalParameter(sp<EffectHalInterface> effect, uint32_t type,
174                                           std::vector<T> *values) {
175         static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
176 
177         uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1];
178         uint32_t reply[sizeof(effect_param_t) / sizeof(uint32_t) + 2 + kMaxEffectParamValues];
179 
180         effect_param_t *p = (effect_param_t *)cmd;
181         p->psize = sizeof(uint32_t);
182         if (MULTI_VALUES) {
183             p->vsize = (kMaxEffectParamValues + 1) * sizeof(T);
184         } else {
185             p->vsize = sizeof(T);
186         }
187         *(uint32_t *)p->data = type;
188         uint32_t replySize = sizeof(effect_param_t) + p->psize + p->vsize;
189 
190         status_t status = effect->command(EFFECT_CMD_GET_PARAM,
191                                           sizeof(effect_param_t) + sizeof(uint32_t), cmd,
192                                           &replySize, reply);
193         if (status != NO_ERROR) {
194             return status;
195         }
196         if (p->status != NO_ERROR) {
197             return p->status;
198         }
199         if (replySize <
200                 sizeof(effect_param_t) + sizeof(uint32_t) + (MULTI_VALUES ? 2 : 1) * sizeof(T)) {
201             return BAD_VALUE;
202         }
203 
204         T *params = (T *)((uint8_t *)reply + sizeof(effect_param_t) + sizeof(uint32_t));
205         int numParams = 1;
206         if (MULTI_VALUES) {
207             numParams = (int)*params++;
208         }
209         if (numParams > kMaxEffectParamValues) {
210             return BAD_VALUE;
211         }
212         (*values).clear();
213         std::copy(&params[0], &params[numParams], back_inserter(*values));
214         return NO_ERROR;
215     }
216 
217     /**
218      * Set a parameter to spatializer engine by calling setParameter on mEngine AudioEffect object.
219      * It is possible to pass more than one value of type T according to the parameter type
220      *  according to values vector size.
221      */
222     template<typename T>
setEffectParameter_l(uint32_t type,const std::vector<T> & values)223     status_t setEffectParameter_l(uint32_t type, const std::vector<T>& values) REQUIRES(mLock) {
224         static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
225 
226         uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1 + values.size()];
227         effect_param_t *p = (effect_param_t *)cmd;
228         p->psize = sizeof(uint32_t);
229         p->vsize = sizeof(T) * values.size();
230         *(uint32_t *)p->data = type;
231         memcpy((uint32_t *)p->data + 1, values.data(), sizeof(T) * values.size());
232 
233         status_t status = mEngine->setParameter(p);
234         if (status != NO_ERROR) {
235             return status;
236         }
237         if (p->status != NO_ERROR) {
238             return p->status;
239         }
240         return NO_ERROR;
241     }
242 
243     /**
244      * Get a parameter from spatializer engine by calling getParameter on AudioEffect object.
245      * It is possible to read more than one value of type T according to the parameter type
246      * by specifying values vector size.
247      */
248     template<typename T>
getEffectParameter_l(uint32_t type,std::vector<T> * values)249     status_t getEffectParameter_l(uint32_t type, std::vector<T> *values) REQUIRES(mLock) {
250         static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
251 
252         uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1 + values->size()];
253         effect_param_t *p = (effect_param_t *)cmd;
254         p->psize = sizeof(uint32_t);
255         p->vsize = sizeof(T) * values->size();
256         *(uint32_t *)p->data = type;
257 
258         status_t status = mEngine->getParameter(p);
259 
260         if (status != NO_ERROR) {
261             return status;
262         }
263         if (p->status != NO_ERROR) {
264             return p->status;
265         }
266 
267         int numValues = std::min(p->vsize / sizeof(T), values->size());
268         (*values).clear();
269         T *retValues = (T *)((uint8_t *)p->data + sizeof(uint32_t));
270         std::copy(&retValues[0], &retValues[numValues], back_inserter(*values));
271 
272         return NO_ERROR;
273     }
274 
275     void postFramesProcessedMsg(int frames);
276 
277     /** Effect engine descriptor */
278     const effect_descriptor_t mEngineDescriptor;
279     /** Callback interface to parent audio policy service */
280     SpatializerPolicyCallback* mPolicyCallback;
281 
282     /** Mutex protecting internal state */
283     mutable std::mutex mLock;
284 
285     /** Client AudioEffect for the engine */
286     sp<AudioEffect> mEngine GUARDED_BY(mLock);
287     /** Output stream the spatializer mixer thread is attached to */
288     audio_io_handle_t mOutput GUARDED_BY(mLock) = AUDIO_IO_HANDLE_NONE;
289 
290     /** Callback interface to the client (AudioService) controlling this`Spatializer */
291     sp<media::INativeSpatializerCallback> mSpatializerCallback GUARDED_BY(mLock);
292 
293     /** Callback interface for head tracking */
294     sp<media::ISpatializerHeadTrackingCallback> mHeadTrackingCallback GUARDED_BY(mLock);
295 
296     /** Requested spatialization level */
297     media::SpatializationLevel mLevel GUARDED_BY(mLock) = media::SpatializationLevel::NONE;
298 
299     /** Control logic for head-tracking, etc. */
300     std::shared_ptr<SpatializerPoseController> mPoseController GUARDED_BY(mLock);
301 
302     /** Last requested head tracking mode */
303     media::HeadTrackingMode mDesiredHeadTrackingMode GUARDED_BY(mLock)
304             = media::HeadTrackingMode::STATIC;
305 
306     /** Last-reported actual head-tracking mode. */
307     media::SpatializerHeadTrackingMode mActualHeadTrackingMode GUARDED_BY(mLock)
308             = media::SpatializerHeadTrackingMode::DISABLED;
309 
310     /** Selected Head pose sensor */
311     int32_t mHeadSensor GUARDED_BY(mLock) = SpatializerPoseController::INVALID_SENSOR;
312 
313     /** Selected Screen pose sensor */
314     int32_t mScreenSensor GUARDED_BY(mLock) = SpatializerPoseController::INVALID_SENSOR;
315 
316     /** Last display orientation received */
317     static constexpr float kDisplayOrientationInvalid = 1000;
318     float mDisplayOrientation GUARDED_BY(mLock) = kDisplayOrientationInvalid;
319 
320     std::vector<media::SpatializationLevel> mLevels;
321     std::vector<media::SpatializationMode> mSpatializationModes;
322     std::vector<audio_channel_mask_t> mChannelMasks;
323     bool mSupportsHeadTracking;
324 
325     // Looper thread for mEngine callbacks
326     class EngineCallbackHandler;
327 
328     sp<ALooper> mLooper;
329     sp<EngineCallbackHandler> mHandler;
330 
331     static const std::vector<const char *> sHeadPoseKeys;
332 };
333 
334 
335 }; // namespace android
336 
337 #endif // ANDROID_MEDIA_SPATIALIZER_H
338