AudioService: make BT A2DP API async
Handle the BT A2DP methods for connection / disconnection / configuration change asynchronous by handling them on AudioService's message queue. Bug: 162448412 Test: atest AudioDeviceBrokerTest Change-Id: I36e6fea87110e3901a1dfb76ef8c36b2b1a732d0
This commit is contained in:
@@ -503,7 +503,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class BtDeviceConnectionInfo {
|
||||
/*package*/ static final class BtDeviceConnectionInfo {
|
||||
final @NonNull BluetoothDevice mDevice;
|
||||
final @AudioService.BtProfileConnectionState int mState;
|
||||
final int mProfile;
|
||||
@@ -520,6 +520,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
mVolume = vol;
|
||||
}
|
||||
|
||||
BtDeviceConnectionInfo(@NonNull BtDeviceConnectionInfo info) {
|
||||
mDevice = info.mDevice;
|
||||
mState = info.mState;
|
||||
mProfile = info.mProfile;
|
||||
mSupprNoisy = info.mSupprNoisy;
|
||||
mVolume = info.mVolume;
|
||||
}
|
||||
|
||||
// redefine equality op so we can match messages intended for this device
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
@@ -541,18 +549,19 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
@NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
|
||||
int profile, boolean suppressNoisyIntent, int a2dpVolume) {
|
||||
final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile,
|
||||
suppressNoisyIntent, a2dpVolume);
|
||||
|
||||
final String name = TextUtils.emptyIfNull(device.getName());
|
||||
/**
|
||||
* will block on mDeviceStateLock, which is held during an A2DP (dis) connection
|
||||
* not just a simple message post
|
||||
* @param info struct with the (dis)connection information
|
||||
*/
|
||||
/*package*/ void queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
@NonNull BtDeviceConnectionInfo info) {
|
||||
final String name = TextUtils.emptyIfNull(info.mDevice.getName());
|
||||
new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
|
||||
+ "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent")
|
||||
.set(MediaMetrics.Property.STATE, state == BluetoothProfile.STATE_CONNECTED
|
||||
.set(MediaMetrics.Property.STATE, info.mState == BluetoothProfile.STATE_CONNECTED
|
||||
? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
|
||||
.set(MediaMetrics.Property.INDEX, a2dpVolume)
|
||||
.set(MediaMetrics.Property.INDEX, info.mVolume)
|
||||
.set(MediaMetrics.Property.NAME, name)
|
||||
.record();
|
||||
|
||||
@@ -562,10 +571,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
// when receiving a request to change the connection state of a device, this last
|
||||
// request is the source of truth, so cancel all previous requests that are already in
|
||||
// the handler
|
||||
removeScheduledA2dpEvents(device);
|
||||
removeScheduledA2dpEvents(info.mDevice);
|
||||
|
||||
sendLMsgNoDelay(
|
||||
state == BluetoothProfile.STATE_CONNECTED
|
||||
info.mState == BluetoothProfile.STATE_CONNECTED
|
||||
? MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION
|
||||
: MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION,
|
||||
SENDMSG_QUEUE, info);
|
||||
|
||||
@@ -310,6 +310,8 @@ public class AudioService extends IAudioService.Stub
|
||||
private static final int MSG_UPDATE_A11Y_SERVICE_UIDS = 35;
|
||||
private static final int MSG_UPDATE_AUDIO_MODE = 36;
|
||||
private static final int MSG_RECORDING_CONFIG_CHANGE = 37;
|
||||
private static final int MSG_SET_A2DP_DEV_CONNECTION_STATE = 38;
|
||||
private static final int MSG_A2DP_DEV_CONFIG_CHANGE = 39;
|
||||
|
||||
// start of messages handled under wakelock
|
||||
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
|
||||
@@ -6074,7 +6076,7 @@ public class AudioService extends IAudioService.Stub
|
||||
* See AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent()
|
||||
*/
|
||||
public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
@NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
|
||||
@NonNull BluetoothDevice device, @BtProfileConnectionState int state,
|
||||
int profile, boolean suppressNoisyIntent, int a2dpVolume) {
|
||||
if (device == null) {
|
||||
throw new IllegalArgumentException("Illegal null device");
|
||||
@@ -6084,8 +6086,13 @@ public class AudioService extends IAudioService.Stub
|
||||
throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
|
||||
+ " (dis)connection, got " + state);
|
||||
}
|
||||
mDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device, state,
|
||||
profile, suppressNoisyIntent, a2dpVolume);
|
||||
|
||||
AudioDeviceBroker.BtDeviceConnectionInfo info =
|
||||
new AudioDeviceBroker.BtDeviceConnectionInfo(device, state,
|
||||
profile, suppressNoisyIntent, a2dpVolume);
|
||||
sendMsg(mAudioHandler, MSG_SET_A2DP_DEV_CONNECTION_STATE, SENDMSG_QUEUE,
|
||||
0 /*arg1*/, 0 /*arg2*/,
|
||||
/*obj*/ info, 0 /*delay*/);
|
||||
}
|
||||
|
||||
/** only public for mocking/spying, do not call outside of AudioService */
|
||||
@@ -6103,7 +6110,8 @@ public class AudioService extends IAudioService.Stub
|
||||
if (device == null) {
|
||||
throw new IllegalArgumentException("Illegal null device");
|
||||
}
|
||||
mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device);
|
||||
sendMsg(mAudioHandler, MSG_A2DP_DEV_CONFIG_CHANGE, SENDMSG_QUEUE, 0, 0,
|
||||
/*obj*/ device, /*delay*/ 0);
|
||||
}
|
||||
|
||||
private static final Set<Integer> DEVICE_MEDIA_UNMUTED_ON_PLUG_SET;
|
||||
@@ -7465,6 +7473,15 @@ public class AudioService extends IAudioService.Stub
|
||||
onUpdateAudioMode(msg.arg1, msg.arg2, (String) msg.obj, false /*force*/);
|
||||
}
|
||||
break;
|
||||
|
||||
case MSG_SET_A2DP_DEV_CONNECTION_STATE:
|
||||
mDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
(AudioDeviceBroker.BtDeviceConnectionInfo) msg.obj);
|
||||
break;
|
||||
|
||||
case MSG_A2DP_DEV_CONFIG_CHANGE:
|
||||
mDeviceBroker.postBluetoothA2dpDeviceConfigChange((BluetoothDevice) msg.obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,8 +454,10 @@ public class BtHelper {
|
||||
}
|
||||
final BluetoothDevice btDevice = deviceList.get(0);
|
||||
// the device is guaranteed CONNECTED
|
||||
mDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(btDevice,
|
||||
BluetoothA2dp.STATE_CONNECTED, BluetoothProfile.A2DP_SINK, true, -1);
|
||||
mDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
new AudioDeviceBroker.BtDeviceConnectionInfo(btDevice,
|
||||
BluetoothA2dp.STATE_CONNECTED, BluetoothProfile.A2DP_SINK,
|
||||
true, -1));
|
||||
}
|
||||
|
||||
/*package*/ synchronized void onA2dpSinkProfileConnected(BluetoothProfile profile) {
|
||||
|
||||
@@ -98,8 +98,9 @@ public class AudioDeviceBrokerTest {
|
||||
Log.i(TAG, "starting testPostA2dpDeviceConnectionChange");
|
||||
Assert.assertNotNull("invalid null BT device", mFakeBtDevice);
|
||||
|
||||
mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
|
||||
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1);
|
||||
mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
|
||||
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1));
|
||||
Thread.sleep(2 * MAX_MESSAGE_HANDLING_DELAY_MS);
|
||||
verify(mSpyDevInventory, times(1)).setBluetoothA2dpDeviceConnectionState(
|
||||
any(BluetoothDevice.class),
|
||||
@@ -209,20 +210,23 @@ public class AudioDeviceBrokerTest {
|
||||
((NoOpAudioSystemAdapter) mSpyAudioSystem).configureIsStreamActive(mockMediaPlayback);
|
||||
|
||||
// first connection: ensure the device is connected as a starting condition for the test
|
||||
mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
|
||||
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1);
|
||||
mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
|
||||
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1));
|
||||
Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS);
|
||||
|
||||
// disconnection
|
||||
mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
|
||||
BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP, false, -1);
|
||||
mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
|
||||
BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP, false, -1));
|
||||
if (delayAfterDisconnection > 0) {
|
||||
Thread.sleep(delayAfterDisconnection);
|
||||
}
|
||||
|
||||
// reconnection
|
||||
mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
|
||||
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 2);
|
||||
mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
|
||||
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 2));
|
||||
Thread.sleep(AudioService.BECOMING_NOISY_DELAY_MS + MAX_MESSAGE_HANDLING_DELAY_MS);
|
||||
|
||||
// Verify disconnection has been cancelled and we're seeing two connections attempts,
|
||||
|
||||
Reference in New Issue
Block a user