[IMPR] AudioService: VolumeGroupState: improve implementation
Bug: 260298113
Test: atest AudioVolumeGroupTest
-User VolumeStreamState.class to synchronize to avoid deadlock
-Profilization & user switch management
-Aligned with stream: music settings are preserved from
one user to the next
-if associated to stream, use same System Settings
-Mute management: only group with zero min index are mutable
Signed-off-by: Francois Gaffie <francois.gaffie@renault.com>
Change-Id: I9c8575c417df7267d81f4346bc66d476157e6d7d
Merged-In: I9c8575c417df7267d81f4346bc66d476157e6d7d
This commit is contained in:
committed by
Eric Laurent
parent
e90ba65e60
commit
8d35da7ed7
@@ -3678,7 +3678,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);
|
||||||
|
|
||||||
@@ -3699,7 +3699,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;
|
||||||
}
|
}
|
||||||
@@ -3713,14 +3713,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) */
|
||||||
@@ -5815,7 +5816,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");
|
||||||
@@ -7290,6 +7291,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.
|
||||||
@@ -7298,11 +7300,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7315,14 +7316,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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7333,7 +7342,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*/);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7346,17 +7355,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
|
||||||
@@ -7370,20 +7386,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7393,10 +7411,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();
|
||||||
}
|
}
|
||||||
@@ -7409,40 +7427,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;
|
||||||
@@ -7451,18 +7530,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() {
|
||||||
@@ -7473,55 +7550,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;
|
||||||
@@ -7530,21 +7660,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);
|
||||||
@@ -7559,7 +7687,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;
|
||||||
}
|
}
|
||||||
@@ -7570,13 +7699,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;
|
||||||
@@ -7587,15 +7717,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: ");
|
||||||
@@ -7605,9 +7737,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(" (");
|
||||||
@@ -7620,7 +7752,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) {
|
||||||
@@ -7629,6 +7761,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) + " "));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user