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