Parse audio config codec capability for LE devices

1. Rename function getHwOffloadEncodingFormatsSupportedForA2DP
    to getHwOffloadFormatsSupportedForBluetoothMedia
 2. Add audio format for LC3
 3. Add public class BluetoothLeAudioCodecConfig to store the
    codec for LE audio
 4. Add test case for BluetoothLeAudioCodecConfig

Tag: #feature
Bug: 203535499
Bug: 150670922
Test: atest BluetoothLeAudioCodecConfigTest BluetoothInstrumentationTests
Change-Id: I5f64d9078ca2c07e13cffd83b879dd95468ed313
Merged-In: I5f64d9078ca2c07e13cffd83b879dd95468ed313
This commit is contained in:
Patty 2021-11-04 21:03:32 +08:00
parent e39da5a9a7
commit ae425ca614
6 changed files with 288 additions and 25 deletions

View File

@ -9452,6 +9452,20 @@ package android.bluetooth {
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED = "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
}
public final class BluetoothLeAudioCodecConfig {
method @NonNull public String getCodecName();
method public int getCodecType();
method public static int getMaxCodecType();
field public static final int SOURCE_CODEC_TYPE_INVALID = 1000000; // 0xf4240
field public static final int SOURCE_CODEC_TYPE_LC3 = 0; // 0x0
}
public static final class BluetoothLeAudioCodecConfig.Builder {
ctor public BluetoothLeAudioCodecConfig.Builder();
method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig build();
method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setCodecType(int);
}
public final class BluetoothManager {
method public android.bluetooth.BluetoothAdapter getAdapter();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);

View File

@ -0,0 +1,129 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.bluetooth;
import android.annotation.IntDef;
import android.annotation.NonNull;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Represents the codec configuration for a Bluetooth LE Audio source device.
* <p>Contains the source codec type.
* <p>The source codec type values are the same as those supported by the
* device hardware.
*
* {@see BluetoothLeAudioCodecConfig}
*/
public final class BluetoothLeAudioCodecConfig {
// Add an entry for each source codec here.
/** @hide */
@IntDef(prefix = "SOURCE_CODEC_TYPE_", value = {
SOURCE_CODEC_TYPE_LC3,
SOURCE_CODEC_TYPE_INVALID
})
@Retention(RetentionPolicy.SOURCE)
public @interface SourceCodecType {};
public static final int SOURCE_CODEC_TYPE_LC3 = 0;
public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
/**
* Represents the count of valid source codec types. Can be accessed via
* {@link #getMaxCodecType}.
*/
private static final int SOURCE_CODEC_TYPE_MAX = 1;
private final @SourceCodecType int mCodecType;
/**
* Creates a new BluetoothLeAudioCodecConfig.
*
* @param codecType the source codec type
*/
private BluetoothLeAudioCodecConfig(@SourceCodecType int codecType) {
mCodecType = codecType;
}
@Override
public String toString() {
return "{codecName:" + getCodecName() + "}";
}
/**
* Gets the codec type.
*
* @return the codec type
*/
public @SourceCodecType int getCodecType() {
return mCodecType;
}
/**
* Returns the valid codec types count.
*/
public static int getMaxCodecType() {
return SOURCE_CODEC_TYPE_MAX;
}
/**
* Gets the codec name.
*
* @return the codec name
*/
public @NonNull String getCodecName() {
switch (mCodecType) {
case SOURCE_CODEC_TYPE_LC3:
return "LC3";
case SOURCE_CODEC_TYPE_INVALID:
return "INVALID CODEC";
default:
break;
}
return "UNKNOWN CODEC(" + mCodecType + ")";
}
/**
* Builder for {@link BluetoothLeAudioCodecConfig}.
* <p> By default, the codec type will be set to
* {@link BluetoothLeAudioCodecConfig#SOURCE_CODEC_TYPE_INVALID}
*/
public static final class Builder {
private int mCodecType = BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID;
/**
* Set codec type for Bluetooth codec config.
*
* @param codecType of this codec
* @return the same Builder instance
*/
public @NonNull Builder setCodecType(@SourceCodecType int codecType) {
mCodecType = codecType;
return this;
}
/**
* Build {@link BluetoothLeAudioCodecConfig}.
* @return new BluetoothLeAudioCodecConfig built
*/
public @NonNull BluetoothLeAudioCodecConfig build() {
return new BluetoothLeAudioCodecConfig(mCodecType);
}
}
}

View File

@ -2273,10 +2273,8 @@ android_media_AudioSystem_getMicrophones(JNIEnv *env, jobject thiz, jobject jMic
return jStatus;
}
static jint
android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP(
JNIEnv *env, jobject thiz, jobject jEncodingFormatList)
{
static jint android_media_AudioSystem_getHwOffloadFormatsSupportedForBluetoothMedia(
JNIEnv *env, jobject thiz, jint deviceType, jobject jEncodingFormatList) {
ALOGV("%s", __FUNCTION__);
jint jStatus = AUDIO_JAVA_SUCCESS;
if (!env->IsInstanceOf(jEncodingFormatList, gArrayListClass)) {
@ -2284,8 +2282,10 @@ android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP(
return (jint)AUDIO_JAVA_BAD_VALUE;
}
std::vector<audio_format_t> encodingFormats;
status_t status = AudioSystem::getHwOffloadEncodingFormatsSupportedForA2DP(
&encodingFormats);
status_t status =
AudioSystem::getHwOffloadFormatsSupportedForBluetoothMedia(static_cast<audio_devices_t>(
deviceType),
&encodingFormats);
if (status != NO_ERROR) {
ALOGE("%s: error %d", __FUNCTION__, status);
jStatus = nativeToJavaStatus(status);
@ -2810,8 +2810,8 @@ static const JNINativeMethod gMethods[] =
{"setA11yServicesUids", "([I)I", (void *)android_media_AudioSystem_setA11yServicesUids},
{"isHapticPlaybackSupported", "()Z",
(void *)android_media_AudioSystem_isHapticPlaybackSupported},
{"getHwOffloadEncodingFormatsSupportedForA2DP", "(Ljava/util/ArrayList;)I",
(void *)android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP},
{"getHwOffloadFormatsSupportedForBluetoothMedia", "(ILjava/util/ArrayList;)I",
(void *)android_media_AudioSystem_getHwOffloadFormatsSupportedForBluetoothMedia},
{"setSupportedSystemUsages", "([I)I",
(void *)android_media_AudioSystem_setSupportedSystemUsages},
{"setAllowedCapturePolicy", "(II)I",

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.bluetooth;
import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.TestCase;
/**
* Unit test cases for {@link BluetoothLeAudioCodecConfig}.
*/
public class BluetoothLeAudioCodecConfigTest extends TestCase {
private int[] mCodecTypeArray = new int[] {
BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3,
BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID,
};
@SmallTest
public void testBluetoothLeAudioCodecConfig_valid_get_methods() {
for (int codecIdx = 0; codecIdx < mCodecTypeArray.length; codecIdx++) {
int codecType = mCodecTypeArray[codecIdx];
BluetoothLeAudioCodecConfig leAudioCodecConfig =
buildBluetoothLeAudioCodecConfig(codecType);
if (codecType == BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3) {
assertEquals("LC3", leAudioCodecConfig.getCodecName());
}
if (codecType == BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
assertEquals("INVALID CODEC", leAudioCodecConfig.getCodecName());
}
assertEquals(1, leAudioCodecConfig.getMaxCodecType());
assertEquals(codecType, leAudioCodecConfig.getCodecType());
}
}
private BluetoothLeAudioCodecConfig buildBluetoothLeAudioCodecConfig(int sourceCodecType) {
return new BluetoothLeAudioCodecConfig.Builder()
.setCodecType(sourceCodecType)
.build();
}
}

View File

@ -32,6 +32,7 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothCodecConfig;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeAudioCodecConfig;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@ -6790,30 +6791,56 @@ public class AudioManager {
/**
* Returns a list of audio formats that corresponds to encoding formats
* supported on offload path for A2DP playback.
* supported on offload path for A2DP and LE audio playback.
*
* @param deviceType Indicates the target device type {@link AudioSystem.DeviceType}
* @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
* supported for offload A2DP playback
* supported for offload A2DP playback or a list of {@link BluetoothLeAudioCodecConfig}
* objects containing encoding formats supported for offload LE Audio playback
* @hide
*/
public List<BluetoothCodecConfig> getHwOffloadEncodingFormatsSupportedForA2DP() {
public List<?> getHwOffloadFormatsSupportedForBluetoothMedia(
@AudioSystem.DeviceType int deviceType) {
ArrayList<Integer> formatsList = new ArrayList<Integer>();
ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<BluetoothCodecConfig>();
ArrayList<BluetoothCodecConfig> a2dpCodecConfigList = new ArrayList<BluetoothCodecConfig>();
ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList =
new ArrayList<BluetoothLeAudioCodecConfig>();
int status = AudioSystem.getHwOffloadEncodingFormatsSupportedForA2DP(formatsList);
if (deviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP
&& deviceType != AudioSystem.DEVICE_OUT_BLE_HEADSET) {
throw new IllegalArgumentException(
"Illegal devicetype for the getHwOffloadFormatsSupportedForBluetoothMedia");
}
int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(deviceType,
formatsList);
if (status != AudioManager.SUCCESS) {
Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
return codecConfigList;
Log.e(TAG, "getHwOffloadFormatsSupportedForBluetoothMedia for deviceType "
+ deviceType + " failed:" + status);
return a2dpCodecConfigList;
}
for (Integer format : formatsList) {
int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
if (btSourceCodec
!= BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
codecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
if (deviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
for (Integer format : formatsList) {
int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
a2dpCodecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
}
}
return a2dpCodecConfigList;
} else if (deviceType == AudioSystem.DEVICE_OUT_BLE_HEADSET) {
for (Integer format : formatsList) {
int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
.setCodecType(btLeAudioCodec)
.build());
}
}
return leAudioCodecConfigList;
}
return codecConfigList;
Log.e(TAG, "Input deviceType " + deviceType + " doesn't support.");
return a2dpCodecConfigList;
}
// Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the

View File

@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
import android.bluetooth.BluetoothCodecConfig;
import android.bluetooth.BluetoothLeAudioCodecConfig;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.PackageManager;
@ -229,6 +230,9 @@ public class AudioSystem
public static final int AUDIO_FORMAT_APTX_HD = 0x21000000;
/** @hide */
public static final int AUDIO_FORMAT_LDAC = 0x23000000;
/** @hide */
public static final int AUDIO_FORMAT_LC3 = 0x2B000000;
/** @hide */
@IntDef(flag = false, prefix = "AUDIO_FORMAT_", value = {
@ -238,11 +242,26 @@ public class AudioSystem
AUDIO_FORMAT_SBC,
AUDIO_FORMAT_APTX,
AUDIO_FORMAT_APTX_HD,
AUDIO_FORMAT_LDAC }
AUDIO_FORMAT_LDAC}
)
@Retention(RetentionPolicy.SOURCE)
public @interface AudioFormatNativeEnumForBtCodec {}
/** @hide */
@IntDef(flag = false, prefix = "AUDIO_FORMAT_", value = {
AUDIO_FORMAT_LC3}
)
@Retention(RetentionPolicy.SOURCE)
public @interface AudioFormatNativeEnumForBtLeAudioCodec {}
/** @hide */
@IntDef(flag = false, prefix = "DEVICE_", value = {
DEVICE_OUT_BLUETOOTH_A2DP,
DEVICE_OUT_BLE_HEADSET}
)
@Retention(RetentionPolicy.SOURCE)
public @interface DeviceType {}
/**
* @hide
* Convert audio format enum values to Bluetooth codec values
@ -262,6 +281,21 @@ public class AudioSystem
}
}
/**
* @hide
* Convert audio format enum values to Bluetooth LE audio codec values
*/
public static int audioFormatToBluetoothLeAudioSourceCodec(
@AudioFormatNativeEnumForBtLeAudioCodec int audioFormat) {
switch (audioFormat) {
case AUDIO_FORMAT_LC3: return BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3;
default:
Log.e(TAG, "Unknown audio format 0x" + Integer.toHexString(audioFormat)
+ " for conversion to BT LE audio codec");
return BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID;
}
}
/**
* @hide
* Convert a Bluetooth codec to an audio format enum
@ -1754,10 +1788,10 @@ public class AudioSystem
/**
* @hide
* Returns a list of audio formats (codec) supported on the A2DP offload path.
* Returns a list of audio formats (codec) supported on the A2DP and LE audio offload path.
*/
public static native int getHwOffloadEncodingFormatsSupportedForA2DP(
ArrayList<Integer> formatList);
public static native int getHwOffloadFormatsSupportedForBluetoothMedia(
@DeviceType int deviceType, ArrayList<Integer> formatList);
/** @hide */
public static native int setSurroundFormatEnabled(int audioFormat, boolean enabled);