Merge "Add core volume group call to set preferred device for strategy" into main
diff --git a/service/src/com/android/car/audio/CarAudioZone.java b/service/src/com/android/car/audio/CarAudioZone.java
index baefea9..f035042 100644
--- a/service/src/com/android/car/audio/CarAudioZone.java
+++ b/service/src/com/android/car/audio/CarAudioZone.java
@@ -225,6 +225,7 @@
mCurrentConfigId = configInfoSwitchedTo.getConfigId();
CarAudioZoneConfig current = mCarAudioZoneConfigs.get(mCurrentConfigId);
current.setIsSelected(true);
+ current.updateVolumeDevices(mCarAudioContext.useCoreAudioRouting());
}
}
@@ -241,6 +242,7 @@
mCurrentConfigId = config.getZoneConfigId();
}
config.setIsSelected(true);
+ config.updateVolumeDevices(mCarAudioContext.useCoreAudioRouting());
}
}
diff --git a/service/src/com/android/car/audio/CarAudioZoneConfig.java b/service/src/com/android/car/audio/CarAudioZoneConfig.java
index 2c85c73..9c2ed6c 100644
--- a/service/src/com/android/car/audio/CarAudioZoneConfig.java
+++ b/service/src/com/android/car/audio/CarAudioZoneConfig.java
@@ -499,6 +499,12 @@
return updated;
}
+ void updateVolumeDevices(boolean useCoreAudioRouting) {
+ for (int c = 0; c < mVolumeGroups.size(); c++) {
+ mVolumeGroups.get(c).updateDevices(useCoreAudioRouting);
+ }
+ }
+
static final class Builder {
private final int mZoneId;
private final int mZoneConfigId;
diff --git a/service/src/com/android/car/audio/CarVolumeGroup.java b/service/src/com/android/car/audio/CarVolumeGroup.java
index 79bdf94..de0d225 100644
--- a/service/src/com/android/car/audio/CarVolumeGroup.java
+++ b/service/src/com/android/car/audio/CarVolumeGroup.java
@@ -346,6 +346,10 @@
return carAudioContexts;
}
+ protected AudioAttributes[] getAudioAttributesForContext(int context) {
+ return mCarAudioContext.getAudioAttributesForContext(context);
+ }
+
/**
* Returns the id of the volume group.
* <p> Note that all clients are already developed in the way that when they get the number of
@@ -920,6 +924,9 @@
}
}
+ void updateDevices(boolean useCoreAudioRouting) {
+ }
+
/**
* Calculates the new gain stages from list of assigned audio device infos
*
diff --git a/service/src/com/android/car/audio/CoreAudioHelper.java b/service/src/com/android/car/audio/CoreAudioHelper.java
index 9302d35..11a76a4 100644
--- a/service/src/com/android/car/audio/CoreAudioHelper.java
+++ b/service/src/com/android/car/audio/CoreAudioHelper.java
@@ -102,7 +102,7 @@
* given {@link AudioAttributes} if found, {@link #INVALID_STRATEGY} id otherwise.
*/
public static int getStrategyForAudioAttributes(AudioAttributes attributes) {
- Preconditions.checkNotNull(attributes, "Audio Attributes must not be null");
+ Preconditions.checkNotNull(attributes, "Audio Attributes can not be null");
for (int index = 0; index < getAudioProductStrategies().size(); index++) {
AudioProductStrategy strategy = getAudioProductStrategies().get(index);
if (strategy.supportsAudioAttributes(attributes)) {
@@ -113,7 +113,7 @@
}
public static int getStrategyForContextName(String contextName) {
- Preconditions.checkNotNull(contextName, "Context name must not be null");
+ Preconditions.checkNotNull(contextName, "Context name can not be null");
for (int index = 0; index < getAudioProductStrategies().size(); index++) {
AudioProductStrategy strategy = getAudioProductStrategies().get(index);
if (Objects.equals(strategy.getName(), contextName)) {
@@ -139,6 +139,20 @@
? getStrategyForAudioAttributes(DEFAULT_ATTRIBUTES) : strategyId;
}
+ @Nullable
+ static AudioProductStrategy getProductStrategyForAudioAttributes(
+ AudioAttributes attributes) {
+ Preconditions.checkNotNull(attributes, "Audio attributes can not be null");
+ for (int index = 0; index < getAudioProductStrategies().size(); index++) {
+ AudioProductStrategy strategy = getAudioProductStrategies().get(index);
+ if (!strategy.supportsAudioAttributes(attributes)) {
+ continue;
+ }
+ return strategy;
+ }
+ return null;
+ }
+
/**
* Gets the {@link AudioProductStrategy} referred by its unique identifier.
*
@@ -236,7 +250,7 @@
*/
@Nullable
public static String getVolumeGroupNameForAudioAttributes(AudioAttributes attributes) {
- Preconditions.checkNotNull(attributes, "Audio Attributes must not be null");
+ Preconditions.checkNotNull(attributes, "Audio Attributes can not be null");
int volumeGroupId = getVolumeGroupIdForAudioAttributes(attributes);
return volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP
? getVolumeGroupNameFromCoreId(volumeGroupId) : null;
@@ -261,7 +275,7 @@
* if found, {@link #INVALID_GROUP_ID} otherwise.
*/
public static int getVolumeGroupIdForAudioAttributes(AudioAttributes attributes) {
- Preconditions.checkNotNull(attributes, "Audio Attributes must not be null");
+ Preconditions.checkNotNull(attributes, "Audio Attributes can not be null");
for (int index = 0; index < getAudioProductStrategies().size(); index++) {
AudioProductStrategy strategy = getAudioProductStrategies().get(index);
int volumeGroupId =
diff --git a/service/src/com/android/car/audio/CoreAudioVolumeGroup.java b/service/src/com/android/car/audio/CoreAudioVolumeGroup.java
index 7e41886..fea621f 100644
--- a/service/src/com/android/car/audio/CoreAudioVolumeGroup.java
+++ b/service/src/com/android/car/audio/CoreAudioVolumeGroup.java
@@ -20,18 +20,25 @@
import static android.car.media.CarVolumeGroupEvent.EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED;
import static com.android.car.CarLog.TAG_AUDIO;
+import static com.android.car.audio.CoreAudioHelper.getProductStrategyForAudioAttributes;
import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
import android.car.builtin.media.AudioManagerHelper;
import android.car.builtin.util.Slogf;
import android.media.AudioAttributes;
+import android.media.AudioDeviceAttributes;
import android.media.AudioManager;
+import android.media.audiopolicy.AudioProductStrategy;
+import android.util.ArraySet;
import android.util.SparseArray;
import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
import com.android.car.internal.util.IndentingPrintWriter;
import com.android.internal.annotations.GuardedBy;
+import java.util.Arrays;
+import java.util.List;
+
/**
* A class encapsulates a volume group in car.
*
@@ -283,6 +290,41 @@
}
@Override
+ void updateDevices(boolean useCoreAudioRouting) {
+ // If not using core audio routing, than device need to be updated to match the information
+ // for audio attributes to core volume groups.
+ if (useCoreAudioRouting) {
+ return;
+ }
+
+ int[] contexts = getContexts();
+ for (int c = 0; c < contexts.length; c++) {
+ int context = contexts[c];
+ AudioAttributes[] audioAttributes = getAudioAttributesForContext(context);
+ AudioDeviceAttributes device = getAudioDeviceForContext(context);
+ setPreferredDeviceForAudioAttribute(Arrays.asList(audioAttributes), device);
+ }
+
+ }
+
+ private void setPreferredDeviceForAudioAttribute(List<AudioAttributes> audioAttributes,
+ AudioDeviceAttributes audioDeviceAttributes) {
+ ArraySet<Integer> strategiesSet = new ArraySet<>();
+ for (int c = 0; c < audioAttributes.size(); c++) {
+ AudioProductStrategy strategy =
+ getProductStrategyForAudioAttributes(audioAttributes.get(c));
+ if (strategy == null) {
+ continue;
+ }
+ if (!strategiesSet.add(strategy.getId())) {
+ continue;
+ }
+ mAudioManager.setPreferredDeviceForStrategy(strategy, audioDeviceAttributes);
+ }
+ }
+
+
+ @Override
protected int getDefaultGainIndex() {
return mDefaultGainIndex;
}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioZoneConfigUnitTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioZoneConfigUnitTest.java
index 8eb88db..9f6b808 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioZoneConfigUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioZoneConfigUnitTest.java
@@ -282,6 +282,30 @@
}
@Test
+ public void updateVolumeDevices_withUseCoreAudioRoutingEnabled() {
+ CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.addVolumeGroup(mMockMusicGroup)
+ .addVolumeGroup(mMockNavGroup).build();
+ boolean useCoreAudioRouting = true;
+
+ zoneConfig.updateVolumeDevices(useCoreAudioRouting);
+
+ verify(mMockMusicGroup).updateDevices(useCoreAudioRouting);
+ verify(mMockNavGroup).updateDevices(useCoreAudioRouting);
+ }
+
+ @Test
+ public void updateVolumeDevices_withUseCoreAudioRoutingDisabled() {
+ CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.addVolumeGroup(mMockMusicGroup)
+ .addVolumeGroup(mMockNavGroup).build();
+ boolean useCoreAudioRouting = false;
+
+ zoneConfig.updateVolumeDevices(useCoreAudioRouting);
+
+ verify(mMockMusicGroup).updateDevices(useCoreAudioRouting);
+ verify(mMockNavGroup).updateDevices(useCoreAudioRouting);
+ }
+
+ @Test
public void validateCanUseDynamicMixRouting_addressSharedAmongGroups_forbidUseDynamicRouting() {
CarAudioDeviceInfo musicCarAudioDeviceInfo = Mockito.mock(CarAudioDeviceInfo.class);
CarVolumeGroup mockMusicGroup = new VolumeGroupBuilder()
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioZoneUnitTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioZoneUnitTest.java
index eb53ca1..13cc386 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioZoneUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioZoneUnitTest.java
@@ -260,7 +260,7 @@
public void isCurrentZoneConfig_forCurrentConfig_returnsFalse() {
mTestAudioZone.addZoneConfig(mMockZoneConfig0);
mTestAudioZone.addZoneConfig(mMockZoneConfig1);
- CarAudioZoneConfigInfo nonCurrentZoneConfigInfo = getNonCurrentZoneConfigInfo();
+ CarAudioZoneConfigInfo nonCurrentZoneConfigInfo = getFirstNonCurrentZoneConfigInfo();
expectWithMessage("Non-current zone config info")
.that(mTestAudioZone.isCurrentZoneConfig(nonCurrentZoneConfigInfo))
@@ -268,10 +268,10 @@
}
@Test
- public void setCurrentCarZoneConfig() {
+ public void setCurrentCarZoneConfig_withCoreAudioRoutingDisabled() {
mTestAudioZone.addZoneConfig(mMockZoneConfig0);
mTestAudioZone.addZoneConfig(mMockZoneConfig1);
- CarAudioZoneConfigInfo currentZoneConfigInfoToSwitch = getNonCurrentZoneConfigInfo();
+ CarAudioZoneConfigInfo currentZoneConfigInfoToSwitch = getFirstNonCurrentZoneConfigInfo();
mTestAudioZone.setCurrentCarZoneConfig(currentZoneConfigInfoToSwitch);
@@ -279,6 +279,29 @@
.that(mTestAudioZone.isCurrentZoneConfig(currentZoneConfigInfoToSwitch))
.isTrue();
verify(mMockZoneConfig1).setIsSelected(true);
+ verify(mMockZoneConfig1).updateVolumeDevices(/* useCoreAudioRouting= */ false);
+ verify(mMockZoneConfig0).setIsSelected(false);
+ }
+
+ @Test
+ public void setCurrentCarZoneConfig_withCoreAudioRoutingEnabled() {
+ CarAudioContext contextWithCoreAudioRouting =
+ new CarAudioContext(CarAudioContext.getAllContextsInfo(),
+ /* useCoreAudioRouting= */ true);
+ CarAudioZone testAudioZone = new CarAudioZone(contextWithCoreAudioRouting, TEST_ZONE_NAME,
+ TEST_ZONE_ID);
+ testAudioZone.addZoneConfig(mMockZoneConfig0);
+ testAudioZone.addZoneConfig(mMockZoneConfig1);
+ CarAudioZoneConfigInfo currentZoneConfigInfoToSwitch =
+ getFirstNonCurrentZoneConfigInfo(testAudioZone);
+
+ testAudioZone.setCurrentCarZoneConfig(currentZoneConfigInfoToSwitch);
+
+ expectWithMessage("Current zone config info after switching zone configuration"
+ + "with core audio routing")
+ .that(testAudioZone.isCurrentZoneConfig(currentZoneConfigInfoToSwitch)).isTrue();
+ verify(mMockZoneConfig1).setIsSelected(true);
+ verify(mMockZoneConfig1).updateVolumeDevices(/* useCoreAudioRouting= */ true);
verify(mMockZoneConfig0).setIsSelected(false);
}
@@ -819,11 +842,10 @@
.hasMessageThat().contains("Audio devices");
}
- private CarAudioZoneConfigInfo getNonCurrentZoneConfigInfo() {
- CarAudioZoneConfigInfo currentZoneConfigInfo = mTestAudioZone
- .getCurrentCarAudioZoneConfig().getCarAudioZoneConfigInfo();
- List<CarAudioZoneConfigInfo> zoneConfigInfoList = mTestAudioZone
- .getCarAudioZoneConfigInfos();
+ private CarAudioZoneConfigInfo getFirstNonCurrentZoneConfigInfo(CarAudioZone audioZone) {
+ CarAudioZoneConfigInfo currentZoneConfigInfo = audioZone.getCurrentCarAudioZoneConfig()
+ .getCarAudioZoneConfigInfo();
+ List<CarAudioZoneConfigInfo> zoneConfigInfoList = audioZone.getCarAudioZoneConfigInfos();
for (int index = 0; index < zoneConfigInfoList.size(); index++) {
CarAudioZoneConfigInfo zoneConfigInfo = zoneConfigInfoList.get(index);
if (!currentZoneConfigInfo.equals(zoneConfigInfo)) {
@@ -833,6 +855,10 @@
return null;
}
+ private CarAudioZoneConfigInfo getFirstNonCurrentZoneConfigInfo() {
+ return getFirstNonCurrentZoneConfigInfo(mTestAudioZone);
+ }
+
private static final class TestCarAudioZoneConfigBuilder {
private static final int INVALID_GROUP_ID = -1;
private static final int INVALID_EVENT_TYPE = 0;
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CoreAudioHelperTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CoreAudioHelperTest.java
index 3fa9ab2..6b329b7 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CoreAudioHelperTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CoreAudioHelperTest.java
@@ -45,6 +45,8 @@
import static com.android.car.audio.CoreAudioRoutingUtils.UNSUPPORTED_ATTRIBUTES;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static org.junit.Assert.assertThrows;
+
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
import android.media.AudioManager;
import android.media.audiopolicy.AudioProductStrategy;
@@ -123,6 +125,35 @@
}
@Test
+ public void getProductStrategyForAudioAttributes_withValidAttributes_succeeds() {
+ expectWithMessage("Music product strategy")
+ .that(CoreAudioHelper.getProductStrategyForAudioAttributes(MUSIC_ATTRIBUTES))
+ .isEqualTo(MUSIC_STRATEGY);
+ expectWithMessage("Navigation product strategy")
+ .that(CoreAudioHelper.getProductStrategyForAudioAttributes(NAV_ATTRIBUTES))
+ .isEqualTo(NAV_STRATEGY);
+ expectWithMessage("OEM product strategy")
+ .that(CoreAudioHelper.getProductStrategyForAudioAttributes(OEM_ATTRIBUTES))
+ .isEqualTo(OEM_STRATEGY);
+ }
+
+ @Test
+ public void getProductStrategyForAudioAttributes_withInvalidAttributes_returnsNull() {
+ expectWithMessage("Null product strategy for invalid audio attribute")
+ .that(CoreAudioHelper.getProductStrategyForAudioAttributes(UNSUPPORTED_ATTRIBUTES))
+ .isNull();
+ }
+
+ @Test
+ public void getProductStrategyForAudioAttributes_withNullAttributes_fails() {
+ NullPointerException exception = assertThrows(NullPointerException.class, () ->
+ CoreAudioHelper.getProductStrategyForAudioAttributes(null));
+
+ expectWithMessage("Null audio attributes exception").that(exception).hasMessageThat()
+ .contains("Audio attributes");
+ }
+
+ @Test
public void getStrategyForContextName_succeeds() {
expectWithMessage("Music strategy for context name (%s)", MUSIC_CONTEXT_NAME)
.that(CoreAudioHelper.getStrategyForContextName(MUSIC_CONTEXT_NAME))
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CoreAudioVolumeGroupTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CoreAudioVolumeGroupTest.java
index 403337b..da34646 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CoreAudioVolumeGroupTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CoreAudioVolumeGroupTest.java
@@ -23,6 +23,7 @@
import static android.car.test.mocks.AndroidMockitoHelper.mockCarGetPlatformVersion;
import static com.android.car.audio.CoreAudioRoutingUtils.MEDIA_CONTEXT_INFO;
+import static com.android.car.audio.CoreAudioRoutingUtils.MOVIE_ATTRIBUTES;
import static com.android.car.audio.CoreAudioRoutingUtils.MUSIC_AM_INIT_INDEX;
import static com.android.car.audio.CoreAudioRoutingUtils.MUSIC_ATTRIBUTES;
import static com.android.car.audio.CoreAudioRoutingUtils.MUSIC_CAR_GROUP_ID;
@@ -31,6 +32,7 @@
import static com.android.car.audio.CoreAudioRoutingUtils.MUSIC_GROUP_NAME;
import static com.android.car.audio.CoreAudioRoutingUtils.MUSIC_MAX_INDEX;
import static com.android.car.audio.CoreAudioRoutingUtils.MUSIC_MIN_INDEX;
+import static com.android.car.audio.CoreAudioRoutingUtils.MUSIC_STRATEGY;
import static com.android.car.audio.CoreAudioRoutingUtils.MUSIC_STRATEGY_ID;
import static com.android.car.audio.CoreAudioRoutingUtils.NAV_ATTRIBUTES;
import static com.android.car.audio.CoreAudioRoutingUtils.NAV_CAR_GROUP_ID;
@@ -57,11 +59,14 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.when;
import android.car.Car;
import android.car.builtin.media.AudioManagerHelper;
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.util.SparseArray;
@@ -93,6 +98,7 @@
private CoreAudioVolumeGroup mMusicCoreAudioVolumeGroup;
private CoreAudioVolumeGroup mNavCoreAudioVolumeGroup;
private CoreAudioVolumeGroup mOemCoreAudioVolumeGroup;
+ private AudioDeviceAttributes mMusicDeviceAttributes;
public CoreAudioVolumeGroupTest() {
super(CoreAudioVolumeGroup.TAG);
@@ -107,8 +113,11 @@
void setupMock() {
doReturn(MUSIC_GROUP_ID)
.when(() -> CoreAudioHelper.getVolumeGroupIdForAudioAttributes(MUSIC_ATTRIBUTES));
- doReturn(MUSIC_ATTRIBUTES)
- .when(() ->
+ doReturn(MUSIC_STRATEGY)
+ .when(() -> CoreAudioHelper.getProductStrategyForAudioAttributes(MUSIC_ATTRIBUTES));
+ doReturn(MUSIC_STRATEGY)
+ .when(() -> CoreAudioHelper.getProductStrategyForAudioAttributes(MOVIE_ATTRIBUTES));
+ doReturn(MUSIC_ATTRIBUTES).when(() ->
CoreAudioHelper.selectAttributesForVolumeGroupName(eq(MUSIC_GROUP_NAME)));
when(mMockAudioManager.getMinVolumeIndexForAttributes(MUSIC_ATTRIBUTES))
.thenReturn(MUSIC_MIN_INDEX);
@@ -156,9 +165,12 @@
mOemContext = new CarAudioContext(
List.of(OEM_CONTEXT_INFO), /* useCoreAudioRouting= */ true);
+ mMusicDeviceAttributes = new AudioDeviceAttributes(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+ MUSIC_DEVICE_ADDRESS);
SparseArray<CarAudioDeviceInfo> musicContextToDeviceInfo = new SparseArray<>();
musicContextToDeviceInfo.put(MUSIC_STRATEGY_ID, mOemInfoMock);
when(mOemInfoMock.getAddress()).thenReturn(MUSIC_DEVICE_ADDRESS);
+ when(mOemInfoMock.getAudioDevice()).thenReturn(mMusicDeviceAttributes);
mMusicCoreAudioVolumeGroup = new CoreAudioVolumeGroup(mMockAudioManager, mMusicContext,
mSettingsMock, musicContextToDeviceInfo, PRIMARY_AUDIO_ZONE, ZONE_CONFIG_ID,
MUSIC_CAR_GROUP_ID, MUSIC_GROUP_NAME, /* useCarVolumeGroupMute= */ false);
@@ -513,4 +525,24 @@
.that(mMusicCoreAudioVolumeGroup.getCurrentGainIndex())
.isEqualTo(MUSIC_AM_INIT_INDEX + 1);
}
+
+ @Test
+ public void updateDevices_withCoreAudioRoutingDisabled() {
+ boolean useCoreAudioRouting = false;
+
+ mMusicCoreAudioVolumeGroup.updateDevices(useCoreAudioRouting);
+
+ verify(mMockAudioManager).setPreferredDeviceForStrategy(MUSIC_STRATEGY,
+ mMusicDeviceAttributes);
+ }
+
+ @Test
+ public void updateDevices_withCoreAudioRoutingEnabled() {
+ boolean useCoreAudioRouting = true;
+
+ mMusicCoreAudioVolumeGroup.updateDevices(useCoreAudioRouting);
+
+ verify(mMockAudioManager, never()).setPreferredDeviceForStrategy(MUSIC_STRATEGY,
+ mMusicDeviceAttributes);
+ }
}