blob: 7a18cbe4c89b67cf3c3eca7abb321af13649478a [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
20#include <android/media/BnEffect.h>
21#include <android/media/BnSpatializer.h>
Eric Laurent6d607012021-07-05 11:54:40 +020022#include <android/media/SpatializationLevel.h>
Eric Laurent2be8b292021-08-23 09:44:33 -070023#include <android/media/SpatializationMode.h>
24#include <android/media/SpatializerHeadTrackingMode.h>
25#include <android/sensor.h>
26#include <media/audiohal/EffectHalInterface.h>
Eric Laurent8a4259f2021-09-14 16:04:00 +020027#include <media/stagefright/foundation/ALooper.h>
Eric Laurent6d607012021-07-05 11:54:40 +020028#include <media/AudioEffect.h>
Eric Laurent1c5e2e32021-08-18 18:50:28 +020029#include <system/audio_effects/effect_spatializer.h>
Eric Laurent6d607012021-07-05 11:54:40 +020030
Eric Laurent2be8b292021-08-23 09:44:33 -070031#include "SpatializerPoseController.h"
Eric Laurent6d607012021-07-05 11:54:40 +020032
33namespace android {
34
35
36// ----------------------------------------------------------------------------
37
38/**
39 * A callback interface from the Spatializer object or its parent AudioPolicyService.
40 * This is implemented by the audio policy service hosting the Spatializer to perform
41 * actions needed when a state change inside the Spatializer requires some audio system
42 * changes that cannot be performed by the Spatializer. For instance opening or closing a
43 * spatializer output stream when the spatializer is enabled or disabled
44 */
45class SpatializerPolicyCallback {
46public:
47 /** Called when a stage change occurs that requires the parent audio policy service to take
48 * some action.
49 */
50 virtual void onCheckSpatializer() = 0;
51
52 virtual ~SpatializerPolicyCallback() = default;
53};
54/**
55 * The Spatializer class implements all functional controlling the multichannel spatializer
56 * with head tracking implementation in the native audio service: audio policy and audio flinger.
57 * It presents an AIDL interface available to the java audio service to discover the availability
58 * of the feature and options, control its state and register an active head tracking sensor.
59 * It maintains the current state of the platform spatializer and applies the stored parameters
60 * when the spatializer engine is created and enabled.
61 * Based on the requested spatializer level, it will request the creation of a specialized output
62 * mixer to the audio policy service which will in turn notify the Spatializer of the output
63 * stream on which a spatializer engine should be created, configured and enabled.
64 * The spatializer also hosts the head tracking management logic. This logic receives the
65 * desired head tracking mode and selected head tracking sensor, registers a sensor event listener
66 * and derives the compounded head pose information to the spatializer engine.
67 *
68 * Workflow:
69 * - Initialization: when the audio policy service starts, it checks if a spatializer effect
70 * engine exists and if the audio policy manager reports a dedicated spatializer output profile.
71 * If both conditions are met, a Spatializer object is created
72 * - Capabilities discovery: AudioService will call AudioSystem::canBeSpatialized() and if true,
73 * acquire an ISpatializer interface with AudioSystem::getSpatializer(). This interface
74 * will be used to query the implementation capabilities and configure the spatializer.
75 * - Enabling: when ISpatializer::setLevel() sets a level different from NONE the spatializer
76 * is considered enabled. The audio policy callback onCheckSpatializer() is called. This
77 * triggers a request to audio policy manager to open a spatialization output stream and a
78 * spatializer mixer is created in audio flinger. When an output is returned by audio policy
79 * manager, Spatializer::attachOutput() is called which creates and enables the spatializer
80 * stage engine on the specified output.
81 * - Disabling: when the spatialization level is set to NONE, the spatializer is considered
82 * disabled. The audio policy callback onCheckSpatializer() is called. This triggers a call
83 * to Spatializer::detachOutput() and the spatializer engine is released. Then a request is
84 * made to audio policy manager to release and close the spatializer output stream and the
85 * spatializer mixer thread is destroyed.
86 */
Eric Laurent2be8b292021-08-23 09:44:33 -070087class Spatializer : public media::BnSpatializer,
88 public IBinder::DeathRecipient,
89 private SpatializerPoseController::Listener {
90 public:
Eric Laurent6d607012021-07-05 11:54:40 +020091 static sp<Spatializer> create(SpatializerPolicyCallback *callback);
92
93 ~Spatializer() override;
94
Eric Laurent8a4259f2021-09-14 16:04:00 +020095 /** RefBase */
96 void onFirstRef();
97
Eric Laurent6d607012021-07-05 11:54:40 +020098 /** ISpatializer, see ISpatializer.aidl */
99 binder::Status release() override;
100 binder::Status getSupportedLevels(std::vector<media::SpatializationLevel>* levels) override;
101 binder::Status setLevel(media::SpatializationLevel level) override;
102 binder::Status getLevel(media::SpatializationLevel *level) override;
103 binder::Status getSupportedHeadTrackingModes(
Ytai Ben-Tsvia16a9df2021-08-05 08:57:06 -0700104 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;
Eric Laurent6d607012021-07-05 11:54:40 +0200110 binder::Status setGlobalTransform(const std::vector<float>& screenToStage) override;
Eric Laurent2be8b292021-08-23 09:44:33 -0700111 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;
Eric Laurent67816e32021-09-16 15:18:40 +0200116 binder::Status registerHeadTrackingCallback(
117 const sp<media::ISpatializerHeadTrackingCallback>& callback) override;
Eric Laurent6d607012021-07-05 11:54:40 +0200118
119 /** IBinder::DeathRecipient. Listen to the death of the INativeSpatializerCallback. */
120 virtual void binderDied(const wp<IBinder>& who);
121
122 /** Registers a INativeSpatializerCallback when a client is attached to this Spatializer
123 * by audio policy service.
124 */
125 status_t registerCallback(const sp<media::INativeSpatializerCallback>& callback);
126
Eric Laurent2be8b292021-08-23 09:44:33 -0700127 status_t loadEngineConfiguration(sp<EffectHalInterface> effect);
128
Eric Laurent6d607012021-07-05 11:54:40 +0200129 /** Level getter for use by local classes. */
Eric Laurent2be8b292021-08-23 09:44:33 -0700130 media::SpatializationLevel getLevel() const { std::lock_guard lock(mLock); return mLevel; }
Eric Laurent6d607012021-07-05 11:54:40 +0200131
132 /** Called by audio policy service when the special output mixer dedicated to spatialization
133 * is opened and the spatializer engine must be created.
134 */
135 status_t attachOutput(audio_io_handle_t output);
136 /** Called by audio policy service when the special output mixer dedicated to spatialization
137 * is closed and the spatializer engine must be release.
138 */
139 audio_io_handle_t detachOutput();
140 /** Returns the output stream the spatializer is attached to. */
Eric Laurent2be8b292021-08-23 09:44:33 -0700141 audio_io_handle_t getOutput() const { std::lock_guard lock(mLock); return mOutput; }
Eric Laurent6d607012021-07-05 11:54:40 +0200142
143 /** Gets the channel mask, sampling rate and format set for the spatializer input. */
Eric Laurent2be8b292021-08-23 09:44:33 -0700144 audio_config_base_t getAudioInConfig() const;
Eric Laurent6d607012021-07-05 11:54:40 +0200145
Eric Laurent8a4259f2021-09-14 16:04:00 +0200146 void calculateHeadPose();
147
Eric Laurent6d607012021-07-05 11:54:40 +0200148 /** An implementation of an IEffect interface that can be used to pass advanced parameters to
149 * the spatializer engine. All APis are noop (i.e. the interface cannot be used to control
150 * the effect) except for passing parameters via the command() API. */
151 class EffectClient: public android::media::BnEffect {
152 public:
153
154 EffectClient(const sp<media::IEffectClient>& effectClient,
155 Spatializer& parent);
156 virtual ~EffectClient();
157
158 // IEffect
159 android::binder::Status enable(int32_t* _aidl_return) override;
160 android::binder::Status disable(int32_t* _aidl_return) override;
161 android::binder::Status command(int32_t cmdCode,
162 const std::vector<uint8_t>& cmdData,
163 int32_t maxResponseSize,
164 std::vector<uint8_t>* response,
165 int32_t* _aidl_return) override;
166 android::binder::Status disconnect() override;
167 android::binder::Status getCblk(media::SharedFileRegion* _aidl_return) override;
168
169 private:
170 const sp<media::IEffectClient> mEffectClient;
171 sp<IMemory> mCblkMemory;
172 const Spatializer& mParent;
173 bool mDisconnected = false;
174 };
175
176private:
Eric Laurent6d607012021-07-05 11:54:40 +0200177 Spatializer(effect_descriptor_t engineDescriptor,
178 SpatializerPolicyCallback *callback);
179
Eric Laurent6d607012021-07-05 11:54:40 +0200180 static void engineCallback(int32_t event, void* user, void *info);
181
Eric Laurent2be8b292021-08-23 09:44:33 -0700182 // From VirtualizerStageController::Listener
183 void onHeadToStagePose(const media::Pose3f& headToStage) override;
184 void onActualModeChange(media::HeadTrackingMode mode) override;
185
Eric Laurent8a4259f2021-09-14 16:04:00 +0200186 void onHeadToStagePoseMsg(const std::vector<float>& headToStage);
187 void onActualModeChangeMsg(media::HeadTrackingMode mode);
188
Eric Laurent2be8b292021-08-23 09:44:33 -0700189
190 static ConversionResult<ASensorRef> getSensorFromHandle(int handle);
191
192 static constexpr int kMaxEffectParamValues = 10;
193 /**
194 * Get a parameter from spatializer engine by calling the effect HAL command method directly.
195 * To be used when the engine instance mEngine is not yet created in the effect framework.
196 * When MULTI_VALUES is false, the expected reply is only one value of type T.
197 * When MULTI_VALUES is true, the expected reply is made of a number (of type T) indicating
198 * how many values are returned, followed by this number for values of type T.
199 */
200 template<bool MULTI_VALUES, typename T>
201 status_t getHalParameter(sp<EffectHalInterface> effect, uint32_t type,
202 std::vector<T> *values) {
203 static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
204
205 uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1];
206 uint32_t reply[sizeof(effect_param_t) / sizeof(uint32_t) + 2 + kMaxEffectParamValues];
207
208 effect_param_t *p = (effect_param_t *)cmd;
209 p->psize = sizeof(uint32_t);
210 if (MULTI_VALUES) {
211 p->vsize = (kMaxEffectParamValues + 1) * sizeof(T);
212 } else {
213 p->vsize = sizeof(T);
214 }
215 *(uint32_t *)p->data = type;
216 uint32_t replySize = sizeof(effect_param_t) + p->psize + p->vsize;
217
218 status_t status = effect->command(EFFECT_CMD_GET_PARAM,
219 sizeof(effect_param_t) + sizeof(uint32_t), cmd,
220 &replySize, reply);
221 if (status != NO_ERROR) {
222 return status;
223 }
224 if (p->status != NO_ERROR) {
225 return p->status;
226 }
227 if (replySize <
228 sizeof(effect_param_t) + sizeof(uint32_t) + (MULTI_VALUES ? 2 : 1) * sizeof(T)) {
229 return BAD_VALUE;
230 }
231
232 T *params = (T *)((uint8_t *)reply + sizeof(effect_param_t) + sizeof(uint32_t));
233 int numParams = 1;
234 if (MULTI_VALUES) {
235 numParams = (int)*params++;
236 }
237 if (numParams > kMaxEffectParamValues) {
238 return BAD_VALUE;
239 }
240 std::copy(&params[0], &params[numParams], back_inserter(*values));
241 return NO_ERROR;
242 }
243
244 /**
245 * Set a parameter to spatializer engine by calling setParameter on mEngine AudioEffect object.
246 * It is possible to pass more than one value of type T according to the parameter type
247 * according to values vector size.
248 */
249 template<typename T>
250 status_t setEffectParameter_l(uint32_t type, const std::vector<T>& values) REQUIRES(mLock) {
251 static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
252
253 uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1 + values.size()];
254 effect_param_t *p = (effect_param_t *)cmd;
255 p->psize = sizeof(uint32_t);
256 p->vsize = sizeof(T) * values.size();
257 *(uint32_t *)p->data = type;
258 memcpy((uint32_t *)p->data + 1, values.data(), sizeof(T) * values.size());
259
260 return mEngine->setParameter(p);
261 }
262
Eric Laurent8a4259f2021-09-14 16:04:00 +0200263 void postFramesProcessedMsg(int frames);
264
Eric Laurent6d607012021-07-05 11:54:40 +0200265 /** Effect engine descriptor */
266 const effect_descriptor_t mEngineDescriptor;
267 /** Callback interface to parent audio policy service */
268 SpatializerPolicyCallback* mPolicyCallback;
269
270 /** Mutex protecting internal state */
Eric Laurent2be8b292021-08-23 09:44:33 -0700271 mutable std::mutex mLock;
Eric Laurent6d607012021-07-05 11:54:40 +0200272
273 /** Client AudioEffect for the engine */
274 sp<AudioEffect> mEngine GUARDED_BY(mLock);
275 /** Output stream the spatializer mixer thread is attached to */
276 audio_io_handle_t mOutput GUARDED_BY(mLock) = AUDIO_IO_HANDLE_NONE;
Eric Laurent6d607012021-07-05 11:54:40 +0200277
278 /** Callback interface to the client (AudioService) controlling this`Spatializer */
279 sp<media::INativeSpatializerCallback> mSpatializerCallback GUARDED_BY(mLock);
280
Eric Laurent67816e32021-09-16 15:18:40 +0200281 /** Callback interface for head tracking */
282 sp<media::ISpatializerHeadTrackingCallback> mHeadTrackingCallback GUARDED_BY(mLock);
283
Eric Laurent6d607012021-07-05 11:54:40 +0200284 /** Requested spatialization level */
285 media::SpatializationLevel mLevel GUARDED_BY(mLock) = media::SpatializationLevel::NONE;
Eric Laurent6d607012021-07-05 11:54:40 +0200286
287 /** Extended IEffect interface is one has been created */
288 sp<EffectClient> mEffectClient GUARDED_BY(mLock);
Eric Laurent2be8b292021-08-23 09:44:33 -0700289
290 /** Control logic for head-tracking, etc. */
291 std::shared_ptr<SpatializerPoseController> mPoseController GUARDED_BY(mLock);
292
293 /** Last requested head tracking mode */
294 media::HeadTrackingMode mDesiredHeadTrackingMode GUARDED_BY(mLock)
295 = media::HeadTrackingMode::STATIC;
296
297 /** Last-reported actual head-tracking mode. */
298 media::SpatializerHeadTrackingMode mActualHeadTrackingMode GUARDED_BY(mLock)
299 = media::SpatializerHeadTrackingMode::DISABLED;
300
301 /** Selected Head pose sensor */
302 ASensorRef mHeadSensor GUARDED_BY(mLock) = nullptr;
303
304 /** Selected Screen pose sensor */
305 ASensorRef mScreenSensor GUARDED_BY(mLock) = nullptr;
306
307 /** Last display orientation received */
308 static constexpr float kDisplayOrientationInvalid = 1000;
309 float mDisplayOrientation GUARDED_BY(mLock) = kDisplayOrientationInvalid;
310
311 std::vector<media::SpatializationLevel> mLevels;
312 std::vector<media::SpatializationMode> mSpatializationModes;
313 std::vector<audio_channel_mask_t> mChannelMasks;
314 bool mSupportsHeadTracking;
Eric Laurent8a4259f2021-09-14 16:04:00 +0200315
316 // Looper thread for mEngine callbacks
317 class EngineCallbackHandler;
318
319 sp<ALooper> mLooper;
320 sp<EngineCallbackHandler> mHandler;
321
322 static const std::vector<const char *> sHeadPoseKeys;
Eric Laurent6d607012021-07-05 11:54:40 +0200323};
324
325
326}; // namespace android
327
328#endif // ANDROID_MEDIA_SPATIALIZER_H