diff options
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; } |