[BUG] AudioService: fix mute/umute of aliased streams.

Mute/umute of aliased streams is asymetric according to activation/
de-activation mute events.
A toggle mute will mute/unmute all aliased whereas a togglemute/raise
will mute all aliased and unmute only the concerned stream of the raise
event.
A toggle mute and a setStreamVolume will mute all aliased and unmute only
the concercend stream of the setVolume request.

This CL makes the behavior homogeneous for aliased stream among
all activation/deactivation mute events.

Test: adb shell am instrument -w com.android.audiopolicytest com.android.audiopolicytest
Bug: 260298113

Signed-off-by: François Gaffie <francois.gaffie@renault.com>
Change-Id: I803f9df1c30755b8b5530c4b373c79ea4efd5010
Merged-In: I803f9df1c30755b8b5530c4b373c79ea4efd5010
This commit is contained in:
François Gaffie
2022-04-01 14:53:26 +02:00
committed by Eric Laurent
parent c8e375e0a3
commit 92a2d9aa7f

View File

@@ -3340,15 +3340,7 @@ public class AudioService extends IAudioService.Stub
} else {
state = direction == AudioManager.ADJUST_MUTE;
}
for (int stream = 0; stream < mStreamStates.length; stream++) {
if (streamTypeAlias == mStreamVolumeAlias[stream]) {
if (!(readCameraSoundForced()
&& (mStreamStates[stream].getStreamType()
== AudioSystem.STREAM_SYSTEM_ENFORCED))) {
mStreamStates[stream].mute(state);
}
}
}
muteAliasStreams(streamTypeAlias, state);
} else if ((direction == AudioManager.ADJUST_RAISE) &&
!checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
@@ -3363,7 +3355,7 @@ public class AudioService extends IAudioService.Stub
// Unmute the stream if it was previously muted
if (direction == AudioManager.ADJUST_RAISE) {
// unmute immediately for volume up
streamState.mute(false);
muteAliasStreams(streamTypeAlias, false);
} else if (direction == AudioManager.ADJUST_LOWER) {
if (mIsSingleVolume) {
sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
@@ -3489,6 +3481,42 @@ public class AudioService extends IAudioService.Stub
sendVolumeUpdate(streamType, oldIndex, newIndex, flags, device);
}
/**
* Loops on aliasted stream, update the mute cache attribute of each
* {@see AudioService#VolumeStreamState}, and then apply the change.
* It prevents to unnecessary {@see AudioSystem#setStreamVolume} done for each stream
* and aliases before mute change changed and after.
*/
private void muteAliasStreams(int streamAlias, boolean state) {
synchronized (VolumeStreamState.class) {
List<Integer> streamsToMute = new ArrayList<>();
for (int stream = 0; stream < mStreamStates.length; stream++) {
if (streamAlias == mStreamVolumeAlias[stream]) {
if (!(readCameraSoundForced()
&& (mStreamStates[stream].getStreamType()
== AudioSystem.STREAM_SYSTEM_ENFORCED))) {
boolean changed = mStreamStates[stream].mute(state, /* apply= */ false);
if (changed) {
streamsToMute.add(stream);
}
}
}
}
streamsToMute.forEach(streamToMute -> {
mStreamStates[streamToMute].doMute();
broadcastMuteSetting(streamToMute, state);
});
}
}
private void broadcastMuteSetting(int streamType, boolean isMuted) {
// Stream mute changed, fire the intent.
Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, isMuted);
sendBroadcastToAll(intent);
}
// Called after a delay when volume down is pressed while muted
private void onUnmuteStream(int stream, int flags) {
boolean wasMuted;
@@ -3608,7 +3636,8 @@ public class AudioService extends IAudioService.Stub
// except for BT SCO stream where only explicit mute is allowed to comply to BT requirements
if ((streamType != AudioSystem.STREAM_BLUETOOTH_SCO)
&& (getDeviceForStream(stream) == device)) {
mStreamStates[stream].mute(index == 0);
// As adjustStreamVolume with muteAdjust flags mute/unmutes stream and aliased streams.
muteAliasStreams(stream, index == 0);
}
}
@@ -7866,8 +7895,8 @@ public class AudioService extends IAudioService.Stub
private int mIndexMinNoPerm;
private int mIndexMax;
private boolean mIsMuted;
private boolean mIsMutedInternally;
private boolean mIsMuted = false;
private boolean mIsMutedInternally = false;
private String mVolumeIndexSettingName;
@NonNull private Set<Integer> mObservedDeviceSet = new TreeSet<>();
@@ -8292,27 +8321,10 @@ public class AudioService extends IAudioService.Stub
public boolean mute(boolean state) {
boolean changed = false;
synchronized (VolumeStreamState.class) {
if (state != mIsMuted) {
changed = true;
mIsMuted = state;
// Set the new mute volume. This propagates the values to
// the audio system, otherwise the volume won't be changed
// at the lower level.
sendMsg(mAudioHandler,
MSG_SET_ALL_VOLUMES,
SENDMSG_QUEUE,
0,
0,
this, 0);
}
changed = mute(state, true);
}
if (changed) {
// Stream mute changed, fire the intent.
Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
sendBroadcastToAll(intent);
broadcastMuteSetting(mStreamType, state);
}
return changed;
}
@@ -8344,6 +8356,41 @@ public class AudioService extends IAudioService.Stub
return mIsMuted || mIsMutedInternally;
}
/**
* Mute/unmute the stream
* @param state the new mute state
* @param apply true to propagate to HW, or false just to update the cache. May be needed
* to mute a stream and its aliases as applyAllVolume will force settings to aliases.
* It prevents unnecessary calls to {@see AudioSystem#setStreamVolume}
* @return true if the mute state was changed
*/
public boolean mute(boolean state, boolean apply) {
synchronized (VolumeStreamState.class) {
boolean changed = state != mIsMuted;
if (changed) {
mIsMuted = state;
if (apply) {
doMute();
}
}
return changed;
}
}
public void doMute() {
synchronized (VolumeStreamState.class) {
// Set the new mute volume. This propagates the values to
// the audio system, otherwise the volume won't be changed
// at the lower level.
sendMsg(mAudioHandler,
MSG_SET_ALL_VOLUMES,
SENDMSG_QUEUE,
0,
0,
this, 0);
}
}
public int getStreamType() {
return mStreamType;
}