server/audio: Add LeAudio support
This patch adds handling active device and set volume Bug: 150670922 Tag: #feature Sponsor: jpawlowski@ Test: Manual Change-Id: I50a966ed2f199464381ff561fd83342b0a9b08a9
This commit is contained in:
parent
f822fdf129
commit
ad46dc5b5e
@ -106,7 +106,7 @@ public final class MediaRoute2Info implements Parcelable {
|
||||
@IntDef({
|
||||
TYPE_UNKNOWN, TYPE_BUILTIN_SPEAKER, TYPE_WIRED_HEADSET,
|
||||
TYPE_WIRED_HEADPHONES, TYPE_BLUETOOTH_A2DP, TYPE_HDMI, TYPE_USB_DEVICE,
|
||||
TYPE_USB_ACCESSORY, TYPE_DOCK, TYPE_USB_HEADSET, TYPE_HEARING_AID,
|
||||
TYPE_USB_ACCESSORY, TYPE_DOCK, TYPE_USB_HEADSET, TYPE_HEARING_AID, TYPE_BLE_HEADSET,
|
||||
TYPE_REMOTE_TV, TYPE_REMOTE_SPEAKER, TYPE_GROUP})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Type {}
|
||||
@ -201,6 +201,14 @@ public final class MediaRoute2Info implements Parcelable {
|
||||
*/
|
||||
public static final int TYPE_HEARING_AID = AudioDeviceInfo.TYPE_HEARING_AID;
|
||||
|
||||
/**
|
||||
* A route type describing a BLE HEADSET.
|
||||
*
|
||||
* @see #getType
|
||||
* @hide
|
||||
*/
|
||||
public static final int TYPE_BLE_HEADSET = AudioDeviceInfo.TYPE_BLE_HEADSET;
|
||||
|
||||
/**
|
||||
* A route type indicating the presentation of the media is happening on a TV.
|
||||
*
|
||||
|
@ -22,6 +22,7 @@ import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothHeadset;
|
||||
import android.bluetooth.BluetoothHearingAid;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.bluetooth.BluetoothLeAudio;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -503,6 +504,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ static final class BleVolumeInfo {
|
||||
final int mIndex;
|
||||
final int mMaxIndex;
|
||||
final int mStreamType;
|
||||
|
||||
BleVolumeInfo(int index, int maxIndex, int streamType) {
|
||||
mIndex = index;
|
||||
mMaxIndex = maxIndex;
|
||||
mStreamType = streamType;
|
||||
}
|
||||
};
|
||||
|
||||
/*package*/ static final class BtDeviceConnectionInfo {
|
||||
final @NonNull BluetoothDevice mDevice;
|
||||
final @AudioService.BtProfileConnectionState int mState;
|
||||
@ -711,6 +724,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType);
|
||||
}
|
||||
|
||||
/*package*/ void postSetLeAudioVolumeIndex(int index, int maxIndex, int streamType) {
|
||||
BleVolumeInfo info = new BleVolumeInfo(index, maxIndex, streamType);
|
||||
sendLMsgNoDelay(MSG_II_SET_LE_AUDIO_OUT_VOLUME, SENDMSG_REPLACE, info);
|
||||
}
|
||||
|
||||
/*package*/ void postSetModeOwnerPid(int pid, int mode) {
|
||||
sendIIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid, mode);
|
||||
}
|
||||
@ -851,6 +869,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
return mAudioService.getVssVolumeForDevice(streamType, device);
|
||||
}
|
||||
|
||||
/*package*/ int getMaxVssVolumeForStream(int streamType) {
|
||||
return mAudioService.getMaxVssVolumeForStream(streamType);
|
||||
}
|
||||
|
||||
/*package*/ int getDeviceForStream(int streamType) {
|
||||
return mAudioService.getDeviceForStream(streamType);
|
||||
}
|
||||
@ -962,6 +984,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE);
|
||||
}
|
||||
|
||||
/*package*/ void postDisconnectLeAudio() {
|
||||
sendMsgNoDelay(MSG_DISCONNECT_BT_LE_AUDIO, SENDMSG_QUEUE);
|
||||
}
|
||||
|
||||
/*package*/ void postDisconnectHeadset() {
|
||||
sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE);
|
||||
}
|
||||
@ -983,6 +1009,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
hearingAidProfile);
|
||||
}
|
||||
|
||||
/*package*/ void postBtLeAudioProfileConnected(BluetoothLeAudio leAudioProfile) {
|
||||
sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO, SENDMSG_QUEUE,
|
||||
leAudioProfile);
|
||||
}
|
||||
|
||||
/*package*/ void postCommunicationRouteClientDied(CommunicationRouteClient client) {
|
||||
sendLMsgNoDelay(MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED, SENDMSG_QUEUE, client);
|
||||
}
|
||||
@ -1321,6 +1352,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2);
|
||||
}
|
||||
break;
|
||||
case MSG_II_SET_LE_AUDIO_OUT_VOLUME: {
|
||||
final BleVolumeInfo info = (BleVolumeInfo) msg.obj;
|
||||
synchronized (mDeviceStateLock) {
|
||||
mBtHelper.setLeAudioVolume(info.mIndex, info.mMaxIndex, info.mStreamType);
|
||||
}
|
||||
} break;
|
||||
case MSG_I_SET_AVRCP_ABSOLUTE_VOLUME:
|
||||
synchronized (mDeviceStateLock) {
|
||||
mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
|
||||
@ -1384,6 +1421,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MSG_DISCONNECT_BT_LE_AUDIO:
|
||||
synchronized(mDeviceStateLock) {
|
||||
mDeviceInventory.disconnectLeAudio();
|
||||
}
|
||||
break;
|
||||
case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP:
|
||||
synchronized (mDeviceStateLock) {
|
||||
mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj);
|
||||
@ -1399,6 +1441,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj);
|
||||
}
|
||||
break;
|
||||
|
||||
case MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO:
|
||||
synchronized(mDeviceStateLock) {
|
||||
mBtHelper.onLeAudioProfileConnected((BluetoothLeAudio) msg.obj);
|
||||
}
|
||||
break;
|
||||
case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET:
|
||||
synchronized (mSetModeLock) {
|
||||
synchronized (mDeviceStateLock) {
|
||||
@ -1586,6 +1634,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
private static final int MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE = 43;
|
||||
private static final int MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT = 44;
|
||||
private static final int MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT = 45;
|
||||
// process set volume for Le Audio, obj is BleVolumeInfo
|
||||
private static final int MSG_II_SET_LE_AUDIO_OUT_VOLUME = 46;
|
||||
|
||||
private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO = 47;
|
||||
private static final int MSG_DISCONNECT_BT_LE_AUDIO = 48;
|
||||
|
||||
private static boolean isMessageHandledUnderWakelock(int msgId) {
|
||||
switch(msgId) {
|
||||
|
@ -887,6 +887,28 @@ public class AudioDeviceInventory {
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void disconnectLeAudio() {
|
||||
synchronized (mDevicesLock) {
|
||||
final ArraySet<String> toRemove = new ArraySet<>();
|
||||
// Disconnect ALL DEVICE_OUT_BLE_HEADSET devices
|
||||
mConnectedDevices.values().forEach(deviceInfo -> {
|
||||
if (deviceInfo.mDeviceType == AudioSystem.DEVICE_OUT_BLE_HEADSET) {
|
||||
toRemove.add(deviceInfo.mDeviceAddress);
|
||||
}
|
||||
});
|
||||
new MediaMetrics.Item(mMetricsId + "disconnectLeAudio")
|
||||
.record();
|
||||
if (toRemove.size() > 0) {
|
||||
final int delay = checkSendBecomingNoisyIntentInt(
|
||||
AudioSystem.DEVICE_OUT_BLE_HEADSET, 0, AudioSystem.DEVICE_NONE);
|
||||
toRemove.stream().forEach(deviceAddress ->
|
||||
makeLeAudioDeviceUnavailable(deviceAddress,
|
||||
AudioSystem.DEVICE_OUT_BLE_HEADSET)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// must be called before removing the device from mConnectedDevices
|
||||
// musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
|
||||
// from AudioSystem
|
||||
@ -1195,6 +1217,10 @@ public class AudioDeviceInventory {
|
||||
return;
|
||||
}
|
||||
|
||||
final int leAudioVolIndex = mDeviceBroker.getVssVolumeForDevice(streamType,
|
||||
AudioSystem.DEVICE_OUT_BLE_HEADSET);
|
||||
final int maxIndex = mDeviceBroker.getMaxVssVolumeForStream(streamType);
|
||||
mDeviceBroker.postSetLeAudioVolumeIndex(leAudioVolIndex, maxIndex, streamType);
|
||||
mDeviceBroker.postApplyVolumeOnDevice(streamType, device, "makeLeAudioDeviceAvailable");
|
||||
}
|
||||
|
||||
@ -1243,6 +1269,7 @@ public class AudioDeviceInventory {
|
||||
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
|
||||
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_LINE);
|
||||
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HEARING_AID);
|
||||
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_BLE_HEADSET);
|
||||
BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
|
||||
BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
|
||||
BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_BLE_SET);
|
||||
|
@ -334,6 +334,10 @@ public class AudioService extends IAudioService.Stub
|
||||
return mStreamStates[stream].getIndex(device);
|
||||
}
|
||||
|
||||
/*package*/ int getMaxVssVolumeForStream(int stream) {
|
||||
return mStreamStates[stream].getMaxIndex();
|
||||
}
|
||||
|
||||
private SettingsObserver mSettingsObserver;
|
||||
|
||||
private AtomicInteger mMode = new AtomicInteger(AudioSystem.MODE_NORMAL);
|
||||
@ -2952,6 +2956,16 @@ public class AudioService extends IAudioService.Stub
|
||||
mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(newIndex / 10);
|
||||
}
|
||||
|
||||
if (device == AudioSystem.DEVICE_OUT_BLE_HEADSET
|
||||
&& streamType == getBluetoothContextualVolumeStream()) {
|
||||
if (DEBUG_VOL) {
|
||||
Log.d(TAG, "adjustSreamVolume postSetLeAudioVolumeIndex index="
|
||||
+ newIndex + " stream=" + streamType);
|
||||
}
|
||||
mDeviceBroker.postSetLeAudioVolumeIndex(newIndex,
|
||||
mStreamStates[streamType].getMaxIndex(), streamType);
|
||||
}
|
||||
|
||||
// Check if volume update should be send to Hearing Aid
|
||||
if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
|
||||
// only modify the hearing aid attenuation when the stream to modify matches
|
||||
@ -3580,6 +3594,16 @@ public class AudioService extends IAudioService.Stub
|
||||
mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10);
|
||||
}
|
||||
|
||||
if (device == AudioSystem.DEVICE_OUT_BLE_HEADSET
|
||||
&& streamType == getBluetoothContextualVolumeStream()) {
|
||||
if (DEBUG_VOL) {
|
||||
Log.d(TAG, "adjustSreamVolume postSetLeAudioVolumeIndex index="
|
||||
+ index + " stream=" + streamType);
|
||||
}
|
||||
mDeviceBroker.postSetLeAudioVolumeIndex(index,
|
||||
mStreamStates[streamType].getMaxIndex(), streamType);
|
||||
}
|
||||
|
||||
if (device == AudioSystem.DEVICE_OUT_HEARING_AID
|
||||
&& streamType == getBluetoothContextualVolumeStream()) {
|
||||
Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index
|
||||
|
@ -155,6 +155,7 @@ public class AudioServiceEvents {
|
||||
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;
|
||||
static final int VOL_SET_LE_AUDIO_VOL = 10;
|
||||
|
||||
final int mOp;
|
||||
final int mStream;
|
||||
@ -310,6 +311,13 @@ public class AudioServiceEvents {
|
||||
.set(MediaMetrics.Property.INDEX, mVal1)
|
||||
.record();
|
||||
return;
|
||||
case VOL_SET_LE_AUDIO_VOL:
|
||||
new MediaMetrics.Item(mMetricsId)
|
||||
.set(MediaMetrics.Property.EVENT, "setLeAudioVolume")
|
||||
.set(MediaMetrics.Property.INDEX, mVal1)
|
||||
.set(MediaMetrics.Property.MAX_INDEX, mVal2)
|
||||
.record();
|
||||
return;
|
||||
case VOL_SET_AVRCP_VOL:
|
||||
new MediaMetrics.Item(mMetricsId)
|
||||
.set(MediaMetrics.Property.EVENT, "setAvrcpVolume")
|
||||
@ -382,6 +390,11 @@ public class AudioServiceEvents {
|
||||
.append(" index:").append(mVal1)
|
||||
.append(" gain dB:").append(mVal2)
|
||||
.toString();
|
||||
case VOL_SET_LE_AUDIO_VOL:
|
||||
return new StringBuilder("setLeAudioVolume:")
|
||||
.append(" index:").append(mVal1)
|
||||
.append(" gain dB:").append(mVal2)
|
||||
.toString();
|
||||
case VOL_SET_AVRCP_VOL:
|
||||
return new StringBuilder("setAvrcpVolume:")
|
||||
.append(" index:").append(mVal1)
|
||||
|
@ -25,6 +25,7 @@ import android.bluetooth.BluetoothCodecStatus;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothHeadset;
|
||||
import android.bluetooth.BluetoothHearingAid;
|
||||
import android.bluetooth.BluetoothLeAudio;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioDeviceAttributes;
|
||||
@ -63,6 +64,8 @@ public class BtHelper {
|
||||
|
||||
private @Nullable BluetoothHearingAid mHearingAid;
|
||||
|
||||
private @Nullable BluetoothLeAudio mLeAudio;
|
||||
|
||||
// Reference to BluetoothA2dp to query for AbsoluteVolume.
|
||||
private @Nullable BluetoothA2dp mA2dp;
|
||||
|
||||
@ -106,6 +109,8 @@ public class BtHelper {
|
||||
private static final int SCO_MODE_MAX = 2;
|
||||
|
||||
private static final int BT_HEARING_AID_GAIN_MIN = -128;
|
||||
private static final int BT_LE_AUDIO_MIN_VOL = 0;
|
||||
private static final int BT_LE_AUDIO_MAX_VOL = 255;
|
||||
|
||||
/**
|
||||
* Returns a string representation of the scoAudioMode.
|
||||
@ -235,6 +240,8 @@ public class BtHelper {
|
||||
mBluetoothProfileServiceListener, BluetoothProfile.A2DP);
|
||||
adapter.getProfileProxy(mDeviceBroker.getContext(),
|
||||
mBluetoothProfileServiceListener, BluetoothProfile.HEARING_AID);
|
||||
adapter.getProfileProxy(mDeviceBroker.getContext(),
|
||||
mBluetoothProfileServiceListener, BluetoothProfile.LE_AUDIO);
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,6 +396,26 @@ public class BtHelper {
|
||||
return requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, SCO_MODE_VIRTUAL_CALL);
|
||||
}
|
||||
|
||||
/*package*/ synchronized void setLeAudioVolume(int index, int maxIndex, int streamType) {
|
||||
if (mLeAudio == null) {
|
||||
if (AudioService.DEBUG_VOL) {
|
||||
Log.i(TAG, "setLeAudioVolume: null mLeAudio");
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* leaudio expect volume value in range 0 to 255
|
||||
*/
|
||||
int volume = (index * (BT_LE_AUDIO_MAX_VOL - BT_LE_AUDIO_MIN_VOL)) / maxIndex ;
|
||||
|
||||
if (AudioService.DEBUG_VOL) {
|
||||
Log.i(TAG, "setLeAudioVolume: calling mLeAudio.setVolume idx="
|
||||
+ index + " volume=" + volume);
|
||||
}
|
||||
AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent(
|
||||
AudioServiceEvents.VolumeEvent.VOL_SET_LE_AUDIO_VOL, index, maxIndex));
|
||||
mLeAudio.setVolume(volume);
|
||||
}
|
||||
|
||||
/*package*/ synchronized void setHearingAidVolume(int index, int streamType) {
|
||||
if (mHearingAid == null) {
|
||||
if (AudioService.DEBUG_VOL) {
|
||||
@ -428,6 +455,7 @@ public class BtHelper {
|
||||
mDeviceBroker.postDisconnectA2dpSink();
|
||||
mDeviceBroker.postDisconnectHeadset();
|
||||
mDeviceBroker.postDisconnectHearingAid();
|
||||
mDeviceBroker.postDisconnectLeAudio();
|
||||
}
|
||||
|
||||
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
|
||||
@ -488,6 +516,23 @@ public class BtHelper {
|
||||
/*eventSource*/ "mBluetoothProfileServiceListener");
|
||||
}
|
||||
|
||||
/*package*/ synchronized void onLeAudioProfileConnected(BluetoothLeAudio leAudio) {
|
||||
mLeAudio = leAudio;
|
||||
final List<BluetoothDevice> deviceList = mLeAudio.getConnectedDevices();
|
||||
if (deviceList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final BluetoothDevice btDevice = deviceList.get(0);
|
||||
final @BluetoothProfile.BtProfileState int state =
|
||||
mLeAudio.getConnectionState(btDevice);
|
||||
mDeviceBroker.postBluetoothLeAudioOutDeviceConnectionState(
|
||||
btDevice, state,
|
||||
/*suppressNoisyIntent*/ false,
|
||||
/*musicDevice android.media.AudioSystem.DEVICE_NONE,*/
|
||||
/*eventSource*/ "mBluetoothProfileServiceListener");
|
||||
}
|
||||
|
||||
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
|
||||
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
|
||||
/*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) {
|
||||
@ -655,6 +700,13 @@ public class BtHelper {
|
||||
mDeviceBroker.postBtHearingAidProfileConnected(
|
||||
(BluetoothHearingAid) proxy);
|
||||
break;
|
||||
|
||||
case BluetoothProfile.LE_AUDIO:
|
||||
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
|
||||
"BT profile service: connecting LE_AUDIO profile"));
|
||||
mDeviceBroker.postBtLeAudioProfileConnected(
|
||||
(BluetoothLeAudio) proxy);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -677,6 +729,9 @@ public class BtHelper {
|
||||
case BluetoothProfile.HEARING_AID:
|
||||
mDeviceBroker.postDisconnectHearingAid();
|
||||
break;
|
||||
case BluetoothProfile.LE_AUDIO:
|
||||
mDeviceBroker.postDisconnectLeAudio();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
@ -899,6 +954,7 @@ public class BtHelper {
|
||||
pw.println(prefix + "mScoAudioState: " + scoAudioStateToString(mScoAudioState));
|
||||
pw.println(prefix + "mScoAudioMode: " + scoAudioModeToString(mScoAudioMode));
|
||||
pw.println("\n" + prefix + "mHearingAid: " + mHearingAid);
|
||||
pw.println("\n" + prefix + "mLeAudio: " + mLeAudio);
|
||||
pw.println(prefix + "mA2dp: " + mA2dp);
|
||||
pw.println(prefix + "mAvrcpAbsVolSupported: " + mAvrcpAbsVolSupported);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import android.bluetooth.BluetoothA2dp;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothHearingAid;
|
||||
import android.bluetooth.BluetoothLeAudio;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
@ -56,6 +57,7 @@ class BluetoothRouteProvider {
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
private static final String HEARING_AID_ROUTE_ID_PREFIX = "HEARING_AID_";
|
||||
private static final String LE_AUDIO_ROUTE_ID_PREFIX = "LE_AUDIO_";
|
||||
|
||||
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
||||
// Maps hardware address to BluetoothRouteInfo
|
||||
@ -66,6 +68,8 @@ class BluetoothRouteProvider {
|
||||
BluetoothA2dp mA2dpProfile;
|
||||
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
||||
BluetoothHearingAid mHearingAidProfile;
|
||||
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
||||
BluetoothLeAudio mLeAudioProfile;
|
||||
|
||||
// Route type -> volume map
|
||||
private final SparseIntArray mVolumeMap = new SparseIntArray();
|
||||
@ -108,6 +112,7 @@ class BluetoothRouteProvider {
|
||||
public void start(UserHandle user) {
|
||||
mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP);
|
||||
mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEARING_AID);
|
||||
mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.LE_AUDIO);
|
||||
|
||||
// Bluetooth on/off broadcasts
|
||||
addEventReceiver(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedReceiver());
|
||||
@ -119,6 +124,10 @@ class BluetoothRouteProvider {
|
||||
deviceStateChangedReceiver);
|
||||
addEventReceiver(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED,
|
||||
deviceStateChangedReceiver);
|
||||
addEventReceiver(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED,
|
||||
deviceStateChangedReceiver);
|
||||
addEventReceiver(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED,
|
||||
deviceStateChangedReceiver);
|
||||
|
||||
mContext.registerReceiverAsUser(mBroadcastReceiver, user,
|
||||
mIntentFilter, null, null);
|
||||
@ -240,6 +249,8 @@ class BluetoothRouteProvider {
|
||||
| AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES
|
||||
| AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) {
|
||||
routeType = MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
|
||||
} else if ((devices & (AudioManager.DEVICE_OUT_BLE_HEADSET)) != 0) {
|
||||
routeType = MediaRoute2Info.TYPE_BLE_HEADSET;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -288,6 +299,12 @@ class BluetoothRouteProvider {
|
||||
routeId = HEARING_AID_ROUTE_ID_PREFIX + mHearingAidProfile.getHiSyncId(device);
|
||||
type = MediaRoute2Info.TYPE_HEARING_AID;
|
||||
}
|
||||
if (mLeAudioProfile != null
|
||||
&& mLeAudioProfile.getConnectedDevices().contains(device)) {
|
||||
newBtRoute.connectedProfiles.put(BluetoothProfile.LE_AUDIO, true);
|
||||
routeId = LE_AUDIO_ROUTE_ID_PREFIX + mLeAudioProfile.getGroupId(device);
|
||||
type = MediaRoute2Info.TYPE_BLE_HEADSET;
|
||||
}
|
||||
|
||||
// Current volume will be set when connected.
|
||||
newBtRoute.route = new MediaRoute2Info.Builder(routeId, deviceName)
|
||||
@ -358,11 +375,7 @@ class BluetoothRouteProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private void addActiveHearingAidDevices(BluetoothDevice device) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Setting active hearing aid devices. device=" + device);
|
||||
}
|
||||
|
||||
private void addActiveDevices(BluetoothDevice device) {
|
||||
// Let the given device be the first active device
|
||||
BluetoothRouteInfo activeBtRoute = mBluetoothRoutes.get(device.getAddress());
|
||||
addActiveRoute(activeBtRoute);
|
||||
@ -376,6 +389,21 @@ class BluetoothRouteProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
private void addActiveHearingAidDevices(BluetoothDevice device) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Setting active hearing aid devices. device=" + device);
|
||||
}
|
||||
|
||||
addActiveDevices(device);
|
||||
}
|
||||
|
||||
private void addActiveLeAudioDevices(BluetoothDevice device) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Setting active le audio devices. device=" + device);
|
||||
}
|
||||
|
||||
addActiveDevices(device);
|
||||
}
|
||||
|
||||
interface BluetoothRoutesUpdatedListener {
|
||||
void onBluetoothRoutesUpdated(@NonNull List<MediaRoute2Info> routes);
|
||||
@ -392,6 +420,11 @@ class BluetoothRouteProvider {
|
||||
if (connectedProfiles.get(BluetoothProfile.HEARING_AID, false)) {
|
||||
return MediaRoute2Info.TYPE_HEARING_AID;
|
||||
}
|
||||
|
||||
if (connectedProfiles.get(BluetoothProfile.LE_AUDIO, false)) {
|
||||
return MediaRoute2Info.TYPE_BLE_HEADSET;
|
||||
}
|
||||
|
||||
return MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
|
||||
}
|
||||
}
|
||||
@ -410,6 +443,10 @@ class BluetoothRouteProvider {
|
||||
mHearingAidProfile = (BluetoothHearingAid) proxy;
|
||||
activeDevices = mHearingAidProfile.getActiveDevices();
|
||||
break;
|
||||
case BluetoothProfile.LE_AUDIO:
|
||||
mLeAudioProfile = (BluetoothLeAudio) proxy;
|
||||
activeDevices = mLeAudioProfile.getActiveDevices();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
@ -434,6 +471,9 @@ class BluetoothRouteProvider {
|
||||
case BluetoothProfile.HEARING_AID:
|
||||
mHearingAidProfile = null;
|
||||
break;
|
||||
case BluetoothProfile.LE_AUDIO:
|
||||
mLeAudioProfile = null;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
@ -490,12 +530,22 @@ class BluetoothRouteProvider {
|
||||
}
|
||||
notifyBluetoothRoutesUpdated();
|
||||
break;
|
||||
case BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED:
|
||||
clearActiveRoutesWithType(MediaRoute2Info.TYPE_BLE_HEADSET);
|
||||
if (device != null) {
|
||||
addActiveLeAudioDevices(device);
|
||||
}
|
||||
notifyBluetoothRoutesUpdated();
|
||||
break;
|
||||
case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
|
||||
handleConnectionStateChanged(BluetoothProfile.A2DP, intent, device);
|
||||
break;
|
||||
case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED:
|
||||
handleConnectionStateChanged(BluetoothProfile.HEARING_AID, intent, device);
|
||||
break;
|
||||
case BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED:
|
||||
handleConnectionStateChanged(BluetoothProfile.LE_AUDIO, intent, device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user