From b25edabd334e48eb737d4d0379819197319891b5 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Thu, 25 Aug 2022 17:51:22 +0000 Subject: [PATCH] AudioService: properties for configuring head tracking default Define new property to indicate whether head tracking for spatial audio is enabled by default. Read property in AudioService and pass it to SpatializerHeper which will use the defalut value every time a new device connects. Fix unit test to account for recent hardening of device compatibility management. Add initialiation test method in SpatializerHelper to ensure we can test settings with devices for binaural and transaural modes. Bug: 242620201 Test: pair BT headset, observe head tracking toggle in UI Test: atest SpatializerHelper Change-Id: Ie3af7a13537d114cb603d3c83e9ca2ba86cd7f67 --- core/res/res/values/config.xml | 4 +++ core/res/res/values/symbols.xml | 1 + .../android/server/audio/AudioService.java | 4 ++- .../server/audio/SpatializerHelper.java | 25 ++++++++++++++++--- .../server/audio/SpatializerHelperTest.java | 15 ++++++++--- 5 files changed, 41 insertions(+), 8 deletions(-) diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 8152b79c86591..d95a5cece3aec 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2058,6 +2058,10 @@ 5 + + false + true diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index c96e452658974..2f311f336b08b 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -278,6 +278,7 @@ + diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 0a081bfbee969..0c4ea9764f51c 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1005,7 +1005,9 @@ public class AudioService extends IAudioService.Stub mSfxHelper = new SoundEffectsHelper(mContext); - mSpatializerHelper = new SpatializerHelper(this, mAudioSystem); + final boolean headTrackingDefault = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_spatial_audio_head_tracking_enabled_default); + mSpatializerHelper = new SpatializerHelper(this, mAudioSystem, headTrackingDefault); mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator(); diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java index b7e817e154528..2187cecee9a3d 100644 --- a/services/core/java/com/android/server/audio/SpatializerHelper.java +++ b/services/core/java/com/android/server/audio/SpatializerHelper.java @@ -169,9 +169,20 @@ public class SpatializerHelper { //------------------------------------------------------ // initialization - SpatializerHelper(@NonNull AudioService mother, @NonNull AudioSystemAdapter asa) { + @SuppressWarnings("StaticAssignmentInConstructor") + SpatializerHelper(@NonNull AudioService mother, @NonNull AudioSystemAdapter asa, + boolean headTrackingEnabledByDefault) { mAudioService = mother; mASA = asa; + // "StaticAssignmentInConstructor" warning is suppressed as the SpatializerHelper being + // constructed here is the factory for SADeviceState, thus SADeviceState and its + // private static field sHeadTrackingEnabledDefault should never be accessed directly. + SADeviceState.sHeadTrackingEnabledDefault = headTrackingEnabledByDefault; + } + + synchronized void initForTest(boolean hasBinaural, boolean hasTransaural) { + mBinauralSupported = hasBinaural; + mTransauralSupported = hasTransaural; } synchronized void init(boolean effectExpected, @Nullable String settings) { @@ -1499,18 +1510,26 @@ public class SpatializerHelper { } /*package*/ static final class SADeviceState { + private static boolean sHeadTrackingEnabledDefault = false; final @AudioDeviceInfo.AudioDeviceType int mDeviceType; final @NonNull String mDeviceAddress; boolean mEnabled = true; // by default, SA is enabled on any device boolean mHasHeadTracker = false; - boolean mHeadTrackerEnabled = true; // by default, if head tracker is present, use it + boolean mHeadTrackerEnabled; static final String SETTING_FIELD_SEPARATOR = ","; static final String SETTING_DEVICE_SEPARATOR_CHAR = "|"; static final String SETTING_DEVICE_SEPARATOR = "\\|"; - SADeviceState(@AudioDeviceInfo.AudioDeviceType int deviceType, @NonNull String address) { + /** + * Constructor + * @param deviceType + * @param address must be non-null for wireless devices + * @throws NullPointerException if a null address is passed for a wireless device + */ + SADeviceState(@AudioDeviceInfo.AudioDeviceType int deviceType, @Nullable String address) { mDeviceType = deviceType; mDeviceAddress = isWireless(deviceType) ? Objects.requireNonNull(address) : ""; + mHeadTrackerEnabled = sHeadTrackingEnabledDefault; } @Override diff --git a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java index b17c3a18d89e2..428eaff9e5bcc 100644 --- a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java @@ -55,14 +55,20 @@ public class SpatializerHelperTest { mMockAudioService = mock(AudioService.class); mSpyAudioSystem = spy(new NoOpAudioSystemAdapter()); - mSpatHelper = new SpatializerHelper(mMockAudioService, mSpyAudioSystem); + mSpatHelper = new SpatializerHelper(mMockAudioService, mSpyAudioSystem, + false /*headTrackingEnabledByDefault*/); } + /** + * Test that constructing an SADeviceState instance requires a non-null address for a + * wireless type, but can take null for a non-wireless type; + * @throws Exception + */ @Test public void testSADeviceStateNullAddressCtor() throws Exception { try { - SADeviceState devState = new SADeviceState( - AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, null); + SADeviceState devState = new SADeviceState(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, null); + devState = new SADeviceState(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, null); Assert.fail(); } catch (NullPointerException e) { } } @@ -88,11 +94,12 @@ public class SpatializerHelperTest { final AudioDeviceAttributes dev1 = new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""); final AudioDeviceAttributes dev2 = - new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "C3:P0:beep"); + new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "C3:PO:beep"); final AudioDeviceAttributes dev3 = new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "R2:D2:bloop"); doNothing().when(mMockAudioService).persistSpatialAudioDeviceSettings(); + mSpatHelper.initForTest(true /*binaural*/, true /*transaural*/); // test with single device mSpatHelper.addCompatibleAudioDevice(dev1);