Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b25edabd authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

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
parent 5effdf21
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -2058,6 +2058,10 @@
    <!-- The default volume for the ring stream -->
    <integer name="config_audio_ring_vol_default">5</integer>

    <!-- The default value for whether head tracking for
         spatial audio is enabled for a newly connected audio device -->
    <bool name="config_spatial_audio_head_tracking_enabled_default">false</bool>

    <!-- Flag indicating whether platform level volume adjustments are enabled for remote sessions
         on grouped devices. -->
    <bool name="config_volumeAdjustmentForRemoteGroupSessions">true</bool>
+1 −0
Original line number Diff line number Diff line
@@ -278,6 +278,7 @@
  <java-symbol type="integer" name="config_audio_notif_vol_steps" />
  <java-symbol type="integer" name="config_audio_ring_vol_default" />
  <java-symbol type="integer" name="config_audio_ring_vol_steps" />
  <java-symbol type="bool" name="config_spatial_audio_head_tracking_enabled_default" />
  <java-symbol type="bool" name="config_avoidGfxAccel" />
  <java-symbol type="bool" name="config_bluetooth_address_validation" />
  <java-symbol type="integer" name="config_chooser_max_targets_per_row" />
+3 −1
Original line number Diff line number Diff line
@@ -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();
+22 −3
Original line number Diff line number Diff line
@@ -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
+11 −4
Original line number Diff line number Diff line
@@ -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);