diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 0899ef5d6956e..1bdfdc2110627 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8965,6 +8965,15 @@ public final class Settings { @Readable public static final String UNSAFE_VOLUME_MUSIC_ACTIVE_MS = "unsafe_volume_music_active_ms"; + /** + * Indicates whether the spatial audio feature was enabled for this user. + * + * Type : int (0 disabled, 1 enabled) + * + * @hide + */ + public static final String SPATIAL_AUDIO_ENABLED = "spatial_audio_enabled"; + /** * Indicates whether notification display on the lock screen is enabled. *

diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 246cf253bda5d..8c192844c8912 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -319,6 +319,7 @@ public class AudioService extends IAudioService.Stub private static final int MSG_DISPATCH_AUDIO_MODE = 40; private static final int MSG_ROUTING_UPDATED = 41; private static final int MSG_INIT_HEADTRACKING_SENSORS = 42; + private static final int MSG_PERSIST_SPATIAL_AUDIO_ENABLED = 43; // start of messages handled under wakelock // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), @@ -1038,12 +1039,13 @@ public class AudioService extends IAudioService.Stub mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false); + mHasSpatializerEffect = SystemProperties.getBoolean("ro.audio.spatializer_enabled", false); + // done with service initialization, continue additional work in our Handler thread queueMsgUnderWakeLock(mAudioHandler, MSG_INIT_STREAMS_VOLUMES, 0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */); queueMsgUnderWakeLock(mAudioHandler, MSG_INIT_SPATIALIZER, - 0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */); - + 0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */); } /** @@ -1237,6 +1239,9 @@ public class AudioService extends IAudioService.Stub // routing monitoring from AudioSystemAdapter @Override public void onRoutingUpdatedFromNative() { + if (!mHasSpatializerEffect) { + return; + } sendMsg(mAudioHandler, MSG_ROUTING_UPDATED, SENDMSG_REPLACE, 0, 0, null, @@ -1433,8 +1438,10 @@ public class AudioService extends IAudioService.Stub } } - // TODO check property if feature enabled - mSpatializerHelper.reset(/* featureEnabled */ SPATIALIZER_FEATURE_ENABLED_DEFAULT); + if (mHasSpatializerEffect) { + mSpatializerHelper.reset(/* featureEnabled */ isSpatialAudioEnabled()); + monitorRoutingChanges(true); + } onIndicateSystemReady(); // indicate the end of reconfiguration phase to audio HAL @@ -7570,9 +7577,11 @@ public class AudioService extends IAudioService.Stub break; case MSG_INIT_SPATIALIZER: - mSpatializerHelper.init(); - // TODO read property to see if enabled - mSpatializerHelper.setFeatureEnabled(SPATIALIZER_FEATURE_ENABLED_DEFAULT); + mSpatializerHelper.init(/*effectExpected*/ mHasSpatializerEffect); + if (mHasSpatializerEffect) { + mSpatializerHelper.setFeatureEnabled(isSpatialAudioEnabled()); + monitorRoutingChanges(true); + } mAudioEventWakeLock.release(); break; @@ -7716,6 +7725,10 @@ public class AudioService extends IAudioService.Stub case MSG_ROUTING_UPDATED: mSpatializerHelper.onRoutingUpdated(); break; + + case MSG_PERSIST_SPATIAL_AUDIO_ENABLED: + onPersistSpatialAudioEnabled(msg.arg1 == 1); + break; } } } @@ -8285,7 +8298,40 @@ public class AudioService extends IAudioService.Stub //========================================================================================== private final @NonNull SpatializerHelper mSpatializerHelper; - private static final boolean SPATIALIZER_FEATURE_ENABLED_DEFAULT = false; + /** + * Initialized from property ro.audio.spatializer_enabled + * Should only be 1 when the device ships with a Spatializer effect + */ + private final boolean mHasSpatializerEffect; + /** + * Default value for the spatial audio feature + */ + private static final boolean SPATIAL_AUDIO_ENABLED_DEFAULT = true; + + /** + * persist in user settings whether the feature is enabled. + * Can change when {@link Spatializer#setEnabled(boolean)} is called and successfully + * changes the state of the feature + * @param featureEnabled + */ + void persistSpatialAudioEnabled(boolean featureEnabled) { + sendMsg(mAudioHandler, + MSG_PERSIST_SPATIAL_AUDIO_ENABLED, + SENDMSG_REPLACE, featureEnabled ? 1 : 0, 0, null, + /*delay ms*/ 100); + } + + void onPersistSpatialAudioEnabled(boolean enabled) { + Settings.Secure.putIntForUser(mContentResolver, + Settings.Secure.SPATIAL_AUDIO_ENABLED, enabled ? 1 : 0, + UserHandle.USER_CURRENT); + } + + boolean isSpatialAudioEnabled() { + return Settings.Secure.getIntForUser(mContentResolver, + Settings.Secure.SPATIAL_AUDIO_ENABLED, SPATIAL_AUDIO_ENABLED_DEFAULT ? 1 : 0, + UserHandle.USER_CURRENT) == 1; + } private void enforceModifyDefaultAudioEffectsPermission() { if (mContext.checkCallingOrSelfPermission( @@ -9044,6 +9090,12 @@ public class AudioService extends IAudioService.Stub sVolumeLogger.dump(pw); pw.println("\n"); dumpSupportedSystemUsage(pw); + + pw.println("\n"); + pw.println("\nSpatial audio:"); + pw.println("mHasSpatializerEffect:" + mHasSpatializerEffect); + pw.println("isSpatializerEnabled:" + isSpatializerEnabled()); + pw.println("isSpatialAudioEnabled:" + isSpatialAudioEnabled()); } private void dumpSupportedSystemUsage(PrintWriter pw) { diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java index 66afe9b508284..b2fa86b69cfc2 100644 --- a/services/core/java/com/android/server/audio/SpatializerHelper.java +++ b/services/core/java/com/android/server/audio/SpatializerHelper.java @@ -106,8 +106,13 @@ public class SpatializerHelper { mASA = asa; } - synchronized void init() { + synchronized void init(boolean effectExpected) { Log.i(TAG, "Initializing"); + if (!effectExpected) { + Log.i(TAG, "Setting state to STATE_NOT_SUPPORTED due to effect not expected"); + mState = STATE_NOT_SUPPORTED; + return; + } if (mState != STATE_UNINITIALIZED) { throw new IllegalStateException(("init() called in state:" + mState)); } @@ -165,7 +170,7 @@ public class SpatializerHelper { mSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE; mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE; mActualHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED; - init(); + init(true); setFeatureEnabled(featureEnabled); } @@ -391,7 +396,7 @@ public class SpatializerHelper { } } mStateCallbacks.finishBroadcast(); - // TODO persist enabled state + mAudioService.persistSpatialAudioEnabled(featureEnabled); } private synchronized void setDispatchAvailableState(boolean available) {