Merge "server/audio: Add LeAudio support" am: 4fef608423
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1856323 Change-Id: I4dbf981c437bb5341a02e52acbf6da1b385c6ad2
This commit is contained in:
@@ -106,7 +106,7 @@ public final class MediaRoute2Info implements Parcelable {
|
|||||||
@IntDef({
|
@IntDef({
|
||||||
TYPE_UNKNOWN, TYPE_BUILTIN_SPEAKER, TYPE_WIRED_HEADSET,
|
TYPE_UNKNOWN, TYPE_BUILTIN_SPEAKER, TYPE_WIRED_HEADSET,
|
||||||
TYPE_WIRED_HEADPHONES, TYPE_BLUETOOTH_A2DP, TYPE_HDMI, TYPE_USB_DEVICE,
|
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})
|
TYPE_REMOTE_TV, TYPE_REMOTE_SPEAKER, TYPE_GROUP})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface Type {}
|
public @interface Type {}
|
||||||
@@ -201,6 +201,14 @@ public final class MediaRoute2Info implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
public static final int TYPE_HEARING_AID = AudioDeviceInfo.TYPE_HEARING_AID;
|
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.
|
* 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.BluetoothHeadset;
|
||||||
import android.bluetooth.BluetoothHearingAid;
|
import android.bluetooth.BluetoothHearingAid;
|
||||||
import android.bluetooth.BluetoothProfile;
|
import android.bluetooth.BluetoothProfile;
|
||||||
|
import android.bluetooth.BluetoothLeAudio;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
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 {
|
/*package*/ static final class BtDeviceConnectionInfo {
|
||||||
final @NonNull BluetoothDevice mDevice;
|
final @NonNull BluetoothDevice mDevice;
|
||||||
final @AudioService.BtProfileConnectionState int mState;
|
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);
|
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) {
|
/*package*/ void postSetModeOwnerPid(int pid, int mode) {
|
||||||
sendIIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid, 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);
|
return mAudioService.getVssVolumeForDevice(streamType, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*package*/ int getMaxVssVolumeForStream(int streamType) {
|
||||||
|
return mAudioService.getMaxVssVolumeForStream(streamType);
|
||||||
|
}
|
||||||
|
|
||||||
/*package*/ int getDeviceForStream(int streamType) {
|
/*package*/ int getDeviceForStream(int streamType) {
|
||||||
return mAudioService.getDeviceForStream(streamType);
|
return mAudioService.getDeviceForStream(streamType);
|
||||||
}
|
}
|
||||||
@@ -962,6 +984,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE);
|
sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*package*/ void postDisconnectLeAudio() {
|
||||||
|
sendMsgNoDelay(MSG_DISCONNECT_BT_LE_AUDIO, SENDMSG_QUEUE);
|
||||||
|
}
|
||||||
|
|
||||||
/*package*/ void postDisconnectHeadset() {
|
/*package*/ void postDisconnectHeadset() {
|
||||||
sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE);
|
sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE);
|
||||||
}
|
}
|
||||||
@@ -983,6 +1009,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
hearingAidProfile);
|
hearingAidProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*package*/ void postBtLeAudioProfileConnected(BluetoothLeAudio leAudioProfile) {
|
||||||
|
sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO, SENDMSG_QUEUE,
|
||||||
|
leAudioProfile);
|
||||||
|
}
|
||||||
|
|
||||||
/*package*/ void postCommunicationRouteClientDied(CommunicationRouteClient client) {
|
/*package*/ void postCommunicationRouteClientDied(CommunicationRouteClient client) {
|
||||||
sendLMsgNoDelay(MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED, SENDMSG_QUEUE, 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);
|
mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2);
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case MSG_I_SET_AVRCP_ABSOLUTE_VOLUME:
|
||||||
synchronized (mDeviceStateLock) {
|
synchronized (mDeviceStateLock) {
|
||||||
mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
|
mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
|
||||||
@@ -1384,6 +1421,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case MSG_DISCONNECT_BT_LE_AUDIO:
|
||||||
|
synchronized(mDeviceStateLock) {
|
||||||
|
mDeviceInventory.disconnectLeAudio();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP:
|
case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP:
|
||||||
synchronized (mDeviceStateLock) {
|
synchronized (mDeviceStateLock) {
|
||||||
mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj);
|
mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj);
|
||||||
@@ -1399,6 +1441,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj);
|
mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj);
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET:
|
||||||
synchronized (mSetModeLock) {
|
synchronized (mSetModeLock) {
|
||||||
synchronized (mDeviceStateLock) {
|
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_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_OUT_CONNECTION_CHANGE_EXT = 44;
|
||||||
private static final int MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT = 45;
|
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) {
|
private static boolean isMessageHandledUnderWakelock(int msgId) {
|
||||||
switch(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
|
// must be called before removing the device from mConnectedDevices
|
||||||
// musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
|
// musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
|
||||||
// from AudioSystem
|
// from AudioSystem
|
||||||
@@ -1195,6 +1217,10 @@ public class AudioDeviceInventory {
|
|||||||
return;
|
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");
|
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_DGTL_DOCK_HEADSET);
|
||||||
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_LINE);
|
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_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_A2DP_SET);
|
||||||
BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_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);
|
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);
|
return mStreamStates[stream].getIndex(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*package*/ int getMaxVssVolumeForStream(int stream) {
|
||||||
|
return mStreamStates[stream].getMaxIndex();
|
||||||
|
}
|
||||||
|
|
||||||
private SettingsObserver mSettingsObserver;
|
private SettingsObserver mSettingsObserver;
|
||||||
|
|
||||||
private AtomicInteger mMode = new AtomicInteger(AudioSystem.MODE_NORMAL);
|
private AtomicInteger mMode = new AtomicInteger(AudioSystem.MODE_NORMAL);
|
||||||
@@ -2952,6 +2956,16 @@ public class AudioService extends IAudioService.Stub
|
|||||||
mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(newIndex / 10);
|
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
|
// Check if volume update should be send to Hearing Aid
|
||||||
if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
|
if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
|
||||||
// only modify the hearing aid attenuation when the stream to modify matches
|
// 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);
|
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
|
if (device == AudioSystem.DEVICE_OUT_HEARING_AID
|
||||||
&& streamType == getBluetoothContextualVolumeStream()) {
|
&& streamType == getBluetoothContextualVolumeStream()) {
|
||||||
Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index
|
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_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;
|
static final int VOL_MUTE_STREAM_INT = 9;
|
||||||
|
static final int VOL_SET_LE_AUDIO_VOL = 10;
|
||||||
|
|
||||||
final int mOp;
|
final int mOp;
|
||||||
final int mStream;
|
final int mStream;
|
||||||
@@ -310,6 +311,13 @@ public class AudioServiceEvents {
|
|||||||
.set(MediaMetrics.Property.INDEX, mVal1)
|
.set(MediaMetrics.Property.INDEX, mVal1)
|
||||||
.record();
|
.record();
|
||||||
return;
|
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:
|
case VOL_SET_AVRCP_VOL:
|
||||||
new MediaMetrics.Item(mMetricsId)
|
new MediaMetrics.Item(mMetricsId)
|
||||||
.set(MediaMetrics.Property.EVENT, "setAvrcpVolume")
|
.set(MediaMetrics.Property.EVENT, "setAvrcpVolume")
|
||||||
@@ -382,6 +390,11 @@ public class AudioServiceEvents {
|
|||||||
.append(" index:").append(mVal1)
|
.append(" index:").append(mVal1)
|
||||||
.append(" gain dB:").append(mVal2)
|
.append(" gain dB:").append(mVal2)
|
||||||
.toString();
|
.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:
|
case VOL_SET_AVRCP_VOL:
|
||||||
return new StringBuilder("setAvrcpVolume:")
|
return new StringBuilder("setAvrcpVolume:")
|
||||||
.append(" index:").append(mVal1)
|
.append(" index:").append(mVal1)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import android.bluetooth.BluetoothCodecStatus;
|
|||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothHeadset;
|
import android.bluetooth.BluetoothHeadset;
|
||||||
import android.bluetooth.BluetoothHearingAid;
|
import android.bluetooth.BluetoothHearingAid;
|
||||||
|
import android.bluetooth.BluetoothLeAudio;
|
||||||
import android.bluetooth.BluetoothProfile;
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.media.AudioDeviceAttributes;
|
import android.media.AudioDeviceAttributes;
|
||||||
@@ -63,6 +64,8 @@ public class BtHelper {
|
|||||||
|
|
||||||
private @Nullable BluetoothHearingAid mHearingAid;
|
private @Nullable BluetoothHearingAid mHearingAid;
|
||||||
|
|
||||||
|
private @Nullable BluetoothLeAudio mLeAudio;
|
||||||
|
|
||||||
// Reference to BluetoothA2dp to query for AbsoluteVolume.
|
// Reference to BluetoothA2dp to query for AbsoluteVolume.
|
||||||
private @Nullable BluetoothA2dp mA2dp;
|
private @Nullable BluetoothA2dp mA2dp;
|
||||||
|
|
||||||
@@ -106,6 +109,8 @@ public class BtHelper {
|
|||||||
private static final int SCO_MODE_MAX = 2;
|
private static final int SCO_MODE_MAX = 2;
|
||||||
|
|
||||||
private static final int BT_HEARING_AID_GAIN_MIN = -128;
|
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.
|
* Returns a string representation of the scoAudioMode.
|
||||||
@@ -235,6 +240,8 @@ public class BtHelper {
|
|||||||
mBluetoothProfileServiceListener, BluetoothProfile.A2DP);
|
mBluetoothProfileServiceListener, BluetoothProfile.A2DP);
|
||||||
adapter.getProfileProxy(mDeviceBroker.getContext(),
|
adapter.getProfileProxy(mDeviceBroker.getContext(),
|
||||||
mBluetoothProfileServiceListener, BluetoothProfile.HEARING_AID);
|
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);
|
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) {
|
/*package*/ synchronized void setHearingAidVolume(int index, int streamType) {
|
||||||
if (mHearingAid == null) {
|
if (mHearingAid == null) {
|
||||||
if (AudioService.DEBUG_VOL) {
|
if (AudioService.DEBUG_VOL) {
|
||||||
@@ -428,6 +455,7 @@ public class BtHelper {
|
|||||||
mDeviceBroker.postDisconnectA2dpSink();
|
mDeviceBroker.postDisconnectA2dpSink();
|
||||||
mDeviceBroker.postDisconnectHeadset();
|
mDeviceBroker.postDisconnectHeadset();
|
||||||
mDeviceBroker.postDisconnectHearingAid();
|
mDeviceBroker.postDisconnectHearingAid();
|
||||||
|
mDeviceBroker.postDisconnectLeAudio();
|
||||||
}
|
}
|
||||||
|
|
||||||
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
|
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
|
||||||
@@ -488,6 +516,23 @@ public class BtHelper {
|
|||||||
/*eventSource*/ "mBluetoothProfileServiceListener");
|
/*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.mSetModeLock")
|
||||||
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
|
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
|
||||||
/*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) {
|
/*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) {
|
||||||
@@ -655,6 +700,13 @@ public class BtHelper {
|
|||||||
mDeviceBroker.postBtHearingAidProfileConnected(
|
mDeviceBroker.postBtHearingAidProfileConnected(
|
||||||
(BluetoothHearingAid) proxy);
|
(BluetoothHearingAid) proxy);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BluetoothProfile.LE_AUDIO:
|
||||||
|
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
|
||||||
|
"BT profile service: connecting LE_AUDIO profile"));
|
||||||
|
mDeviceBroker.postBtLeAudioProfileConnected(
|
||||||
|
(BluetoothLeAudio) proxy);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -677,6 +729,9 @@ public class BtHelper {
|
|||||||
case BluetoothProfile.HEARING_AID:
|
case BluetoothProfile.HEARING_AID:
|
||||||
mDeviceBroker.postDisconnectHearingAid();
|
mDeviceBroker.postDisconnectHearingAid();
|
||||||
break;
|
break;
|
||||||
|
case BluetoothProfile.LE_AUDIO:
|
||||||
|
mDeviceBroker.postDisconnectLeAudio();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -899,6 +954,7 @@ public class BtHelper {
|
|||||||
pw.println(prefix + "mScoAudioState: " + scoAudioStateToString(mScoAudioState));
|
pw.println(prefix + "mScoAudioState: " + scoAudioStateToString(mScoAudioState));
|
||||||
pw.println(prefix + "mScoAudioMode: " + scoAudioModeToString(mScoAudioMode));
|
pw.println(prefix + "mScoAudioMode: " + scoAudioModeToString(mScoAudioMode));
|
||||||
pw.println("\n" + prefix + "mHearingAid: " + mHearingAid);
|
pw.println("\n" + prefix + "mHearingAid: " + mHearingAid);
|
||||||
|
pw.println("\n" + prefix + "mLeAudio: " + mLeAudio);
|
||||||
pw.println(prefix + "mA2dp: " + mA2dp);
|
pw.println(prefix + "mA2dp: " + mA2dp);
|
||||||
pw.println(prefix + "mAvrcpAbsVolSupported: " + mAvrcpAbsVolSupported);
|
pw.println(prefix + "mAvrcpAbsVolSupported: " + mAvrcpAbsVolSupported);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import android.bluetooth.BluetoothA2dp;
|
|||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothHearingAid;
|
import android.bluetooth.BluetoothHearingAid;
|
||||||
|
import android.bluetooth.BluetoothLeAudio;
|
||||||
import android.bluetooth.BluetoothProfile;
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -56,6 +57,7 @@ class BluetoothRouteProvider {
|
|||||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
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 HEARING_AID_ROUTE_ID_PREFIX = "HEARING_AID_";
|
||||||
|
private static final String LE_AUDIO_ROUTE_ID_PREFIX = "LE_AUDIO_";
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
||||||
// Maps hardware address to BluetoothRouteInfo
|
// Maps hardware address to BluetoothRouteInfo
|
||||||
@@ -66,6 +68,8 @@ class BluetoothRouteProvider {
|
|||||||
BluetoothA2dp mA2dpProfile;
|
BluetoothA2dp mA2dpProfile;
|
||||||
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
||||||
BluetoothHearingAid mHearingAidProfile;
|
BluetoothHearingAid mHearingAidProfile;
|
||||||
|
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
||||||
|
BluetoothLeAudio mLeAudioProfile;
|
||||||
|
|
||||||
// Route type -> volume map
|
// Route type -> volume map
|
||||||
private final SparseIntArray mVolumeMap = new SparseIntArray();
|
private final SparseIntArray mVolumeMap = new SparseIntArray();
|
||||||
@@ -108,6 +112,7 @@ class BluetoothRouteProvider {
|
|||||||
public void start(UserHandle user) {
|
public void start(UserHandle user) {
|
||||||
mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP);
|
mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP);
|
||||||
mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEARING_AID);
|
mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEARING_AID);
|
||||||
|
mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.LE_AUDIO);
|
||||||
|
|
||||||
// Bluetooth on/off broadcasts
|
// Bluetooth on/off broadcasts
|
||||||
addEventReceiver(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedReceiver());
|
addEventReceiver(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedReceiver());
|
||||||
@@ -119,6 +124,10 @@ class BluetoothRouteProvider {
|
|||||||
deviceStateChangedReceiver);
|
deviceStateChangedReceiver);
|
||||||
addEventReceiver(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED,
|
addEventReceiver(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED,
|
||||||
deviceStateChangedReceiver);
|
deviceStateChangedReceiver);
|
||||||
|
addEventReceiver(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED,
|
||||||
|
deviceStateChangedReceiver);
|
||||||
|
addEventReceiver(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED,
|
||||||
|
deviceStateChangedReceiver);
|
||||||
|
|
||||||
mContext.registerReceiverAsUser(mBroadcastReceiver, user,
|
mContext.registerReceiverAsUser(mBroadcastReceiver, user,
|
||||||
mIntentFilter, null, null);
|
mIntentFilter, null, null);
|
||||||
@@ -240,6 +249,8 @@ class BluetoothRouteProvider {
|
|||||||
| AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES
|
| AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES
|
||||||
| AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) {
|
| AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) {
|
||||||
routeType = MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
|
routeType = MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
|
||||||
|
} else if ((devices & (AudioManager.DEVICE_OUT_BLE_HEADSET)) != 0) {
|
||||||
|
routeType = MediaRoute2Info.TYPE_BLE_HEADSET;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -288,6 +299,12 @@ class BluetoothRouteProvider {
|
|||||||
routeId = HEARING_AID_ROUTE_ID_PREFIX + mHearingAidProfile.getHiSyncId(device);
|
routeId = HEARING_AID_ROUTE_ID_PREFIX + mHearingAidProfile.getHiSyncId(device);
|
||||||
type = MediaRoute2Info.TYPE_HEARING_AID;
|
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.
|
// Current volume will be set when connected.
|
||||||
newBtRoute.route = new MediaRoute2Info.Builder(routeId, deviceName)
|
newBtRoute.route = new MediaRoute2Info.Builder(routeId, deviceName)
|
||||||
@@ -358,11 +375,7 @@ class BluetoothRouteProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addActiveHearingAidDevices(BluetoothDevice device) {
|
private void addActiveDevices(BluetoothDevice device) {
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "Setting active hearing aid devices. device=" + device);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let the given device be the first active device
|
// Let the given device be the first active device
|
||||||
BluetoothRouteInfo activeBtRoute = mBluetoothRoutes.get(device.getAddress());
|
BluetoothRouteInfo activeBtRoute = mBluetoothRoutes.get(device.getAddress());
|
||||||
addActiveRoute(activeBtRoute);
|
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 {
|
interface BluetoothRoutesUpdatedListener {
|
||||||
void onBluetoothRoutesUpdated(@NonNull List<MediaRoute2Info> routes);
|
void onBluetoothRoutesUpdated(@NonNull List<MediaRoute2Info> routes);
|
||||||
@@ -392,6 +420,11 @@ class BluetoothRouteProvider {
|
|||||||
if (connectedProfiles.get(BluetoothProfile.HEARING_AID, false)) {
|
if (connectedProfiles.get(BluetoothProfile.HEARING_AID, false)) {
|
||||||
return MediaRoute2Info.TYPE_HEARING_AID;
|
return MediaRoute2Info.TYPE_HEARING_AID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (connectedProfiles.get(BluetoothProfile.LE_AUDIO, false)) {
|
||||||
|
return MediaRoute2Info.TYPE_BLE_HEADSET;
|
||||||
|
}
|
||||||
|
|
||||||
return MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
|
return MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -410,6 +443,10 @@ class BluetoothRouteProvider {
|
|||||||
mHearingAidProfile = (BluetoothHearingAid) proxy;
|
mHearingAidProfile = (BluetoothHearingAid) proxy;
|
||||||
activeDevices = mHearingAidProfile.getActiveDevices();
|
activeDevices = mHearingAidProfile.getActiveDevices();
|
||||||
break;
|
break;
|
||||||
|
case BluetoothProfile.LE_AUDIO:
|
||||||
|
mLeAudioProfile = (BluetoothLeAudio) proxy;
|
||||||
|
activeDevices = mLeAudioProfile.getActiveDevices();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -434,6 +471,9 @@ class BluetoothRouteProvider {
|
|||||||
case BluetoothProfile.HEARING_AID:
|
case BluetoothProfile.HEARING_AID:
|
||||||
mHearingAidProfile = null;
|
mHearingAidProfile = null;
|
||||||
break;
|
break;
|
||||||
|
case BluetoothProfile.LE_AUDIO:
|
||||||
|
mLeAudioProfile = null;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -490,12 +530,22 @@ class BluetoothRouteProvider {
|
|||||||
}
|
}
|
||||||
notifyBluetoothRoutesUpdated();
|
notifyBluetoothRoutesUpdated();
|
||||||
break;
|
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:
|
case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
|
||||||
handleConnectionStateChanged(BluetoothProfile.A2DP, intent, device);
|
handleConnectionStateChanged(BluetoothProfile.A2DP, intent, device);
|
||||||
break;
|
break;
|
||||||
case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED:
|
case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED:
|
||||||
handleConnectionStateChanged(BluetoothProfile.HEARING_AID, intent, device);
|
handleConnectionStateChanged(BluetoothProfile.HEARING_AID, intent, device);
|
||||||
break;
|
break;
|
||||||
|
case BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED:
|
||||||
|
handleConnectionStateChanged(BluetoothProfile.LE_AUDIO, intent, device);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user