[IMPR] AudioService: VolumeGroupState: improve implementation am: 8d35da7ed7

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20784867

Change-Id: I57141809d97462dae06be2d275972324ff302105
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Francois Gaffie
2023-01-27 17:12:24 +00:00
committed by Automerger Merge Worker

View File

@@ -3681,7 +3681,7 @@ public class AudioService extends IAudioService.Stub
VolumeGroupState vgs = sVolumeGroupStates.get(volumeGroup); VolumeGroupState vgs = sVolumeGroupStates.get(volumeGroup);
sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_GROUP_VOL, attr, vgs.name(), sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_GROUP_VOL, attr, vgs.name(),
index/*val1*/, flags/*val2*/, callingPackage)); index, flags, callingPackage + ", user " + getCurrentUserId()));
vgs.setVolumeIndex(index, flags); vgs.setVolumeIndex(index, flags);
@@ -3702,7 +3702,7 @@ public class AudioService extends IAudioService.Stub
@Nullable @Nullable
private AudioVolumeGroup getAudioVolumeGroupById(int volumeGroupId) { private AudioVolumeGroup getAudioVolumeGroupById(int volumeGroupId) {
for (final AudioVolumeGroup avg : AudioVolumeGroup.getAudioVolumeGroups()) { for (AudioVolumeGroup avg : AudioVolumeGroup.getAudioVolumeGroups()) {
if (avg.getId() == volumeGroupId) { if (avg.getId() == volumeGroupId) {
return avg; return avg;
} }
@@ -3716,14 +3716,15 @@ public class AudioService extends IAudioService.Stub
public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) { public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
enforceModifyAudioRoutingPermission(); enforceModifyAudioRoutingPermission();
Objects.requireNonNull(attr, "attr must not be null"); Objects.requireNonNull(attr, "attr must not be null");
final int volumeGroup = synchronized (VolumeStreamState.class) {
AudioProductStrategy.getVolumeGroupIdForAudioAttributes( int volumeGroup = AudioProductStrategy.getVolumeGroupIdForAudioAttributes(
attr, /* fallbackOnDefault= */false); attr, /* fallbackOnDefault= */false);
if (sVolumeGroupStates.indexOfKey(volumeGroup) < 0) { if (sVolumeGroupStates.indexOfKey(volumeGroup) < 0) {
throw new IllegalArgumentException("No volume group for attributes " + attr); throw new IllegalArgumentException("No volume group for attributes " + attr);
}
VolumeGroupState vgs = sVolumeGroupStates.get(volumeGroup);
return vgs.isMuted() ? vgs.getMinIndex() : vgs.getVolumeIndex();
} }
final VolumeGroupState vgs = sVolumeGroupStates.get(volumeGroup);
return vgs.getVolumeIndex();
} }
/** @see AudioManager#getMaxVolumeIndexForAttributes(attr) */ /** @see AudioManager#getMaxVolumeIndexForAttributes(attr) */
@@ -5818,7 +5819,7 @@ public class AudioService extends IAudioService.Stub
} }
} }
readVolumeGroupsSettings(); readVolumeGroupsSettings(userSwitch);
if (DEBUG_VOL) { if (DEBUG_VOL) {
Log.d(TAG, "Restoring device volume behavior"); Log.d(TAG, "Restoring device volume behavior");
@@ -7270,6 +7271,7 @@ public class AudioService extends IAudioService.Stub
try { try {
// if no valid attributes, this volume group is not controllable, throw exception // if no valid attributes, this volume group is not controllable, throw exception
ensureValidAttributes(avg); ensureValidAttributes(avg);
sVolumeGroupStates.append(avg.getId(), new VolumeGroupState(avg));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
// Volume Groups without attributes are not controllable through set/get volume // Volume Groups without attributes are not controllable through set/get volume
// using attributes. Do not append them. // using attributes. Do not append them.
@@ -7278,11 +7280,10 @@ public class AudioService extends IAudioService.Stub
} }
continue; continue;
} }
sVolumeGroupStates.append(avg.getId(), new VolumeGroupState(avg));
} }
for (int i = 0; i < sVolumeGroupStates.size(); i++) { for (int i = 0; i < sVolumeGroupStates.size(); i++) {
final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i); final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i);
vgs.applyAllVolumes(); vgs.applyAllVolumes(/* userSwitch= */ false);
} }
} }
@@ -7295,14 +7296,22 @@ public class AudioService extends IAudioService.Stub
} }
} }
private void readVolumeGroupsSettings() { private void readVolumeGroupsSettings(boolean userSwitch) {
if (DEBUG_VOL) { synchronized (mSettingsLock) {
Log.v(TAG, "readVolumeGroupsSettings"); synchronized (VolumeStreamState.class) {
} if (DEBUG_VOL) {
for (int i = 0; i < sVolumeGroupStates.size(); i++) { Log.d(TAG, "readVolumeGroupsSettings userSwitch=" + userSwitch);
final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i); }
vgs.readSettings(); for (int i = 0; i < sVolumeGroupStates.size(); i++) {
vgs.applyAllVolumes(); VolumeGroupState vgs = sVolumeGroupStates.valueAt(i);
// as for STREAM_MUSIC, preserve volume from one user to the next.
if (!(userSwitch && vgs.isMusic())) {
vgs.clearIndexCache();
vgs.readSettings();
}
vgs.applyAllVolumes(userSwitch);
}
}
} }
} }
@@ -7313,7 +7322,7 @@ public class AudioService extends IAudioService.Stub
} }
for (int i = 0; i < sVolumeGroupStates.size(); i++) { for (int i = 0; i < sVolumeGroupStates.size(); i++) {
final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i); final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i);
vgs.applyAllVolumes(); vgs.applyAllVolumes(false/*userSwitch*/);
} }
} }
@@ -7326,17 +7335,24 @@ public class AudioService extends IAudioService.Stub
} }
} }
private static boolean isCallStream(int stream) {
return stream == AudioSystem.STREAM_VOICE_CALL
|| stream == AudioSystem.STREAM_BLUETOOTH_SCO;
}
// NOTE: Locking order for synchronized objects related to volume management: // NOTE: Locking order for synchronized objects related to volume management:
// 1 mSettingsLock // 1 mSettingsLock
// 2 VolumeGroupState.class // 2 VolumeStreamState.class
private class VolumeGroupState { private class VolumeGroupState {
private final AudioVolumeGroup mAudioVolumeGroup; private final AudioVolumeGroup mAudioVolumeGroup;
private final SparseIntArray mIndexMap = new SparseIntArray(8); private final SparseIntArray mIndexMap = new SparseIntArray(8);
private int mIndexMin; private int mIndexMin;
private int mIndexMax; private int mIndexMax;
private int mLegacyStreamType = AudioSystem.STREAM_DEFAULT; private boolean mHasValidStreamType = false;
private int mPublicStreamType = AudioSystem.STREAM_MUSIC; private int mPublicStreamType = AudioSystem.STREAM_MUSIC;
private AudioAttributes mAudioAttributes = AudioProductStrategy.getDefaultAttributes(); private AudioAttributes mAudioAttributes = AudioProductStrategy.getDefaultAttributes();
private boolean mIsMuted = false;
private final String mSettingName;
// No API in AudioSystem to get a device from strategy or from attributes. // No API in AudioSystem to get a device from strategy or from attributes.
// Need a valid public stream type to use current API getDeviceForStream // Need a valid public stream type to use current API getDeviceForStream
@@ -7350,20 +7366,22 @@ public class AudioService extends IAudioService.Stub
Log.v(TAG, "VolumeGroupState for " + avg.toString()); Log.v(TAG, "VolumeGroupState for " + avg.toString());
} }
// mAudioAttributes is the default at this point // mAudioAttributes is the default at this point
for (final AudioAttributes aa : avg.getAudioAttributes()) { for (AudioAttributes aa : avg.getAudioAttributes()) {
if (!aa.equals(mAudioAttributes)) { if (!aa.equals(mAudioAttributes)) {
mAudioAttributes = aa; mAudioAttributes = aa;
break; break;
} }
} }
final int[] streamTypes = mAudioVolumeGroup.getLegacyStreamTypes(); int[] streamTypes = mAudioVolumeGroup.getLegacyStreamTypes();
String streamSettingName = "";
if (streamTypes.length != 0) { if (streamTypes.length != 0) {
// Uses already initialized MIN / MAX if a stream type is attached to group // Uses already initialized MIN / MAX if a stream type is attached to group
mLegacyStreamType = streamTypes[0]; for (int streamType : streamTypes) {
for (final int streamType : streamTypes) {
if (streamType != AudioSystem.STREAM_DEFAULT if (streamType != AudioSystem.STREAM_DEFAULT
&& streamType < AudioSystem.getNumStreamTypes()) { && streamType < AudioSystem.getNumStreamTypes()) {
mPublicStreamType = streamType; mPublicStreamType = streamType;
mHasValidStreamType = true;
streamSettingName = System.VOLUME_SETTINGS_INT[mPublicStreamType];
break; break;
} }
} }
@@ -7373,10 +7391,10 @@ public class AudioService extends IAudioService.Stub
mIndexMin = AudioSystem.getMinVolumeIndexForAttributes(mAudioAttributes); mIndexMin = AudioSystem.getMinVolumeIndexForAttributes(mAudioAttributes);
mIndexMax = AudioSystem.getMaxVolumeIndexForAttributes(mAudioAttributes); mIndexMax = AudioSystem.getMaxVolumeIndexForAttributes(mAudioAttributes);
} else { } else {
Log.e(TAG, "volume group: " + mAudioVolumeGroup.name() throw new IllegalArgumentException("volume group: " + mAudioVolumeGroup.name()
+ " has neither valid attributes nor valid stream types assigned"); + " has neither valid attributes nor valid stream types assigned");
return;
} }
mSettingName = !streamSettingName.isEmpty() ? streamSettingName : ("volume_" + name());
// Load volume indexes from data base // Load volume indexes from data base
readSettings(); readSettings();
} }
@@ -7389,40 +7407,101 @@ public class AudioService extends IAudioService.Stub
return mAudioVolumeGroup.name(); return mAudioVolumeGroup.name();
} }
/**
* Volume group with non null minimum index are considered as non mutable, thus
* bijectivity is broken with potential associated stream type.
* VOICE_CALL stream has minVolumeIndex > 0 but can be muted directly by an
* app that has MODIFY_PHONE_STATE permission.
*/
private boolean isVssMuteBijective(int stream) {
return isStreamAffectedByMute(stream)
&& (getMinIndex() == (mStreamStates[stream].mIndexMin + 5) / 10)
&& (getMinIndex() == 0 || isCallStream(stream));
}
private boolean isMutable() {
return mIndexMin == 0 || (mHasValidStreamType && isVssMuteBijective(mPublicStreamType));
}
/**
* Mute/unmute the volume group
* @param muted the new mute state
*/
@GuardedBy("AudioService.VolumeStreamState.class")
public boolean mute(boolean muted) {
if (!isMutable()) {
// Non mutable volume group
if (DEBUG_VOL) {
Log.d(TAG, "invalid mute on unmutable volume group " + name());
}
return false;
}
boolean changed = (mIsMuted != muted);
// As for VSS, mute shall apply minIndex to all devices found in IndexMap and default.
if (changed) {
mIsMuted = muted;
applyAllVolumes(false /*userSwitch*/);
}
return changed;
}
public boolean isMuted() {
return mIsMuted;
}
public int getVolumeIndex() { public int getVolumeIndex() {
return getIndex(getDeviceForVolume()); synchronized (VolumeStreamState.class) {
return getIndex(getDeviceForVolume());
}
} }
public void setVolumeIndex(int index, int flags) { public void setVolumeIndex(int index, int flags) {
if (mUseFixedVolume) { synchronized (VolumeStreamState.class) {
return; if (mUseFixedVolume) {
return;
}
setVolumeIndex(index, getDeviceForVolume(), flags);
} }
setVolumeIndex(index, getDeviceForVolume(), flags);
} }
@GuardedBy("AudioService.VolumeStreamState.class")
private void setVolumeIndex(int index, int device, int flags) { private void setVolumeIndex(int index, int device, int flags) {
// Set the volume index // Update cache & persist (muted by volume 0 shall be persisted)
setVolumeIndexInt(index, device, flags); updateVolumeIndex(index, device);
// setting non-zero volume for a muted stream unmutes the stream and vice versa,
// Update local cache boolean changed = mute(index == 0);
mIndexMap.put(device, index); if (!changed) {
// Set the volume index only if mute operation is a no-op
// update data base - post a persist volume group msg index = getValidIndex(index);
sendMsg(mAudioHandler, setVolumeIndexInt(index, device, flags);
MSG_PERSIST_VOLUME_GROUP, }
SENDMSG_QUEUE,
device,
0,
this,
PERSIST_DELAY);
} }
@GuardedBy("AudioService.VolumeStreamState.class")
public void updateVolumeIndex(int index, int device) {
// Filter persistency if already exist and the index has not changed
if (mIndexMap.indexOfKey(device) < 0 || mIndexMap.get(device) != index) {
// Update local cache
mIndexMap.put(device, getValidIndex(index));
// update data base - post a persist volume group msg
sendMsg(mAudioHandler,
MSG_PERSIST_VOLUME_GROUP,
SENDMSG_QUEUE,
device,
0,
this,
PERSIST_DELAY);
}
}
@GuardedBy("AudioService.VolumeStreamState.class")
private void setVolumeIndexInt(int index, int device, int flags) { private void setVolumeIndexInt(int index, int device, int flags) {
// Reflect mute state of corresponding stream by forcing index to 0 if muted // Reflect mute state of corresponding stream by forcing index to 0 if muted
// Only set audio policy BT SCO stream volume to 0 when the stream is actually muted. // Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
// This allows RX path muting by the audio HAL only when explicitly muted but not when // This allows RX path muting by the audio HAL only when explicitly muted but not when
// index is just set to 0 to repect BT requirements // index is just set to 0 to repect BT requirements
if (mStreamStates[mPublicStreamType].isFullyMuted()) { if (mHasValidStreamType && isVssMuteBijective(mPublicStreamType)
&& mStreamStates[mPublicStreamType].isFullyMuted()) {
index = 0; index = 0;
} else if (mPublicStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0) { } else if (mPublicStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0) {
index = 1; index = 1;
@@ -7431,18 +7510,16 @@ public class AudioService extends IAudioService.Stub
AudioSystem.setVolumeIndexForAttributes(mAudioAttributes, index, device); AudioSystem.setVolumeIndexForAttributes(mAudioAttributes, index, device);
} }
public int getIndex(int device) { @GuardedBy("AudioService.VolumeStreamState.class")
synchronized (VolumeGroupState.class) { private int getIndex(int device) {
int index = mIndexMap.get(device, -1); int index = mIndexMap.get(device, -1);
// there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
return (index != -1) ? index : mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT); return (index != -1) ? index : mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
}
} }
public boolean hasIndexForDevice(int device) { @GuardedBy("AudioService.VolumeStreamState.class")
synchronized (VolumeGroupState.class) { private boolean hasIndexForDevice(int device) {
return (mIndexMap.get(device, -1) != -1); return (mIndexMap.get(device, -1) != -1);
}
} }
public int getMaxIndex() { public int getMaxIndex() {
@@ -7453,55 +7530,108 @@ public class AudioService extends IAudioService.Stub
return mIndexMin; return mIndexMin;
} }
private boolean isValidLegacyStreamType() { private boolean isValidStream(int stream) {
return (mLegacyStreamType != AudioSystem.STREAM_DEFAULT) return (stream != AudioSystem.STREAM_DEFAULT) && (stream < mStreamStates.length);
&& (mLegacyStreamType < mStreamStates.length);
} }
public void applyAllVolumes() { public boolean isMusic() {
synchronized (VolumeGroupState.class) { return mHasValidStreamType && mPublicStreamType == AudioSystem.STREAM_MUSIC;
int deviceForStream = AudioSystem.DEVICE_NONE; }
int volumeIndexForStream = 0;
if (isValidLegacyStreamType()) { public void applyAllVolumes(boolean userSwitch) {
// Prevent to apply settings twice when group is associated to public stream String caller = "from vgs";
deviceForStream = getDeviceForStream(mLegacyStreamType); synchronized (VolumeStreamState.class) {
volumeIndexForStream = getStreamVolume(mLegacyStreamType);
}
// apply device specific volumes first // apply device specific volumes first
int index;
for (int i = 0; i < mIndexMap.size(); i++) { for (int i = 0; i < mIndexMap.size(); i++) {
final int device = mIndexMap.keyAt(i); int device = mIndexMap.keyAt(i);
int index = mIndexMap.valueAt(i);
boolean synced = false;
if (device != AudioSystem.DEVICE_OUT_DEFAULT) { if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
index = mIndexMap.valueAt(i); for (int stream : getLegacyStreamTypes()) {
if (device == deviceForStream && volumeIndexForStream == index) { if (isValidStream(stream)) {
continue; boolean streamMuted = mStreamStates[stream].mIsMuted;
int deviceForStream = getDeviceForStream(stream);
int indexForStream =
(mStreamStates[stream].getIndex(deviceForStream) + 5) / 10;
if (device == deviceForStream) {
if (indexForStream == index && (isMuted() == streamMuted)
&& isVssMuteBijective(stream)) {
synced = true;
continue;
}
if (indexForStream != index) {
mStreamStates[stream].setIndex(index * 10, device, caller,
true /*hasModifyAudioSettings*/);
}
if ((isMuted() != streamMuted) && isVssMuteBijective(stream)) {
mStreamStates[stream].mute(isMuted());
}
}
}
} }
if (DEBUG_VOL) { if (!synced) {
Log.v(TAG, "applyAllVolumes: restore index " + index + " for group " if (DEBUG_VOL) {
+ mAudioVolumeGroup.name() + " and device " Log.d(TAG, "applyAllVolumes: apply index " + index + ", group "
+ AudioSystem.getOutputDeviceName(device)); + mAudioVolumeGroup.name() + " and device "
+ AudioSystem.getOutputDeviceName(device));
}
setVolumeIndexInt(isMuted() ? 0 : index, device, 0 /*flags*/);
} }
setVolumeIndexInt(index, device, 0 /*flags*/);
} }
} }
// apply default volume last: by convention , default device volume will be used // apply default volume last: by convention , default device volume will be used
// by audio policy manager if no explicit volume is present for a given device type // by audio policy manager if no explicit volume is present for a given device type
index = getIndex(AudioSystem.DEVICE_OUT_DEFAULT); int index = getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
if (DEBUG_VOL) { boolean synced = false;
Log.v(TAG, "applyAllVolumes: restore default device index " + index int deviceForVolume = getDeviceForVolume();
+ " for group " + mAudioVolumeGroup.name()); boolean forceDeviceSync = userSwitch && (mIndexMap.indexOfKey(deviceForVolume) < 0);
} for (int stream : getLegacyStreamTypes()) {
if (isValidLegacyStreamType()) { if (isValidStream(stream)) {
int defaultStreamIndex = (mStreamStates[mLegacyStreamType] boolean streamMuted = mStreamStates[stream].mIsMuted;
.getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5) / 10; int defaultStreamIndex = (mStreamStates[stream].getIndex(
if (defaultStreamIndex == index) { AudioSystem.DEVICE_OUT_DEFAULT) + 5) / 10;
return; if (forceDeviceSync) {
mStreamStates[stream].setIndex(index * 10, deviceForVolume, caller,
true /*hasModifyAudioSettings*/);
}
if (defaultStreamIndex == index && (isMuted() == streamMuted)
&& isVssMuteBijective(stream)) {
synced = true;
continue;
}
if (defaultStreamIndex != index) {
mStreamStates[stream].setIndex(
index * 10, AudioSystem.DEVICE_OUT_DEFAULT, caller,
true /*hasModifyAudioSettings*/);
}
if ((isMuted() != streamMuted) && isVssMuteBijective(stream)) {
mStreamStates[stream].mute(isMuted());
}
} }
} }
setVolumeIndexInt(index, AudioSystem.DEVICE_OUT_DEFAULT, 0 /*flags*/); if (!synced) {
if (DEBUG_VOL) {
Log.d(TAG, "applyAllVolumes: apply default device index " + index
+ ", group " + mAudioVolumeGroup.name());
}
setVolumeIndexInt(
isMuted() ? 0 : index, AudioSystem.DEVICE_OUT_DEFAULT, 0 /*flags*/);
}
if (forceDeviceSync) {
if (DEBUG_VOL) {
Log.d(TAG, "applyAllVolumes: forceDeviceSync index " + index
+ ", device " + AudioSystem.getOutputDeviceName(deviceForVolume)
+ ", group " + mAudioVolumeGroup.name());
}
setVolumeIndexInt(isMuted() ? 0 : index, deviceForVolume, 0);
}
} }
} }
public void clearIndexCache() {
mIndexMap.clear();
}
private void persistVolumeGroup(int device) { private void persistVolumeGroup(int device) {
if (mUseFixedVolume) { if (mUseFixedVolume) {
return; return;
@@ -7510,21 +7640,19 @@ public class AudioService extends IAudioService.Stub
Log.v(TAG, "persistVolumeGroup: storing index " + getIndex(device) + " for group " Log.v(TAG, "persistVolumeGroup: storing index " + getIndex(device) + " for group "
+ mAudioVolumeGroup.name() + mAudioVolumeGroup.name()
+ ", device " + AudioSystem.getOutputDeviceName(device) + ", device " + AudioSystem.getOutputDeviceName(device)
+ " and User=" + ActivityManager.getCurrentUser()); + " and User=" + getCurrentUserId());
} }
boolean success = mSettings.putSystemIntForUser(mContentResolver, boolean success = mSettings.putSystemIntForUser(mContentResolver,
getSettingNameForDevice(device), getSettingNameForDevice(device),
getIndex(device), getIndex(device),
UserHandle.USER_CURRENT); isMusic() ? UserHandle.USER_SYSTEM : UserHandle.USER_CURRENT);
if (!success) { if (!success) {
Log.e(TAG, "persistVolumeGroup failed for group " + mAudioVolumeGroup.name()); Log.e(TAG, "persistVolumeGroup failed for group " + mAudioVolumeGroup.name());
} }
} }
public void readSettings() { public void readSettings() {
synchronized (VolumeGroupState.class) { synchronized (VolumeStreamState.class) {
// First clear previously loaded (previous user?) settings
mIndexMap.clear();
// force maximum volume on all streams if fixed volume property is set // force maximum volume on all streams if fixed volume property is set
if (mUseFixedVolume) { if (mUseFixedVolume) {
mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax); mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
@@ -7539,7 +7667,8 @@ public class AudioService extends IAudioService.Stub
int index; int index;
String name = getSettingNameForDevice(device); String name = getSettingNameForDevice(device);
index = mSettings.getSystemIntForUser( index = mSettings.getSystemIntForUser(
mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT); mContentResolver, name, defaultIndex,
isMusic() ? UserHandle.USER_SYSTEM : UserHandle.USER_CURRENT);
if (index == -1) { if (index == -1) {
continue; continue;
} }
@@ -7550,13 +7679,14 @@ public class AudioService extends IAudioService.Stub
if (DEBUG_VOL) { if (DEBUG_VOL) {
Log.v(TAG, "readSettings: found stored index " + getValidIndex(index) Log.v(TAG, "readSettings: found stored index " + getValidIndex(index)
+ " for group " + mAudioVolumeGroup.name() + ", device: " + name + " for group " + mAudioVolumeGroup.name() + ", device: " + name
+ ", User=" + ActivityManager.getCurrentUser()); + ", User=" + getCurrentUserId());
} }
mIndexMap.put(device, getValidIndex(index)); mIndexMap.put(device, getValidIndex(index));
} }
} }
} }
@GuardedBy("AudioService.VolumeStreamState.class")
private int getValidIndex(int index) { private int getValidIndex(int index) {
if (index < mIndexMin) { if (index < mIndexMin) {
return mIndexMin; return mIndexMin;
@@ -7567,15 +7697,17 @@ public class AudioService extends IAudioService.Stub
} }
public @NonNull String getSettingNameForDevice(int device) { public @NonNull String getSettingNameForDevice(int device) {
final String suffix = AudioSystem.getOutputDeviceName(device); String suffix = AudioSystem.getOutputDeviceName(device);
if (suffix.isEmpty()) { if (suffix.isEmpty()) {
return mAudioVolumeGroup.name(); return mSettingName;
} }
return mAudioVolumeGroup.name() + "_" + AudioSystem.getOutputDeviceName(device); return mSettingName + "_" + AudioSystem.getOutputDeviceName(device);
} }
private void dump(PrintWriter pw) { private void dump(PrintWriter pw) {
pw.println("- VOLUME GROUP " + mAudioVolumeGroup.name() + ":"); pw.println("- VOLUME GROUP " + mAudioVolumeGroup.name() + ":");
pw.print(" Muted: ");
pw.println(mIsMuted);
pw.print(" Min: "); pw.print(" Min: ");
pw.println(mIndexMin); pw.println(mIndexMin);
pw.print(" Max: "); pw.print(" Max: ");
@@ -7585,9 +7717,9 @@ public class AudioService extends IAudioService.Stub
if (i > 0) { if (i > 0) {
pw.print(", "); pw.print(", ");
} }
final int device = mIndexMap.keyAt(i); int device = mIndexMap.keyAt(i);
pw.print(Integer.toHexString(device)); pw.print(Integer.toHexString(device));
final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default" String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
: AudioSystem.getOutputDeviceName(device); : AudioSystem.getOutputDeviceName(device);
if (!deviceName.isEmpty()) { if (!deviceName.isEmpty()) {
pw.print(" ("); pw.print(" (");
@@ -7600,7 +7732,7 @@ public class AudioService extends IAudioService.Stub
pw.println(); pw.println();
pw.print(" Devices: "); pw.print(" Devices: ");
int n = 0; int n = 0;
final int devices = getDeviceForVolume(); int devices = getDeviceForVolume();
for (int device : AudioSystem.DEVICE_OUT_ALL_SET) { for (int device : AudioSystem.DEVICE_OUT_ALL_SET) {
if ((devices & device) == device) { if ((devices & device) == device) {
if (n++ > 0) { if (n++ > 0) {
@@ -7609,6 +7741,10 @@ public class AudioService extends IAudioService.Stub
pw.print(AudioSystem.getOutputDeviceName(device)); pw.print(AudioSystem.getOutputDeviceName(device));
} }
} }
pw.println();
pw.print(" Streams: ");
Arrays.stream(getLegacyStreamTypes())
.forEach(stream -> pw.print(AudioSystem.streamToString(stream) + " "));
} }
} }