Merge "AudioService: mute music during BT A2DP device switch" into rvc-dev

This commit is contained in:
TreeHugger Robot
2020-05-28 14:32:29 +00:00
committed by Android (Google) Code Review
3 changed files with 117 additions and 4 deletions

View File

@@ -45,7 +45,10 @@ import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/** @hide */
@@ -59,6 +62,9 @@ import java.util.NoSuchElementException;
// Timeout for connection to bluetooth headset service
/*package*/ static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
// Delay before checking it music should be unmuted after processing an A2DP message
private static final int BTA2DP_MUTE_CHECK_DELAY_MS = 50;
private final @NonNull AudioService mAudioService;
private final @NonNull Context mContext;
@@ -1050,9 +1056,19 @@ import java.util.NoSuchElementException;
final int strategy = msg.arg1;
mDeviceInventory.onSaveRemovePreferredDevice(strategy);
} break;
case MSG_CHECK_MUTE_MUSIC:
checkMessagesMuteMusic();
break;
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
// Give some time to Bluetooth service to post a connection message
// in case of active device switch
if (MESSAGES_MUTE_MUSIC.contains(msg.what)) {
sendMsg(MSG_CHECK_MUTE_MUSIC, SENDMSG_REPLACE, BTA2DP_MUTE_CHECK_DELAY_MS);
}
if (isMessageHandledUnderWakelock(msg.what)) {
try {
mBrokerEventWakeLock.release();
@@ -1116,6 +1132,7 @@ import java.util.NoSuchElementException;
private static final int MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY = 34;
private static final int MSG_L_SPEAKERPHONE_CLIENT_DIED = 35;
private static final int MSG_CHECK_MUTE_MUSIC = 36;
private static boolean isMessageHandledUnderWakelock(int msgId) {
@@ -1132,6 +1149,7 @@ import java.util.NoSuchElementException;
case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION:
case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION:
case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
case MSG_CHECK_MUTE_MUSIC:
return true;
default:
return false;
@@ -1231,6 +1249,37 @@ import java.util.NoSuchElementException;
mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj),
time);
}
if (MESSAGES_MUTE_MUSIC.contains(msg)) {
checkMessagesMuteMusic();
}
}
/** List of messages for which music is muted while processing is pending */
private static final Set<Integer> MESSAGES_MUTE_MUSIC;
static {
MESSAGES_MUTE_MUSIC = new HashSet<>();
MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED);
MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED);
MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE);
MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE);
MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION);
MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION);
}
private AtomicBoolean mMusicMuted = new AtomicBoolean(false);
/** Mutes or unmutes music according to pending A2DP messages */
private void checkMessagesMuteMusic() {
boolean mute = false;
for (int msg : MESSAGES_MUTE_MUSIC) {
if (mBrokerHandler.hasMessages(msg)) {
mute = true;
break;
}
}
if (mute != mMusicMuted.getAndSet(mute)) {
mAudioService.setMusicMute(mute);
}
}
private class SpeakerphoneClient implements IBinder.DeathRecipient {

View File

@@ -5061,6 +5061,10 @@ public class AudioService extends IAudioService.Stub
profile, suppressNoisyIntent, a2dpVolume);
}
/*package*/ void setMusicMute(boolean mute) {
mStreamStates[AudioSystem.STREAM_MUSIC].muteInternally(mute);
}
/**
* See AudioManager.handleBluetoothA2dpDeviceConfigChange()
* @param device
@@ -5463,6 +5467,7 @@ public class AudioService extends IAudioService.Stub
private int mIndexMax;
private boolean mIsMuted;
private boolean mIsMutedInternally;
private String mVolumeIndexSettingName;
private int mObservedDevices;
@@ -5636,7 +5641,8 @@ public class AudioService extends IAudioService.Stub
// 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
// index is just set to 0 to repect BT requirements
if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0 && !mIsMuted) {
if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0
&& !isFullyMuted()) {
index = 1;
}
AudioSystem.setStreamVolumeIndexAS(mStreamType, index, device);
@@ -5645,7 +5651,7 @@ public class AudioService extends IAudioService.Stub
// must be called while synchronized VolumeStreamState.class
/*package*/ void applyDeviceVolume_syncVSS(int device, boolean isAvrcpAbsVolSupported) {
int index;
if (mIsMuted) {
if (isFullyMuted()) {
index = 0;
} else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
&& isAvrcpAbsVolSupported) {
@@ -5668,7 +5674,7 @@ public class AudioService extends IAudioService.Stub
for (int i = 0; i < mIndexMap.size(); i++) {
final int device = mIndexMap.keyAt(i);
if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
if (mIsMuted) {
if (isFullyMuted()) {
index = 0;
} else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
&& isAvrcpAbsVolSupported) {
@@ -5685,7 +5691,7 @@ public class AudioService extends IAudioService.Stub
}
// 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
if (mIsMuted) {
if (isFullyMuted()) {
index = 0;
} else {
index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
@@ -5867,6 +5873,41 @@ public class AudioService extends IAudioService.Stub
return changed;
}
/**
* Mute/unmute the stream by AudioService
* @param state the new mute state
* @return true if the mute state was changed
*/
public boolean muteInternally(boolean state) {
boolean changed = false;
synchronized (VolumeStreamState.class) {
if (state != mIsMutedInternally) {
changed = true;
mIsMutedInternally = 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);
}
}
if (changed) {
sVolumeLogger.log(new VolumeEvent(
VolumeEvent.VOL_MUTE_STREAM_INT, mStreamType, state));
}
return changed;
}
@GuardedBy("VolumeStreamState.class")
public boolean isFullyMuted() {
return mIsMuted || mIsMutedInternally;
}
public int getStreamType() {
return mStreamType;
}
@@ -5903,6 +5944,8 @@ public class AudioService extends IAudioService.Stub
private void dump(PrintWriter pw) {
pw.print(" Muted: ");
pw.println(mIsMuted);
pw.print(" Muted Internally: ");
pw.println(mIsMutedInternally);
pw.print(" Min: ");
pw.print((mIndexMin + 5) / 10);
if (mIndexMin != mIndexMinNoPerm) {

View File

@@ -100,6 +100,7 @@ public class AudioServiceEvents {
static final int VOL_VOICE_ACTIVITY_HEARING_AID = 6;
static final int VOL_MODE_CHANGE_HEARING_AID = 7;
static final int VOL_SET_GROUP_VOL = 8;
static final int VOL_MUTE_STREAM_INT = 9;
final int mOp;
final int mStream;
@@ -188,6 +189,18 @@ public class AudioServiceEvents {
logMetricEvent();
}
/** used for VOL_MUTE_STREAM_INT */
VolumeEvent(int op, int stream, boolean state) {
mOp = op;
mStream = stream;
mVal1 = state ? 1 : 0;
mVal2 = 0;
mCaller = null;
mGroupName = null;
mAudioAttributes = null;
logMetricEvent();
}
/**
* Audio Analytics unique Id.
@@ -278,6 +291,9 @@ public class AudioServiceEvents {
.set(MediaMetrics.Property.INDEX, mVal1)
.record();
return;
case VOL_MUTE_STREAM_INT:
// No value in logging metrics for this internal event
return;
default:
return;
}
@@ -343,6 +359,11 @@ public class AudioServiceEvents {
.append(" flags:0x").append(Integer.toHexString(mVal2))
.append(") from ").append(mCaller)
.toString();
case VOL_MUTE_STREAM_INT:
return new StringBuilder("VolumeStreamState.muteInternally(stream:")
.append(AudioSystem.streamToString(mStream))
.append(mVal1 == 1 ? ", muted)" : ", unmuted)")
.toString();
default: return new StringBuilder("FIXME invalid op:").append(mOp).toString();
}
}