Spatial Audio: Fix display orientation, add fold state
Test: adb shell dumpsys media.audio_policy
Test: adb shell dumpsys media.audio_flinger
Bug: 271595745
Change-Id: I6e824044a6ad79e17b7861e8fa57103902ab3320
diff --git a/media/libaudioclient/aidl/android/media/ISpatializer.aidl b/media/libaudioclient/aidl/android/media/ISpatializer.aidl
index a61ad58..250c450 100644
--- a/media/libaudioclient/aidl/android/media/ISpatializer.aidl
+++ b/media/libaudioclient/aidl/android/media/ISpatializer.aidl
@@ -96,17 +96,33 @@
/**
* 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 9ee9037..5db82f7 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -20,6 +20,7 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <algorithm>
#include <inttypes.h>
#include <limits.h>
#include <stdint.h>
@@ -94,6 +95,16 @@
return record;
}
+template<typename T>
+static constexpr const T& safe_clamp(const T& value, const T& low, const T& high) {
+ if constexpr (std::is_floating_point_v<T>) {
+ 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::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<float>{physicalToLogicalAngle});
+ SPATIALIZER_PARAM_DISPLAY_ORIENTATION, std::vector<float>{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<float>{hingeAngle});
+ setEffectParameter_l(SPATIALIZER_PARAM_HINGE_ANGLE, std::vector<float>{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<uint8_t>{mFoldedState});
}
return Status::ok();
}
@@ -862,6 +893,14 @@
checkSensorsState_l();
}
callback = mSpatializerCallback;
+
+ // Restore common effect state.
+ setEffectParameter_l(SPATIALIZER_PARAM_DISPLAY_ORIENTATION,
+ std::vector<float>{mDisplayOrientation});
+ setEffectParameter_l(SPATIALIZER_PARAM_FOLD_STATE,
+ std::vector<uint8_t>{mFoldedState});
+ setEffectParameter_l(SPATIALIZER_PARAM_HINGE_ANGLE,
+ std::vector<float>{mHingeAngle});
}
if (outputChanged && callback != nullptr) {
diff --git a/services/audiopolicy/service/Spatializer.h b/services/audiopolicy/service/Spatializer.h
index c677868..b101ae6 100644
--- a/services/audiopolicy/service/Spatializer.h
+++ b/services/audiopolicy/service/Spatializer.h
@@ -118,6 +118,7 @@
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<media::SpatializationMode>* modes) override;
binder::Status registerHeadTrackingCallback(
const sp<media::ISpatializerHeadTrackingCallback>& callback) override;
@@ -374,8 +375,13 @@
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<media::SpatializationLevel> mLevels;
std::vector<media::SpatializerHeadTrackingMode> mHeadTrackingModes;