diff --git a/media/libaudioclient/aidl/android/media/ISpatializer.aidl b/media/libaudioclient/aidl/android/media/ISpatializer.aidl index a61ad58eeb501568ec33e76e945c7b42b082349f..250c450b7b559d384538796a3ccc2a2b0e11e56e 100644 --- a/media/libaudioclient/aidl/android/media/ISpatializer.aidl +++ b/media/libaudioclient/aidl/android/media/ISpatializer.aidl @@ -96,17 +96,33 @@ interface ISpatializer { /** * Sets the display orientation. + * + * This is the rotation of the displayed content relative to its natural orientation. + * * Orientation is expressed in the angle of rotation from the physical "up" side of the screen * to the logical "up" side of the content displayed the screen. Counterclockwise angles, as * viewed while facing the screen are positive. + * + * Note: DisplayManager currently only returns this in increments of 90 degrees, + * so the values will be 0, PI/2, PI, 3PI/2. */ void setDisplayOrientation(float physicalToLogicalAngle); /** * Sets the hinge angle for foldable devices. + * + * Per the hinge angle sensor, this returns a value from 0 to 2PI. + * The value of 0 is considered closed, and PI is considered flat open. */ void setHingeAngle(float hingeAngle); + /** + * Sets whether a foldable is considered "folded" or not. + * + * The fold state may affect which physical screen is active for display. + */ + void setFoldState(boolean folded); + /** Reports the list of supported spatialization modess (see SpatializationMode.aidl). * The list should never be empty if an ISpatializer interface was successfully * retrieved with IAudioPolicyService.getSpatializer(). diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp index 9ee9037e2fb94282e6b03921aa19638bdf5980e3..5db82f7acb0429ce0adcfda4363a68ba4a93f2b3 100644 --- a/services/audiopolicy/service/Spatializer.cpp +++ b/services/audiopolicy/service/Spatializer.cpp @@ -20,6 +20,7 @@ //#define LOG_NDEBUG 0 #include +#include #include #include #include @@ -94,6 +95,16 @@ static std::vector recordFromTranslationRotationVector( return record; } +template +static constexpr const T& safe_clamp(const T& value, const T& low, const T& high) { + if constexpr (std::is_floating_point_v) { + return value != value /* constexpr isnan */ + ? low : std::clamp(value, low, high); + } else /* constexpr */ { + return std::clamp(value, low, high); + } +} + // --------------------------------------------------------------------------- class Spatializer::EngineCallbackHandler : public AHandler { @@ -638,28 +649,48 @@ Status Spatializer::setScreenSensor(int sensorHandle) { Status Spatializer::setDisplayOrientation(float physicalToLogicalAngle) { ALOGV("%s physicalToLogicalAngle %f", __func__, physicalToLogicalAngle); - if (!mSupportsHeadTracking) { - return binderStatusFromStatusT(INVALID_OPERATION); - } - std::lock_guard lock(mLock); - mDisplayOrientation = physicalToLogicalAngle; mLocalLog.log("%s with %f", __func__, physicalToLogicalAngle); + const float angle = safe_clamp(physicalToLogicalAngle, 0.f, (float)(2. * M_PI)); + // It is possible due to numerical inaccuracies to exceed the boundaries of 0 to 2 * M_PI. + ALOGI_IF(angle != physicalToLogicalAngle, + "%s: clamping %f to %f", __func__, physicalToLogicalAngle, angle); + std::lock_guard lock(mLock); + mDisplayOrientation = angle; if (mPoseController != nullptr) { - mPoseController->setDisplayOrientation(mDisplayOrientation); + // This turns on the rate-limiter. + mPoseController->setDisplayOrientation(angle); } if (mEngine != nullptr) { setEffectParameter_l( - SPATIALIZER_PARAM_DISPLAY_ORIENTATION, std::vector{physicalToLogicalAngle}); + SPATIALIZER_PARAM_DISPLAY_ORIENTATION, std::vector{angle}); } return Status::ok(); } Status Spatializer::setHingeAngle(float hingeAngle) { - std::lock_guard lock(mLock); ALOGV("%s hingeAngle %f", __func__, hingeAngle); + mLocalLog.log("%s with %f", __func__, hingeAngle); + const float angle = safe_clamp(hingeAngle, 0.f, (float)(2. * M_PI)); + // It is possible due to numerical inaccuracies to exceed the boundaries of 0 to 2 * M_PI. + ALOGI_IF(angle != hingeAngle, + "%s: clamping %f to %f", __func__, hingeAngle, angle); + std::lock_guard lock(mLock); + mHingeAngle = angle; if (mEngine != nullptr) { - mLocalLog.log("%s with %f", __func__, hingeAngle); - setEffectParameter_l(SPATIALIZER_PARAM_HINGE_ANGLE, std::vector{hingeAngle}); + setEffectParameter_l(SPATIALIZER_PARAM_HINGE_ANGLE, std::vector{angle}); + } + return Status::ok(); +} + +Status Spatializer::setFoldState(bool folded) { + ALOGV("%s foldState %d", __func__, (int)folded); + mLocalLog.log("%s with %d", __func__, (int)folded); + std::lock_guard lock(mLock); + mFoldedState = folded; + if (mEngine != nullptr) { + // we don't suppress multiple calls with the same folded state - that's + // done at the caller. + setEffectParameter_l(SPATIALIZER_PARAM_FOLD_STATE, std::vector{mFoldedState}); } return Status::ok(); } @@ -862,6 +893,14 @@ status_t Spatializer::attachOutput(audio_io_handle_t output, size_t numActiveTra checkSensorsState_l(); } callback = mSpatializerCallback; + + // Restore common effect state. + setEffectParameter_l(SPATIALIZER_PARAM_DISPLAY_ORIENTATION, + std::vector{mDisplayOrientation}); + setEffectParameter_l(SPATIALIZER_PARAM_FOLD_STATE, + std::vector{mFoldedState}); + setEffectParameter_l(SPATIALIZER_PARAM_HINGE_ANGLE, + std::vector{mHingeAngle}); } if (outputChanged && callback != nullptr) { diff --git a/services/audiopolicy/service/Spatializer.h b/services/audiopolicy/service/Spatializer.h index c677868d6d3416229f8b76ced52ba4ea42d89eb4..b101ae6b7e9efa7602d86b42a348f902dd5a9994 100644 --- a/services/audiopolicy/service/Spatializer.h +++ b/services/audiopolicy/service/Spatializer.h @@ -118,6 +118,7 @@ class Spatializer : public media::BnSpatializer, binder::Status setScreenSensor(int sensorHandle) override; binder::Status setDisplayOrientation(float physicalToLogicalAngle) override; binder::Status setHingeAngle(float hingeAngle) override; + binder::Status setFoldState(bool folded) override; binder::Status getSupportedModes(std::vector* modes) override; binder::Status registerHeadTrackingCallback( const sp& callback) override; @@ -374,8 +375,13 @@ private: int32_t mScreenSensor GUARDED_BY(mLock) = SpatializerPoseController::INVALID_SENSOR; /** Last display orientation received */ - static constexpr float kDisplayOrientationInvalid = 1000; - float mDisplayOrientation GUARDED_BY(mLock) = kDisplayOrientationInvalid; + float mDisplayOrientation GUARDED_BY(mLock) = 0.f; // aligned to natural up orientation. + + /** Last folded state */ + bool mFoldedState GUARDED_BY(mLock) = false; // foldable: true means folded. + + /** Last hinge angle */ + float mHingeAngle GUARDED_BY(mLock) = 0.f; // foldable: 0.f is closed, M_PI flat open. std::vector mLevels; std::vector mHeadTrackingModes;