Merge "AudioService: mute music during BT A2DP device switch" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
82938719a8
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user