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(¶ms[0], ¶ms[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