Merge "AudioService: mute music during BT A2DP device switch" into rvc-dev am: 82938719a8 am: 24983e2dab
Change-Id: Ib0ddae7aaa7bbdd7bfd1acd1512230b1b0d8b916
This commit is contained in:
@@ -45,7 +45,10 @@ import com.android.internal.annotations.GuardedBy;
|
|||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
@@ -59,6 +62,9 @@ import java.util.NoSuchElementException;
|
|||||||
// Timeout for connection to bluetooth headset service
|
// Timeout for connection to bluetooth headset service
|
||||||
/*package*/ static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
|
/*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 AudioService mAudioService;
|
||||||
private final @NonNull Context mContext;
|
private final @NonNull Context mContext;
|
||||||
|
|
||||||
@@ -1050,9 +1056,19 @@ import java.util.NoSuchElementException;
|
|||||||
final int strategy = msg.arg1;
|
final int strategy = msg.arg1;
|
||||||
mDeviceInventory.onSaveRemovePreferredDevice(strategy);
|
mDeviceInventory.onSaveRemovePreferredDevice(strategy);
|
||||||
} break;
|
} break;
|
||||||
|
case MSG_CHECK_MUTE_MUSIC:
|
||||||
|
checkMessagesMuteMusic();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Log.wtf(TAG, "Invalid message " + msg.what);
|
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)) {
|
if (isMessageHandledUnderWakelock(msg.what)) {
|
||||||
try {
|
try {
|
||||||
mBrokerEventWakeLock.release();
|
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_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY = 34;
|
||||||
|
|
||||||
private static final int MSG_L_SPEAKERPHONE_CLIENT_DIED = 35;
|
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) {
|
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_CONNECTION:
|
||||||
case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION:
|
case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION:
|
||||||
case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
|
case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
|
||||||
|
case MSG_CHECK_MUTE_MUSIC:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@@ -1231,6 +1249,37 @@ import java.util.NoSuchElementException;
|
|||||||
mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj),
|
mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj),
|
||||||
time);
|
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 {
|
private class SpeakerphoneClient implements IBinder.DeathRecipient {
|
||||||
|
|||||||
@@ -5061,6 +5061,10 @@ public class AudioService extends IAudioService.Stub
|
|||||||
profile, suppressNoisyIntent, a2dpVolume);
|
profile, suppressNoisyIntent, a2dpVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*package*/ void setMusicMute(boolean mute) {
|
||||||
|
mStreamStates[AudioSystem.STREAM_MUSIC].muteInternally(mute);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See AudioManager.handleBluetoothA2dpDeviceConfigChange()
|
* See AudioManager.handleBluetoothA2dpDeviceConfigChange()
|
||||||
* @param device
|
* @param device
|
||||||
@@ -5463,6 +5467,7 @@ public class AudioService extends IAudioService.Stub
|
|||||||
private int mIndexMax;
|
private int mIndexMax;
|
||||||
|
|
||||||
private boolean mIsMuted;
|
private boolean mIsMuted;
|
||||||
|
private boolean mIsMutedInternally;
|
||||||
private String mVolumeIndexSettingName;
|
private String mVolumeIndexSettingName;
|
||||||
private int mObservedDevices;
|
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.
|
// 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 (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0 && !mIsMuted) {
|
if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0
|
||||||
|
&& !isFullyMuted()) {
|
||||||
index = 1;
|
index = 1;
|
||||||
}
|
}
|
||||||
AudioSystem.setStreamVolumeIndexAS(mStreamType, index, device);
|
AudioSystem.setStreamVolumeIndexAS(mStreamType, index, device);
|
||||||
@@ -5645,7 +5651,7 @@ public class AudioService extends IAudioService.Stub
|
|||||||
// must be called while synchronized VolumeStreamState.class
|
// must be called while synchronized VolumeStreamState.class
|
||||||
/*package*/ void applyDeviceVolume_syncVSS(int device, boolean isAvrcpAbsVolSupported) {
|
/*package*/ void applyDeviceVolume_syncVSS(int device, boolean isAvrcpAbsVolSupported) {
|
||||||
int index;
|
int index;
|
||||||
if (mIsMuted) {
|
if (isFullyMuted()) {
|
||||||
index = 0;
|
index = 0;
|
||||||
} else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
|
} else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
|
||||||
&& isAvrcpAbsVolSupported) {
|
&& isAvrcpAbsVolSupported) {
|
||||||
@@ -5668,7 +5674,7 @@ public class AudioService extends IAudioService.Stub
|
|||||||
for (int i = 0; i < mIndexMap.size(); i++) {
|
for (int i = 0; i < mIndexMap.size(); i++) {
|
||||||
final int device = mIndexMap.keyAt(i);
|
final int device = mIndexMap.keyAt(i);
|
||||||
if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
|
if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
|
||||||
if (mIsMuted) {
|
if (isFullyMuted()) {
|
||||||
index = 0;
|
index = 0;
|
||||||
} else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
|
} else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
|
||||||
&& isAvrcpAbsVolSupported) {
|
&& isAvrcpAbsVolSupported) {
|
||||||
@@ -5685,7 +5691,7 @@ public class AudioService extends IAudioService.Stub
|
|||||||
}
|
}
|
||||||
// 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
|
||||||
if (mIsMuted) {
|
if (isFullyMuted()) {
|
||||||
index = 0;
|
index = 0;
|
||||||
} else {
|
} else {
|
||||||
index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
|
index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
|
||||||
@@ -5867,6 +5873,41 @@ public class AudioService extends IAudioService.Stub
|
|||||||
return changed;
|
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() {
|
public int getStreamType() {
|
||||||
return mStreamType;
|
return mStreamType;
|
||||||
}
|
}
|
||||||
@@ -5903,6 +5944,8 @@ public class AudioService extends IAudioService.Stub
|
|||||||
private void dump(PrintWriter pw) {
|
private void dump(PrintWriter pw) {
|
||||||
pw.print(" Muted: ");
|
pw.print(" Muted: ");
|
||||||
pw.println(mIsMuted);
|
pw.println(mIsMuted);
|
||||||
|
pw.print(" Muted Internally: ");
|
||||||
|
pw.println(mIsMutedInternally);
|
||||||
pw.print(" Min: ");
|
pw.print(" Min: ");
|
||||||
pw.print((mIndexMin + 5) / 10);
|
pw.print((mIndexMin + 5) / 10);
|
||||||
if (mIndexMin != mIndexMinNoPerm) {
|
if (mIndexMin != mIndexMinNoPerm) {
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ public class AudioServiceEvents {
|
|||||||
static final int VOL_VOICE_ACTIVITY_HEARING_AID = 6;
|
static final int VOL_VOICE_ACTIVITY_HEARING_AID = 6;
|
||||||
static final int VOL_MODE_CHANGE_HEARING_AID = 7;
|
static final int VOL_MODE_CHANGE_HEARING_AID = 7;
|
||||||
static final int VOL_SET_GROUP_VOL = 8;
|
static final int VOL_SET_GROUP_VOL = 8;
|
||||||
|
static final int VOL_MUTE_STREAM_INT = 9;
|
||||||
|
|
||||||
final int mOp;
|
final int mOp;
|
||||||
final int mStream;
|
final int mStream;
|
||||||
@@ -188,6 +189,18 @@ public class AudioServiceEvents {
|
|||||||
logMetricEvent();
|
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.
|
* Audio Analytics unique Id.
|
||||||
@@ -278,6 +291,9 @@ public class AudioServiceEvents {
|
|||||||
.set(MediaMetrics.Property.INDEX, mVal1)
|
.set(MediaMetrics.Property.INDEX, mVal1)
|
||||||
.record();
|
.record();
|
||||||
return;
|
return;
|
||||||
|
case VOL_MUTE_STREAM_INT:
|
||||||
|
// No value in logging metrics for this internal event
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -343,6 +359,11 @@ public class AudioServiceEvents {
|
|||||||
.append(" flags:0x").append(Integer.toHexString(mVal2))
|
.append(" flags:0x").append(Integer.toHexString(mVal2))
|
||||||
.append(") from ").append(mCaller)
|
.append(") from ").append(mCaller)
|
||||||
.toString();
|
.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();
|
default: return new StringBuilder("FIXME invalid op:").append(mOp).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user