summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--media/java/android/media/AudioSystem.java25
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java27
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java45
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java85
4 files changed, 125 insertions, 57 deletions
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 367b38a152fc..9ffd644493db 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -318,11 +318,12 @@ public class AudioSystem
/**
* @hide
- * Convert a Bluetooth codec to an audio format enum
+ * Convert an A2DP Bluetooth codec to an audio format enum
* @param btCodec the codec to convert.
* @return the audio format, or {@link #AUDIO_FORMAT_DEFAULT} if unknown
*/
- public static @AudioFormatNativeEnumForBtCodec int bluetoothCodecToAudioFormat(int btCodec) {
+ public static @AudioFormatNativeEnumForBtCodec int bluetoothA2dpCodecToAudioFormat(
+ int btCodec) {
switch (btCodec) {
case BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC:
return AudioSystem.AUDIO_FORMAT_SBC;
@@ -339,7 +340,25 @@ public class AudioSystem
case BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS:
return AudioSystem.AUDIO_FORMAT_OPUS;
default:
- Log.e(TAG, "Unknown BT codec 0x" + Integer.toHexString(btCodec)
+ Log.e(TAG, "Unknown A2DP BT codec 0x" + Integer.toHexString(btCodec)
+ + " for conversion to audio format");
+ // TODO returning DEFAULT is the current behavior, should this return INVALID?
+ return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ }
+ }
+
+ /**
+ * @hide
+ * Convert a LE Audio Bluetooth codec to an audio format enum
+ * @param btCodec the codec to convert.
+ * @return the audio format, or {@link #AUDIO_FORMAT_DEFAULT} if unknown
+ */
+ public static @AudioFormatNativeEnumForBtCodec int bluetoothLeCodecToAudioFormat(int btCodec) {
+ switch (btCodec) {
+ case BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3:
+ return AudioSystem.AUDIO_FORMAT_LC3;
+ default:
+ Log.e(TAG, "Unknown LE Audio BT codec 0x" + Integer.toHexString(btCodec)
+ " for conversion to audio format");
// TODO returning DEFAULT is the current behavior, should this return INVALID?
return AudioSystem.AUDIO_FORMAT_DEFAULT;
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index b1706ed61e36..2f7d99fcbc4b 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1595,8 +1595,8 @@ public class AudioDeviceBroker {
sendILMsg(MSG_IL_BTA2DP_TIMEOUT, SENDMSG_QUEUE, a2dpCodec, address, delayMs);
}
- /*package*/ void setLeAudioTimeout(String address, int device, int delayMs) {
- sendILMsg(MSG_IL_BTLEAUDIO_TIMEOUT, SENDMSG_QUEUE, device, address, delayMs);
+ /*package*/ void setLeAudioTimeout(String address, int device, int codec, int delayMs) {
+ sendIILMsg(MSG_IIL_BTLEAUDIO_TIMEOUT, SENDMSG_QUEUE, device, codec, address, delayMs);
}
/*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) {
@@ -1794,8 +1794,9 @@ public class AudioDeviceBroker {
return;
}
@AudioSystem.AudioFormatNativeEnumForBtCodec final int codec =
- mBtHelper.getA2dpCodecWithFallbackToSBC(
- btInfo.mDevice, "MSG_L_SET_BT_ACTIVE_DEVICE");
+ mBtHelper.getCodecWithFallback(btInfo.mDevice,
+ btInfo.mProfile, btInfo.mIsLeOutput,
+ "MSG_L_SET_BT_ACTIVE_DEVICE");
mDeviceInventory.onSetBtActiveDevice(btInfo, codec,
(btInfo.mProfile
!= BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput)
@@ -1819,22 +1820,24 @@ public class AudioDeviceBroker {
case MSG_IL_BTA2DP_TIMEOUT:
// msg.obj == address of BTA2DP device
synchronized (mDeviceStateLock) {
- mDeviceInventory.onMakeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1);
+ mDeviceInventory.onMakeA2dpDeviceUnavailableNow(
+ (String) msg.obj, msg.arg1);
}
break;
- case MSG_IL_BTLEAUDIO_TIMEOUT:
+ case MSG_IIL_BTLEAUDIO_TIMEOUT:
// msg.obj == address of LE Audio device
synchronized (mDeviceStateLock) {
mDeviceInventory.onMakeLeAudioDeviceUnavailableNow(
- (String) msg.obj, msg.arg1);
+ (String) msg.obj, msg.arg1, msg.arg2);
}
break;
case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: {
final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
synchronized (mDeviceStateLock) {
@AudioSystem.AudioFormatNativeEnumForBtCodec final int codec =
- mBtHelper.getA2dpCodecWithFallbackToSBC(
- btInfo.mDevice, "MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE");
+ mBtHelper.getCodecWithFallback(btInfo.mDevice,
+ btInfo.mProfile, btInfo.mIsLeOutput,
+ "MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE");
mDeviceInventory.onBluetoothDeviceConfigChange(
btInfo, codec, BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
}
@@ -2084,7 +2087,7 @@ public class AudioDeviceBroker {
private static final int MSG_IL_SAVE_NDEF_DEVICE_FOR_STRATEGY = 47;
private static final int MSG_IL_SAVE_REMOVE_NDEF_DEVICE_FOR_STRATEGY = 48;
- private static final int MSG_IL_BTLEAUDIO_TIMEOUT = 49;
+ private static final int MSG_IIL_BTLEAUDIO_TIMEOUT = 49;
private static final int MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED = 52;
private static final int MSG_L_CHECK_COMMUNICATION_DEVICE_REMOVAL = 53;
@@ -2104,7 +2107,7 @@ public class AudioDeviceBroker {
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
case MSG_L_SET_BT_ACTIVE_DEVICE:
case MSG_IL_BTA2DP_TIMEOUT:
- case MSG_IL_BTLEAUDIO_TIMEOUT:
+ case MSG_IIL_BTLEAUDIO_TIMEOUT:
case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE:
case MSG_TOGGLE_HDMI:
case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT:
@@ -2196,7 +2199,7 @@ public class AudioDeviceBroker {
case MSG_L_SET_BT_ACTIVE_DEVICE:
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
case MSG_IL_BTA2DP_TIMEOUT:
- case MSG_IL_BTLEAUDIO_TIMEOUT:
+ case MSG_IIL_BTLEAUDIO_TIMEOUT:
case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE:
if (sLastDeviceConnectMsgTime >= time) {
// add a little delay to make sure messages are ordered as expected
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index e9b102bc67b8..91f04878fe6f 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -689,9 +689,11 @@ public class AudioDeviceInventory {
case BluetoothProfile.LE_AUDIO:
case BluetoothProfile.LE_AUDIO_BROADCAST:
if (switchToUnavailable) {
- makeLeAudioDeviceUnavailableNow(address, btInfo.mAudioSystemDevice);
+ makeLeAudioDeviceUnavailableNow(address,
+ btInfo.mAudioSystemDevice, di.mDeviceCodecFormat);
} else if (switchToAvailable) {
- makeLeAudioDeviceAvailable(btInfo, streamType, "onSetBtActiveDevice");
+ makeLeAudioDeviceAvailable(
+ btInfo, streamType, codec, "onSetBtActiveDevice");
}
break;
default: throw new IllegalArgumentException("Invalid profile "
@@ -752,12 +754,13 @@ public class AudioDeviceInventory {
if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
- boolean a2dpCodecChange = false;
- if (btInfo.mProfile == BluetoothProfile.A2DP) {
+ boolean codecChange = false;
+ if (btInfo.mProfile == BluetoothProfile.A2DP
+ || btInfo.mProfile == BluetoothProfile.LE_AUDIO) {
if (di.mDeviceCodecFormat != codec) {
di.mDeviceCodecFormat = codec;
mConnectedDevices.replace(key, di);
- a2dpCodecChange = true;
+ codecChange = true;
}
final int res = mAudioSystem.handleDeviceConfigChange(
btInfo.mAudioSystemDevice, address, BtHelper.getName(btDevice), codec);
@@ -782,7 +785,7 @@ public class AudioDeviceInventory {
}
}
- if (!a2dpCodecChange) {
+ if (!codecChange) {
updateBluetoothPreferredModes_l(btDevice /*connectedDevice*/);
}
}
@@ -796,9 +799,9 @@ public class AudioDeviceInventory {
}
}
- /*package*/ void onMakeLeAudioDeviceUnavailableNow(String address, int device) {
+ /*package*/ void onMakeLeAudioDeviceUnavailableNow(String address, int device, int codec) {
synchronized (mDevicesLock) {
- makeLeAudioDeviceUnavailableNow(address, device);
+ makeLeAudioDeviceUnavailableNow(address, device, codec);
}
}
@@ -1641,11 +1644,12 @@ public class AudioDeviceInventory {
}
synchronized (mDevicesLock) {
- final ArraySet<String> toRemove = new ArraySet<>();
+ final ArraySet<Pair<String, Integer>> toRemove = new ArraySet<>();
// Disconnect ALL DEVICE_OUT_BLE_HEADSET or DEVICE_OUT_BLE_BROADCAST devices
mConnectedDevices.values().forEach(deviceInfo -> {
if (deviceInfo.mDeviceType == device) {
- toRemove.add(deviceInfo.mDeviceAddress);
+ toRemove.add(
+ new Pair<>(deviceInfo.mDeviceAddress, deviceInfo.mDeviceCodecFormat));
}
});
new MediaMetrics.Item(mMetricsId + "disconnectLeAudio")
@@ -1655,8 +1659,8 @@ public class AudioDeviceInventory {
final int delay = checkSendBecomingNoisyIntentInt(device,
AudioService.CONNECTION_STATE_DISCONNECTED,
AudioSystem.DEVICE_NONE);
- toRemove.stream().forEach(deviceAddress ->
- makeLeAudioDeviceUnavailableLater(deviceAddress, device, delay)
+ toRemove.stream().forEach(entry ->
+ makeLeAudioDeviceUnavailableLater(entry.first, device, entry.second, delay)
);
}
}
@@ -2200,7 +2204,8 @@ public class AudioDeviceInventory {
@GuardedBy("mDevicesLock")
private void makeLeAudioDeviceAvailable(
- AudioDeviceBroker.BtDeviceInfo btInfo, int streamType, String eventSource) {
+ AudioDeviceBroker.BtDeviceInfo btInfo, int streamType,
+ @AudioSystem.AudioFormatNativeEnumForBtCodec int codec, String eventSource) {
final int volumeIndex = btInfo.mVolume == -1 ? -1 : btInfo.mVolume * 10;
final int device = btInfo.mAudioSystemDevice;
@@ -2234,7 +2239,7 @@ public class AudioDeviceInventory {
AudioDeviceAttributes ada = new AudioDeviceAttributes(device, address, name);
final int res = AudioSystem.setDeviceConnectionState(ada,
- AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
+ AudioSystem.DEVICE_STATE_AVAILABLE, codec);
if (res != AudioSystem.AUDIO_STATUS_OK) {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
"APM failed to make available LE Audio device addr=" + address
@@ -2249,7 +2254,7 @@ public class AudioDeviceInventory {
// Reset LEA suspend state each time a new sink is connected
mDeviceBroker.clearLeAudioSuspended(true /* internalOnly */);
mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
- new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT,
+ new DeviceInfo(device, name, address, codec,
peerAddress, groupId));
mDeviceBroker.postAccessoryPlugMediaUnmute(device);
setCurrentAudioRouteNameIfPossible(name, /*fromA2dp=*/false);
@@ -2272,13 +2277,14 @@ public class AudioDeviceInventory {
}
@GuardedBy("mDevicesLock")
- private void makeLeAudioDeviceUnavailableNow(String address, int device) {
+ private void makeLeAudioDeviceUnavailableNow(String address, int device,
+ @AudioSystem.AudioFormatNativeEnumForBtCodec int codec) {
AudioDeviceAttributes ada = null;
if (device != AudioSystem.DEVICE_NONE) {
ada = new AudioDeviceAttributes(device, address);
final int res = AudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
- AudioSystem.AUDIO_FORMAT_DEFAULT);
+ codec);
if (res != AudioSystem.AUDIO_STATUS_OK) {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
@@ -2303,7 +2309,8 @@ public class AudioDeviceInventory {
}
@GuardedBy("mDevicesLock")
- private void makeLeAudioDeviceUnavailableLater(String address, int device, int delayMs) {
+ private void makeLeAudioDeviceUnavailableLater(
+ String address, int device, int codec, int delayMs) {
// prevent any activity on the LEA output to avoid unwanted
// reconnection of the sink.
mDeviceBroker.setLeAudioSuspended(
@@ -2311,7 +2318,7 @@ public class AudioDeviceInventory {
// the device will be made unavailable later, so consider it disconnected right away
mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(device, address));
// send the delayed message to make the device unavailable later
- mDeviceBroker.setLeAudioTimeout(address, device, delayMs);
+ mDeviceBroker.setLeAudioTimeout(address, device, codec, delayMs);
}
@GuardedBy("mDevicesLock")
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 7b9621581adf..a078d08a2c8f 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -26,6 +26,7 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothLeAudio;
+import android.bluetooth.BluetoothLeAudioCodecConfig;
import android.bluetooth.BluetoothLeAudioCodecStatus;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
@@ -250,35 +251,73 @@ public class BtHelper {
}
}
- /*package*/ synchronized @AudioSystem.AudioFormatNativeEnumForBtCodec int getA2dpCodec(
- @NonNull BluetoothDevice device) {
- if (mA2dp == null) {
- return AudioSystem.AUDIO_FORMAT_DEFAULT;
- }
- BluetoothCodecStatus btCodecStatus = null;
- try {
- btCodecStatus = mA2dp.getCodecStatus(device);
- } catch (Exception e) {
- Log.e(TAG, "Exception while getting status of " + device, e);
- }
- if (btCodecStatus == null) {
- return AudioSystem.AUDIO_FORMAT_DEFAULT;
- }
- final BluetoothCodecConfig btCodecConfig = btCodecStatus.getCodecConfig();
- if (btCodecConfig == null) {
- return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ /*package*/ synchronized @AudioSystem.AudioFormatNativeEnumForBtCodec int getCodec(
+ @NonNull BluetoothDevice device, @AudioService.BtProfile int profile) {
+ switch (profile) {
+ case BluetoothProfile.A2DP: {
+ if (mA2dp == null) {
+ return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ }
+ BluetoothCodecStatus btCodecStatus = null;
+ try {
+ btCodecStatus = mA2dp.getCodecStatus(device);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while getting status of " + device, e);
+ }
+ if (btCodecStatus == null) {
+ return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ }
+ final BluetoothCodecConfig btCodecConfig = btCodecStatus.getCodecConfig();
+ if (btCodecConfig == null) {
+ return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ }
+ return AudioSystem.bluetoothA2dpCodecToAudioFormat(btCodecConfig.getCodecType());
+ }
+ case BluetoothProfile.LE_AUDIO: {
+ if (mLeAudio == null) {
+ return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ }
+ BluetoothLeAudioCodecStatus btLeCodecStatus = null;
+ int groupId = mLeAudio.getGroupId(device);
+ try {
+ btLeCodecStatus = mLeAudio.getCodecStatus(groupId);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while getting status of " + device, e);
+ }
+ if (btLeCodecStatus == null) {
+ return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ }
+ BluetoothLeAudioCodecConfig btLeCodecConfig =
+ btLeCodecStatus.getOutputCodecConfig();
+ if (btLeCodecConfig == null) {
+ return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ }
+ return AudioSystem.bluetoothLeCodecToAudioFormat(btLeCodecConfig.getCodecType());
+ }
+ default:
+ return AudioSystem.AUDIO_FORMAT_DEFAULT;
}
- return AudioSystem.bluetoothCodecToAudioFormat(btCodecConfig.getCodecType());
}
/*package*/ synchronized @AudioSystem.AudioFormatNativeEnumForBtCodec
- int getA2dpCodecWithFallbackToSBC(
- @NonNull BluetoothDevice device, @NonNull String source) {
- @AudioSystem.AudioFormatNativeEnumForBtCodec int codec = getA2dpCodec(device);
+ int getCodecWithFallback(
+ @NonNull BluetoothDevice device, @AudioService.BtProfile int profile,
+ boolean isLeOutput, @NonNull String source) {
+ // For profiles other than A2DP and LE Audio output, the audio codec format must be
+ // AUDIO_FORMAT_DEFAULT as native audio policy manager expects a specific audio format
+ // only if audio HW module selection based on format is supported for the device type.
+ if (!(profile == BluetoothProfile.A2DP
+ || (profile == BluetoothProfile.LE_AUDIO && isLeOutput))) {
+ return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ }
+ @AudioSystem.AudioFormatNativeEnumForBtCodec int codec =
+ getCodec(device, profile);
if (codec == AudioSystem.AUDIO_FORMAT_DEFAULT) {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
- "getA2dpCodec DEFAULT from " + source + " fallback to SBC"));
- return AudioSystem.AUDIO_FORMAT_SBC;
+ "getCodec DEFAULT from " + source + " fallback to "
+ + (profile == BluetoothProfile.A2DP ? "SBC" : "LC3")));
+ return profile == BluetoothProfile.A2DP
+ ? AudioSystem.AUDIO_FORMAT_SBC : AudioSystem.AUDIO_FORMAT_LC3;
}
return codec;
}