diff options
144 files changed, 11282 insertions, 9357 deletions
diff --git a/OWNERS_chromeos b/OWNERS_chromeos index 0280ec47df..15a57740e4 100644 --- a/OWNERS_chromeos +++ b/OWNERS_chromeos @@ -1,6 +1,5 @@ # Project owners abhishekpandit@google.com -sonnysasaka@google.com # Audio enshuo@google.com @@ -12,3 +11,4 @@ whalechang@google.com michaelfsun@google.com laikatherine@google.com yinghsu@google.com +apusaka@google.com diff --git a/TEST_MAPPING b/TEST_MAPPING index 3a88aa07cb..5f21a9b800 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -108,9 +108,6 @@ "name": "bluetooth_test_common" }, { - "name": "bluetooth_test_gd_unit" - }, - { "name": "bluetooth_test_sdp" }, { diff --git a/android/app/Android.bp b/android/app/Android.bp index b38f847323..71b8a38760 100644 --- a/android/app/Android.bp +++ b/android/app/Android.bp @@ -323,23 +323,39 @@ android_app { enabled: true, javacflags: [ "-Xep:AlmostJavadoc:ERROR", + "-Xep:AlreadyChecked:ERROR", + "-Xep:AndroidFrameworkBinderIdentity:ERROR", "-Xep:AndroidFrameworkEfficientStrings:ERROR", "-Xep:AndroidFrameworkRequiresPermission:ERROR", "-Xep:BadImport:ERROR", "-Xep:ClassCanBeStatic:ERROR", + "-Xep:DateFormatConstant:ERROR", "-Xep:EmptyBlockTag:ERROR", + "-Xep:FallThrough:ERROR", + "-Xep:HidingField:ERROR", "-Xep:InlineMeInliner:ERROR", "-Xep:InvalidBlockTag:ERROR", "-Xep:InvalidParam:ERROR", + "-Xep:LoopOverCharArray:ERROR", + "-Xep:MissingCasesInEnumSwitch:ERROR", "-Xep:MockNotUsedInProduction:ERROR", + "-Xep:ModifyCollectionInEnhancedForLoop:ERROR", + "-Xep:NarrowCalculation:ERROR", "-Xep:NonApiType:ERROR", + "-Xep:NonAtomicVolatileUpdate:ERROR", "-Xep:NonCanonicalType:ERROR", "-Xep:NotJavadoc:ERROR", + "-Xep:OperatorPrecedence:ERROR", "-Xep:ReturnAtTheEndOfVoidFunction:ERROR", "-Xep:StringCaseLocaleUsage:ERROR", "-Xep:StringCharset:ERROR", + "-Xep:ToStringReturnsNull:ERROR", + "-Xep:UnnecessaryStringBuilder:ERROR", + "-Xep:UnrecognisedJavadocTag:ERROR", "-Xep:UnusedMethod:ERROR", + "-Xep:UnusedNestedClass:ERROR", "-Xep:UnusedVariable:ERROR", + "-Xep:WaitNotInLoop:ERROR", "-XepExcludedPaths:.*/srcjars/.*", // Exclude generated files ], }, diff --git a/android/app/aidl/android/bluetooth/IBluetooth.aidl b/android/app/aidl/android/bluetooth/IBluetooth.aidl index aaccb15c95..27061542f7 100644 --- a/android/app/aidl/android/bluetooth/IBluetooth.aidl +++ b/android/app/aidl/android/bluetooth/IBluetooth.aidl @@ -280,6 +280,8 @@ interface IBluetooth @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})") Bundle getPreferredAudioProfiles(in BluetoothDevice device, in AttributionSource source); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})") + int isDualModeAudioEnabled(in AttributionSource attributionSource); + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})") int registerPreferredAudioProfilesChangedCallback(in IBluetoothPreferredAudioProfilesCallback callback, in AttributionSource attributionSource); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})") int unregisterPreferredAudioProfilesChangedCallback(in IBluetoothPreferredAudioProfilesCallback callback, in AttributionSource attributionSource); diff --git a/android/app/jni/com_android_bluetooth_vc.cpp b/android/app/jni/com_android_bluetooth_vc.cpp index f56b913afe..986605dab1 100644 --- a/android/app/jni/com_android_bluetooth_vc.cpp +++ b/android/app/jni/com_android_bluetooth_vc.cpp @@ -67,7 +67,7 @@ public: addr.get()); } - void OnVolumeStateChanged(const RawAddress& bd_addr, uint8_t volume, bool mute, + void OnVolumeStateChanged(const RawAddress& bd_addr, uint8_t volume, bool mute, uint8_t flags, bool isAutonomous) override { log::info(""); @@ -86,7 +86,7 @@ public: sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeStateChanged, (jint)volume, - (jboolean)mute, addr.get(), (jboolean)isAutonomous); + (jboolean)mute, (jint)flags, addr.get(), (jboolean)isAutonomous); } void OnGroupVolumeStateChanged(int group_id, uint8_t volume, bool mute, @@ -533,7 +533,7 @@ int register_com_android_bluetooth_vc(JNIEnv* env) { const JNIJavaMethod javaMethods[] = { {"onConnectionStateChanged", "(I[B)V", &method_onConnectionStateChanged}, - {"onVolumeStateChanged", "(IZ[BZ)V", &method_onVolumeStateChanged}, + {"onVolumeStateChanged", "(IZI[BZ)V", &method_onVolumeStateChanged}, {"onGroupVolumeStateChanged", "(IZIZ)V", &method_onGroupVolumeStateChanged}, {"onDeviceAvailable", "(I[B)V", &method_onDeviceAvailable}, {"onExtAudioOutVolumeOffsetChanged", "(II[B)V", &method_onExtAudioOutVolumeOffsetChanged}, diff --git a/android/app/src/com/android/bluetooth/BluetoothEventLogger.java b/android/app/src/com/android/bluetooth/BluetoothEventLogger.java index c4591ef000..9a5f811bcf 100644 --- a/android/app/src/com/android/bluetooth/BluetoothEventLogger.java +++ b/android/app/src/com/android/bluetooth/BluetoothEventLogger.java @@ -36,7 +36,7 @@ public class BluetoothEventLogger { } public String toString() { - return (new StringBuilder(mTimeStamp).append(" ").append(mMsg).toString()); + return mTimeStamp + " " + mMsg; } } diff --git a/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtManager.java b/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtManager.java index 7ac0842b01..a48b2d5ea2 100644 --- a/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtManager.java +++ b/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtManager.java @@ -128,7 +128,8 @@ public class AvrcpCoverArtManager { */ public static boolean isValidImageHandle(String handle) { if (handle == null || handle.length() != 7) return false; - for (char c : handle.toCharArray()) { + for (int i = 0; i < handle.length(); i++) { + char c = handle.charAt(i); if (!Character.isDigit(c)) { return false; } diff --git a/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipDateTime.java b/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipDateTime.java index 380111aa81..53260b050b 100644 --- a/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipDateTime.java +++ b/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipDateTime.java @@ -16,6 +16,8 @@ package com.android.bluetooth.avrcpcontroller; +import android.annotation.SuppressLint; + import com.android.bluetooth.Utils; import java.util.Calendar; @@ -121,6 +123,7 @@ public class BipDateTime { } @Override + @SuppressLint("ToStringReturnsNull") public String toString() { Date d = getTime(); if (d == null) { diff --git a/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipImageDescriptor.java b/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipImageDescriptor.java index 3eae52076a..4ddac205b0 100644 --- a/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipImageDescriptor.java +++ b/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipImageDescriptor.java @@ -16,6 +16,7 @@ package com.android.bluetooth.avrcpcontroller; +import android.annotation.SuppressLint; import android.util.Log; import android.util.Xml; @@ -262,6 +263,7 @@ public class BipImageDescriptor { } @Override + @SuppressLint("ToStringReturnsNull") // Since this is used for encoding to xml public String toString() { if (mEncoding == null || mPixel == null) { error( diff --git a/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipImageFormat.java b/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipImageFormat.java index cb564b639e..f9a93c560d 100644 --- a/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipImageFormat.java +++ b/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipImageFormat.java @@ -16,6 +16,7 @@ package com.android.bluetooth.avrcpcontroller; +import android.annotation.SuppressLint; import android.util.Log; import java.util.Objects; @@ -179,6 +180,7 @@ public class BipImageFormat { } @Override + @SuppressLint("ToStringReturnsNull") // Since this is used for encoding to xml public String toString() { if (mEncoding == null || mEncoding.getType() == BipEncoding.UNKNOWN diff --git a/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipImageProperties.java b/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipImageProperties.java index e49d9dd5a9..442b03f529 100644 --- a/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipImageProperties.java +++ b/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipImageProperties.java @@ -16,6 +16,7 @@ package com.android.bluetooth.avrcpcontroller; +import android.annotation.SuppressLint; import android.util.Log; import android.util.Xml; @@ -298,6 +299,7 @@ public class BipImageProperties { } @Override + @SuppressLint("ToStringReturnsNull") // Since this is used for encoding to xml public String toString() { StringWriter writer = new StringWriter(); XmlSerializer xmlMsgElement = Xml.newSerializer(); diff --git a/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipPixel.java b/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipPixel.java index f3be13363d..1308c47c12 100644 --- a/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipPixel.java +++ b/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipPixel.java @@ -197,9 +197,11 @@ public class BipPixel { private static int determinePixelType(String pixel) { if (pixel == null || pixel.length() > 23) return TYPE_UNKNOWN; int delimCount = 0; - for (char c : pixel.toCharArray()) { + for (int i = 0; i < pixel.length(); i++) { + char c = pixel.charAt(i); if (c == '*') delimCount++; } + return delimCount > 0 && delimCount <= 3 ? delimCount : TYPE_UNKNOWN; } diff --git a/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipTransformation.java b/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipTransformation.java index 31e4f29a86..830daf563b 100644 --- a/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipTransformation.java +++ b/android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipTransformation.java @@ -16,6 +16,7 @@ package com.android.bluetooth.avrcpcontroller; +import android.annotation.SuppressLint; import android.util.Log; import com.google.common.base.Ascii; @@ -152,6 +153,7 @@ public class BipTransformation { } @Override + @SuppressLint("ToStringReturnsNull") public String toString() { if (!supportsAny()) return null; StringBuilder transformations = new StringBuilder(); diff --git a/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java b/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java index 4739530850..7fd6bb349f 100644 --- a/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java +++ b/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java @@ -171,7 +171,7 @@ public class BassClientStateMachine extends StateMachine { AdapterService adapterService, Looper looper, int connectTimeoutMs) { - super(TAG + "(" + device.toString() + ")", looper); + super(TAG + "(" + device + ")", looper); mDevice = device; mService = svc; mAdapterService = adapterService; @@ -182,21 +182,24 @@ public class BassClientStateMachine extends StateMachine { addState(mConnectedProcessing); setInitialState(mDisconnected); mFirstTimeBisDiscoveryMap = new HashMap<Integer, Boolean>(); - long token = Binder.clearCallingIdentity(); - mIsAllowedList = - DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_BLUETOOTH, "persist.vendor.service.bt.wl", true); - mDefNoPAS = - DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_BLUETOOTH, - "persist.vendor.service.bt.defNoPAS", - false); - mForceSB = - DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_BLUETOOTH, - "persist.vendor.service.bt.forceSB", - false); - Binder.restoreCallingIdentity(token); + final long token = Binder.clearCallingIdentity(); + try { + mIsAllowedList = + DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_BLUETOOTH, "persist.vendor.service.bt.wl", true); + mDefNoPAS = + DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_BLUETOOTH, + "persist.vendor.service.bt.defNoPAS", + false); + mForceSB = + DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_BLUETOOTH, + "persist.vendor.service.bt.forceSB", + false); + } finally { + Binder.restoreCallingIdentity(token); + } } static BassClientStateMachine make( diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterService.java b/android/app/src/com/android/bluetooth/btservice/AdapterService.java index bc5a0dfe46..dde36b7e5d 100644 --- a/android/app/src/com/android/bluetooth/btservice/AdapterService.java +++ b/android/app/src/com/android/bluetooth/btservice/AdapterService.java @@ -794,28 +794,14 @@ public class AdapterService extends Service { } @Override - @RequiresPermission(BLUETOOTH_CONNECT) public boolean onUnbind(Intent intent) { - if (Flags.explicitKillFromSystemServer()) { - Log.d(TAG, "onUnbind()"); - return super.onUnbind(intent); - } - Log.d(TAG, "onUnbind() - calling cleanup"); - cleanup(); + Log.d(TAG, "onUnbind()"); return super.onUnbind(intent); } @Override public void onDestroy() { Log.d(TAG, "onDestroy()"); - if (Flags.explicitKillFromSystemServer()) { - return; - } - if (!isMock()) { - // TODO(b/27859763) - Log.i(TAG, "Force exit to cleanup internal state in Bluetooth stack"); - System.exit(0); - } } public ActiveDeviceManager getActiveDeviceManager() { @@ -1484,14 +1470,6 @@ public class AdapterService extends Service { mBluetoothSocketManagerBinder = null; } - if (!Flags.explicitKillFromSystemServer()) { - // Bluetooth will be killed, no need to cleanup binder - if (mBinder != null) { - mBinder.cleanup(); - mBinder = null; // Do not remove. Otherwise Binder leak! - } - } - mPreferredAudioProfilesCallbacks.kill(); mBluetoothQualityReportReadyCallbacks.kill(); @@ -2252,20 +2230,12 @@ public class AdapterService extends Service { } /** - * The Binder implementation must be declared to be a static class, with the AdapterService - * instance passed in the constructor. Furthermore, when the AdapterService shuts down, the - * reference to the AdapterService must be explicitly removed. - * - * <p>Otherwise, a memory leak can occur from repeated starting/stopping the service...Please - * refer to android.os.Binder for further details on why an inner instance class should be - * avoided. - * - * <p>TODO: b/339548431 -- Delete this comment as it does not apply when we get killed + * There is no leak of this binder since it is never re-used and the process is systematically + * killed */ @VisibleForTesting public static class AdapterServiceBinder extends IBluetooth.Stub { - // TODO: b/339548431 move variable to final - private AdapterService mService; + private final AdapterService mService; AdapterServiceBinder(AdapterService svc) { mService = svc; @@ -2273,18 +2243,11 @@ public class AdapterService extends Service { BluetoothAdapter.getDefaultAdapter().disableBluetoothGetStateCache(); } - public void cleanup() { - mService = null; - } - public AdapterService getService() { - // Cache mService because it can change while getService is called - AdapterService service = mService; - - if (service == null || !service.isAvailable()) { + if (!mService.isAvailable()) { return null; } - return service; + return mService; } @Override @@ -4020,6 +3983,24 @@ public class AdapterService extends Service { } @Override + public int isDualModeAudioEnabled(AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + if (!Utils.isDualModeAudioEnabled()) { + return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED; + } + + return BluetoothStatusCodes.SUCCESS; + } + + @Override public int registerPreferredAudioProfilesChangedCallback( IBluetoothPreferredAudioProfilesCallback callback, AttributionSource source) { AdapterService service = getService(); @@ -4037,7 +4018,7 @@ public class AdapterService extends Service { service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); // If LE only mode is enabled, the dual mode audio feature is disabled - if (!isDualModeAudioEnabled()) { + if (!Utils.isDualModeAudioEnabled()) { return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED; } @@ -6888,15 +6869,4 @@ public class AdapterService extends Service { mPhonePolicy.onUuidsDiscovered(device, uuids); } } - - // TODO: b/339548431 delete isMock - // Returns if this is a mock object. This is currently used in testing so that we may not call - // System.exit() while finalizing the object. Otherwise GC of mock objects unfortunately ends up - // calling finalize() which in turn calls System.exit() and the process crashes. - // - // Mock this in your testing framework to return true to avoid the mentioned behavior. In - // production this has no effect. - public boolean isMock() { - return false; - } } diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterState.java b/android/app/src/com/android/bluetooth/btservice/AdapterState.java index cd2182c1a7..bcdd092716 100644 --- a/android/app/src/com/android/bluetooth/btservice/AdapterState.java +++ b/android/app/src/com/android/bluetooth/btservice/AdapterState.java @@ -22,7 +22,6 @@ import android.os.Message; import android.os.SystemProperties; import android.util.Log; -import com.android.bluetooth.flags.Flags; import com.android.internal.util.State; import com.android.internal.util.StateMachine; @@ -172,10 +171,6 @@ final class AdapterState extends StateMachine { @Override public void enter() { - if (!Flags.explicitKillFromSystemServer()) { - super.enter(); - return; - } int prevState = mPrevState; super.enter(); if (prevState == BluetoothAdapter.STATE_BLE_TURNING_OFF) { diff --git a/android/app/src/com/android/bluetooth/btservice/AudioRoutingManager.java b/android/app/src/com/android/bluetooth/btservice/AudioRoutingManager.java index bad17b6a47..59c3e794e7 100644 --- a/android/app/src/com/android/bluetooth/btservice/AudioRoutingManager.java +++ b/android/app/src/com/android/bluetooth/btservice/AudioRoutingManager.java @@ -68,7 +68,7 @@ public class AudioRoutingManager extends ActiveDeviceManager { private AudioRoutingHandler mHandler = null; private final AudioManager mAudioManager; private final MediaSessionManager mSessionManager; - private final AudioManagerAudioDeviceCallback mAudioManagerAudioDeviceCallback; + private final AudioManagerAudioDeviceCallback mAudioRoutingManagerAudioDeviceCallback; @Override public void onBluetoothStateChange(int prevState, int newState) { @@ -144,7 +144,7 @@ public class AudioRoutingManager extends ActiveDeviceManager { mFactory = factory; mAudioManager = service.getSystemService(AudioManager.class); mSessionManager = service.getSystemService(MediaSessionManager.class); - mAudioManagerAudioDeviceCallback = new AudioManagerAudioDeviceCallback(); + mAudioRoutingManagerAudioDeviceCallback = new AudioManagerAudioDeviceCallback(); } @Override @@ -157,7 +157,8 @@ public class AudioRoutingManager extends ActiveDeviceManager { mHandler = new AudioRoutingHandler(mp.handlerThreadGetLooper(mHandlerThread)); mAudioManager.addOnModeChangedListener(cmd -> mHandler.post(cmd), mHandler); - mAudioManager.registerAudioDeviceCallback(mAudioManagerAudioDeviceCallback, mHandler); + mAudioManager.registerAudioDeviceCallback( + mAudioRoutingManagerAudioDeviceCallback, mHandler); mAdapterService.registerBluetoothStateCallback((command) -> mHandler.post(command), this); } @@ -166,7 +167,7 @@ public class AudioRoutingManager extends ActiveDeviceManager { Log.d(TAG, "cleanup()"); mAudioManager.removeOnModeChangedListener(mHandler); - mAudioManager.unregisterAudioDeviceCallback(mAudioManagerAudioDeviceCallback); + mAudioManager.unregisterAudioDeviceCallback(mAudioRoutingManagerAudioDeviceCallback); mAdapterService.unregisterBluetoothStateCallback(this); if (mHandlerThread != null) { mHandlerThread.quit(); diff --git a/android/app/src/com/android/bluetooth/gatt/GattNativeInterface.java b/android/app/src/com/android/bluetooth/gatt/GattNativeInterface.java index 79f3638f6e..c0a2ca18ef 100644 --- a/android/app/src/com/android/bluetooth/gatt/GattNativeInterface.java +++ b/android/app/src/com/android/bluetooth/gatt/GattNativeInterface.java @@ -438,7 +438,7 @@ public class GattNativeInterface { /** * Connect to the remote Gatt server * - * @see {@link BluetoothDevice#connectGatt} for parameters. + * @see BluetoothDevice#connectGatt for parameters. */ public void gattClientConnect( int clientIf, diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetService.java b/android/app/src/com/android/bluetooth/hfp/HeadsetService.java index df4eac0ea8..f278a3cefa 100644 --- a/android/app/src/com/android/bluetooth/hfp/HeadsetService.java +++ b/android/app/src/com/android/bluetooth/hfp/HeadsetService.java @@ -27,6 +27,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; @@ -581,6 +582,7 @@ public class HeadsetService extends ProfileService { } @Override + @SuppressLint("AndroidFrameworkRequiresPermission") // TODO: b/356478621 - remove public boolean setConnectionPolicy( BluetoothDevice device, int connectionPolicy, AttributionSource source) { HeadsetService service = getService(source); @@ -588,7 +590,8 @@ public class HeadsetService extends ProfileService { return false; } - service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); + // TODO: b/356478621 - put back the permission check + // service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); return service.setConnectionPolicy(device, connectionPolicy); } diff --git a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java index e26b91f048..8c2f9fbf25 100644 --- a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java +++ b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java @@ -1787,6 +1787,7 @@ public class HeadsetClientStateMachine extends StateMachine { break; case SEND_ANDROID_AT_COMMAND: debug("Connected: Received OK for AT+ANDROID"); + break; default: warn("Unhandled AT OK " + event); break; diff --git a/android/app/src/com/android/bluetooth/hfpclient/HfpClientConnection.java b/android/app/src/com/android/bluetooth/hfpclient/HfpClientConnection.java index 66d323a04c..3509906931 100644 --- a/android/app/src/com/android/bluetooth/hfpclient/HfpClientConnection.java +++ b/android/app/src/com/android/bluetooth/hfpclient/HfpClientConnection.java @@ -281,7 +281,7 @@ public class HfpClientConnection extends Connection { return false; } Uri otherAddr = ((HfpClientConnection) o).getAddress(); - return getAddress() == otherAddr || otherAddr != null && otherAddr.equals(getAddress()); + return getAddress() == otherAddr || (otherAddr != null && otherAddr.equals(getAddress())); } @Override diff --git a/android/app/src/com/android/bluetooth/hid/HidHostService.java b/android/app/src/com/android/bluetooth/hid/HidHostService.java index 02481e604d..4189cec8e7 100644 --- a/android/app/src/com/android/bluetooth/hid/HidHostService.java +++ b/android/app/src/com/android/bluetooth/hid/HidHostService.java @@ -109,7 +109,6 @@ public class HidHostService extends ProfileService { private final HidHostNativeInterface mNativeInterface; private boolean mNativeAvailable; - private BluetoothDevice mTargetDevice = null; private static final int MESSAGE_CONNECT = 1; private static final int MESSAGE_DISCONNECT = 2; @@ -698,7 +697,6 @@ public class HidHostService extends ProfileService { if (Flags.allowSwitchingHidAndHogp() || connectionAllowed) { updateConnectionState(device, transport, reportedState); } - updateQuietMode(device, reportedState); } private void handleMessageDisconnect(Message msg) { @@ -781,23 +779,6 @@ public class HidHostService extends ProfileService { return true; } - /** - * Disables the quiet mode if target device gets connected - * - * @param device remote device - * @param state connection state - */ - private void updateQuietMode(BluetoothDevice device, int state) { - if (state == BluetoothProfile.STATE_CONNECTED - && mTargetDevice != null - && mTargetDevice.equals(device)) { - // Locally initiated connection, move out of quiet mode - Log.i(TAG, "updateQuietMode: Move out of quiet mode. device=" + device); - mTargetDevice = null; - mAdapterService.enable(false); - } - } - @VisibleForTesting static class BluetoothHidHostBinder extends IBluetoothHidHost.Stub implements IProfileServiceBinder { @@ -1482,7 +1463,7 @@ public class HidHostService extends ProfileService { @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) public boolean okToConnect(BluetoothDevice device) { // Check if this is an incoming connection in Quiet mode. - if (mAdapterService.isQuietModeEnabled() && mTargetDevice == null) { + if (mAdapterService.isQuietModeEnabled()) { Log.w(TAG, "okToConnect: return false because of quiet mode enabled. device=" + device); return false; } @@ -1510,7 +1491,6 @@ public class HidHostService extends ProfileService { @Override public void dump(StringBuilder sb) { super.dump(sb); - println(sb, "mTargetDevice: " + mTargetDevice); println(sb, "mInputDevices:"); mInputDevices.forEach( (k, v) -> sb.append(" ").append(k).append(" : ").append(v).append("\n")); diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java index 17313b0946..387c5b8d46 100644 --- a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java +++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java @@ -2568,6 +2568,7 @@ public class LeAudioService extends ProfileService { groupDescriptor.mInactivatedDueToContextType = true; setActiveGroupWithDevice(null, false); } + break; default: break; } diff --git a/android/app/src/com/android/bluetooth/le_scan/AppScanStats.java b/android/app/src/com/android/bluetooth/le_scan/AppScanStats.java index 7bf79ca143..5e15fdaba2 100644 --- a/android/app/src/com/android/bluetooth/le_scan/AppScanStats.java +++ b/android/app/src/com/android/bluetooth/le_scan/AppScanStats.java @@ -47,7 +47,8 @@ import java.util.Objects; public class AppScanStats { private static final String TAG = AppScanStats.class.getSimpleName(); - static final DateFormat DATE_FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss"); + private static final ThreadLocal<DateFormat> DATE_FORMAT = + ThreadLocal.withInitial(() -> new SimpleDateFormat("MM-dd HH:mm:ss")); // Weight is the duty cycle of the scan mode static final int OPPORTUNISTIC_WEIGHT = 0; @@ -1031,7 +1032,7 @@ public class AppScanStats { for (int i = 0; i < mLastScans.size(); i++) { LastScan scan = mLastScans.get(i); Date timestamp = new Date(currentTime - currTime + scan.timestamp); - sb.append("\n ").append(DATE_FORMAT.format(timestamp)).append(" - "); + sb.append("\n ").append(DATE_FORMAT.get().format(timestamp)).append(" - "); sb.append(scan.duration).append("ms "); if (scan.isOpportunisticScan) { sb.append("Opp "); @@ -1084,7 +1085,7 @@ public class AppScanStats { for (Integer key : mOngoingScans.keySet()) { LastScan scan = mOngoingScans.get(key); Date timestamp = new Date(currentTime - currTime + scan.timestamp); - sb.append("\n ").append(DATE_FORMAT.format(timestamp)).append(" - "); + sb.append("\n ").append(DATE_FORMAT.get().format(timestamp)).append(" - "); sb.append((currTime - scan.timestamp)).append("ms "); if (scan.isOpportunisticScan) { sb.append("Opp "); diff --git a/android/app/src/com/android/bluetooth/le_scan/PeriodicScanManager.java b/android/app/src/com/android/bluetooth/le_scan/PeriodicScanManager.java index f2af13135a..e3f07a3c3c 100644 --- a/android/app/src/com/android/bluetooth/le_scan/PeriodicScanManager.java +++ b/android/app/src/com/android/bluetooth/le_scan/PeriodicScanManager.java @@ -33,6 +33,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -191,7 +192,9 @@ public class PeriodicScanManager { } synchronized (mSyncs) { - for (Map.Entry<IBinder, SyncInfo> e : mSyncs.entrySet()) { + Iterator<Map.Entry<IBinder, SyncInfo>> it = mSyncs.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<IBinder, SyncInfo> e = it.next(); if (e.getValue().id != regId) { continue; } @@ -224,7 +227,7 @@ public class PeriodicScanManager { status); IBinder binder = e.getKey(); binder.unlinkToDeath(e.getValue().deathRecipient, 0); - mSyncs.remove(binder); + it.remove(); } } } diff --git a/android/app/src/com/android/bluetooth/le_scan/ScanManager.java b/android/app/src/com/android/bluetooth/le_scan/ScanManager.java index 6269e1007f..bfd3019cd0 100644 --- a/android/app/src/com/android/bluetooth/le_scan/ScanManager.java +++ b/android/app/src/com/android/bluetooth/le_scan/ScanManager.java @@ -369,6 +369,7 @@ public class ScanManager { break; case MSG_BT_PROFILE_CONN_STATE_CHANGED: handleProfileConnectionStateChanged(msg); + break; default: // Shouldn't happen. Log.e(TAG, "received an unknown message : " + msg.what); diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapAccountItem.java b/android/app/src/com/android/bluetooth/map/BluetoothMapAccountItem.java index c03347ec32..771d7d4cc9 100644 --- a/android/app/src/com/android/bluetooth/map/BluetoothMapAccountItem.java +++ b/android/app/src/com/android/bluetooth/map/BluetoothMapAccountItem.java @@ -104,7 +104,7 @@ public class BluetoothMapAccountItem implements Comparable<BluetoothMapAccountIt if (mUciPrefix == null) { return null; } - return new StringBuilder(mUciPrefix).append(":").append(mUci).toString(); + return mUciPrefix + ":" + mUci; } @Override diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapMasInstance.java b/android/app/src/com/android/bluetooth/map/BluetoothMapMasInstance.java index 6d0c654aa9..080173aec3 100644 --- a/android/app/src/com/android/bluetooth/map/BluetoothMapMasInstance.java +++ b/android/app/src/com/android/bluetooth/map/BluetoothMapMasInstance.java @@ -34,7 +34,6 @@ import com.android.bluetooth.content_profiles.ContentProfileErrorReportUtils; import com.android.bluetooth.map.BluetoothMapContentObserver.Msg; import com.android.bluetooth.map.BluetoothMapUtils.TYPE; import com.android.bluetooth.sdp.SdpManagerNativeInterface; -import com.android.internal.annotations.VisibleForTesting; import com.android.obex.ServerSession; import java.io.IOException; @@ -47,7 +46,7 @@ import java.util.concurrent.atomic.AtomicLong; public class BluetoothMapMasInstance implements IObexConnectionHandler { private static final String TAG = "BluetoothMapMasInstance"; - @VisibleForTesting static volatile int sInstanceCounter = 0; + private static int sInstanceCounter = 0; private final int mObjectInstanceId; diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapSmsPdu.java b/android/app/src/com/android/bluetooth/map/BluetoothMapSmsPdu.java index 5c3130ece7..14262d9034 100644 --- a/android/app/src/com/android/bluetooth/map/BluetoothMapSmsPdu.java +++ b/android/app/src/com/android/bluetooth/map/BluetoothMapSmsPdu.java @@ -438,7 +438,7 @@ public class BluetoothMapSmsPdu { | TP_MMS_NO_MORE | TP_RP_NO_REPLY_PATH | TP_SRI_NO_REPORT - | (mData[0] & 0xff) & TP_UDHI_MASK); + | ((mData[0] & 0xff) & TP_UDHI_MASK)); encodedAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(originator); if (encodedAddress != null) { @@ -855,14 +855,5 @@ public class BluetoothMapSmsPdu { /** This value is not defined in global standard. Only in Korea, this is used. */ public static final int ENCODING_KSC5601 = 4; - - /** SMS Class enumeration. See TS 23.038. */ - public enum MessageClass { - UNKNOWN, - CLASS_0, - CLASS_1, - CLASS_2, - CLASS_3; - } } } diff --git a/android/app/src/com/android/bluetooth/mapclient/obex/Message.java b/android/app/src/com/android/bluetooth/mapclient/obex/Message.java index 89f40cc7d2..0cfaf74660 100644 --- a/android/app/src/com/android/bluetooth/mapclient/obex/Message.java +++ b/android/app/src/com/android/bluetooth/mapclient/obex/Message.java @@ -262,7 +262,7 @@ public class Message { } /** - * @return {@link .ReceptionStatus} object corresponding to <code>reception_status</code> + * @return {@link ReceptionStatus} object corresponding to <code>reception_status</code> * parameter in MAP specification */ public ReceptionStatus getReceptionStatus() { diff --git a/android/app/src/com/android/bluetooth/mapclient/obex/ObexTime.java b/android/app/src/com/android/bluetooth/mapclient/obex/ObexTime.java index 97d6bdccd8..8f3392be19 100644 --- a/android/app/src/com/android/bluetooth/mapclient/obex/ObexTime.java +++ b/android/app/src/com/android/bluetooth/mapclient/obex/ObexTime.java @@ -16,6 +16,8 @@ package com.android.bluetooth.mapclient; +import android.annotation.SuppressLint; + import com.android.bluetooth.Utils; import java.time.Instant; @@ -82,7 +84,7 @@ public final class ObexTime { int ohh = Integer.parseInt(m.group(9)); int omm = Integer.parseInt(m.group(10)); - /* time zone offset is specified in miliseconds */ + /* time zone offset is specified in milliseconds */ int offset = (ohh * 60 + omm) * 60 * 1000; if (m.group(8).equals("-")) { @@ -123,6 +125,7 @@ public final class ObexTime { } @Override + @SuppressLint("ToStringReturnsNull") public String toString() { if (mInstant == null) { return null; diff --git a/android/app/src/com/android/bluetooth/mcp/MediaControlGattService.java b/android/app/src/com/android/bluetooth/mcp/MediaControlGattService.java index abb87a3ea4..c229f184ae 100644 --- a/android/app/src/com/android/bluetooth/mcp/MediaControlGattService.java +++ b/android/app/src/com/android/bluetooth/mcp/MediaControlGattService.java @@ -1300,7 +1300,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface } private void handlePlaybackSpeedRequest(int speed) { - float floatingSpeed = (float) Math.pow(2, speed / 64); + float floatingSpeed = (float) Math.pow(2, speed / 64.0); mEventLogger.add("handlePlaybackSpeedRequest: floatingSpeed= " + floatingSpeed); mCallbacks.onPlaybackSpeedSetRequest(floatingSpeed); } diff --git a/android/app/src/com/android/bluetooth/mcp/MediaControlProfile.java b/android/app/src/com/android/bluetooth/mcp/MediaControlProfile.java index d025bc7000..32d07d4145 100644 --- a/android/app/src/com/android/bluetooth/mcp/MediaControlProfile.java +++ b/android/app/src/com/android/bluetooth/mcp/MediaControlProfile.java @@ -686,6 +686,9 @@ public class MediaControlProfile implements MediaControlServiceCallbacks { + opcodes); } break; + case TRACK_TITLE: + // Not implemented + break; } } } diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java index ae726f2295..abe3fb10f4 100644 --- a/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java +++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java @@ -774,7 +774,7 @@ public class BluetoothOppService extends ProfileService implements IObexConnecti * contains an entry that's not in the array, insert a new entry * in the array, move to next cursor row and next array entry. */ - while (!isAfterLast || arrayPos < mShares.size() && mListenStarted) { + while (!isAfterLast || (arrayPos < mShares.size() && mListenStarted)) { if (isAfterLast) { // We're beyond the end of the cursor but there's still some // stuff in the local array, which can only be junk diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppTransfer.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppTransfer.java index af1abea1be..b6b742e19c 100644 --- a/android/app/src/com/android/bluetooth/opp/BluetoothOppTransfer.java +++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppTransfer.java @@ -446,6 +446,7 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch mContext.getContentResolver(), contentUri, updateValues, null, null); } + @SuppressLint("WaitNotInLoop") private void markBatchFailed(int failReason) { synchronized (this) { try { diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java index 86ac40b481..77a2191528 100644 --- a/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java +++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java @@ -187,10 +187,10 @@ public class BluetoothOppTransferActivity extends AlertActivity if (isSuccess) { // should not go here mWhichDialog = DIALOG_RECEIVE_COMPLETE_SUCCESS; - } else if (!isSuccess) { + } else { mWhichDialog = DIALOG_RECEIVE_COMPLETE_FAIL; } - } else if (!isComplete) { + } else { mWhichDialog = DIALOG_RECEIVE_ONGOING; } } else if (direction == BluetoothShare.DIRECTION_OUTBOUND) { @@ -198,10 +198,10 @@ public class BluetoothOppTransferActivity extends AlertActivity if (isSuccess) { mWhichDialog = DIALOG_SEND_COMPLETE_SUCCESS; - } else if (!isSuccess) { + } else { mWhichDialog = DIALOG_SEND_COMPLETE_FAIL; } - } else if (!isComplete) { + } else { mWhichDialog = DIALOG_SEND_ONGOING; } } diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapService.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapService.java index cdfaff83b9..0292c6f684 100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapService.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapService.java @@ -155,7 +155,7 @@ public class BluetoothPbapService extends ProfileService implements IObexConnect @VisibleForTesting final HashMap<BluetoothDevice, PbapStateMachine> mPbapStateMachineMap = new HashMap<>(); - private volatile int mNextNotificationId = PBAP_NOTIFICATION_ID_START; + private int mNextNotificationId = PBAP_NOTIFICATION_ID_START; // package and class name to which we send intent to check phone book access permission private static final String ACCESS_AUTHORITY_PACKAGE = "com.android.settings"; diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java index 09965dccde..620074d1c0 100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java @@ -1215,12 +1215,7 @@ public class BluetoothPbapVcardManager { .replace(" ", ""); if (vTagAndTel[1].length() < telLenBefore) { Log.v(TAG, "Fixing vCard TEL to " + vTagAndTel[1]); - attr[i] = - new StringBuilder() - .append(vTagAndTel[0]) - .append(":") - .append(vTagAndTel[1]) - .toString(); + attr[i] = vTagAndTel[0] + ":" + vTagAndTel[1]; } } } diff --git a/android/app/src/com/android/bluetooth/tbs/TbsGatt.java b/android/app/src/com/android/bluetooth/tbs/TbsGatt.java index 47b0139250..1e32efb700 100644 --- a/android/app/src/com/android/bluetooth/tbs/TbsGatt.java +++ b/android/app/src/com/android/bluetooth/tbs/TbsGatt.java @@ -28,6 +28,7 @@ import android.bluetooth.BluetoothGattServerCallback; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothProfile; import android.content.Context; +import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.ParcelUuid; @@ -910,7 +911,12 @@ public class TbsGatt { } public boolean setIncomingCall(int callIndex, String uri) { - Log.d(TAG, "setIncomingCall: callIndex=" + callIndex + " uri=" + uri); + Log.d( + TAG, + "setIncomingCall: callIndex=" + + callIndex + + " uri=" + + Uri.parse(uri).toSafeString()); int uri_len = 0; if (uri != null) { uri_len = uri.length(); diff --git a/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java b/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java index c8a2967d0d..f8fbe2b79b 100644 --- a/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java +++ b/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java @@ -156,6 +156,7 @@ public class BluetoothInCallService extends InCallService { @Override @RequiresPermission(allOf = {BLUETOOTH_CONNECT, MODIFY_PHONE_STATE}) public void onServiceConnected(int profile, BluetoothProfile proxy) { + Log.d(TAG, "onServiceConnected for profile: " + profile); synchronized (LOCK) { if (profile == BluetoothProfile.HEADSET) { mBluetoothHeadset = new BluetoothHeadsetProxy((BluetoothHeadset) proxy); @@ -164,17 +165,20 @@ public class BluetoothInCallService extends InCallService { mBluetoothLeCallControl = new BluetoothLeCallControlProxy((BluetoothLeCallControl) proxy); - mBluetoothLeCallControl.registerBearer( - TAG, - List.of("tel"), - BluetoothLeCallControl.CAPABILITY_HOLD_CALL, - getNetworkOperator(), - getBearerTechnology(), - mExecutor, - mBluetoothLeCallControlCallback); + boolean isBearerRegistered = + mBluetoothLeCallControl.registerBearer( + TAG, + List.of("tel"), + BluetoothLeCallControl.CAPABILITY_HOLD_CALL, + getNetworkOperator(), + getBearerTechnology(), + mExecutor, + mBluetoothLeCallControlCallback); + Log.d(TAG, "isBearerRegistered: " + isBearerRegistered); sendTbsCurrentCallsList(); } } + Log.d(TAG, "Calls updated for profile: " + profile); } @Override @@ -784,6 +788,7 @@ public class BluetoothInCallService extends InCallService { if (mBluetoothLeCallControl != null) { mBluetoothLeCallControl.unregisterBearer(); mBluetoothLeCallControl.closeBluetoothLeCallControlProxy(mAdapter); + mBluetoothLeCallControl = null; } sInstance = null; mCallbacks.clear(); diff --git a/android/app/src/com/android/bluetooth/vc/VolumeControlNativeInterface.java b/android/app/src/com/android/bluetooth/vc/VolumeControlNativeInterface.java index 7293f7f086..4d7e721021 100644 --- a/android/app/src/com/android/bluetooth/vc/VolumeControlNativeInterface.java +++ b/android/app/src/com/android/bluetooth/vc/VolumeControlNativeInterface.java @@ -251,13 +251,15 @@ public class VolumeControlNativeInterface { } @VisibleForTesting - void onVolumeStateChanged(int volume, boolean mute, byte[] address, boolean isAutonomous) { + void onVolumeStateChanged( + int volume, boolean mute, int flags, byte[] address, boolean isAutonomous) { VolumeControlStackEvent event = new VolumeControlStackEvent( VolumeControlStackEvent.EVENT_TYPE_VOLUME_STATE_CHANGED); event.device = getDevice(address); event.valueInt1 = -1; event.valueInt2 = volume; + event.valueInt3 = flags; event.valueBool1 = mute; event.valueBool2 = isAutonomous; diff --git a/android/app/src/com/android/bluetooth/vc/VolumeControlService.java b/android/app/src/com/android/bluetooth/vc/VolumeControlService.java index 29d0a95982..889b9bce53 100644 --- a/android/app/src/com/android/bluetooth/vc/VolumeControlService.java +++ b/android/app/src/com/android/bluetooth/vc/VolumeControlService.java @@ -200,6 +200,11 @@ public class VolumeControlService extends ProfileService { private final Map<Integer, Boolean> mGroupMuteCache = new HashMap<>(); private final Map<BluetoothDevice, Integer> mDeviceVolumeCache = new HashMap<>(); + /* As defined by Volume Control Service 1.0.1, 3.3.1. Volume Flags behavior. + * User Set Volume Setting means that remote keeps volume in its cache. + */ + @VisibleForTesting static final int VOLUME_FLAGS_PERSISTED_USER_SET_VOLUME_MASK = 0x01; + @VisibleForTesting ServiceFactory mFactory = new ServiceFactory(); public VolumeControlService(Context ctx) { @@ -862,14 +867,22 @@ public class VolumeControlService extends ProfileService { } } - void handleVolumeControlChanged( - BluetoothDevice device, int groupId, int volume, boolean mute, boolean isAutonomous) { + int getBleVolumeFromCurrentStream() { + int streamType = getBluetoothContextualVolumeStream(); + int streamVolume = mAudioManager.getStreamVolume(streamType); + int streamMaxVolume = mAudioManager.getStreamMaxVolume(streamType); - if (isAutonomous && device != null) { - Log.e(TAG, "We expect only group notification for autonomous updates"); - return; - } + /* leaudio expect volume value in range 0 to 255 */ + return (int) Math.round((double) streamVolume * LE_AUDIO_MAX_VOL / streamMaxVolume); + } + void handleVolumeControlChanged( + BluetoothDevice device, + int groupId, + int volume, + int flags, + boolean mute, + boolean isAutonomous) { if (groupId == IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID) { LeAudioService leAudioService = mFactory.getLeAudioService(); if (leAudioService == null) { @@ -887,6 +900,34 @@ public class VolumeControlService extends ProfileService { int groupVolume = getGroupVolume(groupId); Boolean groupMute = getGroupMute(groupId); + if (isAutonomous && device != null) { + Log.i( + TAG, + ("Initial volume set after connect, volume: " + volume) + + (", mute: " + mute) + + (", flags: " + flags)); + /* We are here, because system has just started and LeAudio device is connected. If + * remote device has User Persistent flag set or the volume != 0, Android sets the + * volume to local cache and to the audio system. If Reset Flag is set and remote has + * volume set to 0, then Android sets to remote devices either cached volume volume + * taken from audio manager. Note, to match BR/EDR behavior, don't show volume change in + * UI here + */ + if ((flags & VOLUME_FLAGS_PERSISTED_USER_SET_VOLUME_MASK) == 0x01 || (volume != 0)) { + updateGroupCacheAndAudioSystem(groupId, volume, mute, false); + } else { + if (groupVolume != IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME) { + Log.i(TAG, "Setting volume: " + groupVolume + " to the group: " + groupId); + setGroupVolume(groupId, groupVolume); + } else { + int vol = getBleVolumeFromCurrentStream(); + Log.i(TAG, "Setting system volume: " + vol + " to the group: " + groupId); + setGroupVolume(groupId, getBleVolumeFromCurrentStream()); + } + } + return; + } + if (Flags.leaudioBroadcastVolumeControlForConnectedDevices()) { Log.i(TAG, "handleVolumeControlChanged: " + device + "; volume: " + volume); if (device == null) { @@ -906,16 +947,6 @@ public class VolumeControlService extends ProfileService { } } - if (groupVolume == IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME) { - /* We are here, because system was just started and LeAudio device just connected. - * In such case, we take Volume stored on remote device and apply it to our cache and - * audio system. - * Note, to match BR/EDR behavior, don't show volume change in UI here - */ - updateGroupCacheAndAudioSystem(groupId, volume, mute, false); - return; - } - if (!isAutonomous) { /* If the change is triggered by Android device, the stream is already changed. * However it might be called with isAutonomous, one the first read of after @@ -1119,6 +1150,7 @@ public class VolumeControlService extends ProfileService { stackEvent.device, stackEvent.valueInt1, stackEvent.valueInt2, + stackEvent.valueInt3, stackEvent.valueBool1, stackEvent.valueBool2); return; diff --git a/android/app/src/com/android/bluetooth/vc/VolumeControlStackEvent.java b/android/app/src/com/android/bluetooth/vc/VolumeControlStackEvent.java index 502519678e..aba8aedaf0 100644 --- a/android/app/src/com/android/bluetooth/vc/VolumeControlStackEvent.java +++ b/android/app/src/com/android/bluetooth/vc/VolumeControlStackEvent.java @@ -40,6 +40,7 @@ public class VolumeControlStackEvent { public BluetoothDevice device; public int valueInt1; public int valueInt2; + public int valueInt3; public boolean valueBool1; public boolean valueBool2; public String valueString1; @@ -58,6 +59,7 @@ public class VolumeControlStackEvent { result.append(", device:").append(device); result.append(", valueInt1:").append(eventTypeValue1ToString(type, valueInt1)); result.append(", valueInt2:").append(eventTypeValue2ToString(type, valueInt2)); + result.append(", valueInt3:").append(eventTypeValue3ToString(type, valueInt3)); result.append(", valueBool1:").append(eventTypeValueBool1ToString(type, valueBool1)); result.append(", valueBool2:").append(eventTypeValueBool2ToString(type, valueBool2)); result.append(", valueString1:").append(eventTypeString1ToString(type, valueString1)); @@ -138,6 +140,16 @@ public class VolumeControlStackEvent { return Integer.toString(value); } + private static String eventTypeValue3ToString(int type, int value) { + switch (type) { + case EVENT_TYPE_VOLUME_STATE_CHANGED: + return "{flags:" + value + "}"; + default: + break; + } + return Integer.toString(value); + } + private static String eventTypeValueBool1ToString(int type, boolean value) { switch (type) { case EVENT_TYPE_VOLUME_STATE_CHANGED: diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterPropertiesTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterPropertiesTest.java index 3ea1e6d55f..0ada5156b3 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterPropertiesTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterPropertiesTest.java @@ -89,7 +89,6 @@ public class AdapterPropertiesTest { mRemoteDevices.reset(); doReturn(mHandlerThread.getLooper()).when(mAdapterService).getMainLooper(); - doReturn(true).when(mAdapterService).isMock(); when(mAdapterService.getResources()) .thenReturn(InstrumentationRegistry.getTargetContext().getResources()); diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceBinderTest.java index 02dd5930e4..eefa37fd3a 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceBinderTest.java @@ -27,7 +27,6 @@ import android.bluetooth.IBluetoothOobDataCallback; import android.content.AttributionSource; import android.os.ParcelUuid; -import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -56,11 +55,6 @@ public class AdapterServiceBinderTest { mAttributionSource = new AttributionSource.Builder(0).build(); } - @After - public void cleanUp() { - mBinder.cleanup(); - } - @Test public void getAddress() { mBinder.getAddress(mAttributionSource); @@ -73,10 +67,16 @@ public class AdapterServiceBinderTest { String[] args = new String[] {}; mBinder.dump(fd, args); verify(mService).dump(any(), any(), any()); + } + + @Test + public void dumpWhenNotAvailable() { + FileDescriptor fd = new FileDescriptor(); + String[] args = new String[] {}; + doReturn(false).when(mService).isAvailable(); - Mockito.clearInvocations(mService); - mBinder.cleanup(); mBinder.dump(fd, args); + verify(mService, never()).dump(any(), any(), any()); } @@ -86,11 +86,18 @@ public class AdapterServiceBinderTest { IBluetoothOobDataCallback cb = Mockito.mock(IBluetoothOobDataCallback.class); mBinder.generateLocalOobData(transport, cb, mAttributionSource); + verify(mService).generateLocalOobData(transport, cb); + } + + @Test + public void generateLocalOobDataWhenNotAvailable() { + int transport = 0; + IBluetoothOobDataCallback cb = Mockito.mock(IBluetoothOobDataCallback.class); + doReturn(false).when(mService).isAvailable(); - Mockito.clearInvocations(mService); - mBinder.cleanup(); mBinder.generateLocalOobData(transport, cb, mAttributionSource); + verify(mService, never()).generateLocalOobData(transport, cb); } diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java index ff51f15b41..9e96712a48 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java @@ -203,7 +203,7 @@ public class AdapterServiceTest { @Parameters(name = "{0}") public static List<FlagsParameterization> getParams() { - return FlagsParameterization.allCombinationsOf(Flags.FLAG_EXPLICIT_KILL_FROM_SYSTEM_SERVER); + return FlagsParameterization.allCombinationsOf(); } public AdapterServiceTest(FlagsParameterization flags) { @@ -552,12 +552,9 @@ public class AdapterServiceTest { verify(nativeInterface).disable(); adapter.stateChangeCallback(AbstractionLayer.BT_STATE_OFF); TestUtils.syncHandler(looper, AdapterState.BLE_STOPPED); - if (Flags.explicitKillFromSystemServer()) { - // When reaching the OFF state, the cleanup is called that will destroy the state - // machine of the adapterService. Destroying state machine send a -1 event on the - // handler - TestUtils.syncHandler(looper, -1); - } + // When reaching the OFF state, the cleanup is called that will destroy the state machine of + // the adapterService. Destroying state machine send a -1 event on the handler + TestUtils.syncHandler(looper, -1); verifyStateChange(callback, STATE_BLE_TURNING_OFF, STATE_OFF); assertThat(adapter.getState()).isEqualTo(STATE_OFF); @@ -640,12 +637,9 @@ public class AdapterServiceTest { assertThat(mAdapterService.getBluetoothGatt()).isNull(); syncHandler(AdapterState.BLE_STOPPED); - if (Flags.explicitKillFromSystemServer()) { - // When reaching the OFF state, the cleanup is called that will destroy the state - // machine of the adapterService. Destroying state machine send a -1 event on the - // handler - syncHandler(-1); - } + // When reaching the OFF state, the cleanup is called that will destroy the state machine of + // the adapterService. Destroying state machine send a -1 event on the handler + syncHandler(-1); syncHandler(MESSAGE_PROFILE_SERVICE_STATE_CHANGED); syncHandler(MESSAGE_PROFILE_SERVICE_UNREGISTERED); @@ -678,12 +672,9 @@ public class AdapterServiceTest { mLooper.moveTimeForward(120_000); // Skip time so the timeout fires syncHandler(AdapterState.BLE_STOP_TIMEOUT); - if (Flags.explicitKillFromSystemServer()) { - // When reaching the OFF state, the cleanup is called that will destroy the state - // machine of the adapterService. Destroying state machine send a -1 event on the - // handler - syncHandler(-1); - } + // When reaching the OFF state, the cleanup is called that will destroy the state machine of + // the adapterService. Destroying state machine send a -1 event on the handler + syncHandler(-1); verifyStateChange(STATE_BLE_TURNING_OFF, STATE_OFF); assertThat(mAdapterService.getState()).isEqualTo(STATE_OFF); @@ -739,12 +730,9 @@ public class AdapterServiceTest { verify(mNativeInterface).disable(); mAdapterService.stateChangeCallback(AbstractionLayer.BT_STATE_OFF); syncHandler(AdapterState.BLE_STOPPED); - if (Flags.explicitKillFromSystemServer()) { - // When reaching the OFF state, the cleanup is called that will destroy the state - // machine of the adapterService. Destroying state machine send a -1 event on the - // handler - syncHandler(-1); - } + // When reaching the OFF state, the cleanup is called that will destroy the state machine of + // the adapterService. Destroying state machine send a -1 event on the handler + syncHandler(-1); verifyStateChange(callback, STATE_BLE_TURNING_OFF, STATE_OFF); assertThat(mAdapterService.getState()).isEqualTo(STATE_OFF); @@ -890,12 +878,9 @@ public class AdapterServiceTest { // TODO(b/280518177): The only timeout to fire here should be the BREDR mLooper.moveTimeForward(120_000); // Skip time so the timeout fires syncHandler(AdapterState.BLE_STOP_TIMEOUT); - if (Flags.explicitKillFromSystemServer()) { - // When reaching the OFF state, the cleanup is called that will destroy the state - // machine of the adapterService. Destroying state machine send a -1 event on the - // handler - syncHandler(-1); - } + // When reaching the OFF state, the cleanup is called that will destroy the state machine of + // the adapterService. Destroying state machine send a -1 event on the handler + syncHandler(-1); verifyStateChange(STATE_BLE_TURNING_OFF, STATE_OFF); assertThat(mAdapterService.getState()).isEqualTo(STATE_OFF); @@ -938,12 +923,9 @@ public class AdapterServiceTest { mAdapterService.stateChangeCallback(AbstractionLayer.BT_STATE_OFF); syncHandler(AdapterState.BLE_STOPPED); - if (Flags.explicitKillFromSystemServer()) { - // When reaching the OFF state, the cleanup is called that will destroy the state - // machine of the adapterService. Destroying state machine send a -1 event on the - // handler - syncHandler(-1); - } + // When reaching the OFF state, the cleanup is called that will destroy the state machine of + // the adapterService. Destroying state machine send a -1 event on the handler + syncHandler(-1); verifyStateChange(STATE_BLE_TURNING_OFF, STATE_OFF); assertThat(mAdapterService.getState()).isEqualTo(STATE_OFF); diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/CompanionManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/CompanionManagerTest.java index 0be41d1e11..7cd13fe4b4 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/CompanionManagerTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/CompanionManagerTest.java @@ -72,8 +72,6 @@ public class CompanionManagerTest { .when(mAdapterService) .getSharedPreferences( eq(CompanionManager.COMPANION_INFO), eq(Context.MODE_PRIVATE)); - // Tell the AdapterService that it is a mock (see isMock documentation) - doReturn(true).when(mAdapterService).isMock(); // Use the resources in the instrumentation instead of the mocked AdapterService when(mAdapterService.getResources()).thenReturn(mTargetContext.getResources()); diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/PhonePolicyTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/PhonePolicyTest.java index 43975ca1d1..7940da07e0 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/PhonePolicyTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/PhonePolicyTest.java @@ -116,8 +116,6 @@ public class PhonePolicyTest { mHandlerThread.start(); // Mock the looper when(mAdapterService.getMainLooper()).thenReturn(mHandlerThread.getLooper()); - // Tell the AdapterService that it is a mock (see isMock documentation) - doReturn(true).when(mAdapterService).isMock(); // Must be called to initialize services mAdapter = BluetoothAdapter.getDefaultAdapter(); PhonePolicy.sConnectOtherProfilesTimeoutMillis = CONNECT_OTHER_PROFILES_TIMEOUT_MILLIS; diff --git a/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlNativeInterfaceTest.java b/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlNativeInterfaceTest.java index 1ed290c8b9..5fbea684ba 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlNativeInterfaceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlNativeInterfaceTest.java @@ -71,10 +71,11 @@ public class VolumeControlNativeInterfaceTest { public void onVolumeStateChanged() { int volume = 3; boolean mute = false; + int flags = 1; byte[] address = new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; boolean isAutonomous = false; - mNativeInterface.onVolumeStateChanged(volume, mute, address, isAutonomous); + mNativeInterface.onVolumeStateChanged(volume, mute, flags, address, isAutonomous); ArgumentCaptor<VolumeControlStackEvent> event = ArgumentCaptor.forClass(VolumeControlStackEvent.class); diff --git a/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceTest.java index e082b4ad1b..0d216d3cb5 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceTest.java @@ -539,22 +539,18 @@ public class VolumeControlServiceTest { Assert.assertFalse(mService.getDevices().contains(mDevice)); } + /** Test that various Volume Control stack events will broadcast related states. */ @Test public void testVolumeControlStackEvents() { int group_id = -1; int volume = 6; + int flags = 0; boolean mute = false; + boolean isAutonomous = false; // Send a message to trigger volume state changed broadcast - VolumeControlStackEvent stackEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_VOLUME_STATE_CHANGED); - stackEvent.device = mDevice; - stackEvent.valueInt1 = group_id; - stackEvent.valueInt2 = volume; - stackEvent.valueBool1 = mute; - mService.messageFromNative(stackEvent); + generateVolumeStateChanged(mDevice, group_id, volume, flags, mute, isAutonomous); } int getLeAudioVolume(int index, int minIndex, int maxIndex, int streamType) { @@ -614,29 +610,18 @@ public class VolumeControlServiceTest { int streamType = AudioManager.STREAM_MUSIC; int streamVol = getLeAudioVolume(19, MEDIA_MIN_VOL, MEDIA_MAX_VOL, streamType); - // Send a message to trigger volume state changed broadcast - final VolumeControlStackEvent stackEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_VOLUME_STATE_CHANGED); - stackEvent.device = null; - stackEvent.valueInt1 = 1; // groupId - stackEvent.valueInt2 = streamVol; - stackEvent.valueBool1 = false; // isMuted - stackEvent.valueBool2 = true; // isAutonomous - doReturn(false).when(mAudioManager).isStreamMute(eq(AudioManager.STREAM_MUSIC)); // Verify that muting LeAudio device, sets the mute state on the audio device - stackEvent.valueBool1 = true; - mService.messageFromNative(stackEvent); + + generateVolumeStateChanged(null, 1, streamVol, 0, true, true); verify(mAudioManager, times(1)) .adjustStreamVolume(eq(streamType), eq(AudioManager.ADJUST_MUTE), anyInt()); doReturn(true).when(mAudioManager).isStreamMute(eq(AudioManager.STREAM_MUSIC)); // Verify that unmuting LeAudio device, unsets the mute state on the audio device - stackEvent.valueBool1 = false; - mService.messageFromNative(stackEvent); + generateVolumeStateChanged(null, 1, streamVol, 0, false, true); verify(mAudioManager, times(1)) .adjustStreamVolume(eq(streamType), eq(AudioManager.ADJUST_UNMUTE), anyInt()); } @@ -655,15 +640,7 @@ public class VolumeControlServiceTest { volume = 10; // Send autonomous volume change. - VolumeControlStackEvent stackEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_VOLUME_STATE_CHANGED); - stackEvent.device = null; - stackEvent.valueInt1 = groupId; - stackEvent.valueInt2 = volume; - stackEvent.valueBool1 = false; - stackEvent.valueBool2 = true; /* autonomous */ - mService.messageFromNative(stackEvent); + generateVolumeStateChanged(null, groupId, volume, 0, false, true); Assert.assertEquals(volume, mService.getGroupVolume(groupId)); } @@ -710,15 +687,7 @@ public class VolumeControlServiceTest { Assert.assertEquals(false, mService.getGroupMute(groupId)); // Send autonomous volume change - VolumeControlStackEvent stackEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_VOLUME_STATE_CHANGED); - stackEvent.device = null; - stackEvent.valueInt1 = groupId; - stackEvent.valueInt2 = volume; - stackEvent.valueBool1 = false; /* unmuted */ - stackEvent.valueBool2 = true; /* autonomous */ - mService.messageFromNative(stackEvent); + generateVolumeStateChanged(null, groupId, volume, 0, false, true); // Mute mServiceBinder.muteGroup(groupId, mAttributionSource); @@ -728,8 +697,7 @@ public class VolumeControlServiceTest { Assert.assertEquals(volume, mService.getGroupVolume(groupId)); // Send autonomous unmute - stackEvent.valueBool1 = false; /* unmuted */ - mService.messageFromNative(stackEvent); + generateVolumeStateChanged(null, groupId, volume, 0, false, true); Assert.assertEquals(false, mService.getGroupMute(groupId)); } @@ -742,16 +710,7 @@ public class VolumeControlServiceTest { Assert.assertEquals(false, mService.getGroupMute(groupId)); - // Set the initial volume state - VolumeControlStackEvent stackEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_VOLUME_STATE_CHANGED); - stackEvent.device = null; - stackEvent.valueInt1 = groupId; - stackEvent.valueInt2 = volume; - stackEvent.valueBool1 = false; /* unmuted */ - stackEvent.valueBool2 = true; /* autonomous */ - mService.messageFromNative(stackEvent); + generateVolumeStateChanged(null, groupId, volume, 0, false, true); // Mute mService.muteGroup(groupId); @@ -788,6 +747,199 @@ public class VolumeControlServiceTest { verify(mNativeInterface, times(1)).unmuteGroup(eq(groupId)); } + /** Test if phone will set volume which is read from the buds */ + @Test + public void testConnectedDeviceWithUserPersistFlagSet() throws Exception { + int groupId = 1; + int volumeDevice = 56; + int volumeDeviceTwo = 100; + int flags = VolumeControlService.VOLUME_FLAGS_PERSISTED_USER_SET_VOLUME_MASK; + boolean initialMuteState = false; + boolean initialAutonomousFlag = true; + + // Both devices are in the same group + when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId); + when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId); + + // Update the device policy so okToConnect() returns true + when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); + when(mDatabaseManager.getProfileConnectionPolicy( + any(BluetoothDevice.class), eq(BluetoothProfile.VOLUME_CONTROL))) + .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); + doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); + doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); + + generateDeviceAvailableMessageFromNative(mDevice, 1); + generateConnectionMessageFromNative( + mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); + Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); + Assert.assertTrue(mService.getDevices().contains(mDevice)); + + // Group is not active, AF will not be notified + generateVolumeStateChanged( + mDevice, groupId, volumeDevice, flags, initialMuteState, initialAutonomousFlag); + verify(mAudioManager, times(0)).setStreamVolume(anyInt(), anyInt(), anyInt()); + + // Make device Active now. This will trigger setting volume to AF + when(mLeAudioService.getActiveGroupId()).thenReturn(groupId); + mServiceBinder.setGroupActive(groupId, true, mAttributionSource); + int expectedAfVol = + (int) Math.round((double) (volumeDevice * MEDIA_MAX_VOL) / BT_LE_AUDIO_MAX_VOL); + verify(mAudioManager, times(1)).setStreamVolume(anyInt(), eq(expectedAfVol), anyInt()); + + // Connect second device and read different volume. Expect it will be set to AF and to + // another set member + generateDeviceAvailableMessageFromNative(mDeviceTwo, 1); + generateConnectionMessageFromNative( + mDeviceTwo, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); + Assert.assertEquals( + BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDeviceTwo)); + Assert.assertTrue(mService.getDevices().contains(mDeviceTwo)); + + // Group is now active, AF will be notified. Native will take care to sync the volume + generateVolumeStateChanged( + mDeviceTwo, + groupId, + volumeDeviceTwo, + flags, + initialMuteState, + initialAutonomousFlag); + expectedAfVol = + (int) Math.round((double) (volumeDeviceTwo * MEDIA_MAX_VOL) / BT_LE_AUDIO_MAX_VOL); + verify(mAudioManager, times(1)).setStreamVolume(anyInt(), eq(expectedAfVol), anyInt()); + } + + /** Test if phone will set volume which is read from the buds */ + @Test + public void testConnectedDeviceWithResetFlagSetWithNonZeroVolume() throws Exception { + int groupId = 1; + int volumeDevice = 56; + int volumeDeviceTwo = 100; + int flags = 0; + boolean initialMuteState = false; + boolean initialAutonomousFlag = true; + + // Both devices are in the same group + when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId); + when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId); + + // Update the device policy so okToConnect() returns true + when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); + when(mDatabaseManager.getProfileConnectionPolicy( + any(BluetoothDevice.class), eq(BluetoothProfile.VOLUME_CONTROL))) + .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); + doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); + doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); + + generateDeviceAvailableMessageFromNative(mDevice, 1); + generateConnectionMessageFromNative( + mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); + Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); + Assert.assertTrue(mService.getDevices().contains(mDevice)); + + // Group is not active, AF will not be notified + generateVolumeStateChanged( + mDevice, groupId, volumeDevice, flags, initialMuteState, initialAutonomousFlag); + verify(mAudioManager, times(0)).setStreamVolume(anyInt(), anyInt(), anyInt()); + + // Make device Active now. This will trigger setting volume to AF + when(mLeAudioService.getActiveGroupId()).thenReturn(groupId); + mServiceBinder.setGroupActive(groupId, true, mAttributionSource); + int expectedAfVol = + (int) Math.round((double) (volumeDevice * MEDIA_MAX_VOL) / BT_LE_AUDIO_MAX_VOL); + verify(mAudioManager, times(1)).setStreamVolume(anyInt(), eq(expectedAfVol), anyInt()); + + // Connect second device and read different volume. Expect it will be set to AF and to + // another set member + generateDeviceAvailableMessageFromNative(mDeviceTwo, 1); + generateConnectionMessageFromNative( + mDeviceTwo, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); + Assert.assertEquals( + BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDeviceTwo)); + Assert.assertTrue(mService.getDevices().contains(mDeviceTwo)); + + // Group is now active, AF will be notified. Native will take care to sync the volume + generateVolumeStateChanged( + mDeviceTwo, + groupId, + volumeDeviceTwo, + flags, + initialMuteState, + initialAutonomousFlag); + expectedAfVol = + (int) Math.round((double) (volumeDeviceTwo * MEDIA_MAX_VOL) / BT_LE_AUDIO_MAX_VOL); + verify(mAudioManager, times(1)).setStreamVolume(anyInt(), eq(expectedAfVol), anyInt()); + } + + /** Test if phone will set volume to buds which has no volume */ + @Test + public void testConnectedDeviceWithResetFlagSetWithZeroVolume() throws Exception { + int groupId = 1; + int volumeDevice = 0; + int volumeDeviceTwo = 0; + int flags = 0; + boolean initialMuteState = false; + boolean initialAutonomousFlag = true; + int streamVolume = 50; + int streamMaxVolume = 100; + + // Both devices are in the same group + when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId); + when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId); + + when(mAudioManager.getStreamVolume(anyInt())).thenReturn(streamVolume); + when(mAudioManager.getStreamMaxVolume(anyInt())).thenReturn(streamMaxVolume); + + // Update the device policy so okToConnect() returns true + when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); + when(mDatabaseManager.getProfileConnectionPolicy( + any(BluetoothDevice.class), eq(BluetoothProfile.VOLUME_CONTROL))) + .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); + doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); + doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); + + generateDeviceAvailableMessageFromNative(mDevice, 1); + generateConnectionMessageFromNative( + mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); + Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); + Assert.assertTrue(mService.getDevices().contains(mDevice)); + + // Group is not active, AF will not be notified but device will get phone volume + int expectedDeviceVol = + (int) Math.round((double) streamVolume * BT_LE_AUDIO_MAX_VOL / streamMaxVolume); + generateVolumeStateChanged( + mDevice, groupId, volumeDevice, flags, initialMuteState, initialAutonomousFlag); + verify(mAudioManager, times(0)).setStreamVolume(anyInt(), anyInt(), anyInt()); + verify(mNativeInterface, times(1)).setGroupVolume(eq(groupId), eq(expectedDeviceVol)); + + // Make device Active now. This will trigger setting volume to AF + when(mLeAudioService.getActiveGroupId()).thenReturn(groupId); + mServiceBinder.setGroupActive(groupId, true, mAttributionSource); + + verify(mAudioManager, times(1)).setStreamVolume(anyInt(), eq(streamVolume), anyInt()); + + // Connect second device and read different volume. Expect it will be set to AF and to + // another set member + generateDeviceAvailableMessageFromNative(mDeviceTwo, 1); + generateConnectionMessageFromNative( + mDeviceTwo, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); + Assert.assertEquals( + BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDeviceTwo)); + Assert.assertTrue(mService.getDevices().contains(mDeviceTwo)); + + // Group is now active, AF will be notified. Native will take care to sync the volume + generateVolumeStateChanged( + mDeviceTwo, + groupId, + volumeDeviceTwo, + flags, + initialMuteState, + initialAutonomousFlag); + + verify(mAudioManager, times(1)).setStreamVolume(anyInt(), anyInt(), anyInt()); + verify(mNativeInterface, times(2)).setGroupVolume(eq(groupId), eq(expectedDeviceVol)); + } + /** * Test setting volume for a group member who connects after the volume level for a group was * already changed and cached. @@ -1368,30 +1520,15 @@ public class VolumeControlServiceTest { when(mLeAudioService.getGroupDevices(groupId)) .thenReturn(Arrays.asList(mDevice, mDeviceTwo)); + // Send group volume change. - VolumeControlStackEvent stackEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_VOLUME_STATE_CHANGED); - stackEvent.device = null; - stackEvent.valueInt1 = groupId; - stackEvent.valueInt2 = groupVolume; - stackEvent.valueBool1 = false; - stackEvent.valueBool2 = true; - mService.messageFromNative(stackEvent); + generateVolumeStateChanged(null, groupId, groupVolume, 0, false, true); verify(callback).onDeviceVolumeChanged(eq(mDeviceTwo), eq(groupVolume)); verify(callback).onDeviceVolumeChanged(eq(mDevice), eq(groupVolume)); // Send device volume change only for one device - VolumeControlStackEvent stackEvent2 = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_VOLUME_STATE_CHANGED); - stackEvent2.device = mDevice; - stackEvent2.valueInt1 = -1; - stackEvent2.valueInt2 = deviceOneVolume; - stackEvent2.valueBool1 = false; - stackEvent2.valueBool2 = false; - mService.messageFromNative(stackEvent2); + generateVolumeStateChanged(mDevice, -1, deviceOneVolume, 0, false, false); verify(callback).onDeviceVolumeChanged(eq(mDevice), eq(deviceOneVolume)); verify(callback, never()).onDeviceVolumeChanged(eq(mDeviceTwo), eq(deviceOneVolume)); @@ -1480,6 +1617,25 @@ public class VolumeControlServiceTest { mService.messageFromNative(event); } + private void generateVolumeStateChanged( + BluetoothDevice device, + int group_id, + int volume, + int flags, + boolean mute, + boolean isAutonomous) { + VolumeControlStackEvent stackEvent = + new VolumeControlStackEvent( + VolumeControlStackEvent.EVENT_TYPE_VOLUME_STATE_CHANGED); + stackEvent.device = device; + stackEvent.valueInt1 = group_id; + stackEvent.valueInt2 = volume; + stackEvent.valueInt3 = flags; + stackEvent.valueBool1 = mute; + stackEvent.valueBool2 = isAutonomous; + mService.messageFromNative(stackEvent); + } + private void generateDeviceOffsetChangedMessageFromNative( BluetoothDevice device, int extOffsetIndex, int offset) { // Send a message to trigger connection completed diff --git a/flags/Android.bp b/flags/Android.bp index 091d3787c7..d4a9a7928e 100644 --- a/flags/Android.bp +++ b/flags/Android.bp @@ -43,7 +43,6 @@ aconfig_declarations { "rnr.aconfig", "sdp.aconfig", "security.aconfig", - "sniff.aconfig", "sockets.aconfig", "system_service.aconfig", "vcp.aconfig", diff --git a/flags/BUILD.gn b/flags/BUILD.gn index 6cedf5c7d5..9ea5b5afc1 100644 --- a/flags/BUILD.gn +++ b/flags/BUILD.gn @@ -37,7 +37,6 @@ aconfig("bluetooth_flags_c_lib") { "rnr.aconfig", "sdp.aconfig", "security.aconfig", - "sniff.aconfig", "sockets.aconfig", "system_service.aconfig", "vcp.aconfig", diff --git a/flags/active_device_manager.aconfig b/flags/active_device_manager.aconfig index 0835a5fb7e..37f2b65e1c 100644 --- a/flags/active_device_manager.aconfig +++ b/flags/active_device_manager.aconfig @@ -6,6 +6,9 @@ flag { namespace: "bluetooth" description: "Fallback to other connected device when wired audio device disconnects" bug: "348124361" + metadata { + purpose: PURPOSE_BUGFIX + } } flag { @@ -13,4 +16,7 @@ flag { namespace: "bluetooth" description: "Fix audio path and always fallback to available device" bug: "351820274" + metadata { + purpose: PURPOSE_BUGFIX + } }
\ No newline at end of file diff --git a/flags/connectivity.aconfig b/flags/connectivity.aconfig index ef83336d00..2605af718a 100644 --- a/flags/connectivity.aconfig +++ b/flags/connectivity.aconfig @@ -14,3 +14,14 @@ flag { description: "Guard the le shim connection map with a mutex" bug: "302054609" } + +flag { + name: "improve_create_connection_for_already_connecting_device" + namespace: "bluetooth" + description: "Make sure to not stop controller with create connection cancel when not needed" + bug: "356593752" + metadata { + purpose: PURPOSE_BUGFIX + } +} + diff --git a/flags/gap.aconfig b/flags/gap.aconfig index 13c3a57f22..25d9fc2014 100644 --- a/flags/gap.aconfig +++ b/flags/gap.aconfig @@ -239,3 +239,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "android_os_identifier" + namespace: "bluetooth" + description: "Add a custom service to provide Android OS identifier" + bug: "351860033" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/flags/sniff.aconfig b/flags/sniff.aconfig deleted file mode 100644 index 5b66d7494a..0000000000 --- a/flags/sniff.aconfig +++ /dev/null @@ -1,9 +0,0 @@ -package: "com.android.bluetooth.flags" -container: "com.android.btservices" - -flag { - name: "enable_sniff_offload" - namespace: "bluetooth" - description: "Enable sniff offload feature." - bug: "318786790" -} diff --git a/flags/system_service.aconfig b/flags/system_service.aconfig index 976f966dce..b59a9c1b4c 100644 --- a/flags/system_service.aconfig +++ b/flags/system_service.aconfig @@ -30,16 +30,6 @@ flag { } flag { - name: "explicit_kill_from_system_server" - namespace: "bluetooth" - description: "Explicit kill and wait of Bluetooth AdapterService when turning Bluetooth OFF" - metadata { - purpose: PURPOSE_BUGFIX - } - bug: "339548431" -} - -flag { name: "fast_bind_to_app" namespace: "bluetooth" description: "Remove complexity and non necessary initialization when simply binding" diff --git a/floss/hcidoc/packets/Cargo.toml b/floss/hcidoc/packets/Cargo.toml index 6792c71aeb..cd633bb88c 100644 --- a/floss/hcidoc/packets/Cargo.toml +++ b/floss/hcidoc/packets/Cargo.toml @@ -26,7 +26,7 @@ edition = "2018" build = "build.rs" [dependencies] -bindgen = "0.64" +bindgen = "0.69.4" bytes = "1.0" num-derive = "0.3" num-traits = "0.2" diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index de31b2cf25..0b645bccb7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -99,6 +99,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.BiFunction; +import java.util.function.Consumer; /** * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter} lets you perform @@ -888,10 +889,6 @@ public final class BluetoothAdapter { mMetadataListeners = new HashMap<>(); private final Map<BluetoothConnectionCallback, Executor> mBluetoothConnectionCallbackExecutorMap = new HashMap<>(); - private final Map<PreferredAudioProfilesChangedCallback, Executor> - mAudioProfilesChangedCallbackExecutorMap = new HashMap<>(); - private final Map<BluetoothQualityReportReadyCallback, Executor> - mBluetoothQualityReportReadyCallbackExecutorMap = new HashMap<>(); private static final class ProfileConnection { int mProfile; @@ -1106,6 +1103,51 @@ public final class BluetoothAdapter { } finally { mServiceLock.writeLock().unlock(); } + + Consumer<IBluetooth> registerQualityReportCallbackConsumer = + (IBluetooth service) -> { + try { + service.registerBluetoothQualityReportReadyCallback( + mBluetoothQualityReportReadyCallback, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } + }; + Consumer<IBluetooth> unregisterQualityReportCallbackConsumer = + (IBluetooth service) -> { + try { + service.unregisterBluetoothQualityReportReadyCallback( + mBluetoothQualityReportReadyCallback, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } + }; + mQualityCallbackWrapper = + new CallbackWrapper( + registerQualityReportCallbackConsumer, + unregisterQualityReportCallbackConsumer); + Consumer<IBluetooth> registerAudioProfilesCallbackConsumer = + (IBluetooth service) -> { + try { + service.registerPreferredAudioProfilesChangedCallback( + mPreferredAudioProfilesChangedCallback, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } + }; + Consumer<IBluetooth> unregisterAudioProfilesCallbackConsumer = + (IBluetooth service) -> { + try { + service.unregisterPreferredAudioProfilesChangedCallback( + mPreferredAudioProfilesChangedCallback, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } + }; + mAudioProfilesCallbackWrapper = + new CallbackWrapper( + registerAudioProfilesCallbackConsumer, + unregisterAudioProfilesCallbackConsumer); } /** @@ -3740,36 +3782,8 @@ public final class BluetoothAdapter { } }); } - synchronized (mAudioProfilesChangedCallbackExecutorMap) { - if (!mAudioProfilesChangedCallbackExecutorMap.isEmpty()) { - try { - mService.registerPreferredAudioProfilesChangedCallback( - mPreferredAudioProfilesChangedCallback, - mAttributionSource); - } catch (RemoteException e) { - Log.e( - TAG, - "onBluetoothServiceUp: Failed to register bluetooth" - + "connection callback", - e); - } - } - } - synchronized (mBluetoothQualityReportReadyCallbackExecutorMap) { - if (!mBluetoothQualityReportReadyCallbackExecutorMap.isEmpty()) { - try { - mService.registerBluetoothQualityReportReadyCallback( - mBluetoothQualityReportReadyCallback, - mAttributionSource); - } catch (RemoteException e) { - Log.e( - TAG, - "onBluetoothServiceUp: Failed to register bluetooth" - + "quality report callback", - e); - } - } - } + mAudioProfilesCallbackWrapper.registerToNewService(mService); + mQualityCallbackWrapper.registerToNewService(mService); } finally { mServiceLock.readLock().unlock(); } @@ -5060,23 +5074,18 @@ public final class BluetoothAdapter { return BluetoothStatusCodes.ERROR_UNKNOWN; } - @SuppressLint("AndroidFrameworkBluetoothPermission") + private final CallbackWrapper<PreferredAudioProfilesChangedCallback, IBluetooth> + mAudioProfilesCallbackWrapper; + private final IBluetoothPreferredAudioProfilesCallback mPreferredAudioProfilesChangedCallback = new IBluetoothPreferredAudioProfilesCallback.Stub() { @Override public void onPreferredAudioProfilesChanged( BluetoothDevice device, Bundle preferredAudioProfiles, int status) { - for (Map.Entry<PreferredAudioProfilesChangedCallback, Executor> - callbackExecutorEntry : - mAudioProfilesChangedCallbackExecutorMap.entrySet()) { - PreferredAudioProfilesChangedCallback callback = - callbackExecutorEntry.getKey(); - Executor executor = callbackExecutorEntry.getValue(); - executor.execute( - () -> - callback.onPreferredAudioProfilesChanged( - device, preferredAudioProfiles, status)); - } + mAudioProfilesCallbackWrapper.forEach( + (cb) -> + cb.onPreferredAudioProfilesChanged( + device, preferredAudioProfiles, status)); } }; @@ -5118,36 +5127,20 @@ public final class BluetoothAdapter { @NonNull @CallbackExecutor Executor executor, @NonNull PreferredAudioProfilesChangedCallback callback) { if (DBG) Log.d(TAG, "registerPreferredAudioProfilesChangedCallback()"); - requireNonNull(executor, "executor cannot be null"); - requireNonNull(callback, "callback cannot be null"); - - synchronized (mAudioProfilesChangedCallbackExecutorMap) { - // If the callback map is empty, we register the service-to-app callback - if (mAudioProfilesChangedCallbackExecutorMap.isEmpty()) { - int serviceCallStatus = BluetoothStatusCodes.ERROR_UNKNOWN; - mServiceLock.readLock().lock(); - try { - if (mService != null) { - serviceCallStatus = - mService.registerPreferredAudioProfilesChangedCallback( - mPreferredAudioProfilesChangedCallback, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } finally { - mServiceLock.readLock().unlock(); - } - if (serviceCallStatus != BluetoothStatusCodes.SUCCESS) { - return serviceCallStatus; - } - } + requireNonNull(callback); + requireNonNull(executor); - // Adds the passed in callback to our local mapping - if (mAudioProfilesChangedCallbackExecutorMap.containsKey(callback)) { - throw new IllegalArgumentException("This callback has already been registered"); - } else { - mAudioProfilesChangedCallbackExecutorMap.put(callback, executor); + mServiceLock.readLock().lock(); + try { + int status = mService.isDualModeAudioEnabled(mAttributionSource); + if (status != BluetoothStatusCodes.SUCCESS) { + return status; } + mAudioProfilesCallbackWrapper.registerCallback(mService, callback, executor); + } catch (RemoteException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } finally { + mServiceLock.readLock().unlock(); } return BluetoothStatusCodes.SUCCESS; @@ -5188,32 +5181,15 @@ public final class BluetoothAdapter { public int unregisterPreferredAudioProfilesChangedCallback( @NonNull PreferredAudioProfilesChangedCallback callback) { if (DBG) Log.d(TAG, "unregisterPreferredAudioProfilesChangedCallback()"); - requireNonNull(callback, "callback cannot be null"); - synchronized (mAudioProfilesChangedCallbackExecutorMap) { - if (mAudioProfilesChangedCallbackExecutorMap.remove(callback) == null) { - throw new IllegalArgumentException("This callback has not been registered"); - } - } - - if (!mAudioProfilesChangedCallbackExecutorMap.isEmpty()) { - return BluetoothStatusCodes.SUCCESS; - } - - // If the callback map is empty, we unregister the service-to-app callback mServiceLock.readLock().lock(); try { - if (mService != null) { - return mService.unregisterPreferredAudioProfilesChangedCallback( - mPreferredAudioProfilesChangedCallback, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + mAudioProfilesCallbackWrapper.unregisterCallback(mService, callback); } finally { mServiceLock.readLock().unlock(); } - return BluetoothStatusCodes.ERROR_UNKNOWN; + return BluetoothStatusCodes.SUCCESS; } /** @@ -5255,27 +5231,20 @@ public final class BluetoothAdapter { int status); } - @SuppressLint("AndroidFrameworkBluetoothPermission") + private final CallbackWrapper<BluetoothQualityReportReadyCallback, IBluetooth> + mQualityCallbackWrapper; + private final IBluetoothQualityReportReadyCallback mBluetoothQualityReportReadyCallback = new IBluetoothQualityReportReadyCallback.Stub() { @Override public void onBluetoothQualityReportReady( BluetoothDevice device, - BluetoothQualityReport bluetoothQualityReport, + BluetoothQualityReport report, int status) { - for (Map.Entry<BluetoothQualityReportReadyCallback, Executor> - callbackExecutorEntry : - mBluetoothQualityReportReadyCallbackExecutorMap.entrySet()) { - BluetoothQualityReportReadyCallback callback = - callbackExecutorEntry.getKey(); - Executor executor = callbackExecutorEntry.getValue(); - executor.execute( - () -> - callback.onBluetoothQualityReportReady( - device, bluetoothQualityReport, status)); + mQualityCallbackWrapper.forEach( + (cb) -> cb.onBluetoothQualityReportReady(device, report, status)); } - } - }; + }; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -5312,38 +5281,13 @@ public final class BluetoothAdapter { @NonNull @CallbackExecutor Executor executor, @NonNull BluetoothQualityReportReadyCallback callback) { if (DBG) Log.d(TAG, "registerBluetoothQualityReportReadyCallback()"); - requireNonNull(executor, "executor cannot be null"); - requireNonNull(callback, "callback cannot be null"); - - synchronized (mBluetoothQualityReportReadyCallbackExecutorMap) { - // If the callback map is empty, we register the service-to-app callback - if (mBluetoothQualityReportReadyCallbackExecutorMap.isEmpty()) { - int serviceCallStatus = BluetoothStatusCodes.ERROR_UNKNOWN; - mServiceLock.readLock().lock(); - try { - if (mService != null) { - serviceCallStatus = - mService.registerBluetoothQualityReportReadyCallback( - mBluetoothQualityReportReadyCallback, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } finally { - mServiceLock.readLock().unlock(); - } - if (serviceCallStatus != BluetoothStatusCodes.SUCCESS) { - return serviceCallStatus; - } - } - // Adds the passed in callback to our local mapping - if (mBluetoothQualityReportReadyCallbackExecutorMap.containsKey(callback)) { - throw new IllegalArgumentException("This callback has already been registered"); - } else { - mBluetoothQualityReportReadyCallbackExecutorMap.put(callback, executor); - } + mServiceLock.readLock().lock(); + try { + mQualityCallbackWrapper.registerCallback(mService, callback, executor); + } finally { + mServiceLock.readLock().unlock(); } - return BluetoothStatusCodes.SUCCESS; } @@ -5380,32 +5324,15 @@ public final class BluetoothAdapter { public int unregisterBluetoothQualityReportReadyCallback( @NonNull BluetoothQualityReportReadyCallback callback) { if (DBG) Log.d(TAG, "unregisterBluetoothQualityReportReadyCallback()"); - requireNonNull(callback, "callback cannot be null"); - - synchronized (mBluetoothQualityReportReadyCallbackExecutorMap) { - if (mBluetoothQualityReportReadyCallbackExecutorMap.remove(callback) == null) { - throw new IllegalArgumentException("This callback has not been registered"); - } - } - - if (!mBluetoothQualityReportReadyCallbackExecutorMap.isEmpty()) { - return BluetoothStatusCodes.SUCCESS; - } - // If the callback map is empty, we unregister the service-to-app callback mServiceLock.readLock().lock(); try { - if (mService != null) { - return mService.unregisterBluetoothQualityReportReadyCallback( - mBluetoothQualityReportReadyCallback, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + mQualityCallbackWrapper.unregisterCallback(mService, callback); } finally { mServiceLock.readLock().unlock(); } - return BluetoothStatusCodes.ERROR_UNKNOWN; + return BluetoothStatusCodes.SUCCESS; } /** diff --git a/framework/java/android/bluetooth/BluetoothLeCallControl.java b/framework/java/android/bluetooth/BluetoothLeCallControl.java index c3d68f444e..383b32e927 100644 --- a/framework/java/android/bluetooth/BluetoothLeCallControl.java +++ b/framework/java/android/bluetooth/BluetoothLeCallControl.java @@ -55,8 +55,6 @@ import java.util.concurrent.Executor; */ public final class BluetoothLeCallControl implements BluetoothProfile { private static final String TAG = "BluetoothLeCallControl"; - private static final boolean DBG = true; - private static final boolean VDBG = false; /** @hide */ @IntDef( @@ -296,6 +294,7 @@ public final class BluetoothLeCallControl implements BluetoothProfile { @Override public void onBearerRegistered(int ccid) { if (mCallback != null) { + Log.d(TAG, "onBearerRegistered: ccid is " + ccid); mCcid = ccid; } else { // registration timeout @@ -390,9 +389,7 @@ public final class BluetoothLeCallControl implements BluetoothProfile { /** @hide */ public void close() { - if (VDBG) { - Log.d(TAG, "close()"); - } + Log.v(TAG, "close()"); mAdapter.closeProfileProxy(this); } @@ -489,13 +486,12 @@ public final class BluetoothLeCallControl implements BluetoothProfile { int technology, @NonNull Executor executor, @NonNull Callback callback) { - if (DBG) { - Log.d(TAG, "registerBearer"); - } + Log.d(TAG, "registerBearer"); if (callback == null) { throw new IllegalArgumentException("null parameter: " + callback); } if (mCcid != 0) { + Log.e(TAG, "Ccid is already set to " + mCcid); return false; } @@ -546,9 +542,7 @@ public final class BluetoothLeCallControl implements BluetoothProfile { */ @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) public void unregisterBearer() { - if (DBG) { - Log.d(TAG, "unregisterBearer"); - } + Log.d(TAG, "unregisterBearer"); if (mCcid == 0) { return; } @@ -581,9 +575,7 @@ public final class BluetoothLeCallControl implements BluetoothProfile { */ @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) public void onCallAdded(@NonNull BluetoothLeCall call) { - if (DBG) { - Log.d(TAG, "onCallAdded: call=" + call); - } + Log.d(TAG, "onCallAdded: call=" + call); if (mCcid == 0) { return; } @@ -614,9 +606,7 @@ public final class BluetoothLeCallControl implements BluetoothProfile { */ @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) public void onCallRemoved(@NonNull UUID callId, @TerminationReason int reason) { - if (DBG) { - Log.d(TAG, "callRemoved: callId=" + callId); - } + Log.d(TAG, "callRemoved: callId=" + callId); if (mCcid == 0) { return; } @@ -646,9 +636,7 @@ public final class BluetoothLeCallControl implements BluetoothProfile { */ @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) public void onCallStateChanged(@NonNull UUID callId, @BluetoothLeCall.State int state) { - if (DBG) { - Log.d(TAG, "callStateChanged: callId=" + callId + " state=" + state); - } + Log.d(TAG, "callStateChanged: callId=" + callId + " state=" + state); if (mCcid == 0) { return; } @@ -705,9 +693,7 @@ public final class BluetoothLeCallControl implements BluetoothProfile { */ @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) public void networkStateChanged(@NonNull String provider, int technology) { - if (DBG) { - Log.d(TAG, "networkStateChanged: provider=" + provider + ", technology=" + technology); - } + Log.d(TAG, "networkStateChanged: provider=" + provider + ", technology=" + technology); if (mCcid == 0) { return; } @@ -745,9 +731,7 @@ public final class BluetoothLeCallControl implements BluetoothProfile { */ @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) public void requestResult(int requestId, @Result int result) { - if (DBG) { - Log.d(TAG, "requestResult: requestId=" + requestId + " result=" + result); - } + Log.d(TAG, "requestResult: requestId=" + requestId + " result=" + result); if (mCcid == 0) { return; } diff --git a/framework/java/android/bluetooth/le/PeriodicAdvertisingManager.java b/framework/java/android/bluetooth/le/PeriodicAdvertisingManager.java index 3f178c58c5..93e1cf8522 100644 --- a/framework/java/android/bluetooth/le/PeriodicAdvertisingManager.java +++ b/framework/java/android/bluetooth/le/PeriodicAdvertisingManager.java @@ -25,6 +25,7 @@ import android.bluetooth.Attributable; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.IBluetoothGatt; +import android.bluetooth.IBluetoothScan; import android.bluetooth.annotations.RequiresBluetoothLocationPermission; import android.bluetooth.annotations.RequiresBluetoothScanPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; @@ -34,6 +35,8 @@ import android.os.Looper; import android.os.RemoteException; import android.util.Log; +import com.android.bluetooth.flags.Flags; + import java.util.IdentityHashMap; import java.util.Objects; @@ -149,8 +152,6 @@ public final class PeriodicAdvertisingManager { "timeout must be between " + TIMEOUT_MIN + " and " + TIMEOUT_MAX); } - IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); - if (handler == null) { handler = new Handler(Looper.getMainLooper()); } @@ -158,11 +159,22 @@ public final class PeriodicAdvertisingManager { IPeriodicAdvertisingCallback wrapped = wrap(callback, handler); mCallbackWrappers.put(callback, wrapped); - try { - gatt.registerSync(scanResult, skip, timeout, wrapped, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Failed to register sync - ", e); - return; + if (Flags.scanManagerRefactor()) { + IBluetoothScan scan = mBluetoothAdapter.getBluetoothScan(); + + try { + scan.registerSync(scanResult, skip, timeout, wrapped, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, "Failed to register sync - ", e); + } + } else { + IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); + + try { + gatt.registerSync(scanResult, skip, timeout, wrapped, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, "Failed to register sync - ", e); + } } } @@ -181,18 +193,27 @@ public final class PeriodicAdvertisingManager { throw new IllegalArgumentException("callback can't be null"); } - IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); - IPeriodicAdvertisingCallback wrapper = mCallbackWrappers.remove(callback); if (wrapper == null) { throw new IllegalArgumentException("callback was not properly registered"); } - try { - gatt.unregisterSync(wrapper, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Failed to cancel sync creation - ", e); - return; + if (Flags.scanManagerRefactor()) { + IBluetoothScan scan = mBluetoothAdapter.getBluetoothScan(); + + try { + scan.unregisterSync(wrapper, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, "Failed to cancel sync creation - ", e); + } + } else { + IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); + + try { + gatt.unregisterSync(wrapper, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, "Failed to cancel sync creation - ", e); + } } } @@ -202,13 +223,22 @@ public final class PeriodicAdvertisingManager { * @hide */ public void transferSync(BluetoothDevice bda, int serviceData, int syncHandle) { - IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); + if (Flags.scanManagerRefactor()) { + IBluetoothScan scan = mBluetoothAdapter.getBluetoothScan(); - try { - gatt.transferSync(bda, serviceData, syncHandle, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Failed to register sync - ", e); - return; + try { + scan.transferSync(bda, serviceData, syncHandle, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, "Failed to register sync - ", e); + } + } else { + IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); + + try { + gatt.transferSync(bda, serviceData, syncHandle, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, "Failed to register sync - ", e); + } } } @@ -239,19 +269,32 @@ public final class PeriodicAdvertisingManager { if (callback == null) { throw new IllegalArgumentException("callback can't be null"); } - IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); + if (handler == null) { handler = new Handler(Looper.getMainLooper()); } + IPeriodicAdvertisingCallback wrapper = wrap(callback, handler); if (wrapper == null) { throw new IllegalArgumentException("callback was not properly registered"); } - try { - gatt.transferSetInfo(bda, serviceData, advHandle, wrapper, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Failed to register sync - ", e); - return; + + if (Flags.scanManagerRefactor()) { + IBluetoothScan scan = mBluetoothAdapter.getBluetoothScan(); + + try { + scan.transferSetInfo(bda, serviceData, advHandle, wrapper, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, "Failed to register sync - ", e); + } + } else { + IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); + + try { + gatt.transferSetInfo(bda, serviceData, advHandle, wrapper, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, "Failed to register sync - ", e); + } } } diff --git a/framework/tests/bumble/src/android/bluetooth/GattClientTest.java b/framework/tests/bumble/src/android/bluetooth/GattClientTest.java index b30fdb7c2b..ba6ccf17cf 100644 --- a/framework/tests/bumble/src/android/bluetooth/GattClientTest.java +++ b/framework/tests/bumble/src/android/bluetooth/GattClientTest.java @@ -368,11 +368,16 @@ public class GattClientTest { BluetoothGatt gatt = device.connectGatt(mContext, false, gattCallback); BluetoothGatt gatt2 = device.connectGatt(mContext, false, gattCallback2); - gatt.disconnect(); - gatt.close(); + try { + gatt.disconnect(); + gatt.close(); - verify(gattCallback2, timeout(1000)) - .onConnectionStateChange(eq(gatt2), eq(GATT_SUCCESS), eq(STATE_CONNECTED)); + verify(gattCallback2, timeout(1000)) + .onConnectionStateChange(eq(gatt2), eq(GATT_SUCCESS), eq(STATE_CONNECTED)); + } finally { + gatt2.disconnect(); + gatt2.close(); + } } private void registerWritableGattService() { diff --git a/framework/tests/bumble/src/android/bluetooth/Host.kt b/framework/tests/bumble/src/android/bluetooth/Host.kt index 886dcbb37a..af0736df61 100644 --- a/framework/tests/bumble/src/android/bluetooth/Host.kt +++ b/framework/tests/bumble/src/android/bluetooth/Host.kt @@ -72,13 +72,17 @@ public class Host(context: Context) : Closeable { runBlocking(scope.coroutineContext) { withTimeout(TIMEOUT) { Truth.assertThat(remoteDevice.createBond()).isTrue() - flow - .filter { it.getAction() == BluetoothDevice.ACTION_PAIRING_REQUEST } - .filter { it.getBluetoothDeviceExtra() == remoteDevice } - .first() - - remoteDevice.setPairingConfirmation(true) + val pairingRequestJob = launch { + Log.d(TAG, "Waiting for ACTION_PAIRING_REQUEST") + flow + .filter { it.action == BluetoothDevice.ACTION_PAIRING_REQUEST } + .filter { it.getBluetoothDeviceExtra() == remoteDevice } + .first() + + remoteDevice.setPairingConfirmation(true) + } + Log.d(TAG, "Waiting for ACTION_BOND_STATE_CHANGED") flow .filter { it.action == BluetoothDevice.ACTION_BOND_STATE_CHANGED } .filter { it.getBluetoothDeviceExtra() == remoteDevice } @@ -87,6 +91,11 @@ public class Host(context: Context) : Closeable { BluetoothDevice.BOND_BONDED } .first() + + if (pairingRequestJob.isActive) { + pairingRequestJob.cancel() + } + Log.d(TAG, "createBondAndVerify: bonded") } } @@ -118,6 +127,7 @@ public class Host(context: Context) : Closeable { val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { + Log.d(TAG, "intentFlow: onReceive: ${intent.action}") scope.launch { trySendBlocking(intent) } } } diff --git a/framework/tests/bumble/src/android/bluetooth/SdpClientTest.java b/framework/tests/bumble/src/android/bluetooth/SdpClientTest.java index 0a45df521e..2d400e44a3 100644 --- a/framework/tests/bumble/src/android/bluetooth/SdpClientTest.java +++ b/framework/tests/bumble/src/android/bluetooth/SdpClientTest.java @@ -31,6 +31,8 @@ import com.android.compatibility.common.util.AdoptShellPermissionsRule; import com.google.common.util.concurrent.SettableFuture; import com.google.protobuf.ByteString; +import org.junit.After; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -63,16 +65,26 @@ public class SdpClientTest { ParcelUuid[] parcelUuids = intent.getParcelableArrayExtra( BluetoothDevice.EXTRA_UUID, ParcelUuid.class); - mFutureIntent.set(Arrays.asList(parcelUuids)); + if (parcelUuids != null) { + mFutureIntent.set(Arrays.asList(parcelUuids)); + } } } }; - @Test - public void remoteConnectServiceDiscoveryTest() throws Exception { + @Before + public void setup() { IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_UUID); mContext.registerReceiver(mConnectionStateReceiver, filter); + } + + @After + public void tearDown() { + mContext.unregisterReceiver(mConnectionStateReceiver); + } + @Test + public void remoteConnectServiceDiscoveryTest() throws Exception { mFutureIntent = SettableFuture.create(); String local_addr = mAdapter.getAddress(); @@ -89,12 +101,10 @@ public class SdpClientTest { assertThat(device.fetchUuidsWithSdp()).isTrue(); assertThat(mFutureIntent.get()) - .containsExactly( + .containsAtLeast( BluetoothUuid.HFP, BluetoothUuid.A2DP_SOURCE, BluetoothUuid.A2DP_SINK, BluetoothUuid.AVRCP); - - mContext.unregisterReceiver(mConnectionStateReceiver); } } diff --git a/framework/tests/bumble/src/android/bluetooth/hid/HidHostTest.java b/framework/tests/bumble/src/android/bluetooth/hid/HidHostTest.java index f6bad4ef21..2a2a20ef18 100644 --- a/framework/tests/bumble/src/android/bluetooth/hid/HidHostTest.java +++ b/framework/tests/bumble/src/android/bluetooth/hid/HidHostTest.java @@ -54,6 +54,7 @@ import java.util.concurrent.TimeUnit; /** Test cases for {@link Hid Host}. */ @RunWith(AndroidJUnit4.class) +@Ignore("b/355328584") public class HidHostTest { private static final String TAG = "HidHostTest"; private SettableFuture<Integer> mFutureConnectionIntent, diff --git a/framework/tests/util/src/BlockingBluetoothAdapter.kt b/framework/tests/util/src/BlockingBluetoothAdapter.kt index 424beb79aa..49b08c8c43 100644 --- a/framework/tests/util/src/BlockingBluetoothAdapter.kt +++ b/framework/tests/util/src/BlockingBluetoothAdapter.kt @@ -79,7 +79,7 @@ object BlockingBluetoothAdapter { if (adapter.isBleScanAlwaysAvailable()) { break } - Log.d(TAG, "Ble scan not yet available… Sleeping 20 ms $i/5") + Log.d(TAG, "Ble scan not yet available... Sleeping 20 ms $i/5") Thread.sleep(20) } if (!adapter.isBleScanAlwaysAvailable()) { diff --git a/pandora/server/bumble_experimental/hid.py b/pandora/server/bumble_experimental/hid.py index d68ca1eb3c..6da25ec6e1 100644 --- a/pandora/server/bumble_experimental/hid.py +++ b/pandora/server/bumble_experimental/hid.py @@ -355,7 +355,7 @@ def on_hid_control_point_write(_connection, value): # ----------------------------------------------------------------------------- def sdp_records(): - service_record_handle = 0x00010002 + service_record_handle = 0x00010006 return { service_record_handle: [ ServiceAttribute( diff --git a/pandora/server/bumble_experimental/rfcomm.py b/pandora/server/bumble_experimental/rfcomm.py index 0680b4a688..bdc0ad5966 100644 --- a/pandora/server/bumble_experimental/rfcomm.py +++ b/pandora/server/bumble_experimental/rfcomm.py @@ -42,7 +42,7 @@ from pandora_experimental.rfcomm_pb2 import ( TxResponse, ) -FIRST_SERVICE_RECORD_HANDLE = 0x00010000 +FIRST_SERVICE_RECORD_HANDLE = 0x00010010 class RFCOMMService(RFCOMMServicer): diff --git a/service/src/LogTest.kt b/service/src/LogTest.kt index c1a48642a4..3f59d16e10 100644 --- a/service/src/LogTest.kt +++ b/service/src/LogTest.kt @@ -57,7 +57,7 @@ class LogTest { @Test fun log_errorThrowable() { - Log.e(TAG, "Logging error… ", RuntimeException("With a Throwable")) + Log.e(TAG, "Logging error... ", RuntimeException("With a Throwable")) } @Test diff --git a/service/src/com/android/server/bluetooth/BluetoothManagerService.java b/service/src/com/android/server/bluetooth/BluetoothManagerService.java index 4e4aaa9cc0..42abcb5706 100644 --- a/service/src/com/android/server/bluetooth/BluetoothManagerService.java +++ b/service/src/com/android/server/bluetooth/BluetoothManagerService.java @@ -501,14 +501,14 @@ class BluetoothManagerService { if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) { String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME); if (newName != null) { - Log.d(TAG, "Bluetooth Adapter name changed to " + newName); + Log.d(TAG, "Local name changed to: " + newName); storeNameAndAddress(newName, null); } } else if (BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED.equals(action)) { String newAddress = intent.getStringExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS); if (newAddress != null) { - Log.d(TAG, "Local address changed to …" + logAddress(newAddress)); + Log.d(TAG, "Local address changed to: " + logAddress(newAddress)); storeNameAndAddress(null, newAddress); } else { Log.e(TAG, "No Bluetooth Adapter address parameter found"); @@ -1207,13 +1207,6 @@ class BluetoothManagerService { Log.e(TAG, "Unable to unregister BluetoothCallback", e); } - if (!Flags.explicitKillFromSystemServer()) { - mAdapter = null; - mContext.unbindService(mConnection); - mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); - return; - } - CompletableFuture<Void> binderDead = new CompletableFuture<>(); try { mAdapter.getAdapterBinder() diff --git a/system/TEST_MAPPING b/system/TEST_MAPPING new file mode 100644 index 0000000000..8b04c16b05 --- /dev/null +++ b/system/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "bluetooth_test_gd_unit" + } + ] +} diff --git a/system/audio_hal_interface/aidl/client_interface_aidl.cc b/system/audio_hal_interface/aidl/client_interface_aidl.cc index 3db108d206..1bb98b77c8 100644 --- a/system/audio_hal_interface/aidl/client_interface_aidl.cc +++ b/system/audio_hal_interface/aidl/client_interface_aidl.cc @@ -620,7 +620,7 @@ void BluetoothAudioClientInterface::SetCodecPriority(CodecId codec_id, int32_t p log::assert_that(provider_ != nullptr, "assert failed: provider_ != nullptr"); auto aidl_retval = provider_->setCodecPriority(codec_id, priority); if (!aidl_retval.isOk()) { - log::fatal("BluetoothAudioHal::setCodecPriority failure: {}", aidl_retval.getDescription()); + log::error("BluetoothAudioHal::setCodecPriority failure: {}", aidl_retval.getDescription()); } } @@ -641,14 +641,15 @@ BluetoothAudioClientInterface::GetLeAudioAseConfiguration( requirements, &configurations); if (!aidl_retval.isOk()) { - log::fatal("BluetoothAudioHal::getLeAudioAseConfiguration failure: {}", + log::error("BluetoothAudioHal::getLeAudioAseConfiguration failure: {}", aidl_retval.getDescription()); + } else { + log::info( + "BluetoothAudioHal::getLeAudioAseConfiguration returned {} " + "configurations.", + configurations.size()); } - log::info( - "BluetoothAudioHal::getLeAudioAseConfiguration returned {} " - "configurations.", - configurations.size()); return configurations; } @@ -661,7 +662,7 @@ BluetoothAudioClientInterface::getLeAudioAseQosConfiguration( auto aidl_retval = provider_->getLeAudioAseQosConfiguration(qosRequirement, &qos_configuration); if (!aidl_retval.isOk()) { - log::fatal("BluetoothAudioHal::getLeAudioAseQosConfiguration failure: {}", + log::error("BluetoothAudioHal::getLeAudioAseQosConfiguration failure: {}", aidl_retval.getDescription()); } return qos_configuration; @@ -675,7 +676,7 @@ void BluetoothAudioClientInterface::onSinkAseMetadataChanged( auto aidl_retval = provider_->onSinkAseMetadataChanged(state, cigId, cisId, metadata); if (!aidl_retval.isOk()) { - log::fatal("BluetoothAudioHal::onSinkAseMetadataChanged failure: {}", + log::error("BluetoothAudioHal::onSinkAseMetadataChanged failure: {}", aidl_retval.getDescription()); } } @@ -688,7 +689,7 @@ void BluetoothAudioClientInterface::onSourceAseMetadataChanged( auto aidl_retval = provider_->onSourceAseMetadataChanged(state, cigId, cisId, metadata); if (!aidl_retval.isOk()) { - log::fatal("BluetoothAudioHal::onSinkAseMetadataChanged failure: {}", + log::error("BluetoothAudioHal::onSourceAseMetadataChanged failure: {}", aidl_retval.getDescription()); } } @@ -706,7 +707,7 @@ BluetoothAudioClientInterface::getLeAudioBroadcastConfiguration( requirement, &setting); if (!aidl_retval.isOk()) { - log::fatal("BluetoothAudioHal::onSinkAseMetadataChanged failure: {}", + log::error("BluetoothAudioHal::getLeAudioBroadcastConfiguration failure: {}", aidl_retval.getDescription()); } diff --git a/system/bta/ag/bta_ag_sco.cc b/system/bta/ag/bta_ag_sco.cc index 6e33195a77..5804162a24 100644 --- a/system/bta/ag/bta_ag_sco.cc +++ b/system/bta/ag/bta_ag_sco.cc @@ -640,6 +640,7 @@ void bta_ag_codec_negotiate(tBTA_AG_SCB* p_scb) { bta_ag_cb.sco.p_curr_scb = p_scb; uint8_t* p_rem_feat = get_btm_client_interface().peer.BTM_ReadRemoteFeatures(p_scb->peer_addr); bool sdp_wbs_support = p_scb->peer_sdp_features & BTA_AG_FEAT_WBS_SUPPORT; + bool sdp_swb_support = p_scb->peer_sdp_features & BTA_AG_FEAT_SWB_SUPPORT; if (p_rem_feat == nullptr) { log::warn("Skip codec negotiation, failed to read remote features"); @@ -648,7 +649,7 @@ void bta_ag_codec_negotiate(tBTA_AG_SCB* p_scb) { } // Workaround for misbehaving HFs, which indicate which one is not support on - // Transparent Synchronous Data in Remote Supported Features, WBS in SDP and + // Transparent Synchronous Data in Remote Supported Features, WBS and SWB in SDP // and Codec Negotiation in BRSF. Fluoride will assume CVSD codec by default. // In Sony XAV AX100 car kit and Sony MW600 Headset case, which indicate // Transparent Synchronous Data and WBS support, but no codec negotiation @@ -656,7 +657,10 @@ void bta_ag_codec_negotiate(tBTA_AG_SCB* p_scb) { // In Skullcandy JIB case, which indicate WBS and codec negotiation support, // but no Transparent Synchronous Data support, using mSBC codec can result // SCO setup fail by Firmware reject. - if (!HCI_LMP_TRANSPNT_SUPPORTED(p_rem_feat) || !sdp_wbs_support || + if (!HCI_LMP_TRANSPNT_SUPPORTED(p_rem_feat) || + !(sdp_wbs_support || + (com::android::bluetooth::flags::choose_wrong_hfp_codec_in_specific_config() && + sdp_swb_support)) || !(p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC)) { log::info("Assume CVSD by default due to mask mismatch"); p_scb->sco_codec = BTM_SCO_CODEC_CVSD; diff --git a/system/bta/dm/bta_dm_act.cc b/system/bta/dm/bta_dm_act.cc index 0dfe3cb08e..56ecb8fb71 100644 --- a/system/bta/dm/bta_dm_act.cc +++ b/system/bta/dm/bta_dm_act.cc @@ -89,7 +89,7 @@ static void bta_dm_adjust_roles(bool delay_role_switch); tBTM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void); static void bta_dm_ctrl_features_rd_cmpl_cback(tHCI_STATUS result); -static const char kPropertySniffOffloadEnabled[] = "bluetooth.sniff_offload.enabled"; +static const char kPropertySniffOffloadEnabled[] = "persist.bluetooth.sniff_offload.enabled"; #ifndef BTA_DM_BLE_ADV_CHNL_MAP #define BTA_DM_BLE_ADV_CHNL_MAP (BTM_BLE_ADV_CHNL_37 | BTM_BLE_ADV_CHNL_38 | BTM_BLE_ADV_CHNL_39) @@ -288,8 +288,8 @@ void BTA_dm_on_hw_on() { bta_sys_rm_register(bta_dm_rm_cback); /* if sniff is offload, no need to handle it in the stack */ - if (com::android::bluetooth::flags::enable_sniff_offload() && - osi_property_get_bool(kPropertySniffOffloadEnabled, false)) { + if (osi_property_get_bool(kPropertySniffOffloadEnabled, false)) { + log::info("Sniff offloaded. Skip bta_dm_init_pm."); } else { /* initialize bluetooth low power manager */ bta_dm_init_pm(); @@ -322,9 +322,8 @@ void bta_dm_disable() { } /* if sniff is offload, no need to handle it in the stack */ - if (com::android::bluetooth::flags::enable_sniff_offload() && - osi_property_get_bool(kPropertySniffOffloadEnabled, false)) { - log::info("Sniff offloading. Skip bta_dm_disable_pm."); + if (osi_property_get_bool(kPropertySniffOffloadEnabled, false)) { + log::info("Sniff offloaded. Skip bta_dm_disable_pm."); } else { /* Disable bluetooth low power manager */ bta_dm_disable_pm(); diff --git a/system/bta/gatt/bta_gattc_act.cc b/system/bta/gatt/bta_gattc_act.cc index e2fd540d1c..42f6149e95 100644 --- a/system/bta/gatt/bta_gattc_act.cc +++ b/system/bta/gatt/bta_gattc_act.cc @@ -138,13 +138,28 @@ void bta_gattc_disable() { return; } - for (i = 0; i < BTA_GATTC_CL_MAX; i++) { - if (!bta_gattc_cb.cl_rcb[i].in_use) { - continue; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + if (!bta_gattc_cb.cl_rcb_map.empty()) { + bta_gattc_cb.state = BTA_GATTC_STATE_DISABLING; + } + + // An entry can be erased during deregister, use a copied collection + std::vector<tGATT_IF> gatt_ifs; + for (auto& [gatt_if, p_rcb] : bta_gattc_cb.cl_rcb_map) { + gatt_ifs.push_back(gatt_if); } + for (auto& gatt_if : gatt_ifs) { + bta_gattc_deregister(bta_gattc_cb.cl_rcb_map[gatt_if].get()); + } + } else { + for (i = 0; i < BTA_GATTC_CL_MAX; i++) { + if (!bta_gattc_cb.cl_rcb[i].in_use) { + continue; + } - bta_gattc_cb.state = BTA_GATTC_STATE_DISABLING; - bta_gattc_deregister(&bta_gattc_cb.cl_rcb[i]); + bta_gattc_cb.state = BTA_GATTC_STATE_DISABLING; + bta_gattc_deregister(&bta_gattc_cb.cl_rcb[i]); + } } /* no registered apps, indicate disable completed */ @@ -177,29 +192,54 @@ void bta_gattc_register(const Uuid& app_uuid, tBTA_GATTC_CBACK* p_cback, BtaAppR log::debug("GATTC module not enabled, enabling it"); bta_gattc_enable(); } - /* todo need to check duplicate uuid */ - for (uint8_t i = 0; i < BTA_GATTC_CL_MAX; i++) { - if (!bta_gattc_cb.cl_rcb[i].in_use) { - bta_gattc_cb.cl_rcb[i].client_if = - GATT_Register(app_uuid, "GattClient", &bta_gattc_cl_cback, eatt_support); - if (bta_gattc_cb.cl_rcb[i].client_if == 0) { - log::error("Register with GATT stack failed with index {}, trying next index", i); - status = GATT_ERROR; - } else { - bta_gattc_cb.cl_rcb[i].in_use = true; - bta_gattc_cb.cl_rcb[i].p_cback = p_cback; - bta_gattc_cb.cl_rcb[i].app_uuid = app_uuid; - - /* BTA use the same client interface as BTE GATT statck */ - client_if = bta_gattc_cb.cl_rcb[i].client_if; - - log::debug("Registered GATT client interface {} with uuid={}, starting it on main thread", - client_if, app_uuid.ToString()); - - do_in_main_thread(base::BindOnce(&bta_gattc_start_if, client_if)); - status = GATT_SUCCESS; - break; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + tGATT_IF client_if = GATT_Register(app_uuid, "GattClient", &bta_gattc_cl_cback, eatt_support); + if (client_if == 0) { + log::error("Register with GATT stack failed"); + status = GATT_ERROR; + } else { + auto p_rcb = std::make_unique<tBTA_GATTC_RCB>(); + p_rcb->in_use = true; + p_rcb->p_cback = p_cback; + p_rcb->app_uuid = app_uuid; + p_rcb->client_if = client_if; + bta_gattc_cb.cl_rcb_map.emplace(client_if, std::move(p_rcb)); + + log::debug( + "Registered GATT client interface {} with uuid={}, starting it on " + "main thread", + client_if, app_uuid.ToString()); + + do_in_main_thread(base::BindOnce(&bta_gattc_start_if, client_if)); + status = GATT_SUCCESS; + } + } else { + for (uint8_t i = 0; i < BTA_GATTC_CL_MAX; i++) { + if (!bta_gattc_cb.cl_rcb[i].in_use) { + bta_gattc_cb.cl_rcb[i].client_if = + GATT_Register(app_uuid, "GattClient", &bta_gattc_cl_cback, eatt_support); + if (bta_gattc_cb.cl_rcb[i].client_if == 0) { + log::error("Register with GATT stack failed with index {}, trying next index", i); + status = GATT_ERROR; + } else { + bta_gattc_cb.cl_rcb[i].in_use = true; + bta_gattc_cb.cl_rcb[i].p_cback = p_cback; + bta_gattc_cb.cl_rcb[i].app_uuid = app_uuid; + + /* BTA use the same client interface as BTE GATT statck */ + client_if = bta_gattc_cb.cl_rcb[i].client_if; + + log::debug( + "Registered GATT client interface {} with uuid={}, starting it on " + "main thread", + client_if, app_uuid.ToString()); + + do_in_main_thread(base::BindOnce(&bta_gattc_start_if, client_if)); + + status = GATT_SUCCESS; + break; + } } } } @@ -224,11 +264,26 @@ void bta_gattc_deregister(tBTA_GATTC_RCB* p_clreg) { continue; } - if (bta_gattc_cb.bg_track[i].cif_mask & ((tBTA_GATTC_CIF_MASK)1 << (p_clreg->client_if - 1))) { - bta_gattc_mark_bg_conn(p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false); - if (!GATT_CancelConnect(p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false)) { - log::warn("Unable to cancel GATT connection client_if:{} peer:{} is_direct:{}", + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + if (bta_gattc_cb.bg_track[i].cif_set.contains(p_clreg->client_if)) { + bta_gattc_mark_bg_conn(p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false); + if (!GATT_CancelConnect(p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false)) { + log::warn( + "Unable to cancel GATT connection client_if:{} peer:{} " + "is_direct:{}", p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false); + } + } + } else { + if (bta_gattc_cb.bg_track[i].cif_mask & + ((tBTA_GATTC_CIF_MASK)1 << (p_clreg->client_if - 1))) { + bta_gattc_mark_bg_conn(p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false); + if (!GATT_CancelConnect(p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false)) { + log::warn( + "Unable to cancel GATT connection client_if:{} peer:{} " + "is_direct:{}", + p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false); + } } } } @@ -239,17 +294,35 @@ void bta_gattc_deregister(tBTA_GATTC_RCB* p_clreg) { } /* close all CLCB related to this app */ - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { - if (!bta_gattc_cb.clcb[i].in_use || (bta_gattc_cb.clcb[i].p_rcb != p_clreg)) { - continue; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& p_clcb : bta_gattc_cb.clcb_set) { + if (p_clcb->p_rcb != p_clreg) { + continue; + } + p_clreg->dereg_pending = true; + + tBTA_GATTC_DATA gattc_data = { + .hdr = + { + .event = BTA_GATTC_API_CLOSE_EVT, + .layer_specific = p_clcb->bta_conn_id, + }, + }; + bta_gattc_close(p_clcb.get(), &gattc_data); } + } else { + for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { + if (!bta_gattc_cb.clcb[i].in_use || (bta_gattc_cb.clcb[i].p_rcb != p_clreg)) { + continue; + } - p_clreg->dereg_pending = true; + p_clreg->dereg_pending = true; - BT_HDR_RIGID buf; - buf.event = BTA_GATTC_API_CLOSE_EVT; - buf.layer_specific = bta_gattc_cb.clcb[i].bta_conn_id; - bta_gattc_close(&bta_gattc_cb.clcb[i], (tBTA_GATTC_DATA*)&buf); + BT_HDR_RIGID buf; + buf.event = BTA_GATTC_API_CLOSE_EVT; + buf.layer_specific = bta_gattc_cb.clcb[i].bta_conn_id; + bta_gattc_close(&bta_gattc_cb.clcb[i], (tBTA_GATTC_DATA*)&buf); + } } } @@ -671,10 +744,20 @@ void bta_gattc_close(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) { /** when a SRCB finished discovery, tell all related clcb */ void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb, tGATT_STATUS status) { - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { - if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) { - bta_gattc_cb.clcb[i].status = status; - bta_gattc_sm_execute(&bta_gattc_cb.clcb[i], BTA_GATTC_DISCOVER_CMPL_EVT, NULL); + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& p_clcb : bta_gattc_cb.clcb_set) { + if (p_clcb->p_srcb != p_srcb) { + continue; + } + p_clcb->status = status; + bta_gattc_sm_execute(p_clcb.get(), BTA_GATTC_DISCOVER_CMPL_EVT, NULL); + } + } else { + for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { + if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) { + bta_gattc_cb.clcb[i].status = status; + bta_gattc_sm_execute(&bta_gattc_cb.clcb[i], BTA_GATTC_DISCOVER_CMPL_EVT, NULL); + } } } } @@ -703,11 +786,22 @@ void bta_gattc_disc_close(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data /** when a SRCB start discovery, tell all related clcb and set the state */ static void bta_gattc_set_discover_st(tBTA_GATTC_SERV* p_srcb) { - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { - if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) { - bta_gattc_cb.clcb[i].status = GATT_SUCCESS; - bta_gattc_cb.clcb[i].state = BTA_GATTC_DISCOVER_ST; - bta_gattc_cb.clcb[i].request_during_discovery = BTA_GATTC_DISCOVER_REQ_NONE; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& p_clcb : bta_gattc_cb.clcb_set) { + if (p_clcb->p_srcb != p_srcb) { + continue; + } + p_clcb->status = GATT_SUCCESS; + p_clcb->state = BTA_GATTC_DISCOVER_ST; + p_clcb->request_during_discovery = BTA_GATTC_DISCOVER_REQ_NONE; + } + } else { + for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { + if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) { + bta_gattc_cb.clcb[i].status = GATT_SUCCESS; + bta_gattc_cb.clcb[i].state = BTA_GATTC_DISCOVER_ST; + bta_gattc_cb.clcb[i].request_during_discovery = BTA_GATTC_DISCOVER_REQ_NONE; + } } } } @@ -1329,7 +1423,13 @@ static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB* p_clreg) { memset(&cb_data, 0, sizeof(tBTA_GATTC)); GATT_Deregister(p_clreg->client_if); - memset(p_clreg, 0, sizeof(tBTA_GATTC_RCB)); + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + if (bta_gattc_cb.cl_rcb_map.erase(p_clreg->client_if) == 0) { + log::warn("deregistered unknown rcb client_if={}", p_clreg->client_if); + } + } else { + memset(p_clreg, 0, sizeof(tBTA_GATTC_RCB)); + } cb_data.reg_oper.client_if = client_if; cb_data.reg_oper.status = GATT_SUCCESS; @@ -1391,10 +1491,19 @@ void bta_gattc_process_api_refresh(const RawAddress& remote_bda) { if (p_srvc_cb->connected && p_srvc_cb->num_clcb != 0) { bool found = false; tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0]; - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) { - if (p_clcb->in_use && p_clcb->p_srcb == p_srvc_cb) { - found = true; - break; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& p_clcb_i : bta_gattc_cb.clcb_set) { + if (p_clcb_i->p_srcb == p_srvc_cb) { + found = true; + break; + } + } + } else { + for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) { + if (p_clcb->in_use && p_clcb->p_srcb == p_srvc_cb) { + found = true; + break; + } } } if (found) { @@ -1454,11 +1563,20 @@ static bool bta_gattc_process_srvc_chg_ind(uint16_t conn_id, tBTA_GATTC_RCB* p_c /* not an opened connection; or connection busy */ /* search for first available clcb and start discovery */ if (p_clcb == NULL || (p_clcb && p_clcb->p_q_cmd != NULL)) { - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { - if (bta_gattc_cb.clcb[i].in_use && bta_gattc_cb.clcb[i].p_srcb == p_srcb && - bta_gattc_cb.clcb[i].p_q_cmd == NULL) { - p_clcb = &bta_gattc_cb.clcb[i]; - break; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& p_clcb_i : bta_gattc_cb.clcb_set) { + if (p_clcb_i->p_srcb == p_srcb && p_clcb_i->p_q_cmd == NULL) { + p_clcb = p_clcb_i.get(); + break; + } + } + } else { + for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { + if (bta_gattc_cb.clcb[i].in_use && bta_gattc_cb.clcb[i].p_srcb == p_srcb && + bta_gattc_cb.clcb[i].p_q_cmd == NULL) { + p_clcb = &bta_gattc_cb.clcb[i]; + break; + } } } } diff --git a/system/bta/gatt/bta_gattc_int.h b/system/bta/gatt/bta_gattc_int.h index bf5e4cb56d..d213e68814 100644 --- a/system/bta/gatt/bta_gattc_int.h +++ b/system/bta/gatt/bta_gattc_int.h @@ -28,6 +28,7 @@ #include <cstdint> #include <deque> +#include <unordered_set> #include "bta/gatt/database.h" #include "bta/gatt/database_builder.h" @@ -322,7 +323,7 @@ typedef struct { bool in_use; RawAddress remote_bda; tBTA_GATTC_CIF_MASK cif_mask; - + std::unordered_set<tGATT_IF> cif_set; } tBTA_GATTC_BG_TCK; typedef struct { @@ -343,8 +344,10 @@ typedef struct { tBTA_GATTC_CONN conn_track[GATT_MAX_PHY_CHANNEL]; tBTA_GATTC_BG_TCK bg_track[BTA_GATTC_KNOWN_SR_MAX]; tBTA_GATTC_RCB cl_rcb[BTA_GATTC_CL_MAX]; + std::unordered_map<tGATT_IF, std::unique_ptr<tBTA_GATTC_RCB>> cl_rcb_map; tBTA_GATTC_CLCB clcb[BTA_GATTC_CLCB_MAX]; + std::unordered_set<std::unique_ptr<tBTA_GATTC_CLCB>> clcb_set; tBTA_GATTC_SERV known_server[BTA_GATTC_KNOWN_SR_MAX]; } tBTA_GATTC_CB; diff --git a/system/bta/gatt/bta_gattc_utils.cc b/system/bta/gatt/bta_gattc_utils.cc index 005ef08204..a44e1da9e3 100644 --- a/system/bta/gatt/bta_gattc_utils.cc +++ b/system/bta/gatt/bta_gattc_utils.cc @@ -25,6 +25,7 @@ #define LOG_TAG "bt_bta_gattc" #include <bluetooth/log.h> +#include <com_android_bluetooth_flags.h> #include <cstdint> @@ -57,15 +58,24 @@ static uint8_t ble_acceptlist_size() { * ******************************************************************************/ tBTA_GATTC_RCB* bta_gattc_cl_get_regcb(uint8_t client_if) { - uint8_t i = 0; - tBTA_GATTC_RCB* p_clrcb = &bta_gattc_cb.cl_rcb[0]; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + auto it = bta_gattc_cb.cl_rcb_map.find(client_if); + if (it == bta_gattc_cb.cl_rcb_map.end()) { + return NULL; + } else { + return it->second.get(); + } + } else { + uint8_t i = 0; + tBTA_GATTC_RCB* p_clrcb = &bta_gattc_cb.cl_rcb[0]; - for (i = 0; i < BTA_GATTC_CL_MAX; i++, p_clrcb++) { - if (p_clrcb->in_use && p_clrcb->client_if == client_if) { - return p_clrcb; + for (i = 0; i < BTA_GATTC_CL_MAX; i++, p_clrcb++) { + if (p_clrcb->in_use && p_clrcb->client_if == client_if) { + return p_clrcb; + } } + return NULL; } - return NULL; } /******************************************************************************* * @@ -77,14 +87,18 @@ tBTA_GATTC_RCB* bta_gattc_cl_get_regcb(uint8_t client_if) { * ******************************************************************************/ uint8_t bta_gattc_num_reg_app(void) { - uint8_t i = 0, j = 0; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + return (uint8_t)bta_gattc_cb.cl_rcb_map.size(); + } else { + uint8_t i = 0, j = 0; - for (i = 0; i < BTA_GATTC_CL_MAX; i++) { - if (bta_gattc_cb.cl_rcb[i].in_use) { - j++; + for (i = 0; i < BTA_GATTC_CL_MAX; i++) { + if (bta_gattc_cb.cl_rcb[i].in_use) { + j++; + } } + return j; } - return j; } /******************************************************************************* * @@ -97,12 +111,21 @@ uint8_t bta_gattc_num_reg_app(void) { ******************************************************************************/ tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_cif(uint8_t client_if, const RawAddress& remote_bda, tBT_TRANSPORT transport) { - tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0]; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& p_clcb : bta_gattc_cb.clcb_set) { + if (p_clcb->in_use && p_clcb->p_rcb->client_if == client_if && + p_clcb->transport == transport && p_clcb->bda == remote_bda) { + return p_clcb.get(); + } + } + } else { + tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0]; - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) { - if (p_clcb->in_use && p_clcb->p_rcb->client_if == client_if && p_clcb->transport == transport && - p_clcb->bda == remote_bda) { - return p_clcb; + for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) { + if (p_clcb->in_use && p_clcb->p_rcb->client_if == client_if && + p_clcb->transport == transport && p_clcb->bda == remote_bda) { + return p_clcb; + } } } return NULL; @@ -117,11 +140,19 @@ tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_cif(uint8_t client_if, const RawAddress& * ******************************************************************************/ tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_conn_id(uint16_t conn_id) { - tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0]; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& p_clcb : bta_gattc_cb.clcb_set) { + if (p_clcb->bta_conn_id == conn_id) { + return p_clcb.get(); + } + } + } else { + tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0]; - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) { - if (p_clcb->in_use && p_clcb->bta_conn_id == conn_id) { - return p_clcb; + for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) { + if (p_clcb->in_use && p_clcb->bta_conn_id == conn_id) { + return p_clcb; + } } } return NULL; @@ -140,34 +171,61 @@ tBTA_GATTC_CLCB* bta_gattc_clcb_alloc(tGATT_IF client_if, const RawAddress& remo tBT_TRANSPORT transport) { tBTA_GATTC_CLCB* p_clcb = NULL; - for (int i_clcb = 0; i_clcb < BTA_GATTC_CLCB_MAX; i_clcb++) { - if (!bta_gattc_cb.clcb[i_clcb].in_use) { + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + auto [p_clcb_i, b] = bta_gattc_cb.clcb_set.emplace(std::make_unique<tBTA_GATTC_CLCB>()); + p_clcb = p_clcb_i->get(); + + p_clcb->in_use = true; + p_clcb->status = GATT_SUCCESS; + p_clcb->transport = transport; + p_clcb->bda = remote_bda; + p_clcb->p_q_cmd = NULL; + + p_clcb->p_rcb = bta_gattc_cl_get_regcb(client_if); + + p_clcb->p_srcb = bta_gattc_find_srcb(remote_bda); + if (p_clcb->p_srcb == NULL) { + p_clcb->p_srcb = bta_gattc_srcb_alloc(remote_bda); + } + + if (p_clcb->p_rcb != NULL && p_clcb->p_srcb != NULL) { + p_clcb->p_srcb->num_clcb++; + p_clcb->p_rcb->num_clcb++; + } else { + /* release this clcb if clcb or srcb allocation failed */ + bta_gattc_cb.clcb_set.erase(p_clcb_i); + p_clcb = NULL; + } + } else { + for (int i_clcb = 0; i_clcb < BTA_GATTC_CLCB_MAX; i_clcb++) { + if (!bta_gattc_cb.clcb[i_clcb].in_use) { #if (BTA_GATT_DEBUG == TRUE) - log::verbose("found clcb:{} available", i_clcb); + log::verbose("found clcb:{} available", i_clcb); #endif - p_clcb = &bta_gattc_cb.clcb[i_clcb]; - p_clcb->in_use = true; - p_clcb->status = GATT_SUCCESS; - p_clcb->transport = transport; - p_clcb->bda = remote_bda; - p_clcb->p_q_cmd = NULL; - - p_clcb->p_rcb = bta_gattc_cl_get_regcb(client_if); - - p_clcb->p_srcb = bta_gattc_find_srcb(remote_bda); - if (p_clcb->p_srcb == NULL) { - p_clcb->p_srcb = bta_gattc_srcb_alloc(remote_bda); - } + p_clcb = &bta_gattc_cb.clcb[i_clcb]; + p_clcb->in_use = true; + p_clcb->status = GATT_SUCCESS; + p_clcb->transport = transport; + p_clcb->bda = remote_bda; + p_clcb->p_q_cmd = NULL; + + p_clcb->p_rcb = bta_gattc_cl_get_regcb(client_if); + + p_clcb->p_srcb = bta_gattc_find_srcb(remote_bda); + if (p_clcb->p_srcb == NULL) { + p_clcb->p_srcb = bta_gattc_srcb_alloc(remote_bda); + } - if (p_clcb->p_rcb != NULL && p_clcb->p_srcb != NULL) { - p_clcb->p_srcb->num_clcb++; - p_clcb->p_rcb->num_clcb++; - } else { - /* release this clcb if clcb or srcb allocation failed */ - p_clcb->in_use = false; - p_clcb = NULL; + if (p_clcb->p_rcb != NULL && p_clcb->p_srcb != NULL) { + p_clcb->p_srcb->num_clcb++; + p_clcb->p_rcb->num_clcb++; + } else { + /* release this clcb if clcb or srcb allocation failed */ + p_clcb->in_use = false; + p_clcb = NULL; + } + break; } - break; } } return p_clcb; @@ -258,17 +316,26 @@ void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB* p_clcb) { /* Clear p_clcb. Some of the fields are already reset e.g. p_q_cmd_queue and * p_q_cmd. */ - p_clcb->bta_conn_id = 0; - p_clcb->bda = {}; - p_clcb->transport = BT_TRANSPORT_AUTO; - p_clcb->p_rcb = NULL; - p_clcb->p_srcb = NULL; - p_clcb->request_during_discovery = 0; - p_clcb->auto_update = 0; - p_clcb->disc_active = 0; - p_clcb->in_use = 0; - p_clcb->state = BTA_GATTC_IDLE_ST; - p_clcb->status = GATT_SUCCESS; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& p_clcb_i : bta_gattc_cb.clcb_set) { + if (p_clcb_i.get() == p_clcb) { + bta_gattc_cb.clcb_set.erase(p_clcb_i); + break; + } + } + } else { + p_clcb->bta_conn_id = 0; + p_clcb->bda = {}; + p_clcb->transport = BT_TRANSPORT_AUTO; + p_clcb->p_rcb = NULL; + p_clcb->p_srcb = NULL; + p_clcb->request_during_discovery = 0; + p_clcb->auto_update = 0; + p_clcb->disc_active = 0; + p_clcb->in_use = 0; + p_clcb->state = BTA_GATTC_IDLE_ST; + p_clcb->status = GATT_SUCCESS; + } } /******************************************************************************* @@ -555,20 +622,38 @@ bool bta_gattc_mark_bg_conn(tGATT_IF client_if, const RawAddress& remote_bda_ptr for (i = 0; i < ble_acceptlist_size(); i++, p_bg_tck++) { if (p_bg_tck->in_use && ((p_bg_tck->remote_bda == remote_bda_ptr) || (p_bg_tck->remote_bda.IsEmpty()))) { - p_cif_mask = &p_bg_tck->cif_mask; - - if (add) { /* mask on the cif bit */ - *p_cif_mask |= (1 << (client_if - 1)); + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + auto& p_cif_set = p_bg_tck->cif_set; + if (add) { /* mask on the cif bit */ + p_cif_set.insert(client_if); + } else { + if (client_if != 0) { + p_cif_set.erase(client_if); + } else { + p_cif_set.clear(); + } + } + /* no BG connection for this device, make it available */ + if (p_bg_tck->cif_set.empty()) { + p_bg_tck->in_use = false; + p_bg_tck->remote_bda = RawAddress::kEmpty; + } } else { - if (client_if != 0) { - *p_cif_mask &= (~(1 << (client_if - 1))); + p_cif_mask = &p_bg_tck->cif_mask; + + if (add) { /* mask on the cif bit */ + *p_cif_mask |= (1 << (client_if - 1)); } else { - *p_cif_mask = 0; + if (client_if != 0) { + *p_cif_mask &= (~(1 << (client_if - 1))); + } else { + *p_cif_mask = 0; + } + } + /* no BG connection for this device, make it available */ + if (p_bg_tck->cif_mask == 0) { + memset(p_bg_tck, 0, sizeof(tBTA_GATTC_BG_TCK)); } - } - /* no BG connection for this device, make it available */ - if (p_bg_tck->cif_mask == 0) { - memset(p_bg_tck, 0, sizeof(tBTA_GATTC_BG_TCK)); } return true; } @@ -823,32 +908,55 @@ void bta_gatt_client_dump(int fd) { stream << " -- used: " << entry_count << "\n"; entry_count = 0; - stream << " ->cl_rcb (BTA_GATTC_CL_MAX=" << BTA_GATTC_CL_MAX << ")\n"; - for (int i = 0; i < BTA_GATTC_CL_MAX; i++) { - tBTA_GATTC_RCB* p_cl_rcb = &bta_gattc_cb.cl_rcb[i]; - if (!p_cl_rcb->in_use) { - continue; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + stream << " ->cl_rcb (dynamic)\n"; + for (auto& [i, p_cl_rcb] : bta_gattc_cb.cl_rcb_map) { + entry_count++; + stream << " client_if: " << +p_cl_rcb->client_if << " app uuids: " << p_cl_rcb->app_uuid + << " clcb_num: " << +p_cl_rcb->num_clcb; + stream << "\n"; + } + } else { + stream << " ->cl_rcb (BTA_GATTC_CL_MAX=" << BTA_GATTC_CL_MAX << ")\n"; + for (int i = 0; i < BTA_GATTC_CL_MAX; i++) { + tBTA_GATTC_RCB* p_cl_rcb = &bta_gattc_cb.cl_rcb[i]; + if (!p_cl_rcb->in_use) { + continue; + } + entry_count++; + stream << " client_if: " << +p_cl_rcb->client_if << " app uuids: " << p_cl_rcb->app_uuid + << " clcb_num: " << +p_cl_rcb->num_clcb; + stream << "\n"; } - entry_count++; - stream << " client_if: " << +p_cl_rcb->client_if << " app uuids: " << p_cl_rcb->app_uuid - << " clcb_num: " << +p_cl_rcb->num_clcb; - stream << "\n"; } stream << " -- used: " << entry_count << "\n"; entry_count = 0; - stream << " ->clcb (BTA_GATTC_CLCB_MAX=" << BTA_GATTC_CLCB_MAX << ")\n"; - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { - tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[i]; - if (!p_clcb->in_use) { - continue; + + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + stream << " ->clcb (dynamic)\n"; + for (auto& p_clcb : bta_gattc_cb.clcb_set) { + entry_count++; + stream << " conn_id: " << loghex(p_clcb->bta_conn_id) + << " address: " << ADDRESS_TO_LOGGABLE_STR(p_clcb->bda) + << " transport: " << bt_transport_text(p_clcb->transport) + << " state: " << bta_clcb_state_text(p_clcb->state); + stream << "\n"; + } + } else { + stream << " ->clcb (BTA_GATTC_CLCB_MAX=" << BTA_GATTC_CLCB_MAX << ")\n"; + for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { + tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[i]; + if (!p_clcb->in_use) { + continue; + } + entry_count++; + stream << " conn_id: " << loghex(p_clcb->bta_conn_id) + << " address: " << ADDRESS_TO_LOGGABLE_STR(p_clcb->bda) + << " transport: " << bt_transport_text(p_clcb->transport) + << " state: " << bta_clcb_state_text(p_clcb->state); + stream << "\n"; } - entry_count++; - stream << " conn_id: " << loghex(p_clcb->bta_conn_id) - << " address: " << ADDRESS_TO_LOGGABLE_STR(p_clcb->bda) - << " transport: " << bt_transport_text(p_clcb->transport) - << " state: " << bta_clcb_state_text(p_clcb->state); - stream << "\n"; } stream << " -- used: " << entry_count << "\n"; diff --git a/system/bta/hh/bta_hh_act.cc b/system/bta/hh/bta_hh_act.cc index 56d4de0ce3..cb3a3fce98 100644 --- a/system/bta/hh/bta_hh_act.cc +++ b/system/bta/hh/bta_hh_act.cc @@ -199,22 +199,30 @@ void bta_hh_disc_cmpl(void) { * Returns void * ******************************************************************************/ -static void bta_hh_sdp_cback(tSDP_STATUS result, uint16_t attr_mask, tHID_DEV_SDP_INFO* sdp_rec) { - tBTA_HH_DEV_CB* p_cb = bta_hh_cb.p_cur; - uint8_t hdl = 0; +static void bta_hh_sdp_cback(const RawAddress& bd_addr, tSDP_STATUS result, uint16_t attr_mask, + tHID_DEV_SDP_INFO* sdp_rec) { tBTA_HH_STATUS status = BTA_HH_ERR_SDP; + tAclLinkSpec link_spec = { + .addrt = {.type = BLE_ADDR_PUBLIC, .bda = bd_addr}, + .transport = BT_TRANSPORT_BR_EDR, + }; + tBTA_HH_DEV_CB* p_cb = bta_hh_find_cb(link_spec); + if (p_cb == nullptr) { + log::error("Unknown device {}", bd_addr); + return; + } - /* make sure sdp succeeded and hh has not been disabled */ - if ((result == SDP_SUCCESS) && (p_cb != NULL)) { + if (result == SDP_SUCCESS) { /* security is required for the connection, add attr_mask bit*/ attr_mask |= HID_SEC_REQUIRED; - log::verbose("p_cb:{} result:0x{:02x}, attr_mask:0x{:02x}, handle:0x{:x}", fmt::ptr(p_cb), - result, attr_mask, p_cb->hid_handle); + log::verbose("Device:{} result:0x{:02x}, attr_mask:0x{:02x}, handle:0x{:x}", bd_addr, result, + attr_mask, p_cb->hid_handle); /* check to see type of device is supported , and should not been added * before */ if (bta_hh_tod_spt(p_cb, sdp_rec->sub_class)) { + uint8_t hdl = 0; /* if not added before */ if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) { /* add device/update attr_mask information */ @@ -247,14 +255,12 @@ static void bta_hh_sdp_cback(tSDP_STATUS result, uint16_t attr_mask, tHID_DEV_SD } /* free disc_db when SDP is completed */ - osi_free_and_reset((void**)&bta_hh_cb.p_disc_db); + osi_free_and_reset((void**)&p_cb->p_disc_db); /* send SDP_CMPL_EVT into state machine */ tBTA_HH_DATA bta_hh_data; bta_hh_data.status = status; bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, &bta_hh_data); - - return; } /******************************************************************************* * @@ -265,12 +271,19 @@ static void bta_hh_sdp_cback(tSDP_STATUS result, uint16_t attr_mask, tHID_DEV_SD * Returns void * ******************************************************************************/ -static void bta_hh_di_sdp_cback(const RawAddress& /* bd_addr */, tSDP_RESULT result) { - tBTA_HH_DEV_CB* p_cb = bta_hh_cb.p_cur; +static void bta_hh_di_sdp_cback(const RawAddress& bd_addr, tSDP_RESULT result) { tBTA_HH_STATUS status = BTA_HH_ERR_SDP; - tSDP_DI_GET_RECORD di_rec; - tHID_STATUS ret; - log::verbose("p_cb:{} result:0x{:02x}", fmt::ptr(p_cb), result); + tAclLinkSpec link_spec = { + .addrt = {.type = BLE_ADDR_PUBLIC, .bda = bd_addr}, + .transport = BT_TRANSPORT_BR_EDR, + }; + tBTA_HH_DEV_CB* p_cb = bta_hh_find_cb(link_spec); + if (p_cb == nullptr) { + log::error("Unknown device {}", bd_addr); + return; + } + + log::verbose("device:{} result:0x{:02x}", bd_addr, result); /* if DI record does not exist on remote device, vendor_id in * tBTA_HH_DEV_DSCP_INFO will be set to 0xffff and we will allow the @@ -278,38 +291,38 @@ static void bta_hh_di_sdp_cback(const RawAddress& /* bd_addr */, tSDP_RESULT res * HID devices do not set this. So for IOP purposes, we allow the connection * to go through and update the DI record to invalid DI entry. */ - if (((result == SDP_SUCCESS) || (result == SDP_NO_RECS_MATCH)) && (p_cb != NULL)) { + if (result == SDP_SUCCESS || result == SDP_NO_RECS_MATCH) { if (result == SDP_SUCCESS && - get_legacy_stack_sdp_api()->device_id.SDP_GetNumDiRecords(bta_hh_cb.p_disc_db) != 0) { + get_legacy_stack_sdp_api()->device_id.SDP_GetNumDiRecords(p_cb->p_disc_db) != 0) { + tSDP_DI_GET_RECORD di_rec; + /* always update information with primary DI record */ - if (get_legacy_stack_sdp_api()->device_id.SDP_GetDiRecord(1, &di_rec, bta_hh_cb.p_disc_db) == + if (get_legacy_stack_sdp_api()->device_id.SDP_GetDiRecord(1, &di_rec, p_cb->p_disc_db) == SDP_SUCCESS) { bta_hh_update_di_info(p_cb, di_rec.rec.vendor, di_rec.rec.product, di_rec.rec.version, 0, 0); } - } else /* no DI record available */ - { + } else /* no DI record available */ { bta_hh_update_di_info(p_cb, BTA_HH_VENDOR_ID_INVALID, 0, 0, 0, 0); } - ret = HID_HostGetSDPRecord(p_cb->link_spec.addrt.bda, bta_hh_cb.p_disc_db, - p_bta_hh_cfg->sdp_db_size, bta_hh_sdp_cback); + tHID_STATUS ret = HID_HostGetSDPRecord(p_cb->link_spec.addrt.bda, p_cb->p_disc_db, + p_bta_hh_cfg->sdp_db_size, bta_hh_sdp_cback); if (ret == HID_SUCCESS) { status = BTA_HH_OK; } else { - log::verbose("failure Status 0x{:2x}", ret); + log::warn("failure Status 0x{:2x}", ret); } } if (status != BTA_HH_OK) { - osi_free_and_reset((void**)&bta_hh_cb.p_disc_db); + osi_free_and_reset((void**)&p_cb->p_disc_db); /* send SDP_CMPL_EVT into state machine */ tBTA_HH_DATA bta_hh_data; bta_hh_data.status = status; bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, &bta_hh_data); } - return; } /******************************************************************************* @@ -324,27 +337,8 @@ static void bta_hh_di_sdp_cback(const RawAddress& /* bd_addr */, tSDP_RESULT res * Returns void * ******************************************************************************/ -static void bta_hh_start_sdp(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { - if (!bta_hh_cb.p_disc_db) { - bta_hh_cb.p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(p_bta_hh_cfg->sdp_db_size); - - /* Do DI discovery first */ - if (get_legacy_stack_sdp_api()->device_id.SDP_DiDiscover( - p_data->api_conn.link_spec.addrt.bda, bta_hh_cb.p_disc_db, - p_bta_hh_cfg->sdp_db_size, bta_hh_di_sdp_cback) == SDP_SUCCESS) { - /* SDP search started successfully - * Connection will be triggered at the end of successful SDP search - */ - } else { - log::error("SDP_DiDiscover failed"); - - osi_free_and_reset((void**)&bta_hh_cb.p_disc_db); - - tBTA_HH_DATA bta_hh_data; - bta_hh_data.status = BTA_HH_ERR_SDP; - bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, &bta_hh_data); - } - } else if (bta_hh_cb.p_disc_db) { +static void bta_hh_start_sdp(tBTA_HH_DEV_CB* p_cb) { + if (p_cb->p_disc_db != nullptr) { /* Incoming/outgoing collision case. DUT initiated HID connection at the * same time as the remote connected HID control channel. * When flow reaches here due to remote initiated connection, DUT may be @@ -352,6 +346,25 @@ static void bta_hh_start_sdp(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { * or failure will handle this case. */ log::warn("Ignoring as SDP already in progress"); + return; + } + + p_cb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(p_bta_hh_cfg->sdp_db_size); + + /* Do DI discovery first */ + if (get_legacy_stack_sdp_api()->device_id.SDP_DiDiscover( + p_cb->link_spec.addrt.bda, p_cb->p_disc_db, p_bta_hh_cfg->sdp_db_size, + bta_hh_di_sdp_cback) == SDP_SUCCESS) { + // SDP search started successfully. Connection will be triggered at the end of successful SDP + // search + } else { + log::error("SDP_DiDiscover failed"); + + osi_free_and_reset((void**)&p_cb->p_disc_db); + + tBTA_HH_DATA bta_hh_data; + bta_hh_data.status = BTA_HH_ERR_SDP; + bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, &bta_hh_data); } } @@ -447,12 +460,10 @@ void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { * Returns void * ******************************************************************************/ -static void bta_hh_bredr_conn(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { - bta_hh_cb.p_cur = p_cb; - +static void bta_hh_bredr_conn(tBTA_HH_DEV_CB* p_cb) { /* If previously virtually cabled device */ if (p_cb->app_id) { - tBTA_HH_DATA bta_hh_data; + tBTA_HH_DATA bta_hh_data = {}; bta_hh_data.status = BTA_HH_OK; log::verbose("skip SDP for known devices"); @@ -461,7 +472,7 @@ static void bta_hh_bredr_conn(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) uint8_t hdl; if (HID_HostAddDev(p_cb->link_spec.addrt.bda, p_cb->attr_mask, &hdl) == HID_SUCCESS) { /* update device CB with newly register device handle */ - bta_hh_add_device_to_list(p_cb, hdl, p_cb->attr_mask, NULL, p_cb->sub_class, + bta_hh_add_device_to_list(p_cb, hdl, p_cb->attr_mask, nullptr, p_cb->sub_class, p_cb->dscp_info.ssr_max_latency, p_cb->dscp_info.ssr_min_tout, p_cb->app_id); /* update cb_index[] map */ @@ -473,7 +484,7 @@ static void bta_hh_bredr_conn(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, &bta_hh_data); } else { /* First time connection, start SDP */ - bta_hh_start_sdp(p_cb, p_data); + bta_hh_start_sdp(p_cb); } } @@ -487,15 +498,13 @@ static void bta_hh_bredr_conn(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) * ******************************************************************************/ void bta_hh_connect(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { - p_cb->link_spec = p_data->api_conn.link_spec; p_cb->mode = p_data->api_conn.mode; - bta_hh_cb.p_cur = p_cb; // Initiate HID host connection if (p_cb->link_spec.transport == BT_TRANSPORT_LE) { - bta_hh_le_open_conn(p_cb, p_data->api_conn.link_spec); + bta_hh_le_open_conn(p_cb); } else { - bta_hh_bredr_conn(p_cb, p_data); + bta_hh_bredr_conn(p_cb); } } @@ -601,8 +610,6 @@ void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { * ******************************************************************************/ void bta_hh_open_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { - tBTA_HH_API_CONN conn_data; - uint8_t dev_handle = p_data ? (uint8_t)p_data->hid_cback.hdr.layer_specific : p_cb->hid_handle; log::verbose("Device[{}] connected", dev_handle); @@ -619,13 +626,8 @@ void bta_hh_open_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { /* store the handle here in case sdp fails - need to disconnect */ p_cb->incoming_hid_handle = dev_handle; - memset(&conn_data, 0, sizeof(tBTA_HH_API_CONN)); - conn_data.link_spec = p_cb->link_spec; - bta_hh_cb.p_cur = p_cb; - bta_hh_bredr_conn(p_cb, (tBTA_HH_DATA*)&conn_data); + bta_hh_bredr_conn(p_cb); } - - return; } /******************************************************************************* diff --git a/system/bta/hh/bta_hh_api.cc b/system/bta/hh/bta_hh_api.cc index ff1ef18e7c..10ca7f2d65 100644 --- a/system/bta/hh/bta_hh_api.cc +++ b/system/bta/hh/bta_hh_api.cc @@ -348,3 +348,14 @@ void BTA_HhRemoveDev(uint8_t dev_handle) { bta_sys_sendmsg(p_buf); } + +/******************************************************************************* + * + * Function BTA_HhDump + * + * Description Dump BTA HH control block + * + * Returns void + * + ******************************************************************************/ +void BTA_HhDump(int fd) { bta_hh_dump(fd); } diff --git a/system/bta/hh/bta_hh_int.h b/system/bta/hh/bta_hh_int.h index 7a011b8f51..1929153182 100644 --- a/system/bta/hh/bta_hh_int.h +++ b/system/bta/hh/bta_hh_int.h @@ -223,6 +223,8 @@ typedef struct { #define BTA_HH_LE_SCPS_NOTIFY_ENB 0x02 uint8_t scps_notify; /* scan refresh supported/notification enabled */ bool security_pending; + + tSDP_DISCOVERY_DB* p_disc_db; } tBTA_HH_DEV_CB; /****************************************************************************** @@ -230,15 +232,12 @@ typedef struct { ******************************************************************************/ typedef struct { tBTA_HH_DEV_CB kdev[BTA_HH_MAX_DEVICE]; /* device control block */ - tBTA_HH_DEV_CB* p_cur; /* current device control - block idx, used in sdp */ uint8_t cb_index[BTA_HH_MAX_KNOWN]; /* maintain a CB index map to dev handle */ uint8_t le_cb_index[BTA_HH_LE_MAX_KNOWN]; /* maintain a CB index map to LE dev handle */ tGATT_IF gatt_if; tBTA_HH_CBACK* p_cback; /* Application callbacks */ - tSDP_DISCOVERY_DB* p_disc_db; uint8_t cnt_num; /* connected device number */ bool w4_disable; /* w4 disable flag */ } tBTA_HH_CB; @@ -252,7 +251,7 @@ extern tBTA_HH_CFG* p_bta_hh_cfg; * Function prototypes ****************************************************************************/ bool bta_hh_hdl_event(const BT_HDR_RIGID* p_msg); -void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, uint16_t event, const tBTA_HH_DATA* p_data); +void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, tBTA_HH_INT_EVT event, const tBTA_HH_DATA* p_data); /* action functions */ void bta_hh_api_disc_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data); @@ -270,8 +269,9 @@ void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data); void bta_hh_open_failure(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data); /* utility functions */ -uint8_t bta_hh_find_cb(const tAclLinkSpec& link_spec); +tBTA_HH_DEV_CB* bta_hh_find_cb(const tAclLinkSpec& link_spec); tBTA_HH_DEV_CB* bta_hh_get_cb(const tAclLinkSpec& link_spec); +tBTA_HH_DEV_CB* bta_hh_find_cb_by_handle(uint8_t hid_handle); bool bta_hh_tod_spt(tBTA_HH_DEV_CB* p_cb, uint8_t sub_class); void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB* p_cb); @@ -282,8 +282,6 @@ void bta_hh_update_di_info(tBTA_HH_DEV_CB* p_cb, uint16_t vendor_id, uint16_t pr uint16_t version, uint8_t flag, uint8_t ctry_code); void bta_hh_cleanup_disable(tBTA_HH_STATUS status); -uint8_t bta_hh_dev_handle_to_cb_idx(uint8_t dev_handle); - /* action functions used outside state machine */ void bta_hh_api_enable(tBTA_HH_CBACK* p_cback, bool enable_hid, bool enable_hogp); void bta_hh_api_disable(void); @@ -295,7 +293,7 @@ tBTA_HH_STATUS bta_hh_read_ssr_param(const tAclLinkSpec& link_spec, uint16_t* p_ /* functions for LE HID */ void bta_hh_le_enable(void); void bta_hh_le_deregister(void); -void bta_hh_le_open_conn(tBTA_HH_DEV_CB* p_cb, const tAclLinkSpec& link_spec); +void bta_hh_le_open_conn(tBTA_HH_DEV_CB* p_cb); void bta_hh_le_api_disc_act(tBTA_HH_DEV_CB* p_cb); void bta_hh_le_get_dscp_act(tBTA_HH_DEV_CB* p_cb); void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data); @@ -322,6 +320,8 @@ void bta_hh_headtracker_parse_service(tBTA_HH_DEV_CB* p_dev_cb, const gatt::Serv bool bta_hh_headtracker_supported(tBTA_HH_DEV_CB* p_dev_cb); uint16_t bta_hh_get_uuid16(tBTA_HH_DEV_CB* p_dev_cb, bluetooth::Uuid uuid); +void bta_hh_dump(int fd); + #if (BTA_HH_DEBUG == TRUE) void bta_hh_trace_dev_db(void); #endif diff --git a/system/bta/hh/bta_hh_le.cc b/system/bta/hh/bta_hh_le.cc index 542704edd2..04a38d65c3 100644 --- a/system/bta/hh/bta_hh_le.cc +++ b/system/bta/hh/bta_hh_le.cc @@ -241,19 +241,16 @@ void bta_hh_le_deregister(void) { BTA_GATTC_AppDeregister(bta_hh_cb.gatt_if); } * ******************************************************************************/ static uint8_t bta_hh_le_get_le_dev_hdl(uint8_t cb_index) { - uint8_t i; - for (i = 0; i < ARRAY_SIZE(bta_hh_cb.le_cb_index); i++) { + uint8_t available_handle = BTA_HH_IDX_INVALID; + for (uint8_t i = 0; i < ARRAY_SIZE(bta_hh_cb.le_cb_index); i++) { if (bta_hh_cb.le_cb_index[i] == cb_index) { return BTA_HH_GET_LE_DEV_HDL(i); + } else if (available_handle == BTA_HH_IDX_INVALID && + bta_hh_cb.le_cb_index[i] == BTA_HH_IDX_INVALID) { + available_handle = BTA_HH_GET_LE_DEV_HDL(i); } } - - for (i = 0; i < ARRAY_SIZE(bta_hh_cb.le_cb_index); i++) { - if (bta_hh_cb.le_cb_index[i] == BTA_HH_IDX_INVALID) { - return BTA_HH_GET_LE_DEV_HDL(i); - } - } - return BTA_HH_IDX_INVALID; + return available_handle; } /******************************************************************************* @@ -265,21 +262,17 @@ static uint8_t bta_hh_le_get_le_dev_hdl(uint8_t cb_index) { * Parameters: * ******************************************************************************/ -void bta_hh_le_open_conn(tBTA_HH_DEV_CB* p_cb, const tAclLinkSpec& link_spec) { - tBTA_HH_STATUS status = BTA_HH_ERR_NO_RES; - - /* update cb_index[] map */ +void bta_hh_le_open_conn(tBTA_HH_DEV_CB* p_cb) { p_cb->hid_handle = bta_hh_le_get_le_dev_hdl(p_cb->index); if (p_cb->hid_handle == BTA_HH_IDX_INVALID) { + tBTA_HH_STATUS status = BTA_HH_ERR_NO_RES; bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status); return; } - p_cb->link_spec = link_spec; - bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index; - p_cb->in_use = true; + bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index; // Update index map - BTA_GATTC_Open(bta_hh_cb.gatt_if, link_spec.addrt.bda, BTM_BLE_DIRECT_CONNECTION, false); + BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->link_spec.addrt.bda, BTM_BLE_DIRECT_CONNECTION, false); } /******************************************************************************* @@ -291,15 +284,13 @@ void bta_hh_le_open_conn(tBTA_HH_DEV_CB* p_cb, const tAclLinkSpec& link_spec) { * ******************************************************************************/ static tBTA_HH_DEV_CB* bta_hh_le_find_dev_cb_by_conn_id(uint16_t conn_id) { - uint8_t i; - tBTA_HH_DEV_CB* p_dev_cb = &bta_hh_cb.kdev[0]; - - for (i = 0; i < BTA_HH_MAX_DEVICE; i++, p_dev_cb++) { + for (uint8_t i = 0; i < BTA_HH_MAX_DEVICE; i++) { + tBTA_HH_DEV_CB* p_dev_cb = &bta_hh_cb.kdev[i]; if (p_dev_cb->in_use && p_dev_cb->conn_id == conn_id) { return p_dev_cb; } } - return NULL; + return nullptr; } /******************************************************************************* @@ -311,16 +302,14 @@ static tBTA_HH_DEV_CB* bta_hh_le_find_dev_cb_by_conn_id(uint16_t conn_id) { * ******************************************************************************/ static tBTA_HH_DEV_CB* bta_hh_le_find_dev_cb_by_bda(const tAclLinkSpec& link_spec) { - uint8_t i; - tBTA_HH_DEV_CB* p_dev_cb = &bta_hh_cb.kdev[0]; - - for (i = 0; i < BTA_HH_MAX_DEVICE; i++, p_dev_cb++) { + for (uint8_t i = 0; i < BTA_HH_MAX_DEVICE; i++) { + tBTA_HH_DEV_CB* p_dev_cb = &bta_hh_cb.kdev[i]; if (p_dev_cb->in_use && p_dev_cb->link_spec.addrt.bda == link_spec.addrt.bda && p_dev_cb->link_spec.transport == BT_TRANSPORT_LE) { return p_dev_cb; } } - return NULL; + return nullptr; } /******************************************************************************* @@ -968,9 +957,9 @@ static void bta_hh_le_encrypt_cback(RawAddress bd_addr, tBT_TRANSPORT transport, .transport = transport, }; - tBTA_HH_DEV_CB* p_dev_cb = bta_hh_get_cb(link_spec); + tBTA_HH_DEV_CB* p_dev_cb = bta_hh_find_cb(link_spec); if (p_dev_cb == nullptr) { - log::error("unexpected encryption callback, ignore"); + log::error("Unexpected encryption callback for {}", bd_addr); return; } @@ -1085,11 +1074,6 @@ static void bta_hh_clear_service_cache(tBTA_HH_DEV_CB* p_cb) { ******************************************************************************/ void bta_hh_start_security(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* /* p_buf */) { log::verbose("addr:{}", p_cb->link_spec.addrt.bda); - if (BTM_SecIsSecurityPending(p_cb->link_spec.addrt.bda)) { - /* if security collision happened, wait for encryption done */ - p_cb->security_pending = true; - return; - } /* if link has been encrypted */ if (BTM_IsEncrypted(p_cb->link_spec.addrt.bda, BT_TRANSPORT_LE)) { @@ -1103,9 +1087,12 @@ void bta_hh_start_security(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* /* p_buf */ p_cb->status = BTA_HH_ERR_AUTH_FAILED; BTM_SetEncryption(p_cb->link_spec.addrt.bda, BT_TRANSPORT_LE, bta_hh_le_encrypt_cback, NULL, BTM_BLE_SEC_ENCRYPT); - } - /* unbonded device, report security error here */ - else { + } else if (BTM_SecIsSecurityPending(p_cb->link_spec.addrt.bda)) { + /* if security collision happened, wait for encryption done */ + log::debug("addr:{} security collision", p_cb->link_spec.addrt.bda); + p_cb->security_pending = true; + } else { + /* unbonded device, report security error here */ log::debug("addr:{} not bonded", p_cb->link_spec.addrt.bda); p_cb->status = BTA_HH_ERR_AUTH_FAILED; bta_hh_clear_service_cache(p_cb); diff --git a/system/bta/hh/bta_hh_main.cc b/system/bta/hh/bta_hh_main.cc index 0b14004c65..e28f24341c 100644 --- a/system/bta/hh/bta_hh_main.cc +++ b/system/bta/hh/bta_hh_main.cc @@ -30,6 +30,7 @@ #include <cstdint> #include "bta/hh/bta_hh_int.h" +#include "main/shim/dumpsys.h" #include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" @@ -44,14 +45,132 @@ tBTA_HH_CB bta_hh_cb; /***************************************************************************** * Static functions ****************************************************************************/ -static const char* bta_hh_evt_code(tBTA_HH_INT_EVT evt_code); -static const char* bta_hh_state_code(tBTA_HH_STATE state_code); +/******************************************************************************* + * + * Function bta_hh_evt_code + * + * Description + * + * Returns void + * + ******************************************************************************/ +static const char* bta_hh_evt_code(tBTA_HH_INT_EVT evt_code) { + switch (evt_code) { + case BTA_HH_API_OPEN_EVT: + return "BTA_HH_API_OPEN_EVT"; + case BTA_HH_API_CLOSE_EVT: + return "BTA_HH_API_CLOSE_EVT"; + case BTA_HH_INT_OPEN_EVT: + return "BTA_HH_INT_OPEN_EVT"; + case BTA_HH_INT_CLOSE_EVT: + return "BTA_HH_INT_CLOSE_EVT"; + case BTA_HH_INT_HANDSK_EVT: + return "BTA_HH_INT_HANDSK_EVT"; + case BTA_HH_INT_DATA_EVT: + return "BTA_HH_INT_DATA_EVT"; + case BTA_HH_INT_CTRL_DATA: + return "BTA_HH_INT_CTRL_DATA"; + case BTA_HH_API_WRITE_DEV_EVT: + return "BTA_HH_API_WRITE_DEV_EVT"; + case BTA_HH_SDP_CMPL_EVT: + return "BTA_HH_SDP_CMPL_EVT"; + case BTA_HH_API_MAINT_DEV_EVT: + return "BTA_HH_API_MAINT_DEV_EVT"; + case BTA_HH_API_GET_DSCP_EVT: + return "BTA_HH_API_GET_DSCP_EVT"; + case BTA_HH_OPEN_CMPL_EVT: + return "BTA_HH_OPEN_CMPL_EVT"; + case BTA_HH_GATT_CLOSE_EVT: + return "BTA_HH_GATT_CLOSE_EVT"; + case BTA_HH_GATT_OPEN_EVT: + return "BTA_HH_GATT_OPEN_EVT"; + case BTA_HH_START_ENC_EVT: + return "BTA_HH_START_ENC_EVT"; + case BTA_HH_ENC_CMPL_EVT: + return "BTA_HH_ENC_CMPL_EVT"; + default: + return "unknown HID Host event code"; + } +} + +/******************************************************************************* + * + * Function bta_hh_state_code + * + * Description get string representation of HID host state code. + * + * Returns void + * + ******************************************************************************/ +static const char* bta_hh_state_code(tBTA_HH_STATE state_code) { + switch (state_code) { + case BTA_HH_NULL_ST: + return "BTA_HH_NULL_ST"; + case BTA_HH_IDLE_ST: + return "BTA_HH_IDLE_ST"; + case BTA_HH_W4_CONN_ST: + return "BTA_HH_W4_CONN_ST"; + case BTA_HH_CONN_ST: + return "BTA_HH_CONN_ST"; + case BTA_HH_W4_SEC: + return "BTA_HH_W4_SEC"; + default: + return "unknown HID Host state"; + } +} + +/* Finds the related control block, if any */ +static tBTA_HH_DEV_CB* bta_hh_find_cb_by_event(const BT_HDR_RIGID* p_msg) { + tBTA_HH_DEV_CB* p_cb = nullptr; -static void bta_hh_better_state_machine(tBTA_HH_DEV_CB* p_cb, uint16_t event, - const tBTA_HH_DATA* p_data) { - log::verbose("state:{}, event:{}", bta_hh_state_code(p_cb->state), - bta_hh_evt_code(static_cast<tBTA_HH_INT_EVT>(event))); - switch (p_cb->state) { + if (p_msg->event == BTA_HH_API_OPEN_EVT) { + // Connection requested, find or allocate the control block + p_cb = bta_hh_get_cb(((tBTA_HH_API_CONN*)p_msg)->link_spec); + } else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT) { + if (((tBTA_HH_MAINT_DEV*)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT) { + // Device is being added, find or allocate the control block + p_cb = bta_hh_get_cb(((tBTA_HH_MAINT_DEV*)p_msg)->link_spec); + } else /* else remove device by handle */ { + p_cb = bta_hh_find_cb_by_handle((uint8_t)p_msg->layer_specific); + /* If BT disable is done while the HID device is connected and + * Link_Key uses unauthenticated combination + * then we can get into a situation where remove_bonding is called + * with the index set to 0 (without getting + * cleaned up). Only when VIRTUAL_UNPLUG is called do we cleanup the + * index and make it MAX_KNOWN. + * So if REMOVE_DEVICE is called and in_use is false then we should + * treat this as a NULL p_cb. Hence we + * force the index to be IDX_INVALID + */ + if (p_cb != nullptr && !p_cb->in_use) { + log::warn("Control block getting removed, device: {}, index: {}, handle: {}", + p_cb->link_spec, p_cb->index, p_cb->hid_handle); + p_cb = nullptr; + } + } + } else if (p_msg->event == BTA_HH_INT_OPEN_EVT) { + p_cb = bta_hh_get_cb(((tBTA_HH_CBACK_DATA*)p_msg)->link_spec); + } else { + p_cb = bta_hh_find_cb_by_handle((uint8_t)p_msg->layer_specific); + } + + return p_cb; +} + +/* Handles events related to connection control blocks */ +void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, tBTA_HH_INT_EVT event, const tBTA_HH_DATA* p_data) { + tBTA_HH_STATE in_state = p_cb->state; + if (p_cb->state == BTA_HH_NULL_ST || p_cb->state >= BTA_HH_INVALID_ST) { + log::error("Invalid state State:{}, Event:{} for {}", bta_hh_state_code(in_state), + bta_hh_evt_code(event), p_cb->link_spec); + return; + } + + bool unexpected_event = false; + log::verbose("State {}, Event {} for {}", bta_hh_state_code(in_state), bta_hh_evt_code(event), + p_cb->link_spec); + + switch (in_state) { case BTA_HH_IDLE_ST: switch (event) { case BTA_HH_API_OPEN_EVT: @@ -76,6 +195,9 @@ static void bta_hh_better_state_machine(tBTA_HH_DEV_CB* p_cb, uint16_t event, p_cb->state = BTA_HH_W4_CONN_ST; bta_hh_gatt_open(p_cb, p_data); break; + default: + unexpected_event = true; + break; } break; case BTA_HH_W4_CONN_ST: @@ -115,6 +237,9 @@ static void bta_hh_better_state_machine(tBTA_HH_DEV_CB* p_cb, uint16_t event, p_cb->state = BTA_HH_W4_SEC; bta_hh_start_security(p_cb, p_data); break; + default: + unexpected_event = true; + break; } break; case BTA_HH_CONN_ST: @@ -151,6 +276,9 @@ static void bta_hh_better_state_machine(tBTA_HH_DEV_CB* p_cb, uint16_t event, p_cb->state = BTA_HH_IDLE_ST; bta_hh_gatt_close(p_cb, p_data); break; + default: + unexpected_event = true; + break; } break; case BTA_HH_W4_SEC: @@ -176,117 +304,103 @@ static void bta_hh_better_state_machine(tBTA_HH_DEV_CB* p_cb, uint16_t event, case BTA_HH_GATT_ENC_CMPL_EVT: bta_hh_le_notify_enc_cmpl(p_cb, p_data); break; + default: + unexpected_event = true; + break; } break; } + + if (unexpected_event) { + log::warn("Unexpected event event {} in state {} for {}", bta_hh_evt_code(event), + bta_hh_state_code(in_state), p_cb->link_spec); + } else if (in_state != p_cb->state) { + log::debug("State Change: [{}] -> [{}] after Event [{}]", bta_hh_state_code(in_state), + bta_hh_state_code(p_cb->state), bta_hh_evt_code(event)); + } } /******************************************************************************* * - * Function bta_hh_sm_execute - * - * Description State machine event handling function for HID Host + * Function bta_hh_hdl_failure * + * Description Handler for state machine failures * * Returns void * ******************************************************************************/ -void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, uint16_t event, const tBTA_HH_DATA* p_data) { - tBTA_HH cback_data; - tBTA_HH_EVT cback_event = 0; - tBTA_HH_STATE in_state; - tBTA_HH_INT_EVT debug_event = static_cast<tBTA_HH_INT_EVT>(event); - - memset(&cback_data, 0, sizeof(tBTA_HH)); - - /* handle exception, no valid control block was found */ - if (!p_cb) { - log::verbose("Event:{}, bta_hh_cb.p_cback:{}", bta_hh_evt_code(debug_event), - fmt::ptr(bta_hh_cb.p_cback)); - /* BTA HH enabled already? otherwise ignore the event although it's bad*/ - if (bta_hh_cb.p_cback != NULL) { - switch (event) { - /* no control block available for new connection */ - case BTA_HH_API_OPEN_EVT: - cback_event = BTA_HH_OPEN_EVT; - /* build cback data */ - cback_data.conn.link_spec = ((tBTA_HH_API_CONN*)p_data)->link_spec; - cback_data.conn.status = BTA_HH_ERR_DB_FULL; - cback_data.conn.handle = BTA_HH_INVALID_HANDLE; - break; - /* DB full, BTA_HhAddDev */ - case BTA_HH_API_MAINT_DEV_EVT: - cback_event = p_data->api_maintdev.sub_event; - - if (p_data->api_maintdev.sub_event == BTA_HH_ADD_DEV_EVT) { - cback_data.dev_info.link_spec = p_data->api_maintdev.link_spec; - cback_data.dev_info.status = BTA_HH_ERR_DB_FULL; - cback_data.dev_info.handle = BTA_HH_INVALID_HANDLE; - } else { - cback_data.dev_info.status = BTA_HH_ERR_HDL; - cback_data.dev_info.handle = (uint8_t)p_data->api_maintdev.hdr.layer_specific; - } - break; - case BTA_HH_API_WRITE_DEV_EVT: - cback_event = (p_data->api_sndcmd.t_type - HID_TRANS_GET_REPORT) + BTA_HH_GET_RPT_EVT; - osi_free_and_reset((void**)&p_data->api_sndcmd.p_data); - if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL || - p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT || - p_data->api_sndcmd.t_type == HID_TRANS_SET_IDLE) { - cback_data.dev_status.status = BTA_HH_ERR_HDL; - cback_data.dev_status.handle = (uint8_t)p_data->api_sndcmd.hdr.layer_specific; - } else if (p_data->api_sndcmd.t_type != HID_TRANS_DATA && - p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) { - cback_data.hs_data.handle = (uint8_t)p_data->api_sndcmd.hdr.layer_specific; - cback_data.hs_data.status = BTA_HH_ERR_HDL; - /* hs_data.rsp_data will be all zero, which is not valid value */ - } else if (p_data->api_sndcmd.t_type == HID_TRANS_CONTROL && - p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) { - cback_data.status = BTA_HH_ERR_HDL; - cback_event = BTA_HH_VC_UNPLUG_EVT; - } else { - cback_event = 0; - } - break; - - case BTA_HH_API_CLOSE_EVT: - cback_event = BTA_HH_CLOSE_EVT; +void bta_hh_hdl_failure(tBTA_HH_INT_EVT event, const tBTA_HH_DATA* p_data) { + if (bta_hh_cb.p_cback == nullptr) { + log::error("No callback handler"); + return; + } - cback_data.dev_status.status = BTA_HH_ERR_HDL; - cback_data.dev_status.handle = (uint8_t)p_data->api_sndcmd.hdr.layer_specific; - break; + log::verbose("Event:{}", bta_hh_evt_code(event)); + tBTA_HH cback_data = {}; + tBTA_HH_EVT cback_event = BTA_HH_EMPTY_EVT; + switch (event) { + /* no control block available for new connection */ + case BTA_HH_API_OPEN_EVT: + cback_event = BTA_HH_OPEN_EVT; + /* build cback data */ + cback_data.conn.link_spec = ((tBTA_HH_API_CONN*)p_data)->link_spec; + cback_data.conn.status = BTA_HH_ERR_DB_FULL; + cback_data.conn.handle = BTA_HH_INVALID_HANDLE; + break; + /* DB full, BTA_HhAddDev */ + case BTA_HH_API_MAINT_DEV_EVT: + cback_event = p_data->api_maintdev.sub_event; - default: - /* invalid handle, call bad API event */ - log::error("wrong device handle:{}", p_data->hdr.layer_specific); - /* Free the callback buffer now */ - if (p_data != NULL) { - osi_free_and_reset((void**)&p_data->hid_cback.p_data); - } - break; + if (p_data->api_maintdev.sub_event == BTA_HH_ADD_DEV_EVT) { + cback_data.dev_info.link_spec = p_data->api_maintdev.link_spec; + cback_data.dev_info.status = BTA_HH_ERR_DB_FULL; + cback_data.dev_info.handle = BTA_HH_INVALID_HANDLE; + } else { + cback_data.dev_info.status = BTA_HH_ERR_HDL; + cback_data.dev_info.handle = (uint8_t)p_data->api_maintdev.hdr.layer_specific; } - if (cback_event) { - (*bta_hh_cb.p_cback)(cback_event, &cback_data); + break; + case BTA_HH_API_WRITE_DEV_EVT: + cback_event = (p_data->api_sndcmd.t_type - HID_TRANS_GET_REPORT) + BTA_HH_GET_RPT_EVT; + osi_free_and_reset((void**)&p_data->api_sndcmd.p_data); + if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL || + p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT || + p_data->api_sndcmd.t_type == HID_TRANS_SET_IDLE) { + cback_data.dev_status.status = BTA_HH_ERR_HDL; + cback_data.dev_status.handle = (uint8_t)p_data->api_sndcmd.hdr.layer_specific; + } else if (p_data->api_sndcmd.t_type != HID_TRANS_DATA && + p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) { + cback_data.hs_data.handle = (uint8_t)p_data->api_sndcmd.hdr.layer_specific; + cback_data.hs_data.status = BTA_HH_ERR_HDL; + /* hs_data.rsp_data will be all zero, which is not valid value */ + } else if (p_data->api_sndcmd.t_type == HID_TRANS_CONTROL && + p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) { + cback_data.status = BTA_HH_ERR_HDL; + cback_event = BTA_HH_VC_UNPLUG_EVT; + } else { + cback_event = 0; } - } - } - /* corresponding CB is found, go to state machine */ - else { - in_state = p_cb->state; - log::verbose("State 0x{:02x} [{}], Event [{}]", in_state, bta_hh_state_code(in_state), - bta_hh_evt_code(debug_event)); + break; - if ((p_cb->state == BTA_HH_NULL_ST) || (p_cb->state >= BTA_HH_INVALID_ST)) { - log::error("Invalid state State=0x{:x}, Event={}", p_cb->state, event); - return; - } + case BTA_HH_API_CLOSE_EVT: + cback_event = BTA_HH_CLOSE_EVT; + cback_data.dev_status.status = BTA_HH_ERR_HDL; + cback_data.dev_status.handle = (uint8_t)p_data->api_sndcmd.hdr.layer_specific; + break; - bta_hh_better_state_machine(p_cb, event, p_data); + default: + /* Likely an invalid handle, call bad API event */ + log::error("wrong device handle:{} in event:{}", p_data->hdr.layer_specific, + bta_hh_evt_code(event)); + /* Free the callback buffer now */ + if (p_data != nullptr) { + osi_free_and_reset((void**)&p_data->hid_cback.p_data); + } + break; + } - if (in_state != p_cb->state) { - log::debug("HHID State Change: [{}] -> [{}] after Event [{}]", bta_hh_state_code(in_state), - bta_hh_state_code(p_cb->state), bta_hh_evt_code(debug_event)); - } + if (cback_event) { + (*bta_hh_cb.p_cback)(cback_event, &cback_data); } } @@ -301,122 +415,26 @@ void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, uint16_t event, const tBTA_HH_DATA* * ******************************************************************************/ bool bta_hh_hdl_event(const BT_HDR_RIGID* p_msg) { - uint8_t index = BTA_HH_IDX_INVALID; - tBTA_HH_DEV_CB* p_cb = NULL; + tBTA_HH_DEV_CB* p_cb = bta_hh_find_cb_by_event(p_msg); + tBTA_HH_INT_EVT event = static_cast<tBTA_HH_INT_EVT>(p_msg->event); - /* all events processed in state machine need to find corresponding - CB before proceed */ - if (p_msg->event == BTA_HH_API_OPEN_EVT) { - index = bta_hh_find_cb(((tBTA_HH_API_CONN*)p_msg)->link_spec); - } else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT) { - /* if add device */ - if (((tBTA_HH_MAINT_DEV*)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT) { - index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV*)p_msg)->link_spec); - } else /* else remove device by handle */ { - index = bta_hh_dev_handle_to_cb_idx((uint8_t)p_msg->layer_specific); - /* If BT disable is done while the HID device is connected and - * Link_Key uses unauthenticated combination - * then we can get into a situation where remove_bonding is called - * with the index set to 0 (without getting - * cleaned up). Only when VIRTUAL_UNPLUG is called do we cleanup the - * index and make it MAX_KNOWN. - * So if REMOVE_DEVICE is called and in_use is false then we should - * treat this as a NULL p_cb. Hence we - * force the index to be IDX_INVALID - */ - if ((index != BTA_HH_IDX_INVALID) && (!bta_hh_cb.kdev[index].in_use)) { - index = BTA_HH_IDX_INVALID; - } - } - } else if (p_msg->event == BTA_HH_INT_OPEN_EVT) { - index = bta_hh_find_cb(((tBTA_HH_CBACK_DATA*)p_msg)->link_spec); + if (p_cb != nullptr) { + bta_hh_sm_execute(p_cb, event, (tBTA_HH_DATA*)p_msg); } else { - index = bta_hh_dev_handle_to_cb_idx((uint8_t)p_msg->layer_specific); + bta_hh_hdl_failure(event, (tBTA_HH_DATA*)p_msg); } - if (index != BTA_HH_IDX_INVALID) { - p_cb = &bta_hh_cb.kdev[index]; - } - - log::verbose("handle={} dev_cb[{}]", p_msg->layer_specific, index); - bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA*)p_msg); - return true; } -/***************************************************************************** - * Debug Functions - ****************************************************************************/ -/******************************************************************************* - * - * Function bta_hh_evt_code - * - * Description - * - * Returns void - * - ******************************************************************************/ -static const char* bta_hh_evt_code(tBTA_HH_INT_EVT evt_code) { - switch (evt_code) { - case BTA_HH_API_OPEN_EVT: - return "BTA_HH_API_OPEN_EVT"; - case BTA_HH_API_CLOSE_EVT: - return "BTA_HH_API_CLOSE_EVT"; - case BTA_HH_INT_OPEN_EVT: - return "BTA_HH_INT_OPEN_EVT"; - case BTA_HH_INT_CLOSE_EVT: - return "BTA_HH_INT_CLOSE_EVT"; - case BTA_HH_INT_HANDSK_EVT: - return "BTA_HH_INT_HANDSK_EVT"; - case BTA_HH_INT_DATA_EVT: - return "BTA_HH_INT_DATA_EVT"; - case BTA_HH_INT_CTRL_DATA: - return "BTA_HH_INT_CTRL_DATA"; - case BTA_HH_API_WRITE_DEV_EVT: - return "BTA_HH_API_WRITE_DEV_EVT"; - case BTA_HH_SDP_CMPL_EVT: - return "BTA_HH_SDP_CMPL_EVT"; - case BTA_HH_API_MAINT_DEV_EVT: - return "BTA_HH_API_MAINT_DEV_EVT"; - case BTA_HH_API_GET_DSCP_EVT: - return "BTA_HH_API_GET_DSCP_EVT"; - case BTA_HH_OPEN_CMPL_EVT: - return "BTA_HH_OPEN_CMPL_EVT"; - case BTA_HH_GATT_CLOSE_EVT: - return "BTA_HH_GATT_CLOSE_EVT"; - case BTA_HH_GATT_OPEN_EVT: - return "BTA_HH_GATT_OPEN_EVT"; - case BTA_HH_START_ENC_EVT: - return "BTA_HH_START_ENC_EVT"; - case BTA_HH_ENC_CMPL_EVT: - return "BTA_HH_ENC_CMPL_EVT"; - default: - return "unknown HID Host event code"; - } -} - -/******************************************************************************* - * - * Function bta_hh_state_code - * - * Description get string representation of HID host state code. - * - * Returns void - * - ******************************************************************************/ -static const char* bta_hh_state_code(tBTA_HH_STATE state_code) { - switch (state_code) { - case BTA_HH_NULL_ST: - return "BTA_HH_NULL_ST"; - case BTA_HH_IDLE_ST: - return "BTA_HH_IDLE_ST"; - case BTA_HH_W4_CONN_ST: - return "BTA_HH_W4_CONN_ST"; - case BTA_HH_CONN_ST: - return "BTA_HH_CONN_ST"; - case BTA_HH_W4_SEC: - return "BTA_HH_W4_SEC"; - default: - return "unknown HID Host state"; +#define DUMPSYS_TAG "shim::legacy::hid" +void bta_hh_dump(int fd) { + for (auto dev : bta_hh_cb.kdev) { + if (dev.in_use) { + LOG_DUMPSYS(fd, "[%d] Device:%s, handle:%d, state:%s, sub class:%d, ", dev.index, + dev.link_spec.ToRedactedStringForLogging().c_str(), dev.hid_handle, + bta_hh_state_code(dev.state), dev.sub_class); + } } } +#undef DUMPSYS_TAG diff --git a/system/bta/hh/bta_hh_utils.cc b/system/bta/hh/bta_hh_utils.cc index 2191f0c056..e924cc59b3 100644 --- a/system/bta/hh/bta_hh_utils.cc +++ b/system/bta/hh/bta_hh_utils.cc @@ -51,59 +51,136 @@ constexpr uint16_t kSsrMaxLatency = 18; /* slots * 0.625ms */ /******************************************************************************* * - * Function bta_hh_find_cb + * Function bta_hh_get_cb_index + * + * Description Find suitable control block index for ACL link specification + * + * Returns void + * + ******************************************************************************/ +static uint8_t bta_hh_get_cb_index(const tAclLinkSpec& link_spec) { + if (link_spec.addrt.bda.IsEmpty()) { + return BTA_HH_IDX_INVALID; + } + + uint8_t available_handle = BTA_HH_IDX_INVALID; + for (uint8_t i = 0; i < BTA_HH_MAX_DEVICE; i++) { + /* Check if any active/known devices is a match */ + tBTA_HH_DEV_CB& dev = bta_hh_cb.kdev[i]; + if (link_spec == dev.link_spec) { + log::verbose("Reusing handle {} for {}, ", i, link_spec); + return i; + } else if (available_handle == BTA_HH_IDX_INVALID && !dev.in_use) { + available_handle = i; + } + } + + if (available_handle != BTA_HH_IDX_INVALID) { + log::verbose("Using unused handle {} for {}", available_handle, link_spec); + } + return available_handle; +} + +/******************************************************************************* * - * Description Find best available control block according to ACL link - * specification. + * Function bta_hh_get_cb * + * Description Find or allocate control block for ACL link specification * * Returns void * ******************************************************************************/ -uint8_t bta_hh_find_cb(const tAclLinkSpec& link_spec) { - uint8_t xx; +tBTA_HH_DEV_CB* bta_hh_get_cb(const tAclLinkSpec& link_spec) { + uint8_t idx = bta_hh_get_cb_index(link_spec); + if (idx == BTA_HH_IDX_INVALID) { + log::error("No handle available for {}", link_spec); + return nullptr; + } + + tBTA_HH_DEV_CB& dev = bta_hh_cb.kdev[idx]; + dev.link_spec = link_spec; + dev.in_use = true; + return &dev; +} + +/******************************************************************************* + * + * Function bta_hh_find_cb + * + * Description Find the existing control block for ACL link specification + * + * Returns void + * + ******************************************************************************/ +tBTA_HH_DEV_CB* bta_hh_find_cb(const tAclLinkSpec& link_spec) { + if (link_spec.addrt.bda.IsEmpty()) { + return nullptr; + } - /* See how many active devices there are. */ - for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) { + for (uint8_t i = 0; i < BTA_HH_MAX_DEVICE; i++) { /* check if any active/known devices is a match */ - if (link_spec == bta_hh_cb.kdev[xx].link_spec && !link_spec.addrt.bda.IsEmpty()) { -#if (BTA_HH_DEBUG == TRUE) - log::verbose("found kdev_cb[{}] hid_handle={}", xx, bta_hh_cb.kdev[xx].hid_handle); -#endif - return xx; + if (link_spec == bta_hh_cb.kdev[i].link_spec) { + return &bta_hh_cb.kdev[i]; } -#if (BTA_HH_DEBUG == TRUE) - else - log::verbose("in_use ? [{}] kdev[{}].hid_handle={} state=[{}]", bta_hh_cb.kdev[xx].in_use, xx, - bta_hh_cb.kdev[xx].hid_handle, bta_hh_cb.kdev[xx].state); -#endif } + return nullptr; +} + +/******************************************************************************* + * + * Function bta_hh_dev_handle_to_cb_idx + * + * Description convert a HID device handle to the device control block + * index. + * + * + * Returns uint8_t: index of the device control block. + * + ******************************************************************************/ +static uint8_t bta_hh_dev_handle_to_cb_idx(uint8_t dev_handle) { + uint8_t index = BTA_HH_IDX_INVALID; - /* if no active device match, find a spot for it */ - for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) { - if (!bta_hh_cb.kdev[xx].in_use) { - bta_hh_cb.kdev[xx].link_spec = link_spec; - break; + if (BTA_HH_IS_LE_DEV_HDL(dev_handle)) { + if (BTA_HH_IS_LE_DEV_HDL_VALID(dev_handle)) { + index = bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(dev_handle)]; } - } -/* If device list full, report BTA_HH_IDX_INVALID */ -#if (BTA_HH_DEBUG == TRUE) - log::verbose("index={} while max={}", xx, BTA_HH_MAX_DEVICE); -#endif + } else + /* regular HID device checking */ + if (dev_handle < BTA_HH_MAX_KNOWN) { + index = bta_hh_cb.cb_index[dev_handle]; + } + + return index; +} - if (xx == BTA_HH_MAX_DEVICE) { - xx = BTA_HH_IDX_INVALID; +/******************************************************************************* + * + * Function bta_hh_find_cb + * + * Description Find the existing control block for handle + * + * Returns void + * + ******************************************************************************/ +tBTA_HH_DEV_CB* bta_hh_find_cb_by_handle(uint8_t hid_handle) { + uint8_t index = bta_hh_dev_handle_to_cb_idx(hid_handle); + if (index == BTA_HH_IDX_INVALID) { + return nullptr; } - return xx; + return &bta_hh_cb.kdev[index]; } -tBTA_HH_DEV_CB* bta_hh_get_cb(const tAclLinkSpec& link_spec) { - uint8_t idx = bta_hh_find_cb(link_spec); - if (idx == BTA_HH_IDX_INVALID) { - return nullptr; +static void bta_hh_reset_cb(tBTA_HH_DEV_CB* p_cb) { + // Free buffer for report descriptor info + osi_free_and_reset((void**)&p_cb->dscp_info.descriptor.dsc_list); + + // Cancel SDP if it had been started + if (p_cb->p_disc_db != nullptr) { + (void)get_legacy_stack_sdp_api()->service.SDP_CancelServiceSearch(p_cb->p_disc_db); + osi_free_and_reset((void**)&p_cb->p_disc_db); } - return &bta_hh_cb.kdev[idx]; + *p_cb = {}; } /******************************************************************************* @@ -117,8 +194,6 @@ tBTA_HH_DEV_CB* bta_hh_get_cb(const tAclLinkSpec& link_spec) { * ******************************************************************************/ void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB* p_cb) { - uint8_t index; - if (p_cb->link_spec.transport == BT_TRANSPORT_LE) { uint8_t le_hid_handle = BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle); if (le_hid_handle >= BTA_HH_LE_MAX_KNOWN) { @@ -134,14 +209,8 @@ void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB* p_cb) { } } - /* reset device control block */ - index = p_cb->index; /* Preserve index for this control block */ - - /* Free buffer for report descriptor info */ - osi_free_and_reset((void**)&p_cb->dscp_info.descriptor.dsc_list); - - memset(p_cb, 0, sizeof(tBTA_HH_DEV_CB)); /* Reset control block */ - + uint8_t index = p_cb->index; // Preserve index for this control block + bta_hh_reset_cb(p_cb); // Reset control block p_cb->index = index; /* Restore index for this control block */ p_cb->state = BTA_HH_IDLE_ST; p_cb->hid_handle = BTA_HH_INVALID_HANDLE; @@ -244,7 +313,7 @@ bool bta_hh_tod_spt(tBTA_HH_DEV_CB* p_cb, uint8_t sub_class) { ******************************************************************************/ tBTA_HH_STATUS bta_hh_read_ssr_param(const tAclLinkSpec& link_spec, uint16_t* p_max_ssr_lat, uint16_t* p_min_ssr_tout) { - tBTA_HH_DEV_CB* p_cb = bta_hh_get_cb(link_spec); + tBTA_HH_DEV_CB* p_cb = bta_hh_find_cb(link_spec); if (p_cb == nullptr) { log::warn("Unable to find device:{}", link_spec); return BTA_HH_ERR; @@ -305,16 +374,9 @@ tBTA_HH_STATUS bta_hh_read_ssr_param(const tAclLinkSpec& link_spec, uint16_t* p_ * ******************************************************************************/ void bta_hh_cleanup_disable(tBTA_HH_STATUS status) { - uint8_t xx; /* free buffer in CB holding report descriptors */ - for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) { - osi_free_and_reset((void**)&bta_hh_cb.kdev[xx].dscp_info.descriptor.dsc_list); - } - - if (bta_hh_cb.p_disc_db) { - /* Cancel SDP if it had been started. */ - (void)get_legacy_stack_sdp_api()->service.SDP_CancelServiceSearch(bta_hh_cb.p_disc_db); - osi_free_and_reset((void**)&bta_hh_cb.p_disc_db); + for (uint8_t i = 0; i < BTA_HH_MAX_DEVICE; i++) { + bta_hh_reset_cb(&bta_hh_cb.kdev[i]); } if (bta_hh_cb.p_cback) { @@ -326,35 +388,6 @@ void bta_hh_cleanup_disable(tBTA_HH_STATUS status) { } } -/******************************************************************************* - * - * Function bta_hh_dev_handle_to_cb_idx - * - * Description convert a HID device handle to the device control block - * index. - * - * - * Returns uint8_t: index of the device control block. - * - ******************************************************************************/ -uint8_t bta_hh_dev_handle_to_cb_idx(uint8_t dev_handle) { - uint8_t index = BTA_HH_IDX_INVALID; - - if (BTA_HH_IS_LE_DEV_HDL(dev_handle)) { - if (BTA_HH_IS_LE_DEV_HDL_VALID(dev_handle)) { - index = bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(dev_handle)]; - } -#if (BTA_HH_DEBUG == TRUE) - log::verbose("dev_handle={} index={}", dev_handle, index); -#endif - } else - /* regular HID device checking */ - if (dev_handle < BTA_HH_MAX_KNOWN) { - index = bta_hh_cb.cb_index[dev_handle]; - } - - return index; -} #if (BTA_HH_DEBUG == TRUE) /******************************************************************************* * @@ -366,17 +399,14 @@ uint8_t bta_hh_dev_handle_to_cb_idx(uint8_t dev_handle) { * ******************************************************************************/ void bta_hh_trace_dev_db(void) { - uint8_t xx; - - log::verbose("bta_hh_trace_dev_db:: Device DB list********************"); - - for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) { - log::verbose("kdev[{}] in_use[{}] handle[{}]", xx, bta_hh_cb.kdev[xx].in_use, - bta_hh_cb.kdev[xx].hid_handle); - - log::verbose("\t\t\t attr_mask[{:04x}] state [{}] sub_class[{:02x}] index = {}", - bta_hh_cb.kdev[xx].attr_mask, bta_hh_cb.kdev[xx].state, - bta_hh_cb.kdev[xx].sub_class, bta_hh_cb.kdev[xx].index); + log::verbose("Device DB list*******************************************"); + for (auto dev : bta_hh_cb.kdev) { + if (dev.in_use) { + log::verbose( + "kdev[{:02x}] handle[{:02x}] attr_mask[{:04x}] sub_class[{:02x}] state [{}] " + "device[{}] ", + dev.index, dev.hid_handle, dev.attr_mask, dev.sub_class, dev.state, dev.link_spec); + } } log::verbose("*********************************************************"); } diff --git a/system/bta/include/bta_hh_api.h b/system/bta/include/bta_hh_api.h index 8864cf0e38..1de1fa2c85 100644 --- a/system/bta/include/bta_hh_api.h +++ b/system/bta/include/bta_hh_api.h @@ -551,6 +551,17 @@ void BTA_HhAddDev(const tAclLinkSpec& link_spec, tBTA_HH_ATTR_MASK attr_mask, ui ******************************************************************************/ void BTA_HhRemoveDev(uint8_t dev_handle); +/******************************************************************************* + * + * Function BTA_HhDump + * + * Description Dump BTA HH control block + * + * Returns void + * + ******************************************************************************/ +void BTA_HhDump(int fd); + namespace fmt { template <> struct formatter<tBTA_HH_STATUS> : enum_formatter<tBTA_HH_STATUS> {}; diff --git a/system/bta/include/bta_jv_api.h b/system/bta/include/bta_jv_api.h index 3eabbad6db..c3e0f9cd5d 100644 --- a/system/bta/include/bta_jv_api.h +++ b/system/bta/include/bta_jv_api.h @@ -21,19 +21,19 @@ * This is the public interface file the BTA Java I/F * ******************************************************************************/ -#ifndef BTA_JV_API_H -#define BTA_JV_API_H +#pragma once #include <cstdint> #include <memory> #include <string> #include "bta/include/bta_api.h" -#include "bta_sec_api.h" +#include "bta/include/bta_sec_api.h" #include "include/macros.h" #include "internal_include/bt_target.h" #include "stack/include/bt_hdr.h" #include "stack/include/l2c_api.h" +#include "stack/include/rfcdefs.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -78,9 +78,8 @@ typedef uint8_t tBTA_JV_L2CAP_REASON; #define BTA_JV_MAX_UUIDS SDP_MAX_UUID_FILTERS #define BTA_JV_MAX_ATTRS SDP_MAX_ATTR_FILTERS #define BTA_JV_MAX_SDP_REC SDP_MAX_RECORDS -#define BTA_JV_MAX_L2C_CONN \ - GAP_MAX_CONNECTIONS /* GAP handle is used as index, hence do not change this \ - value */ +/* GAP handle is used as index, hence do not change this value */ +#define BTA_JV_MAX_L2C_CONN GAP_MAX_CONNECTIONS #define BTA_JV_MAX_RFC_CONN MAX_RFC_PORTS #ifndef BTA_JV_DEF_RFC_MTU @@ -271,7 +270,6 @@ typedef struct { int32_t tx_mtu; /* The transmit MTU */ void** p_p_cback; /* set them for new socket */ void** p_user_data; /* set them for new socket */ - } tBTA_JV_L2CAP_LE_OPEN; /* data associated with BTA_JV_L2CAP_CLOSE_EVT */ @@ -310,8 +308,7 @@ typedef struct { tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ uint32_t handle; /* The connection handle */ uint32_t req_id; /* The req_id in the associated BTA_JvL2capRead() */ - uint8_t* p_data; /* This points the same location as the p_data - * parameter in BTA_JvL2capRead () */ + uint8_t* p_data; /* Points to the same location as p_data parameter in BTA_JvL2capRead() */ uint16_t len; /* The length of the data read. */ } tBTA_JV_L2CAP_READ; @@ -423,8 +420,7 @@ typedef union { tBTA_JV_RFCOMM_CL_INIT rfc_cl_init; /* BTA_JV_RFCOMM_CL_INIT_EVT */ tBTA_JV_RFCOMM_CONG rfc_cong; /* BTA_JV_RFCOMM_CONG_EVT */ tBTA_JV_RFCOMM_WRITE rfc_write; /* BTA_JV_RFCOMM_WRITE_EVT */ - tBTA_JV_DATA_IND data_ind; /* BTA_JV_L2CAP_DATA_IND_EVT - BTA_JV_RFCOMM_DATA_IND_EVT */ + tBTA_JV_DATA_IND data_ind; /* BTA_JV_L2CAP_DATA_IND_EVT, BTA_JV_RFCOMM_DATA_IND_EVT */ tBTA_JV_LE_DATA_IND le_data_ind; /* BTA_JV_L2CAP_LE_DATA_IND_EVT */ tBTA_JV_L2CAP_LE_OPEN l2c_le_open; /* BTA_JV_L2CAP_OPEN_EVT */ } tBTA_JV; @@ -760,5 +756,3 @@ tBTA_JV_STATUS BTA_JvSetPmProfile(uint32_t handle, tBTA_JV_PM_ID app_id, * ******************************************************************************/ uint16_t BTA_JvRfcommGetPortHdl(uint32_t handle); - -#endif /* BTA_JV_API_H */ diff --git a/system/bta/jv/bta_jv_act.cc b/system/bta/jv/bta_jv_act.cc index 5c201230b5..5b8eed6943 100644 --- a/system/bta/jv/bta_jv_act.cc +++ b/system/bta/jv/bta_jv_act.cc @@ -50,6 +50,7 @@ #include "stack/include/gap_api.h" #include "stack/include/l2cdefs.h" #include "stack/include/port_api.h" +#include "stack/include/rfcdefs.h" #include "stack/include/sdp_api.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -1737,6 +1738,7 @@ static tBTA_JV_PCB* bta_jv_add_rfc_port(tBTA_JV_RFC_CB* p_cb, tBTA_JV_PCB* p_pcb port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT); if (PORT_SetState(p_pcb->port_handle, &port_state) != PORT_SUCCESS) { + log::warn("Unable to set RFCOMM server state handle:{}", p_pcb->port_handle); } p_pcb->handle = BTA_JV_RFC_H_S_TO_HDL(p_cb->handle, si); log::verbose("p_pcb->handle=0x{:x}, curr_sess={}", p_pcb->handle, p_cb->curr_sess); @@ -1804,7 +1806,7 @@ void bta_jv_rfcomm_start_server(tBTA_SEC sec_mask, uint8_t local_scn, uint8_t ma if (PORT_SetState(handle, &port_state) != PORT_SUCCESS) { log::warn("Unable to set RFCOMM port state handle:{}", handle); - }; + } } while (0); tBTA_JV bta_jv; @@ -1890,8 +1892,7 @@ void bta_jv_set_pm_profile(uint32_t handle, tBTA_JV_PM_ID app_id, tBTA_JV_CONN_S if (status != tBTA_JV_STATUS::SUCCESS) { log::warn("free pm cb failed: reason={}", bta_jv_status_text(status)); } - } else /* set PM control block */ - { + } else { /* set PM control block */ p_cb = bta_jv_alloc_set_pm_profile_cb(handle, app_id); if (NULL != p_cb) { diff --git a/system/bta/le_audio/audio_set_configurations.json b/system/bta/le_audio/audio_set_configurations.json index 09708f32d6..7cd9070ec8 100644 --- a/system/bta/le_audio/audio_set_configurations.json +++ b/system/bta/le_audio/audio_set_configurations.json @@ -1,7492 +1,8309 @@ { - "_comments_": [ - " == Audio Set Configurations == ", - " Contains: ", - " 1. configurations : ", - " Maps configuration name with codec and qos config to be used", - " 2. codec_configurations : ", - " Array of codec specific configurations", - " 3. qos_configurations : ", - " Array of QoS specific configurations", - " QoS configuration values are as per BAP spec 1.0", - " Example values which can be used as 'codec_configuration.type'", - " Codec Configuration parameter types:", - " SUPPORTED_SAMPLING_FREQUENCY = 1", - " SUPPORTED_FRAME_DURATION = 2", - " SUPPORTED_OCTETS_PER_CODEC_FRAME = 4", - " SUPPORTED_CODEC_FRAME_BLOCKS_PER_SDU = 5", - " Example values which can be used as 'codec_configuration.compound_value'", - " Codec Coding formats:", - " LC3 = 6", - " Sampling Frequencies: ", - " 8000Hz = 1", - " 11025Hz = 2", - " 16000Hz = 3", - " 22050Hz = 4", - " 24000Hz = 5", - " 32000Hz = 6", - " 44100Hz = 7", - " 48000Hz = 8", - " 88200Hz = 9", - " 96000Hz = 10", - " 176400Hz = 11", - " 192000Hz = 12", - " 384000Hz = 13", - " Frame Durations:", - " 7500us = 0", - " 10000us = 1" - ], - "configurations": [ - { - "name": "Two-OneChan-SnkAse-Lc3_16_1_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_2" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_1_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_1_Balanced_Reliability", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_1_1", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_1" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_1_2", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_2" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_2_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_2_Balanced_Reliability", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_2_1", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_1" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_2_2", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_2" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_32_1_Balanced_Reliability", - "codec_config_name": "One-OneChan-SnkAse-Lc3_32_1", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_32_1_1", - "codec_config_name": "One-OneChan-SnkAse-Lc3_32_1", - "qos_config_name": [ - "QoS_Config_32_1_1" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_32_1_2", - "codec_config_name": "One-OneChan-SnkAse-Lc3_32_1", - "qos_config_name": [ - "QoS_Config_32_1_2" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_32_2_Balanced_Reliability", - "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_32_2_1", - "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_32_2_1" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_32_2_2", - "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_32_2_2" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability", - "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_1_1", - "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_1" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_1_2", - "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability", - "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_2_1", - "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_1" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_2_2", - "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_2" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_1", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_32_2_1" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_2", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_2" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_1", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_1" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_2", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_2" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_1", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_1" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_1" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_2", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_2" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_1" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_2", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_2" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", - "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_1" - ] - }, - { - "name": "Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_48_4_Balanced_Reliability", - "codec_config_name": "One-OneChan-SrcAse-Lc3_48_4", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_48_3_Balanced_Reliability", - "codec_config_name": "One-OneChan-SrcAse-Lc3_48_3", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_48_2_Balanced_Reliability", - "codec_config_name": "One-OneChan-SrcAse-Lc3_48_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_48_1_Balanced_Reliability", - "codec_config_name": "One-OneChan-SrcAse-Lc3_48_1", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", - "codec_config_name": "One-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_32_1_Balanced_Reliability", - "codec_config_name": "One-OneChan-SrcAse-Lc3_32_1", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", - "codec_config_name": "One-OneChan-SrcAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_24_1_Balanced_Reliability", - "codec_config_name": "One-OneChan-SrcAse-Lc3_24_1", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "codec_config_name": "One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_16_1_Balanced_Reliability", - "codec_config_name": "One-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_2", - "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "qos_config_name": [ - "QoS_Config_16_1_2" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", - "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_1" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_2", - "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_16_2_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_24_1_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_24_1_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_24_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_24_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_24_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_24_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_24_2_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_24_2_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_24_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_24_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_24_2_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_24_2_2" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_24_2_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_24_2_Balanced_Reliability", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_24_2_2", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_24_2_2" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_24_2_Balanced_Reliability", - "codec_config_name": "One-OneChan-SnkAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_24_2_2", - "codec_config_name": "One-OneChan-SnkAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_24_2_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_32_2_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_32_2_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_32_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_32_1_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_32_1_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_32_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_32_1_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_32_2_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_32_2_1" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", - "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_32_2_1" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_32_2_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4_High_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4", - "qos_config_name": [ - "QoS_Config_48_4_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4", - "qos_config_name": [ - "QoS_Config_48_4_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_3_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_3_High_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_3_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3", - "qos_config_name": [ - "QoS_Config_48_3_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_2_High_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_2_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2", - "qos_config_name": [ - "QoS_Config_48_2_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_1_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_1_High_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_1_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1", - "qos_config_name": [ - "QoS_Config_48_1_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4_High_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4_1", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4", - "qos_config_name": [ - "QoS_Config_48_4_1" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4", - "qos_config_name": [ - "QoS_Config_48_4_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_3_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_3_High_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_3_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3", - "qos_config_name": [ - "QoS_Config_48_3_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_2_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_2_High_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_2_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2", - "qos_config_name": [ - "QoS_Config_48_2_2" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_1_Low_Latency", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_1_High_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_1_2", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1", - "qos_config_name": [ - "QoS_Config_48_1_2" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4_High_Reliability", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4_1", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4", - "qos_config_name": [ - "QoS_Config_48_4_1" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4_2", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4", - "qos_config_name": [ - "QoS_Config_48_4_2" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_3_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_3", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_3_High_Reliability", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_3", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_3_2", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_3", - "qos_config_name": [ - "QoS_Config_48_3_2" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_2_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_2_High_Reliability", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_2", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_2_2", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_2", - "qos_config_name": [ - "QoS_Config_48_2_2" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_1_Low_Latency", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_1_High_Reliability", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_1", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_1_2", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_1", - "qos_config_name": [ - "QoS_Config_48_1_2" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_4_High_Reliability", - "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_4_1", - "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4", - "qos_config_name": [ - "QoS_Config_48_4_1" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_4_2", - "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4", - "qos_config_name": [ - "QoS_Config_48_4_2" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_3_High_Reliability", - "codec_config_name": "One-OneChan-SnkAse-Lc3_48_3", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_3_2", - "codec_config_name": "One-OneChan-SnkAse-Lc3_48_3", - "qos_config_name": [ - "QoS_Config_48_3_2" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_2_High_Reliability", - "codec_config_name": "One-OneChan-SnkAse-Lc3_48_2", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_2_2", - "codec_config_name": "One-OneChan-SnkAse-Lc3_48_2", - "qos_config_name": [ - "QoS_Config_48_2_2" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_1_High_Reliability", - "codec_config_name": "One-OneChan-SnkAse-Lc3_48_1", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_1_2", - "codec_config_name": "One-OneChan-SnkAse-Lc3_48_1", - "qos_config_name": [ - "QoS_Config_48_1_2" - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_Low_Latency_1", - "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60oct_R3_L22_1", - "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_1", - "qos_config_name": [ - "VND_QoS_Config_R3_L22" - ] - }, - { - "name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1", - "codec_config_name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_1", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_R15_L70_1", - "codec_config_name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_1", - "qos_config_name": [ - "VND_QoS_Config_R15_L70" - ] - }, - { - "name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1", - "codec_config_name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_1", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_R15_L70_1", - "codec_config_name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_1", - "qos_config_name": [ - "VND_QoS_Config_R15_L70" - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_High_Reliability_1", - "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_1", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_R15_L70_1", - "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_1", - "qos_config_name": [ - "VND_QoS_Config_R15_L70" - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_High_Reliability_1", - "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_1", - "qos_config_name": [ - "QoS_Config_High_Reliability" - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_1", - "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_1", - "qos_config_name": [ - "VND_QoS_Config_R5_L12" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_32_2_Balanced_Reliability", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_24_2_Balanced_Reliability", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", - "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", - "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Low_Latency", - "codec_config_name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Balanced_Reliability", - "codec_config_name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Low_Latency", - "codec_config_name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2", - "qos_config_name": [ - "QoS_Config_Low_Latency" - ] - }, - { - "name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Balanced_Reliability", - "codec_config_name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_Balanced_Reliability_1", - "codec_config_name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_1", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_R11_L40_1", - "codec_config_name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_1", - "qos_config_name": [ - "VND_QoS_Config_R11_L40" - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_TwoChanStereoSrc_16khz_30octs_R3_L12_1", - "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_1", - "qos_config_name": [ - "VND_QoS_Config_R5_L12", - "VND_QoS_Config_R3_L12" - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_Balanced_Reliability_1", - "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_1", - "qos_config_name": [ - "QoS_Config_Balanced_Reliability" - ] + "_comments_": [ + " == Audio Set Configurations == ", + " Contains: ", + " 1. configurations : ", + " Maps configuration name with codec and qos config to be used", + " 2. codec_configurations : ", + " Array of codec specific configurations", + " 3. qos_configurations : ", + " Array of QoS specific configurations", + " QoS configuration values are as per BAP spec 1.0", + " Example values which can be used as 'codec_configuration.type'", + " Codec Configuration parameter types:", + " SUPPORTED_SAMPLING_FREQUENCY = 1", + " SUPPORTED_FRAME_DURATION = 2", + " SUPPORTED_OCTETS_PER_CODEC_FRAME = 4", + " SUPPORTED_CODEC_FRAME_BLOCKS_PER_SDU = 5", + " Example values which can be used as 'codec_configuration.compound_value'", + " Codec Coding formats:", + " LC3 = 6", + " Sampling Frequencies: ", + " 8000Hz = 1", + " 11025Hz = 2", + " 16000Hz = 3", + " 22050Hz = 4", + " 24000Hz = 5", + " 32000Hz = 6", + " 44100Hz = 7", + " 48000Hz = 8", + " 88200Hz = 9", + " 96000Hz = 10", + " 176400Hz = 11", + " 192000Hz = 12", + " 384000Hz = 13", + " Frame Durations:", + " 7500us = 0", + " 10000us = 1" + ], + "configurations": [ + { + "name": "Two-OneChan-SnkAse-Lc3_16_1_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_1_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_1_Balanced_Reliability", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_1_1", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_1_2", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_2_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_2_Balanced_Reliability", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_2_1", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_2_2", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_32_1_Balanced_Reliability", + "codec_config_name": "One-OneChan-SnkAse-Lc3_32_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_32_1_1", + "codec_config_name": "One-OneChan-SnkAse-Lc3_32_1", + "qos_config_name": [ + "QoS_Config_32_1_1" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_32_1_2", + "codec_config_name": "One-OneChan-SnkAse-Lc3_32_1", + "qos_config_name": [ + "QoS_Config_32_1_2" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_32_2_Balanced_Reliability", + "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_32_2_1", + "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_32_2_2", + "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_32_2_2" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability", + "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_1_1", + "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_1_2", + "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability", + "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_2_1", + "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_2_2", + "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_1", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_2", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_1", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_2", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_1", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_2", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_2", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", + "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "codec_config_name": "Two-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "codec_config_name": "Two-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SrcAse-Lc3_16_2_Low_Latency", + "codec_config_name": "One-TwoChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SrcAse-Lc3_16_1_Low_Latency", + "codec_config_name": "One-TwoChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "codec_config_name": "One-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "codec_config_name": "One-TwoChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_48_4_Balanced_Reliability", + "codec_config_name": "One-OneChan-SrcAse-Lc3_48_4", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_48_3_Balanced_Reliability", + "codec_config_name": "One-OneChan-SrcAse-Lc3_48_3", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_48_2_Balanced_Reliability", + "codec_config_name": "One-OneChan-SrcAse-Lc3_48_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_48_1_Balanced_Reliability", + "codec_config_name": "One-OneChan-SrcAse-Lc3_48_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", + "codec_config_name": "One-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_32_1_Balanced_Reliability", + "codec_config_name": "One-OneChan-SrcAse-Lc3_32_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "codec_config_name": "One-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_32_1_Low_Latency", + "codec_config_name": "One-OneChan-SrcAse-Lc3_32_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", + "codec_config_name": "One-OneChan-SrcAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "codec_config_name": "Two-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SrcAse-Lc3_32_1_Low_Latency", + "codec_config_name": "Two-OneChan-SrcAse-Lc3_32_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_24_1_Balanced_Reliability", + "codec_config_name": "One-OneChan-SrcAse-Lc3_24_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_24_2_Low_Latency", + "codec_config_name": "One-OneChan-SrcAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_24_1_Low_Latency", + "codec_config_name": "One-OneChan-SrcAse-Lc3_24_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SrcAse-Lc3_24_2_Low_Latency", + "codec_config_name": "Two-OneChan-SrcAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SrcAse-Lc3_24_1_Low_Latency", + "codec_config_name": "Two-OneChan-SrcAse-Lc3_24_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SrcAse-Lc3_24_2_Low_Latency", + "codec_config_name": "One-TwoChan-SrcAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SrcAse-Lc3_24_1_Low_Latency", + "codec_config_name": "One-TwoChan-SrcAse-Lc3_24_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "codec_config_name": "One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_16_1_Balanced_Reliability", + "codec_config_name": "One-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "codec_config_name": "One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_2", + "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", + "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_2", + "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_24_1_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_24_1_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_24_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_24_2_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_24_2_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_24_2_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_24_2_2" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_24_2_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_24_2_Balanced_Reliability", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_24_2_2", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_24_2_2" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_24_2_Balanced_Reliability", + "codec_config_name": "One-OneChan-SnkAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_24_2_2", + "codec_config_name": "One-OneChan-SnkAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_24_2_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_32_2_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_32_1_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_32_1_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", + "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_32_2_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4_High_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4", + "qos_config_name": [ + "QoS_Config_48_4_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4", + "qos_config_name": [ + "QoS_Config_48_4_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_3_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_2_High_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_1_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_1_High_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_1_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1", + "qos_config_name": [ + "QoS_Config_48_1_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4_High_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4_1", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4", + "qos_config_name": [ + "QoS_Config_48_4_1" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4", + "qos_config_name": [ + "QoS_Config_48_4_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_3_High_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_3_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3", + "qos_config_name": [ + "QoS_Config_48_3_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_2_Low_Latency", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_2_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2", + "qos_config_name": [ + "QoS_Config_48_2_2" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_1_High_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_1_2", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1", + "qos_config_name": [ + "QoS_Config_48_1_2" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4_High_Reliability", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4_1", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4", + "qos_config_name": [ + "QoS_Config_48_4_1" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4_2", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4", + "qos_config_name": [ + "QoS_Config_48_4_2" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_3_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_3", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_3_High_Reliability", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_3", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_3_2", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_3", + "qos_config_name": [ + "QoS_Config_48_3_2" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_2_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_2_High_Reliability", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_2", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_2_2", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_2", + "qos_config_name": [ + "QoS_Config_48_2_2" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_1_Low_Latency", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_1_High_Reliability", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_1", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_1_2", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_1", + "qos_config_name": [ + "QoS_Config_48_1_2" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_4_High_Reliability", + "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_4_1", + "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4", + "qos_config_name": [ + "QoS_Config_48_4_1" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_4_2", + "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4", + "qos_config_name": [ + "QoS_Config_48_4_2" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_3_High_Reliability", + "codec_config_name": "One-OneChan-SnkAse-Lc3_48_3", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_3_2", + "codec_config_name": "One-OneChan-SnkAse-Lc3_48_3", + "qos_config_name": [ + "QoS_Config_48_3_2" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_2_High_Reliability", + "codec_config_name": "One-OneChan-SnkAse-Lc3_48_2", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_2_2", + "codec_config_name": "One-OneChan-SnkAse-Lc3_48_2", + "qos_config_name": [ + "QoS_Config_48_2_2" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_1_High_Reliability", + "codec_config_name": "One-OneChan-SnkAse-Lc3_48_1", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_1_2", + "codec_config_name": "One-OneChan-SnkAse-Lc3_48_1", + "qos_config_name": [ + "QoS_Config_48_1_2" + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_Low_Latency_1", + "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60oct_R3_L22_1", + "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_1", + "qos_config_name": [ + "VND_QoS_Config_R3_L22" + ] + }, + { + "name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1", + "codec_config_name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_1", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_R15_L70_1", + "codec_config_name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_1", + "qos_config_name": [ + "VND_QoS_Config_R15_L70" + ] + }, + { + "name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1", + "codec_config_name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_1", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_R15_L70_1", + "codec_config_name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_1", + "qos_config_name": [ + "VND_QoS_Config_R15_L70" + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_High_Reliability_1", + "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_1", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_R15_L70_1", + "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_1", + "qos_config_name": [ + "VND_QoS_Config_R15_L70" + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_High_Reliability_1", + "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_1", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_1", + "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_1", + "qos_config_name": [ + "VND_QoS_Config_R5_L12" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_32_2_Balanced_Reliability", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_24_2_Balanced_Reliability", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", + "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", + "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Low_Latency", + "codec_config_name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Balanced_Reliability", + "codec_config_name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Low_Latency", + "codec_config_name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Balanced_Reliability", + "codec_config_name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_Balanced_Reliability_1", + "codec_config_name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_R11_L40_1", + "codec_config_name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_1", + "qos_config_name": [ + "VND_QoS_Config_R11_L40" + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_TwoChanStereoSrc_16khz_30octs_R3_L12_1", + "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_1", + "qos_config_name": [ + "VND_QoS_Config_R5_L12", + "VND_QoS_Config_R3_L12" + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_Balanced_Reliability_1", + "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + } + ], + "codec_configurations": [ + { + "name": "Two-OneChan-SnkAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 } - ], - "codec_configurations": [ - { - "name": "Two-OneChan-SnkAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "Two-OneChan-SrcAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_24_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 5 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_32_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_32_1", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_32_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_32_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 2, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 2, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_48_4", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_48_3", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 90, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_48_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 100, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_48_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 75, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_32_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_32_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_24_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 5 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 45, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SrcAse-Lc3_16_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_3", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 90, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 100, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_1", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 75, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_3", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 90, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 100, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 75, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_4", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_3", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 90, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 100, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 75, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 100, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_1", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 100, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_1", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 100, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 75, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_32_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 2, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_24_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 2, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 5 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 2, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 5 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_32_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_24_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 5 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 5 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 5 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 120, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 40, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 75, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 75, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 100, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 100, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 100, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 8 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 75, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 3 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 30, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_24_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 5 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_24_1", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 5 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 45, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_24_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 5 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_24_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 5 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 45, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_24_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 5 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 2, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", - "subconfigurations": [ - { - "ase_cnt": 2, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - }, - { - "ase_cnt": 1, - "direction": "SOURCE", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 1 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_32_2", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 1 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 80, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] - }, - { - "name": "One-TwoChan-SnkAse-Lc3_32_1", - "subconfigurations": [ - { - "ase_cnt": 1, - "direction": "SINK", - "codec_id": { - "coding_format": 6, - "vendor_company_id": 0, - "vendor_codec_id": 0 - }, - "codec_configuration": [ - { - "name": "sampling_frequency", - "type": 1, - "compound_value": { - "value": [ - 6 - ] - } - }, - { - "name": "frame_duration", - "type": 2, - "compound_value": { - "value": [ - 0 - ] - } - }, - { - "name": "octets_per_codec_frame", - "type": 4, - "compound_value": { - "value": [ - 60, - 0 - ] - } - }, - { - "name": "codec_frame_blocks_per_sdu", - "type": 5, - "compound_value": { - "value": [ - 1 - ] - } - } - ], - "ase_channel_cnt": 2 - } - ] + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 } - ], - "qos_configurations": [ - { - "name": "QoS_Config_16_1_1", - "retransmission_number": 2, - "max_transport_latency": 8 - }, - { - "name": "QoS_Config_16_1_2", - "retransmission_number": 13, - "max_transport_latency": 75 - }, - { - "name": "QoS_Config_16_2_1", - "retransmission_number": 2, - "max_transport_latency": 10 - }, - { - "name": "QoS_Config_16_2_2", - "retransmission_number": 13, - "max_transport_latency": 95 - }, - { - "name": "QoS_Config_24_1_1", - "retransmission_number": 2, - "max_transport_latency": 8 - }, - { - "name": "QoS_Config_24_1_2", - "retransmission_number": 13, - "max_transport_latency": 75 - }, - { - "name": "QoS_Config_24_2_1", - "retransmission_number": 2, - "max_transport_latency": 10 - }, - { - "name": "QoS_Config_24_2_2", - "retransmission_number": 13, - "max_transport_latency": 95 - }, - { - "name": "QoS_Config_32_1_1", - "retransmission_number": 2, - "max_transport_latency": 8 - }, - { - "name": "QoS_Config_32_1_2", - "retransmission_number": 13, - "max_transport_latency": 75 - }, - { - "name": "QoS_Config_32_2_1", - "retransmission_number": 2, - "max_transport_latency": 10 - }, - { - "name": "QoS_Config_32_2_2", - "retransmission_number": 13, - "max_transport_latency": 95 - }, - { - "name": "QoS_Config_48_1_2", - "retransmission_number": 13, - "max_transport_latency": 75 - }, - { - "name": "QoS_Config_48_2_2", - "retransmission_number": 13, - "max_transport_latency": 95 - }, - { - "name": "QoS_Config_48_3_2", - "retransmission_number": 13, - "max_transport_latency": 75 - }, - { - "name": "QoS_Config_48_4_1", - "retransmission_number": 5, - "max_transport_latency": 20 - }, - { - "name": "QoS_Config_48_4_2", - "retransmission_number": 13, - "max_transport_latency": 100 - }, - { - "name": "VND_QoS_Config_R3_L22", - "retransmission_number": 3, - "max_transport_latency": 22 - }, - { - "name": "VND_QoS_Config_R15_L70", - "retransmission_number": 15, - "max_transport_latency": 70 - }, - { - "name": "VND_QoS_Config_R5_L12", - "retransmission_number": 5, - "max_transport_latency": 12 - }, - { - "name": "VND_QoS_Config_R11_L40", - "retransmission_number": 11, - "max_transport_latency": 40 - }, - { - "name": "VND_QoS_Config_R3_L12", - "retransmission_number": 3, - "max_transport_latency": 12 - }, - { - "name": "QoS_Config_Low_Latency", - "target_latency": "LOW", - "retransmission_number": 0, - "max_transport_latency": 0 - }, - { - "name": "QoS_Config_Balanced_Reliability", - "target_latency": "BALANCED_RELIABILITY", - "retransmission_number": 0, - "max_transport_latency": 0 - }, - { - "name": "QoS_Config_High_Reliability", - "target_latency": "HIGH_RELIABILITY", - "retransmission_number": 0, - "max_transport_latency": 0 + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "Two-OneChan-SrcAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SrcAse-Lc3_32_1", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-TwoChan-SrcAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SrcAse-Lc3_32_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_32_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SrcAse-Lc3_24_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SrcAse-Lc3_24_1", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 45, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-TwoChan-SrcAse-Lc3_24_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SrcAse-Lc3_24_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 45, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_24_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 5 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SrcAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SrcAse-Lc3_16_1", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-TwoChan-SrcAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SrcAse-Lc3_16_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_16_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_32_1", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_32_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 2, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 2, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_48_4", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_48_3", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 90, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_48_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 100, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_48_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 75, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_32_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_24_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 5 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 45, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SrcAse-Lc3_16_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_3", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 90, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 100, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_1", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 75, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_3", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 90, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 100, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 75, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_4", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_3", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 90, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 100, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 75, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 100, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_1", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 100, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_1", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 100, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 75, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 2, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_24_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 2, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 5 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 2, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 5 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_24_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 5 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 5 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 5 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 40, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 75, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 75, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 100, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 100, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 100, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 75, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 30, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_24_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 5 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_24_1", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 5 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 45, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_24_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 5 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_24_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 5 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 45, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_24_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 5 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 2, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 2, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + }, + { + "ase_cnt": 1, + "direction": "SOURCE", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 1 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_32_2", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 + } + ] + }, + { + "name": "One-TwoChan-SnkAse-Lc3_32_1", + "subconfigurations": [ + { + "ase_cnt": 1, + "direction": "SINK", + "codec_id": { + "coding_format": 6, + "vendor_company_id": 0, + "vendor_codec_id": 0 + }, + "codec_configuration": [ + { + "name": "sampling_frequency", + "type": 1, + "compound_value": { + "value": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 60, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ], + "ase_channel_cnt": 2 } - ] + ] + } + ], + "qos_configurations": [ + { + "name": "QoS_Config_16_1_1", + "retransmission_number": 2, + "max_transport_latency": 8 + }, + { + "name": "QoS_Config_16_1_2", + "retransmission_number": 13, + "max_transport_latency": 75 + }, + { + "name": "QoS_Config_16_2_1", + "retransmission_number": 2, + "max_transport_latency": 10 + }, + { + "name": "QoS_Config_16_2_2", + "retransmission_number": 13, + "max_transport_latency": 95 + }, + { + "name": "QoS_Config_24_1_1", + "retransmission_number": 2, + "max_transport_latency": 8 + }, + { + "name": "QoS_Config_24_1_2", + "retransmission_number": 13, + "max_transport_latency": 75 + }, + { + "name": "QoS_Config_24_2_1", + "retransmission_number": 2, + "max_transport_latency": 10 + }, + { + "name": "QoS_Config_24_2_2", + "retransmission_number": 13, + "max_transport_latency": 95 + }, + { + "name": "QoS_Config_32_1_1", + "retransmission_number": 2, + "max_transport_latency": 8 + }, + { + "name": "QoS_Config_32_1_2", + "retransmission_number": 13, + "max_transport_latency": 75 + }, + { + "name": "QoS_Config_32_2_1", + "retransmission_number": 2, + "max_transport_latency": 10 + }, + { + "name": "QoS_Config_32_2_2", + "retransmission_number": 13, + "max_transport_latency": 95 + }, + { + "name": "QoS_Config_48_1_2", + "retransmission_number": 13, + "max_transport_latency": 75 + }, + { + "name": "QoS_Config_48_2_2", + "retransmission_number": 13, + "max_transport_latency": 95 + }, + { + "name": "QoS_Config_48_3_2", + "retransmission_number": 13, + "max_transport_latency": 75 + }, + { + "name": "QoS_Config_48_4_1", + "retransmission_number": 5, + "max_transport_latency": 20 + }, + { + "name": "QoS_Config_48_4_2", + "retransmission_number": 13, + "max_transport_latency": 100 + }, + { + "name": "VND_QoS_Config_R3_L22", + "retransmission_number": 3, + "max_transport_latency": 22 + }, + { + "name": "VND_QoS_Config_R15_L70", + "retransmission_number": 15, + "max_transport_latency": 70 + }, + { + "name": "VND_QoS_Config_R5_L12", + "retransmission_number": 5, + "max_transport_latency": 12 + }, + { + "name": "VND_QoS_Config_R11_L40", + "retransmission_number": 11, + "max_transport_latency": 40 + }, + { + "name": "VND_QoS_Config_R3_L12", + "retransmission_number": 3, + "max_transport_latency": 12 + }, + { + "name": "QoS_Config_Low_Latency", + "target_latency": "LOW", + "retransmission_number": 0, + "max_transport_latency": 0 + }, + { + "name": "QoS_Config_Balanced_Reliability", + "target_latency": "BALANCED_RELIABILITY", + "retransmission_number": 0, + "max_transport_latency": 0 + }, + { + "name": "QoS_Config_High_Reliability", + "target_latency": "HIGH_RELIABILITY", + "retransmission_number": 0, + "max_transport_latency": 0 + } + ] }
\ No newline at end of file diff --git a/system/bta/le_audio/audio_set_scenarios.json b/system/bta/le_audio/audio_set_scenarios.json index b29dba516e..52857f3356 100644 --- a/system/bta/le_audio/audio_set_scenarios.json +++ b/system/bta/le_audio/audio_set_scenarios.json @@ -1,259 +1,295 @@ { - "_comments_": [ - "== Audio Set Scenarios ==", - " Each defined scenario references externally defined audio set", - " configurations, listed in the order of priority." - ], - "scenarios": [ - { - "name": "Conversational", - "configurations": [ - "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1", - "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_1", - "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_2", - "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_1", - "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_2", - "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", - "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", - "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", - "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_1", - "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_1", - "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_2", - "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_1", - "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_2", - "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", - "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", - "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", - "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", - "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", - "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", - "Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_48_4_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_48_2_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_48_3_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_48_1_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_32_1_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_24_1_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_16_1_Balanced_Reliability", - "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60oct_R3_L22_1", - "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability", - "One-TwoChan-SnkAse-Lc3_16_2_Balanced_Reliability", - "One-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability" - ] - }, - { - "name": "Media", - "configurations": [ - "Two-OneChan-SnkAse-Lc3_48_4_High_Reliability", - "Two-OneChan-SnkAse-Lc3_48_4_2", - "Two-OneChan-SnkAse-Lc3_48_2_High_Reliability", - "Two-OneChan-SnkAse-Lc3_48_2_2", - "Two-OneChan-SnkAse-Lc3_48_3_High_Reliability", - "Two-OneChan-SnkAse-Lc3_48_3_2", - "Two-OneChan-SnkAse-Lc3_48_1_High_Reliability", - "Two-OneChan-SnkAse-Lc3_48_1_2", - "Two-OneChan-SnkAse-Lc3_24_2_Balanced_Reliability", - "Two-OneChan-SnkAse-Lc3_24_2_2", - "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability", - "Two-OneChan-SnkAse-Lc3_16_2_2", - "Two-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability", - "Two-OneChan-SnkAse-Lc3_16_1_2", - "One-TwoChan-SnkAse-Lc3_48_4_High_Reliability", - "One-TwoChan-SnkAse-Lc3_48_4_2", - "One-TwoChan-SnkAse-Lc3_48_2_High_Reliability", - "One-TwoChan-SnkAse-Lc3_48_2_2", - "One-TwoChan-SnkAse-Lc3_48_3_High_Reliability", - "One-TwoChan-SnkAse-Lc3_48_3_2", - "One-TwoChan-SnkAse-Lc3_48_1_High_Reliability", - "One-TwoChan-SnkAse-Lc3_48_1_2", - "One-TwoChan-SnkAse-Lc3_24_2_Balanced_Reliability", - "One-TwoChan-SnkAse-Lc3_24_2_2", - "One-TwoChan-SnkAse-Lc3_16_2_Balanced_Reliability", - "One-TwoChan-SnkAse-Lc3_16_2_2", - "One-TwoChan-SnkAse-Lc3_16_1_Balanced_Reliability", - "One-TwoChan-SnkAse-Lc3_16_1_2", - "One-OneChan-SnkAse-Lc3_48_4_High_Reliability", - "One-OneChan-SnkAse-Lc3_48_4_2", - "One-OneChan-SnkAse-Lc3_48_2_High_Reliability", - "One-OneChan-SnkAse-Lc3_48_2_2", - "One-OneChan-SnkAse-Lc3_48_3_High_Reliability", - "One-OneChan-SnkAse-Lc3_48_3_2", - "One-OneChan-SnkAse-Lc3_48_1_High_Reliability", - "One-OneChan-SnkAse-Lc3_48_1_2", - "One-OneChan-SnkAse-Lc3_32_2_Balanced_Reliability", - "One-OneChan-SnkAse-Lc3_32_2_2", - "One-OneChan-SnkAse-Lc3_32_1_Balanced_Reliability", - "One-OneChan-SnkAse-Lc3_32_1_2", - "One-OneChan-SnkAse-Lc3_24_2_Balanced_Reliability", - "One-OneChan-SnkAse-Lc3_24_2_2", - "One-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability", - "One-OneChan-SnkAse-Lc3_16_2_2", - "One-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability", - "One-OneChan-SnkAse-Lc3_16_1_2", - "VND_DualDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1", - "VND_DualDev_OneChanStereoSnk_48khz_100octs_R15_L70_1", - "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_High_Reliability_1", - "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_R15_L70_1", - "VND_SingleDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1", - "VND_SingleDev_OneChanStereoSnk_48khz_100octs_R15_L70_1", - "Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability" - ] - }, - { - "name": "Game", - "configurations": [ - "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1", - "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Low_Latency", - "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Low_Latency", - "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency", - "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_Balanced_Reliability_1", - "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_TwoChanStereoSrc_16khz_30octs_R3_L12_1", - "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_High_Reliability_1", - "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_1", - "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", - "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "Two-OneChan-SnkAse-Lc3_48_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_48_3_Low_Latency", - "Two-OneChan-SnkAse-Lc3_48_1_Low_Latency", - "Two-OneChan-SnkAse-Lc3_32_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_32_1_Low_Latency", - "Two-OneChan-SnkAse-Lc3_24_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_24_1_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_1_Low_Latency", - "One-TwoChan-SnkAse-Lc3_48_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_48_3_Low_Latency", - "One-TwoChan-SnkAse-Lc3_48_1_Low_Latency", - "One-TwoChan-SnkAse-Lc3_32_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_32_1_Low_Latency", - "One-TwoChan-SnkAse-Lc3_24_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_24_1_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_1_Low_Latency" - ] - }, - { - "name": "VoiceAssistants", - "configurations": [ - "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1", - "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_1", - "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_1", - "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Balanced_Reliability", - "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Balanced_Reliability", - "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_1", - "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_1", - "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_1", - "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", - "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", - "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", - "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", - "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", - "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", - "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", - "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", - "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", - "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", - "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_24_2_Balanced_Reliability", - "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_32_2_Balanced_Reliability", - "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", - "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", - "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", - "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability" - ] - }, - { - "name": "Live", - "configurations": [ - "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_Balanced_Reliability_1", - "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_R11_L40_1", - "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1", - "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_1", - "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_1", - "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Balanced_Reliability", - "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Balanced_Reliability", - "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_1", - "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_1", - "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_1", - "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", - "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", - "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", - "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", - "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", - "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", - "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", - "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", - "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", - "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", - "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", - "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", - "One-OneChan-SrcAse-Lc3_48_2_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_48_1_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_32_1_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", - "One-OneChan-SrcAse-Lc3_16_1_Balanced_Reliability" - ] - } - ] + "_comments_": [ + "== Audio Set Scenarios ==", + " Each defined scenario references externally defined audio set", + " configurations, listed in the order of priority." + ], + "scenarios": [ + { + "name": "Conversational", + "configurations": [ + "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1", + "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_1", + "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_2", + "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_1", + "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_2", + "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", + "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", + "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", + "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_1", + "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_1", + "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_2", + "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_1", + "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_2", + "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", + "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", + "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", + "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", + "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", + "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", + "Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_48_4_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_48_2_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_48_3_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_48_1_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_32_1_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_24_1_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_16_1_Balanced_Reliability", + "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60oct_R3_L22_1", + "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability", + "One-TwoChan-SnkAse-Lc3_16_2_Balanced_Reliability", + "One-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability" + ] + }, + { + "name": "Media", + "configurations": [ + "Two-OneChan-SnkAse-Lc3_48_4_High_Reliability", + "Two-OneChan-SnkAse-Lc3_48_4_2", + "Two-OneChan-SnkAse-Lc3_48_2_High_Reliability", + "Two-OneChan-SnkAse-Lc3_48_2_2", + "Two-OneChan-SnkAse-Lc3_48_3_High_Reliability", + "Two-OneChan-SnkAse-Lc3_48_3_2", + "Two-OneChan-SnkAse-Lc3_48_1_High_Reliability", + "Two-OneChan-SnkAse-Lc3_48_1_2", + "Two-OneChan-SnkAse-Lc3_24_2_Balanced_Reliability", + "Two-OneChan-SnkAse-Lc3_24_2_2", + "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability", + "Two-OneChan-SnkAse-Lc3_16_2_2", + "Two-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability", + "Two-OneChan-SnkAse-Lc3_16_1_2", + "One-TwoChan-SnkAse-Lc3_48_4_High_Reliability", + "One-TwoChan-SnkAse-Lc3_48_4_2", + "One-TwoChan-SnkAse-Lc3_48_2_High_Reliability", + "One-TwoChan-SnkAse-Lc3_48_2_2", + "One-TwoChan-SnkAse-Lc3_48_3_High_Reliability", + "One-TwoChan-SnkAse-Lc3_48_3_2", + "One-TwoChan-SnkAse-Lc3_48_1_High_Reliability", + "One-TwoChan-SnkAse-Lc3_48_1_2", + "One-TwoChan-SnkAse-Lc3_24_2_Balanced_Reliability", + "One-TwoChan-SnkAse-Lc3_24_2_2", + "One-TwoChan-SnkAse-Lc3_16_2_Balanced_Reliability", + "One-TwoChan-SnkAse-Lc3_16_2_2", + "One-TwoChan-SnkAse-Lc3_16_1_Balanced_Reliability", + "One-TwoChan-SnkAse-Lc3_16_1_2", + "One-OneChan-SnkAse-Lc3_48_4_High_Reliability", + "One-OneChan-SnkAse-Lc3_48_4_2", + "One-OneChan-SnkAse-Lc3_48_2_High_Reliability", + "One-OneChan-SnkAse-Lc3_48_2_2", + "One-OneChan-SnkAse-Lc3_48_3_High_Reliability", + "One-OneChan-SnkAse-Lc3_48_3_2", + "One-OneChan-SnkAse-Lc3_48_1_High_Reliability", + "One-OneChan-SnkAse-Lc3_48_1_2", + "One-OneChan-SnkAse-Lc3_32_2_Balanced_Reliability", + "One-OneChan-SnkAse-Lc3_32_2_2", + "One-OneChan-SnkAse-Lc3_32_1_Balanced_Reliability", + "One-OneChan-SnkAse-Lc3_32_1_2", + "One-OneChan-SnkAse-Lc3_24_2_Balanced_Reliability", + "One-OneChan-SnkAse-Lc3_24_2_2", + "One-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability", + "One-OneChan-SnkAse-Lc3_16_2_2", + "One-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability", + "One-OneChan-SnkAse-Lc3_16_1_2", + "VND_DualDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1", + "VND_DualDev_OneChanStereoSnk_48khz_100octs_R15_L70_1", + "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_High_Reliability_1", + "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_R15_L70_1", + "VND_SingleDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1", + "VND_SingleDev_OneChanStereoSnk_48khz_100octs_R15_L70_1", + "Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability" + ] + }, + { + "name": "Game", + "configurations": [ + "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1", + "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Low_Latency", + "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_Balanced_Reliability_1", + "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_TwoChanStereoSrc_16khz_30octs_R3_L12_1", + "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_High_Reliability_1", + "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_1", + "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", + "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "Two-OneChan-SnkAse-Lc3_48_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_48_3_Low_Latency", + "Two-OneChan-SnkAse-Lc3_48_1_Low_Latency", + "Two-OneChan-SnkAse-Lc3_32_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_32_1_Low_Latency", + "Two-OneChan-SnkAse-Lc3_24_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_24_1_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_48_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_48_3_Low_Latency", + "One-TwoChan-SnkAse-Lc3_48_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_32_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_32_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_24_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_24_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_1_Low_Latency" + ] + }, + { + "name": "VoiceAssistants", + "configurations": [ + "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1", + "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_1", + "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_1", + "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Balanced_Reliability", + "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Balanced_Reliability", + "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_1", + "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_1", + "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_1", + "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", + "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", + "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", + "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", + "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", + "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", + "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", + "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", + "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", + "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", + "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_24_2_Balanced_Reliability", + "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_32_2_Balanced_Reliability", + "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", + "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", + "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability", + "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", + "Two-OneChan-SnkAse-Lc3_48_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_48_3_Low_Latency", + "Two-OneChan-SnkAse-Lc3_48_1_Low_Latency", + "Two-OneChan-SnkAse-Lc3_32_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_32_1_Low_Latency", + "Two-OneChan-SnkAse-Lc3_24_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_24_1_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_48_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_48_3_Low_Latency", + "One-TwoChan-SnkAse-Lc3_48_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_32_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_32_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_24_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_24_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_1_Low_Latency", + "Two-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "Two-OneChan-SrcAse-Lc3_32_1_Low_Latency", + "Two-OneChan-SrcAse-Lc3_24_2_Low_Latency", + "Two-OneChan-SrcAse-Lc3_24_1_Low_Latency", + "Two-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "Two-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "One-TwoChan-SrcAse-Lc3_32_2_Low_Latency", + "One-TwoChan-SrcAse-Lc3_32_1_Low_Latency", + "One-TwoChan-SrcAse-Lc3_24_2_Low_Latency", + "One-TwoChan-SrcAse-Lc3_24_1_Low_Latency", + "One-TwoChan-SrcAse-Lc3_16_2_Low_Latency", + "One-TwoChan-SrcAse-Lc3_16_1_Low_Latency", + "One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "One-OneChan-SrcAse-Lc3_32_1_Low_Latency", + "One-OneChan-SrcAse-Lc3_24_2_Low_Latency", + "One-OneChan-SrcAse-Lc3_24_1_Low_Latency", + "One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "One-OneChan-SrcAse-Lc3_16_1_Low_Latency" + ] + }, + { + "name": "Live", + "configurations": [ + "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_Balanced_Reliability_1", + "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_R11_L40_1", + "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1", + "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_1", + "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_1", + "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Balanced_Reliability", + "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Balanced_Reliability", + "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_1", + "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_1", + "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_1", + "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", + "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", + "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", + "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", + "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", + "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", + "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency", + "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1", + "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency", + "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1", + "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency", + "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1", + "One-OneChan-SrcAse-Lc3_48_2_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_48_1_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_32_1_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability", + "One-OneChan-SrcAse-Lc3_16_1_Balanced_Reliability" + ] + } + ] }
\ No newline at end of file diff --git a/system/bta/le_audio/client.cc b/system/bta/le_audio/client.cc index d30a9dd255..2cc636cbdb 100644 --- a/system/bta/le_audio/client.cc +++ b/system/bta/le_audio/client.cc @@ -317,8 +317,8 @@ public: } /* Choose the right configuration context */ - auto new_configuration_context = AdjustForVoiceAssistant( - group, ChooseConfigurationContextType(local_metadata_context_types_.source)); + auto new_configuration_context = + ChooseConfigurationContextType(local_metadata_context_types_.source); log::debug("new_configuration_context= {}", ToString(new_configuration_context)); ReconfigureOrUpdateMetadata(group, new_configuration_context, @@ -4374,9 +4374,6 @@ public: LeAudioContextType context_priority_list[] = { /* Highest priority first */ LeAudioContextType::CONVERSATIONAL, - /* Handling RINGTONE will cause the ringtone volume slider to trigger - * reconfiguration. This will be fixed in b/283349711. - */ LeAudioContextType::RINGTONE, LeAudioContextType::LIVE, LeAudioContextType::VOICEASSISTANTS, @@ -4755,46 +4752,6 @@ public: return remote_metadata; } - LeAudioContextType AdjustForVoiceAssistant(LeAudioDeviceGroup* group, - LeAudioContextType new_configuration_context) { - if (!com::android::bluetooth::flags::le_audio_support_unidirectional_voice_assistant()) { - log::debug("Flag le_audio_support_unidirectional_voice_assistant NOT enabled"); - return new_configuration_context; - } - - /* Some remote devices expect VOICE ASSISTANT to be unidirectional Phone is - * Source and Earbuds are Sink */ - if (new_configuration_context != LeAudioContextType::VOICEASSISTANTS) { - return new_configuration_context; - } - - auto sink_supported_contexts = - group->GetSupportedContexts(bluetooth::le_audio::types::kLeAudioDirectionSink); - auto source_supported_contexts = - group->GetSupportedContexts(bluetooth::le_audio::types::kLeAudioDirectionSource); - - log::debug("group_id: {}, sink_supported: {}, source_supported {}", group->group_id_, - ToString(sink_supported_contexts), ToString(source_supported_contexts)); - if (sink_supported_contexts.test(LeAudioContextType::VOICEASSISTANTS) && - source_supported_contexts.test(LeAudioContextType::VOICEASSISTANTS)) { - return new_configuration_context; - } - - if (sink_supported_contexts.test(LeAudioContextType::VOICEASSISTANTS)) { - log::info( - "group_id {} supports only Sink direction for Voice Assistant. " - "Selecting configurarion context type {}", - group->group_id_, ToString(LeAudioContextType::INSTRUCTIONAL)); - - return LeAudioContextType::INSTRUCTIONAL; - } - - log::warn("group_id: {}, unexpected configuration, sink_supported: {}, source_supported {}", - group->group_id_, ToString(sink_supported_contexts), - ToString(source_supported_contexts)); - return new_configuration_context; - } - /* Return true if stream is started */ bool ReconfigureOrUpdateRemote(LeAudioDeviceGroup* group, int remote_direction) { if (stack_config_get_interface()->get_pts_force_le_audio_multiple_contexts_metadata()) { @@ -4811,8 +4768,7 @@ public: local_metadata_context_types_.source.to_string(), override_contexts.to_string()); /* Choose the right configuration context */ - auto new_configuration_context = - AdjustForVoiceAssistant(group, ChooseConfigurationContextType(override_contexts)); + auto new_configuration_context = ChooseConfigurationContextType(override_contexts); log::debug("new_configuration_context= {}.", ToString(new_configuration_context)); BidirectionalPair<AudioContexts> remote_contexts = {.sink = override_contexts, @@ -4829,8 +4785,7 @@ public: /* Choose the right configuration context */ auto config_context_candids = get_bidirectional(remote_metadata); - auto new_config_context = - AdjustForVoiceAssistant(group, ChooseConfigurationContextType(config_context_candids)); + auto new_config_context = ChooseConfigurationContextType(config_context_candids); log::debug("config_context_candids= {}, new_config_context= {}", ToString(config_context_candids), ToString(new_config_context)); diff --git a/system/bta/le_audio/codec_manager.cc b/system/bta/le_audio/codec_manager.cc index fda45e7946..aedf5f244d 100644 --- a/system/bta/le_audio/codec_manager.cc +++ b/system/bta/le_audio/codec_manager.cc @@ -325,7 +325,7 @@ public: std::unique_ptr<AudioSetConfiguration> GetCodecConfig( const CodecManager::UnicastConfigurationRequirements& requirements, - CodecManager::UnicastConfigurationVerifier verifier) { + CodecManager::UnicastConfigurationProvider provider) { if (IsUsingCodecExtensibility()) { auto hal_config = unicast_local_source_hal_client->GetUnicastConfig(requirements); if (hal_config) { @@ -361,8 +361,7 @@ public: // configuration with group capabilities. Note that this path only // supports the LC3 codec format. For the multicodec support we should // rely on the configuration matcher behind the AIDL interface. - auto conf = verifier(requirements, &configs); - return conf ? std::make_unique<AudioSetConfiguration>(*conf) : nullptr; + return provider(requirements, &configs); } bool CheckCodecConfigIsBiDirSwb(const AudioSetConfiguration& config) { @@ -1192,9 +1191,9 @@ bool CodecManager::UpdateActiveBroadcastAudioHalClient( std::unique_ptr<AudioSetConfiguration> CodecManager::GetCodecConfig( const CodecManager::UnicastConfigurationRequirements& requirements, - CodecManager::UnicastConfigurationVerifier verifier) { + CodecManager::UnicastConfigurationProvider provider) { if (pimpl_->IsRunning()) { - return pimpl_->codec_manager_impl_->GetCodecConfig(requirements, verifier); + return pimpl_->codec_manager_impl_->GetCodecConfig(requirements, provider); } return nullptr; diff --git a/system/bta/le_audio/codec_manager.h b/system/bta/le_audio/codec_manager.h index 92c0e0e279..4ba95fbde6 100644 --- a/system/bta/le_audio/codec_manager.h +++ b/system/bta/le_audio/codec_manager.h @@ -77,16 +77,16 @@ public: std::optional<std::vector<DeviceDirectionRequirements>> source_requirements; }; - /* The verifier function checks each possible configuration (from the set of + /* The provider function checks each possible configuration (from the set of * all possible, supported configuration acquired from * AudioSetConfigurationProvider for the given scenario), to select a single * configuration, matching the current streaming audio group requirements. * Note: Used only with the legacy AudioSetConfigurationProvider. */ - typedef std::function<const set_configurations::AudioSetConfiguration*( + typedef std::function<std::unique_ptr<set_configurations::AudioSetConfiguration>( const UnicastConfigurationRequirements& requirements, const set_configurations::AudioSetConfigurations* confs)> - UnicastConfigurationVerifier; + UnicastConfigurationProvider; struct BroadcastConfigurationRequirements { std::vector<std::pair<bluetooth::le_audio::types::LeAudioContextType, uint8_t>> @@ -119,7 +119,7 @@ public: std::function<void(const offload_config& config, uint8_t direction)> update_receiver); virtual std::unique_ptr<::bluetooth::le_audio::set_configurations::AudioSetConfiguration> GetCodecConfig(const UnicastConfigurationRequirements& requirements, - UnicastConfigurationVerifier verifier); + UnicastConfigurationProvider provider); virtual bool CheckCodecConfigIsBiDirSwb( const ::bluetooth::le_audio::set_configurations::AudioSetConfiguration& config) const; virtual bool CheckCodecConfigIsDualBiDirSwb( diff --git a/system/bta/le_audio/codec_manager_test.cc b/system/bta/le_audio/codec_manager_test.cc index 896d257ce8..8d0a1f6aa4 100644 --- a/system/bta/le_audio/codec_manager_test.cc +++ b/system/bta/le_audio/codec_manager_test.cc @@ -510,7 +510,7 @@ TEST_F(CodecManagerTestAdsp, test_capabilities_none) { bool has_null_config = false; auto match_first_config = [&](const CodecManager::UnicastConfigurationRequirements& requirements, const set_configurations::AudioSetConfigurations* confs) - -> const set_configurations::AudioSetConfiguration* { + -> std::unique_ptr<set_configurations::AudioSetConfiguration> { // Don't expect the matcher being called on nullptr if (confs == nullptr) { has_null_config = true; @@ -518,7 +518,7 @@ TEST_F(CodecManagerTestAdsp, test_capabilities_none) { if (confs && confs->size()) { // For simplicity return the first element, the real matcher should // check the group capabilities. - return confs->at(0); + return std::make_unique<AudioSetConfiguration>(*(confs->at(0))); } return nullptr; }; @@ -558,12 +558,12 @@ TEST_F(CodecManagerTestAdsp, test_capabilities) { [&available_configs_size]( const CodecManager::UnicastConfigurationRequirements& requirements, const set_configurations::AudioSetConfigurations* confs) - -> const set_configurations::AudioSetConfiguration* { + -> std::unique_ptr<set_configurations::AudioSetConfiguration> { if (confs && confs->size()) { available_configs_size = confs->size(); // For simplicity return the first element, the real matcher should // check the group capabilities. - return confs->at(0); + return std::make_unique<AudioSetConfiguration>(*(confs->at(0))); } return nullptr; }; @@ -989,7 +989,7 @@ TEST_F(CodecManagerTestHost, test_dual_bidir_swb_supported) { {.audio_context_type = context}, [&](const CodecManager::UnicastConfigurationRequirements& requirements, const set_configurations::AudioSetConfigurations* confs) - -> const set_configurations::AudioSetConfiguration* { + -> std::unique_ptr<set_configurations::AudioSetConfiguration> { if (confs == nullptr) { got_null_cfgs_container = true; } else { @@ -1039,7 +1039,7 @@ TEST_F(CodecManagerTestAdsp, test_dual_bidir_swb_supported) { {.audio_context_type = context}, [&](const CodecManager::UnicastConfigurationRequirements& requirements, const set_configurations::AudioSetConfigurations* confs) - -> const set_configurations::AudioSetConfiguration* { + -> std::unique_ptr<set_configurations::AudioSetConfiguration> { if (confs == nullptr) { got_null_cfgs_container = true; } else { @@ -1071,7 +1071,7 @@ TEST_F(CodecManagerTestHostNoSwb, test_dual_bidir_swb_not_supported) { {.audio_context_type = context}, [&](const CodecManager::UnicastConfigurationRequirements& requirements, const set_configurations::AudioSetConfigurations* confs) - -> const set_configurations::AudioSetConfiguration* { + -> std::unique_ptr<set_configurations::AudioSetConfiguration> { if (confs == nullptr) { got_null_cfgs_container = true; } else { @@ -1120,7 +1120,7 @@ TEST_F(CodecManagerTestAdspNoSwb, test_dual_bidir_swb_not_supported) { {.audio_context_type = context}, [&](const CodecManager::UnicastConfigurationRequirements& requirements, const set_configurations::AudioSetConfigurations* confs) - -> const set_configurations::AudioSetConfiguration* { + -> std::unique_ptr<set_configurations::AudioSetConfiguration> { if (confs == nullptr) { got_null_cfgs_container = true; } else { diff --git a/system/bta/le_audio/device_groups.cc b/system/bta/le_audio/device_groups.cc index 0aa6adc705..cfeb71d265 100644 --- a/system/bta/le_audio/device_groups.cc +++ b/system/bta/le_audio/device_groups.cc @@ -828,6 +828,23 @@ LeAudioDeviceGroup::GetAudioSetConfigurationRequirements(types::LeAudioContextTy continue; } + if ((com::android::bluetooth::flags::le_audio_support_unidirectional_voice_assistant() && + ctx_type == types::LeAudioContextType::VOICEASSISTANTS) || + (com::android::bluetooth::flags::leaudio_multicodec_aidl_support() && + ctx_type == types::LeAudioContextType::GAME)) { + // For GAME and VOICE ASSISTANT, ignore direction if it is not supported only on a single + // direction. + auto group_contexts = GetSupportedContexts(types::kLeAudioDirectionBoth); + if (group_contexts.test(ctx_type)) { + auto direction_contexs = device->GetSupportedContexts(direction); + if (!direction_contexs.test(ctx_type)) { + log::warn("Device {} has no {} context support", device->address_, + common::ToString(ctx_type)); + continue; + } + } + } + auto& dev_locations = (direction == types::kLeAudioDirectionSink) ? device->snk_audio_locations_ : device->src_audio_locations_; @@ -1399,6 +1416,22 @@ bool LeAudioDeviceGroup::IsAudioSetConfigurationSupported( continue; } + if (com::android::bluetooth::flags::le_audio_support_unidirectional_voice_assistant() || + com::android::bluetooth::flags::leaudio_multicodec_aidl_support()) { + // Verify the direction requirements. + if (direction == types::kLeAudioDirectionSink && + requirements.sink_requirements->size() == 0) { + log::debug("There is no requirement for Sink direction."); + return false; + } + + if (direction == types::kLeAudioDirectionSource && + requirements.source_requirements->size() == 0) { + log::debug("There is no requirement for source direction."); + return false; + } + } + // In some tests we expect the configuration to be there even when the // contexts are not supported. Then we might want to configure the device // but use UNSPECIFIED which is always supported (but can be unavailable) @@ -1873,7 +1906,7 @@ bool LeAudioDeviceGroup::IsConfiguredForContext(LeAudioContextType context_type) return stream_conf.conf.get() == GetActiveConfiguration().get(); } -const set_configurations::AudioSetConfiguration* +std::unique_ptr<set_configurations::AudioSetConfiguration> LeAudioDeviceGroup::FindFirstSupportedConfiguration( const CodecManager::UnicastConfigurationRequirements& requirements, const set_configurations::AudioSetConfigurations* confs) const { @@ -1887,7 +1920,7 @@ LeAudioDeviceGroup::FindFirstSupportedConfiguration( log::assert_that(conf != nullptr, "confs should not be null"); if (IsAudioSetConfigurationSupported(requirements, conf)) { log::debug("found: {}", conf->name); - return conf; + return std::make_unique<set_configurations::AudioSetConfiguration>(*conf); } } diff --git a/system/bta/le_audio/device_groups.h b/system/bta/le_audio/device_groups.h index 55dec0ce98..16c4240ca5 100644 --- a/system/bta/le_audio/device_groups.h +++ b/system/bta/le_audio/device_groups.h @@ -390,7 +390,7 @@ public: * configurations. This will not be used for finding best possible vendor * codec configuration. */ - const set_configurations::AudioSetConfiguration* FindFirstSupportedConfiguration( + std::unique_ptr<set_configurations::AudioSetConfiguration> FindFirstSupportedConfiguration( const CodecManager::UnicastConfigurationRequirements& requirements, const set_configurations::AudioSetConfigurations* confs) const; diff --git a/system/bta/le_audio/devices_test.cc b/system/bta/le_audio/devices_test.cc index c41e715d4b..ff2783502f 100644 --- a/system/bta/le_audio/devices_test.cc +++ b/system/bta/le_audio/devices_test.cc @@ -610,7 +610,7 @@ protected: auto num_of_allocations_per_ase = std::min(target_max_channel_counts_per_ase, (uint8_t)split_allocations.size()); // Note: This is very important to set for the unit test - // Configuration verifier + // Configuration provider endpoint_cfg.codec.channel_count_per_iso_stream = num_of_allocations_per_ase; // Consume the `num_of_allocations_per_ase` amount of allocations for @@ -683,7 +683,7 @@ protected: .WillByDefault(Invoke( [&](const bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements& requirements, - bluetooth::le_audio::CodecManager::UnicastConfigurationVerifier verifier) { + bluetooth::le_audio::CodecManager::UnicastConfigurationProvider provider) { if (codec_coding_format_ == kLeAudioCodingFormatLC3) { auto filtered = *bluetooth::le_audio::AudioSetConfigurationProvider::Get() @@ -702,7 +702,7 @@ protected: }), filtered.end()); } - auto cfg = verifier(requirements, &filtered); + auto cfg = provider(requirements, &filtered); if (cfg == nullptr) { return std::unique_ptr<AudioSetConfiguration>(nullptr); } @@ -1244,7 +1244,7 @@ protected: .WillByDefault(Invoke([&configs](const bluetooth::le_audio::CodecManager:: UnicastConfigurationRequirements& requirements, bluetooth::le_audio::CodecManager:: - UnicastConfigurationVerifier verifier) { + UnicastConfigurationProvider provider) { auto filtered = configs; // Filter out the dual bidir SWB configurations if (!bluetooth::le_audio::CodecManager::GetInstance()->IsDualBiDirSwbSupported()) { @@ -1258,7 +1258,7 @@ protected: }), filtered.end()); } - auto cfg = verifier(requirements, &filtered); + auto cfg = provider(requirements, &filtered); if (cfg == nullptr) { return std::unique_ptr<AudioSetConfiguration>(nullptr); } @@ -1897,7 +1897,7 @@ TEST_P(LeAudioAseConfigurationTest, test_lc3_config_media_codec_extensibility_fb .WillByDefault(Invoke( [&](const bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements& requirements, - bluetooth::le_audio::CodecManager::UnicastConfigurationVerifier verifier) { + bluetooth::le_audio::CodecManager::UnicastConfigurationProvider provider) { auto filtered = *bluetooth::le_audio::AudioSetConfigurationProvider::Get() ->GetConfigurations(requirements.audio_context_type); // Filter out the dual bidir SWB configurations @@ -1914,7 +1914,7 @@ TEST_P(LeAudioAseConfigurationTest, test_lc3_config_media_codec_extensibility_fb }), filtered.end()); } - auto cfg = verifier(requirements, &filtered); + auto cfg = provider(requirements, &filtered); if (cfg == nullptr) { return std::unique_ptr<AudioSetConfiguration>(nullptr); } diff --git a/system/bta/le_audio/le_audio_client_test.cc b/system/bta/le_audio/le_audio_client_test.cc index fb514c31be..49bd009db1 100644 --- a/system/bta/le_audio/le_audio_client_test.cc +++ b/system/bta/le_audio/le_audio_client_test.cc @@ -1452,7 +1452,7 @@ protected: ON_CALL(*mock_codec_manager_, GetCodecConfig) .WillByDefault(Invoke([](const CodecManager::UnicastConfigurationRequirements& requirements, - CodecManager::UnicastConfigurationVerifier verifier) { + CodecManager::UnicastConfigurationProvider provider) { auto filtered = *le_audio::AudioSetConfigurationProvider::Get()->GetConfigurations( requirements.audio_context_type); // Filter out the dual bidir SWB configurations @@ -1467,9 +1467,7 @@ protected: }), filtered.end()); } - auto cptr = verifier(requirements, &filtered); - return cptr ? std::make_unique<set_configurations::AudioSetConfiguration>(*cptr) - : nullptr; + return provider(requirements, &filtered); })); } @@ -5840,14 +5838,16 @@ TEST_F(UnicastTest, TestUnidirectionalVoiceAssistant_Sink) { types::BidirectionalPair<types::AudioContexts> metadata_contexts = { .sink = types::AudioContexts(types::LeAudioContextType::VOICEASSISTANTS), - .source = types::AudioContexts()}; + .source = types::AudioContexts(types::LeAudioContextType::UNSPECIFIED)}; EXPECT_CALL(mock_state_machine_, - StartStream(_, types::LeAudioContextType::INSTRUCTIONAL, metadata_contexts, _)) + StartStream(_, types::LeAudioContextType::VOICEASSISTANTS, metadata_contexts, _)) .Times(1); + + log::info("Connecting LeAudio to {}", test_address0); ConnectLeAudio(test_address0); ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); - // Start streaming + // We do expect only unidirectional CIS uint8_t cis_count_out = 1; uint8_t cis_count_in = 0; @@ -5885,7 +5885,7 @@ TEST_F(UnicastTest, TestUnidirectionalVoiceAssistant_Source) { * Scenario test steps * 1. Configure group to support VOICEASSISTANT only on SOURCE * 2. Start stream - * 5. Verify that bi-direction VOICEASSISTANT has been created + * 5. Verify that uni-direction VOICEASSISTANT has been created */ available_snk_context_types_ = @@ -5917,11 +5917,14 @@ TEST_F(UnicastTest, TestUnidirectionalVoiceAssistant_Source) { EXPECT_CALL(mock_state_machine_, StartStream(_, types::LeAudioContextType::VOICEASSISTANTS, metadata_contexts, _)) .Times(1); + + log::info("Connecting LeAudio device {}", test_address0); + ConnectLeAudio(test_address0); ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); - // Start streaming - uint8_t cis_count_out = 1; + // Expected only unidirectional CIS + uint8_t cis_count_out = 0; uint8_t cis_count_in = 1; // Audio sessions are started only when device gets active @@ -5930,8 +5933,8 @@ TEST_F(UnicastTest, TestUnidirectionalVoiceAssistant_Source) { LeAudioClient::Get()->GroupSetActive(group_id); SyncOnMainLoop(); - StartStreaming(AUDIO_USAGE_ASSISTANT, AUDIO_CONTENT_TYPE_UNKNOWN, group_id, - AUDIO_SOURCE_VOICE_RECOGNITION); + UpdateLocalSinkMetadata(AUDIO_SOURCE_VOICE_RECOGNITION); + LocalAudioSinkResume(); // Verify Data transfer on one local audio source cis TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); @@ -10502,13 +10505,13 @@ TEST_F(UnicastTest, CodecFrameBlocks2) { } }); - // Add a frame block PAC passing verifier + // Add a frame block PAC passing provider bool is_fb2_passed_as_requirement = false; ON_CALL(*mock_codec_manager_, GetCodecConfig) .WillByDefault(Invoke( [&](const bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements& requirements, - bluetooth::le_audio::CodecManager::UnicastConfigurationVerifier verifier) { + bluetooth::le_audio::CodecManager::UnicastConfigurationProvider provider) { auto filtered = *bluetooth::le_audio::AudioSetConfigurationProvider::Get() ->GetConfigurations(requirements.audio_context_type); // Filter out the dual bidir SWB configurations @@ -10525,13 +10528,13 @@ TEST_F(UnicastTest, CodecFrameBlocks2) { }), filtered.end()); } - auto cfg = verifier(requirements, &filtered); + auto cfg = provider(requirements, &filtered); if (cfg == nullptr) { - return std::unique_ptr<set_configurations::AudioSetConfiguration>(nullptr); + return std::unique_ptr< + bluetooth::le_audio::set_configurations::AudioSetConfiguration>( + nullptr); } - auto config = *cfg; - if (requirements.sink_pacs.has_value()) { for (auto const& rec : requirements.sink_pacs.value()) { auto caps = rec.codec_spec_caps.GetAsCoreCodecCapabilities(); @@ -10540,7 +10543,7 @@ TEST_F(UnicastTest, CodecFrameBlocks2) { max_codec_frames_per_sdu) { // Inject the proper Codec Frames Per SDU as the json // configs are conservative and will always give us 1 - for (auto& entry : config.confs.sink) { + for (auto& entry : cfg->confs.sink) { entry.codec.params.Add( codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu, (uint8_t)max_codec_frames_per_sdu); @@ -10550,7 +10553,7 @@ TEST_F(UnicastTest, CodecFrameBlocks2) { } } } - return std::make_unique<set_configurations::AudioSetConfiguration>(config); + return cfg; })); types::BidirectionalPair<stream_parameters> codec_manager_stream_params; diff --git a/system/bta/le_audio/mock_codec_manager.cc b/system/bta/le_audio/mock_codec_manager.cc index a3c476a252..53f1f78706 100644 --- a/system/bta/le_audio/mock_codec_manager.cc +++ b/system/bta/le_audio/mock_codec_manager.cc @@ -79,7 +79,7 @@ void CodecManager::UpdateActiveAudioConfig( std::unique_ptr<set_configurations::AudioSetConfiguration> CodecManager::GetCodecConfig( const CodecManager::UnicastConfigurationRequirements& requirements, - CodecManager::UnicastConfigurationVerifier verifier) { + CodecManager::UnicastConfigurationProvider verifier) { if (!pimpl_) { return nullptr; } diff --git a/system/bta/le_audio/mock_codec_manager.h b/system/bta/le_audio/mock_codec_manager.h index ae125a1fe1..8352742a96 100644 --- a/system/bta/le_audio/mock_codec_manager.h +++ b/system/bta/le_audio/mock_codec_manager.h @@ -60,7 +60,7 @@ public: (std::unique_ptr<bluetooth::le_audio::set_configurations::AudioSetConfiguration>), GetCodecConfig, (const bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements& requirements, - bluetooth::le_audio::CodecManager::UnicastConfigurationVerifier), + bluetooth::le_audio::CodecManager::UnicastConfigurationProvider), (const)); MOCK_METHOD((bool), CheckCodecConfigIsBiDirSwb, (const bluetooth::le_audio::set_configurations::AudioSetConfiguration& config), diff --git a/system/bta/le_audio/state_machine_test.cc b/system/bta/le_audio/state_machine_test.cc index b3af9c9321..b3e7024d5f 100644 --- a/system/bta/le_audio/state_machine_test.cc +++ b/system/bta/le_audio/state_machine_test.cc @@ -572,7 +572,7 @@ protected: .WillByDefault(Invoke( [](const bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements& requirements, - bluetooth::le_audio::CodecManager::UnicastConfigurationVerifier verifier) { + bluetooth::le_audio::CodecManager::UnicastConfigurationProvider provider) { auto configs = *bluetooth::le_audio::AudioSetConfigurationProvider::Get() ->GetConfigurations(requirements.audio_context_type); // Note: This dual bidir SWB exclusion logic has to match the @@ -590,14 +590,7 @@ protected: configs.end()); } - auto cfg = verifier(requirements, &configs); - if (cfg == nullptr) { - return std::unique_ptr< - bluetooth::le_audio::set_configurations::AudioSetConfiguration>( - nullptr); - } - return std::make_unique< - bluetooth::le_audio::set_configurations::AudioSetConfiguration>(*cfg); + return provider(requirements, &configs); })); } @@ -1652,8 +1645,8 @@ TEST_F(StateMachineTest, testConfigureCodecSingleFb2) { ON_CALL(*mock_codec_manager_, GetCodecConfig) .WillByDefault(Invoke([&](const bluetooth::le_audio::CodecManager:: UnicastConfigurationRequirements& requirements, - bluetooth::le_audio::CodecManager::UnicastConfigurationVerifier - verifier) { + bluetooth::le_audio::CodecManager::UnicastConfigurationProvider + provider) { auto configs = *bluetooth::le_audio::AudioSetConfigurationProvider::Get()->GetConfigurations( requirements.audio_context_type); @@ -1671,12 +1664,11 @@ TEST_F(StateMachineTest, testConfigureCodecSingleFb2) { configs.end()); } - auto cfg = verifier(requirements, &configs); + auto cfg = provider(requirements, &configs); if (cfg == nullptr) { return std::unique_ptr< bluetooth::le_audio::set_configurations::AudioSetConfiguration>(nullptr); } - auto config = *cfg; if (requirements.sink_pacs.has_value()) { for (auto const& rec : requirements.sink_pacs.value()) { @@ -1685,7 +1677,7 @@ TEST_F(StateMachineTest, testConfigureCodecSingleFb2) { if (caps.supported_max_codec_frames_per_sdu.value() == codec_frame_blocks_per_sdu_) { // Scale by Codec Frames Per SDU = 2 - for (auto& entry : config.confs.sink) { + for (auto& entry : cfg->confs.sink) { entry.codec.params.Add(codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu, (uint8_t)codec_frame_blocks_per_sdu_); entry.qos.maxSdu *= codec_frame_blocks_per_sdu_; @@ -1704,7 +1696,7 @@ TEST_F(StateMachineTest, testConfigureCodecSingleFb2) { if (caps.supported_max_codec_frames_per_sdu.value() == codec_frame_blocks_per_sdu_) { // Scale by Codec Frames Per SDU = 2 - for (auto& entry : config.confs.source) { + for (auto& entry : cfg->confs.source) { entry.codec.params.Add(codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu, (uint8_t)codec_frame_blocks_per_sdu_); entry.qos.maxSdu *= codec_frame_blocks_per_sdu_; @@ -1717,8 +1709,7 @@ TEST_F(StateMachineTest, testConfigureCodecSingleFb2) { } } - return std::make_unique<bluetooth::le_audio::set_configurations::AudioSetConfiguration>( - config); + return cfg; })); /* Device is banded headphones with 1x snk + 0x src ase diff --git a/system/bta/test/bta_dm_test.cc b/system/bta/test/bta_dm_test.cc index b12278642d..e3309ecee7 100644 --- a/system/bta/test/bta_dm_test.cc +++ b/system/bta/test/bta_dm_test.cc @@ -461,20 +461,19 @@ TEST_F(BtaDmCustomAlarmTest, bta_dm_sniff_cback) { ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); } -TEST_F_WITH_FLAGS(BtaDmCustomAlarmTest, sniff_offload_feature__enable_flag, - REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, enable_sniff_offload))) { +TEST_F(BtaDmCustomAlarmTest, sniff_offload_feature__test_sysprop) { bool is_property_enabled = true; test::mock::osi_properties::osi_property_get_bool.body = [&](const char* key, bool default_value) -> int { return is_property_enabled; }; - // Expect not to trigger bta_dm_init_pm due to both flag and prop are enabled + // Expect not to trigger bta_dm_init_pm due to sysprop enabled // and reset the value of .srvc_id. is_property_enabled = true; bluetooth::legacy::testing::BTA_dm_on_hw_on(); ASSERT_EQ(0, bta_dm_cb.pm_timer[0].srvc_id[0]); // Expect to trigger bta_dm_init_pm and init the value of .srvc_id to - // BTA_ID_MAX. + // BTA_ID_MAX due to sysprop disabled. is_property_enabled = false; bluetooth::legacy::testing::BTA_dm_on_hw_on(); ASSERT_EQ((uint8_t)BTA_ID_MAX, bta_dm_cb.pm_timer[0].srvc_id[0]); @@ -485,22 +484,3 @@ TEST_F_WITH_FLAGS(BtaDmCustomAlarmTest, sniff_offload_feature__enable_flag, bta_dm_cb.pm_timer[0].srvc_id[0] = kUnusedTimer; bta_dm_disable_pm(); } - -TEST_F_WITH_FLAGS(BtaDmCustomAlarmTest, sniff_offload_feature__disable_flag, - REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(TEST_BT, enable_sniff_offload))) { - bool is_property_enabled = true; - test::mock::osi_properties::osi_property_get_bool.body = - [&](const char* key, bool default_value) -> int { return is_property_enabled; }; - - // Expect to trigger bta_dm_init_pm and init the value of .srvc_id to - // BTA_ID_MAX. - is_property_enabled = true; - bluetooth::legacy::testing::BTA_dm_on_hw_on(); - ASSERT_EQ((uint8_t)BTA_ID_MAX, bta_dm_cb.pm_timer[0].srvc_id[0]); - - // Expect to trigger bta_dm_init_pm and init the value of .srvc_id to - // BTA_ID_MAX. - is_property_enabled = false; - bluetooth::legacy::testing::BTA_dm_on_hw_on(); - ASSERT_EQ((uint8_t)BTA_ID_MAX, bta_dm_cb.pm_timer[0].srvc_id[0]); -} diff --git a/system/bta/vc/vc.cc b/system/bta/vc/vc.cc index e48934d205..b12a216939 100644 --- a/system/bta/vc/vc.cc +++ b/system/bta/vc/vc.cc @@ -366,14 +366,16 @@ public: auto csis_api = CsisClient::Get(); if (!csis_api) { log::warn("Csis module is not available"); - callbacks_->OnVolumeStateChanged(device->address, device->volume, device->mute, true); + callbacks_->OnVolumeStateChanged(device->address, device->volume, device->mute, device->flags, + true); return; } auto group_id = csis_api->GetGroupId(device->address, le_audio::uuid::kCapServiceUuid); if (group_id == bluetooth::groups::kGroupUnknown) { log::warn("No group for device {}", device->address); - callbacks_->OnVolumeStateChanged(device->address, device->volume, device->mute, true); + callbacks_->OnVolumeStateChanged(device->address, device->volume, device->mute, device->flags, + true); return; } @@ -438,7 +440,8 @@ public: /* This is just a read, send single notification */ if (!is_notification) { - callbacks_->OnVolumeStateChanged(device->address, device->volume, device->mute, false); + callbacks_->OnVolumeStateChanged(device->address, device->volume, device->mute, device->flags, + false); return; } @@ -468,7 +471,8 @@ public: } else { /* op->is_autonomous_ will always be false, since we only make it true for group operations */ - callbacks_->OnVolumeStateChanged(device->address, device->volume, device->mute, false); + callbacks_->OnVolumeStateChanged(device->address, device->volume, device->mute, device->flags, + false); } ongoing_operations_.erase(op); @@ -1067,7 +1071,8 @@ private: callbacks_->OnConnectionState(ConnectionState::CONNECTED, device->address); // once profile connected we can notify current states - callbacks_->OnVolumeStateChanged(device->address, device->volume, device->mute, false); + callbacks_->OnVolumeStateChanged(device->address, device->volume, device->mute, device->flags, + true); for (auto const& offset : device->audio_offsets.volume_offsets) { callbacks_->OnExtAudioOutVolumeOffsetChanged(device->address, offset.id, offset.offset); diff --git a/system/bta/vc/vc_test.cc b/system/bta/vc/vc_test.cc index dfb436e903..708a0a6b65 100644 --- a/system/bta/vc/vc_test.cc +++ b/system/bta/vc/vc_test.cc @@ -82,7 +82,8 @@ public: MOCK_METHOD((void), OnDeviceAvailable, (const RawAddress& address, uint8_t num_offset), (override)); MOCK_METHOD((void), OnVolumeStateChanged, - (const RawAddress& address, uint8_t volume, bool mute, bool isAutonomous), + (const RawAddress& address, uint8_t volume, bool mute, uint8_t flags, + bool isAutonomous), (override)); MOCK_METHOD((void), OnGroupVolumeStateChanged, (int group_id, uint8_t volume, bool mute, bool isAutonomous), (override)); @@ -885,7 +886,7 @@ TEST_F(VolumeControlTest, test_subscribe_vocs_output_description) { TEST_F(VolumeControlTest, test_read_vcs_volume_state) { const RawAddress test_address = GetTestAddress(0); - EXPECT_CALL(*callbacks, OnVolumeStateChanged(test_address, _, _, false)); + EXPECT_CALL(*callbacks, OnVolumeStateChanged(test_address, _, _, _, true)).Times(1); std::vector<uint16_t> handles({0x0021}); TestReadCharacteristic(test_address, 1, handles); } @@ -960,7 +961,7 @@ TEST_F(VolumeControlTest, test_discovery_vocs_broken) { TEST_F(VolumeControlTest, test_read_vcs_database_out_of_sync) { const RawAddress test_address = GetTestAddress(0); - EXPECT_CALL(*callbacks, OnVolumeStateChanged(test_address, _, _, false)); + EXPECT_CALL(*callbacks, OnVolumeStateChanged(test_address, _, _, _, true)); std::vector<uint16_t> handles({0x0021}); uint16_t conn_id = 1; @@ -1033,12 +1034,12 @@ protected: TEST_F(VolumeControlCallbackTest, test_volume_state_changed_stress) { std::vector<uint8_t> value({0x03, 0x01, 0x02}); - EXPECT_CALL(*callbacks, OnVolumeStateChanged(test_address, 0x03, true, true)); + EXPECT_CALL(*callbacks, OnVolumeStateChanged(test_address, 0x03, true, _, true)); GetNotificationEvent(0x0021, value); } TEST_F(VolumeControlCallbackTest, test_volume_state_changed_malformed) { - EXPECT_CALL(*callbacks, OnVolumeStateChanged(test_address, _, _, _)).Times(0); + EXPECT_CALL(*callbacks, OnVolumeStateChanged(test_address, _, _, _, _)).Times(0); std::vector<uint8_t> too_short({0x03, 0x01}); GetNotificationEvent(0x0021, too_short); std::vector<uint8_t> too_long({0x03, 0x01, 0x02, 0x03}); @@ -1527,6 +1528,8 @@ TEST_F(VolumeControlCsis, test_set_volume) { VolumeControl::Get()->SetVolume(test_address_1, 20); VolumeControl::Get()->SetVolume(test_address_2, 20); + EXPECT_CALL(*callbacks, OnVolumeStateChanged(test_address_1, 20, false, _, false)); + EXPECT_CALL(*callbacks, OnVolumeStateChanged(test_address_2, 20, false, _, false)); std::vector<uint8_t> value2({20, 0x00, 0x03}); GetNotificationEvent(conn_id_1, test_address_1, 0x0021, value2); GetNotificationEvent(conn_id_2, test_address_2, 0x0021, value2); diff --git a/system/btif/src/btif_gatt.cc b/system/btif/src/btif_gatt.cc index 3292ddbe7a..ed20db4821 100644 --- a/system/btif/src/btif_gatt.cc +++ b/system/btif/src/btif_gatt.cc @@ -28,12 +28,14 @@ #include "btif_gatt.h" +#include <com_android_bluetooth_flags.h> #include <hardware/bluetooth.h> #include <hardware/bt_gatt.h> #include <stdlib.h> #include <string.h> -#include "bta_gatt_api.h" +#include "bta/include/bta_gatt_api.h" +#include "btif/include/btif_common.h" #include "main/shim/distance_measurement_manager.h" #include "main/shim/le_advertising_manager.h" diff --git a/system/btif/src/btif_gatt_client.cc b/system/btif/src/btif_gatt_client.cc index 8e9ada0c8c..3589114ab0 100644 --- a/system/btif/src/btif_gatt_client.cc +++ b/system/btif/src/btif_gatt_client.cc @@ -30,6 +30,7 @@ #include <base/functional/bind.h> #include <base/threading/thread.h> #include <bluetooth/log.h> +#include <com_android_bluetooth_flags.h> #include <hardware/bluetooth.h> #include <hardware/bt_gatt.h> #include <hardware/bt_gatt_types.h> @@ -89,7 +90,8 @@ static btif_test_cb_t test_cb; ******************************************************************************/ #define CLI_CBACK_WRAP_IN_JNI(P_CBACK, P_CBACK_WRAP) \ do { \ - if (bt_gatt_callbacks && bt_gatt_callbacks->client->P_CBACK) { \ + auto callbacks = bt_gatt_callbacks; \ + if (callbacks && callbacks->client->P_CBACK) { \ log::verbose("HAL bt_gatt_callbacks->client->{}", #P_CBACK); \ do_in_jni_thread(P_CBACK_WRAP); \ } else { \ @@ -97,14 +99,15 @@ static btif_test_cb_t test_cb; } \ } while (0) -#define CLI_CBACK_IN_JNI(P_CBACK, ...) \ - do { \ - if (bt_gatt_callbacks && bt_gatt_callbacks->client->P_CBACK) { \ - log::verbose("HAL bt_gatt_callbacks->client->{}", #P_CBACK); \ - do_in_jni_thread(Bind(bt_gatt_callbacks->client->P_CBACK, __VA_ARGS__)); \ - } else { \ - ASSERTC(0, "Callback is NULL", 0); \ - } \ +#define CLI_CBACK_IN_JNI(P_CBACK, ...) \ + do { \ + auto callbacks = bt_gatt_callbacks; \ + if (callbacks && callbacks->client->P_CBACK) { \ + log::verbose("HAL bt_gatt_callbacks->client->{}", #P_CBACK); \ + do_in_jni_thread(Bind(callbacks->client->P_CBACK, __VA_ARGS__)); \ + } else { \ + ASSERTC(0, "Callback is NULL", 0); \ + } \ } while (0) #define CHECK_BTGATT_INIT() \ @@ -139,16 +142,17 @@ uint8_t rssi_request_client_if; static void btif_gattc_upstreams_evt(uint16_t event, char* p_param) { log::debug("Event {} [{}]", gatt_client_event_text(static_cast<tBTA_GATTC_EVT>(event)), event); + auto callbacks = bt_gatt_callbacks; tBTA_GATTC* p_data = (tBTA_GATTC*)p_param; switch (event) { case BTA_GATTC_EXEC_EVT: { - HAL_CBACK(bt_gatt_callbacks, client->execute_write_cb, p_data->exec_cmpl.conn_id, + HAL_CBACK(callbacks, client->execute_write_cb, p_data->exec_cmpl.conn_id, p_data->exec_cmpl.status); break; } case BTA_GATTC_SEARCH_CMPL_EVT: { - HAL_CBACK(bt_gatt_callbacks, client->search_complete_cb, p_data->search_cmpl.conn_id, + HAL_CBACK(callbacks, client->search_complete_cb, p_data->search_cmpl.conn_id, p_data->search_cmpl.status); break; } @@ -163,7 +167,7 @@ static void btif_gattc_upstreams_evt(uint16_t event, char* p_param) { data.is_notify = p_data->notify.is_notify; data.len = p_data->notify.len; - HAL_CBACK(bt_gatt_callbacks, client->notify_cb, p_data->notify.conn_id, data); + HAL_CBACK(callbacks, client->notify_cb, p_data->notify.conn_id, data); if (!p_data->notify.is_notify) { BTA_GATTC_SendIndConfirm(p_data->notify.conn_id, p_data->notify.cid); @@ -174,12 +178,12 @@ static void btif_gattc_upstreams_evt(uint16_t event, char* p_param) { case BTA_GATTC_OPEN_EVT: { log::debug("BTA_GATTC_OPEN_EVT {}", p_data->open.remote_bda); - HAL_CBACK(bt_gatt_callbacks, client->open_cb, p_data->open.conn_id, p_data->open.status, + HAL_CBACK(callbacks, client->open_cb, p_data->open.conn_id, p_data->open.status, p_data->open.client_if, p_data->open.remote_bda); if (GATT_DEF_BLE_MTU_SIZE != p_data->open.mtu && p_data->open.mtu) { - HAL_CBACK(bt_gatt_callbacks, client->configure_mtu_cb, p_data->open.conn_id, - p_data->open.status, p_data->open.mtu); + HAL_CBACK(callbacks, client->configure_mtu_cb, p_data->open.conn_id, p_data->open.status, + p_data->open.mtu); } if (p_data->open.status == GATT_SUCCESS) { @@ -190,7 +194,7 @@ static void btif_gattc_upstreams_evt(uint16_t event, char* p_param) { case BTA_GATTC_CLOSE_EVT: { log::debug("BTA_GATTC_CLOSE_EVT {}", p_data->close.remote_bda); - HAL_CBACK(bt_gatt_callbacks, client->close_cb, p_data->close.conn_id, p_data->close.status, + HAL_CBACK(callbacks, client->close_cb, p_data->close.conn_id, p_data->close.status, p_data->close.client_if, p_data->close.remote_bda); break; } @@ -203,33 +207,33 @@ static void btif_gattc_upstreams_evt(uint16_t event, char* p_param) { break; case BTA_GATTC_CFG_MTU_EVT: { - HAL_CBACK(bt_gatt_callbacks, client->configure_mtu_cb, p_data->cfg_mtu.conn_id, + HAL_CBACK(callbacks, client->configure_mtu_cb, p_data->cfg_mtu.conn_id, p_data->cfg_mtu.status, p_data->cfg_mtu.mtu); break; } case BTA_GATTC_CONGEST_EVT: - HAL_CBACK(bt_gatt_callbacks, client->congestion_cb, p_data->congest.conn_id, + HAL_CBACK(callbacks, client->congestion_cb, p_data->congest.conn_id, p_data->congest.congested); break; case BTA_GATTC_PHY_UPDATE_EVT: - HAL_CBACK(bt_gatt_callbacks, client->phy_updated_cb, p_data->phy_update.conn_id, + HAL_CBACK(callbacks, client->phy_updated_cb, p_data->phy_update.conn_id, p_data->phy_update.tx_phy, p_data->phy_update.rx_phy, p_data->phy_update.status); break; case BTA_GATTC_CONN_UPDATE_EVT: - HAL_CBACK(bt_gatt_callbacks, client->conn_updated_cb, p_data->conn_update.conn_id, + HAL_CBACK(callbacks, client->conn_updated_cb, p_data->conn_update.conn_id, p_data->conn_update.interval, p_data->conn_update.latency, p_data->conn_update.timeout, p_data->conn_update.status); break; case BTA_GATTC_SRVC_CHG_EVT: - HAL_CBACK(bt_gatt_callbacks, client->service_changed_cb, p_data->service_changed.conn_id); + HAL_CBACK(callbacks, client->service_changed_cb, p_data->service_changed.conn_id); break; case BTA_GATTC_SUBRATE_CHG_EVT: - HAL_CBACK(bt_gatt_callbacks, client->subrate_chg_cb, p_data->subrate_chg.conn_id, + HAL_CBACK(callbacks, client->subrate_chg_cb, p_data->subrate_chg.conn_id, p_data->subrate_chg.subrate_factor, p_data->subrate_chg.latency, p_data->subrate_chg.cont_num, p_data->subrate_chg.timeout, p_data->subrate_chg.status); @@ -274,8 +278,9 @@ static bt_status_t btif_gattc_register_app(const Uuid& uuid, bool eatt_support) [](const Uuid& uuid, uint8_t client_id, uint8_t status) { do_in_jni_thread(Bind( [](const Uuid& uuid, uint8_t client_id, uint8_t status) { - HAL_CBACK(bt_gatt_callbacks, client->register_client_cb, - status, client_id, uuid); + auto callbacks = bt_gatt_callbacks; + HAL_CBACK(callbacks, client->register_client_cb, status, + client_id, uuid); }, uuid, client_id, status)); }, @@ -319,7 +324,8 @@ void btif_gattc_open_impl(int client_if, RawAddress address, tBLE_ADDR_TYPE addr tBTM_BLE_VSC_CB vnd_capabilities; BTM_BleGetVendorCapabilities(&vnd_capabilities); if (!vnd_capabilities.rpa_offloading) { - HAL_CBACK(bt_gatt_callbacks, client->open_cb, 0, BT_STATUS_UNSUPPORTED, client_if, address); + auto callbacks = bt_gatt_callbacks; + HAL_CBACK(callbacks, client->open_cb, 0, BT_STATUS_UNSUPPORTED, client_if, address); return; } } @@ -404,7 +410,8 @@ void btif_gattc_get_gatt_db_impl(int conn_id) { int count = 0; BTA_GATTC_GetGattDb(conn_id, 0x0000, 0xFFFF, &db, &count); - HAL_CBACK(bt_gatt_callbacks, client->get_gatt_db_cb, conn_id, db, count); + auto callbacks = bt_gatt_callbacks; + HAL_CBACK(callbacks, client->get_gatt_db_cb, conn_id, db, count); osi_free(db); } @@ -469,7 +476,6 @@ void read_desc_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16 if (len > 0) { memcpy(params.value.value, value, len); } - CLI_CBACK_IN_JNI(read_descriptor_cb, conn_id, status, params); } @@ -546,7 +552,8 @@ static void btif_gattc_reg_for_notification_impl(tGATT_IF client_if, const RawAd tGATT_STATUS status = BTA_GATTC_RegisterForNotifications(client_if, bda, handle); // TODO(jpawlowski): conn_id is currently unused - HAL_CBACK(bt_gatt_callbacks, client->register_for_notification_cb, + auto callbacks = bt_gatt_callbacks; + HAL_CBACK(callbacks, client->register_for_notification_cb, /* conn_id */ 0, 1, status, handle); } @@ -563,7 +570,8 @@ static void btif_gattc_dereg_for_notification_impl(tGATT_IF client_if, const Raw tGATT_STATUS status = BTA_GATTC_DeregisterForNotifications(client_if, bda, handle); // TODO(jpawlowski): conn_id is currently unused - HAL_CBACK(bt_gatt_callbacks, client->register_for_notification_cb, + auto callbacks = bt_gatt_callbacks; + HAL_CBACK(callbacks, client->register_for_notification_cb, /* conn_id */ 0, 0, status, handle); } diff --git a/system/btif/src/btif_gatt_server.cc b/system/btif/src/btif_gatt_server.cc index a273f8d9d7..3714269c23 100644 --- a/system/btif/src/btif_gatt_server.cc +++ b/system/btif/src/btif_gatt_server.cc @@ -147,10 +147,11 @@ static void btapp_gatts_free_req_data(uint16_t event, tBTA_GATTS* p_data) { static void btapp_gatts_handle_cback(uint16_t event, char* p_param) { log::verbose("Event {}", event); + auto callbacks = bt_gatt_callbacks; tBTA_GATTS* p_data = (tBTA_GATTS*)p_param; switch (event) { case BTA_GATTS_REG_EVT: { - HAL_CBACK(bt_gatt_callbacks, server->register_server_cb, p_data->reg_oper.status, + HAL_CBACK(callbacks, server->register_server_cb, p_data->reg_oper.status, p_data->reg_oper.server_if, p_data->reg_oper.uuid); break; } @@ -161,29 +162,29 @@ static void btapp_gatts_handle_cback(uint16_t event, char* p_param) { case BTA_GATTS_CONNECT_EVT: { btif_gatt_check_encrypted_link(p_data->conn.remote_bda, p_data->conn.transport); - HAL_CBACK(bt_gatt_callbacks, server->connection_cb, p_data->conn.conn_id, - p_data->conn.server_if, true, p_data->conn.remote_bda); + HAL_CBACK(callbacks, server->connection_cb, p_data->conn.conn_id, p_data->conn.server_if, + true, p_data->conn.remote_bda); break; } case BTA_GATTS_DISCONNECT_EVT: { - HAL_CBACK(bt_gatt_callbacks, server->connection_cb, p_data->conn.conn_id, - p_data->conn.server_if, false, p_data->conn.remote_bda); + HAL_CBACK(callbacks, server->connection_cb, p_data->conn.conn_id, p_data->conn.server_if, + false, p_data->conn.remote_bda); break; } case BTA_GATTS_STOP_EVT: - HAL_CBACK(bt_gatt_callbacks, server->service_stopped_cb, p_data->srvc_oper.status, + HAL_CBACK(callbacks, server->service_stopped_cb, p_data->srvc_oper.status, p_data->srvc_oper.server_if, p_data->srvc_oper.service_id); break; case BTA_GATTS_DELETE_EVT: - HAL_CBACK(bt_gatt_callbacks, server->service_deleted_cb, p_data->srvc_oper.status, + HAL_CBACK(callbacks, server->service_deleted_cb, p_data->srvc_oper.status, p_data->srvc_oper.server_if, p_data->srvc_oper.service_id); break; case BTA_GATTS_READ_CHARACTERISTIC_EVT: { - HAL_CBACK(bt_gatt_callbacks, server->request_read_characteristic_cb, p_data->req_data.conn_id, + HAL_CBACK(callbacks, server->request_read_characteristic_cb, p_data->req_data.conn_id, p_data->req_data.trans_id, p_data->req_data.remote_bda, p_data->req_data.p_data->read_req.handle, p_data->req_data.p_data->read_req.offset, p_data->req_data.p_data->read_req.is_long); @@ -191,7 +192,7 @@ static void btapp_gatts_handle_cback(uint16_t event, char* p_param) { } case BTA_GATTS_READ_DESCRIPTOR_EVT: { - HAL_CBACK(bt_gatt_callbacks, server->request_read_descriptor_cb, p_data->req_data.conn_id, + HAL_CBACK(callbacks, server->request_read_descriptor_cb, p_data->req_data.conn_id, p_data->req_data.trans_id, p_data->req_data.remote_bda, p_data->req_data.p_data->read_req.handle, p_data->req_data.p_data->read_req.offset, p_data->req_data.p_data->read_req.is_long); @@ -200,39 +201,39 @@ static void btapp_gatts_handle_cback(uint16_t event, char* p_param) { case BTA_GATTS_WRITE_CHARACTERISTIC_EVT: { const auto& req = p_data->req_data.p_data->write_req; - HAL_CBACK(bt_gatt_callbacks, server->request_write_characteristic_cb, - p_data->req_data.conn_id, p_data->req_data.trans_id, p_data->req_data.remote_bda, - req.handle, req.offset, req.need_rsp, req.is_prep, req.value, req.len); + HAL_CBACK(callbacks, server->request_write_characteristic_cb, p_data->req_data.conn_id, + p_data->req_data.trans_id, p_data->req_data.remote_bda, req.handle, req.offset, + req.need_rsp, req.is_prep, req.value, req.len); break; } case BTA_GATTS_WRITE_DESCRIPTOR_EVT: { const auto& req = p_data->req_data.p_data->write_req; - HAL_CBACK(bt_gatt_callbacks, server->request_write_descriptor_cb, p_data->req_data.conn_id, + HAL_CBACK(callbacks, server->request_write_descriptor_cb, p_data->req_data.conn_id, p_data->req_data.trans_id, p_data->req_data.remote_bda, req.handle, req.offset, req.need_rsp, req.is_prep, req.value, req.len); break; } case BTA_GATTS_EXEC_WRITE_EVT: { - HAL_CBACK(bt_gatt_callbacks, server->request_exec_write_cb, p_data->req_data.conn_id, + HAL_CBACK(callbacks, server->request_exec_write_cb, p_data->req_data.conn_id, p_data->req_data.trans_id, p_data->req_data.remote_bda, p_data->req_data.p_data->exec_write); break; } case BTA_GATTS_CONF_EVT: - HAL_CBACK(bt_gatt_callbacks, server->indication_sent_cb, p_data->req_data.conn_id, + HAL_CBACK(callbacks, server->indication_sent_cb, p_data->req_data.conn_id, p_data->req_data.status); break; case BTA_GATTS_CONGEST_EVT: - HAL_CBACK(bt_gatt_callbacks, server->congestion_cb, p_data->congest.conn_id, + HAL_CBACK(callbacks, server->congestion_cb, p_data->congest.conn_id, p_data->congest.congested); break; case BTA_GATTS_MTU_EVT: - HAL_CBACK(bt_gatt_callbacks, server->mtu_changed_cb, p_data->req_data.conn_id, + HAL_CBACK(callbacks, server->mtu_changed_cb, p_data->req_data.conn_id, p_data->req_data.p_data->mtu); break; @@ -243,18 +244,18 @@ static void btapp_gatts_handle_cback(uint16_t event, char* p_param) { break; case BTA_GATTS_PHY_UPDATE_EVT: - HAL_CBACK(bt_gatt_callbacks, server->phy_updated_cb, p_data->phy_update.conn_id, + HAL_CBACK(callbacks, server->phy_updated_cb, p_data->phy_update.conn_id, p_data->phy_update.tx_phy, p_data->phy_update.rx_phy, p_data->phy_update.status); break; case BTA_GATTS_CONN_UPDATE_EVT: - HAL_CBACK(bt_gatt_callbacks, server->conn_updated_cb, p_data->conn_update.conn_id, + HAL_CBACK(callbacks, server->conn_updated_cb, p_data->conn_update.conn_id, p_data->conn_update.interval, p_data->conn_update.latency, p_data->conn_update.timeout, p_data->conn_update.status); break; case BTA_GATTS_SUBRATE_CHG_EVT: - HAL_CBACK(bt_gatt_callbacks, server->subrate_chg_cb, p_data->subrate_chg.conn_id, + HAL_CBACK(callbacks, server->subrate_chg_cb, p_data->subrate_chg.conn_id, p_data->subrate_chg.subrate_factor, p_data->subrate_chg.latency, p_data->subrate_chg.cont_num, p_data->subrate_chg.timeout, p_data->subrate_chg.status); @@ -390,8 +391,8 @@ static bt_status_t btif_gatts_close(int server_if, const RawAddress& bd_addr, in static void on_service_added_cb(tGATT_STATUS status, int server_if, vector<btgatt_db_element_t> service) { - HAL_CBACK(bt_gatt_callbacks, server->service_added_cb, status, server_if, service.data(), - service.size()); + auto callbacks = bt_gatt_callbacks; + HAL_CBACK(callbacks, server->service_added_cb, status, server_if, service.data(), service.size()); } static void add_service_impl(int server_if, vector<btgatt_db_element_t> service) { @@ -401,7 +402,8 @@ static void add_service_impl(int server_if, vector<btgatt_db_element_t> service) if (service[0].uuid == Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER) || service[0].uuid == Uuid::From16Bit(UUID_SERVCLASS_GAP_SERVER)) { log::error("Attept to register restricted service"); - HAL_CBACK(bt_gatt_callbacks, server->service_added_cb, BT_STATUS_AUTH_REJECTED, server_if, + auto callbacks = bt_gatt_callbacks; + HAL_CBACK(callbacks, server->service_added_cb, BT_STATUS_AUTH_REJECTED, server_if, service.data(), service.size()); return; } @@ -448,7 +450,8 @@ static void btif_gatts_send_response_impl(int conn_id, int trans_id, int status, BTA_GATTS_SendRsp(conn_id, trans_id, static_cast<tGATT_STATUS>(status), &rsp_struct); - HAL_CBACK(bt_gatt_callbacks, server->response_confirmation_cb, 0, rsp_struct.attr_value.handle); + auto callbacks = bt_gatt_callbacks; + HAL_CBACK(callbacks, server->response_confirmation_cb, 0, rsp_struct.attr_value.handle); } static bt_status_t btif_gatts_send_response(int conn_id, int trans_id, int status, diff --git a/system/btif/src/btif_hh.cc b/system/btif/src/btif_hh.cc index 47907ae833..0114d2b42a 100644 --- a/system/btif/src/btif_hh.cc +++ b/system/btif/src/btif_hh.cc @@ -2186,6 +2186,7 @@ void DumpsysHid(int fd) { p_dev->reconnect_allowed ? "T" : "F"); } } + BTA_HhDump(fd); } namespace bluetooth { diff --git a/system/btif/src/btif_vc.cc b/system/btif/src/btif_vc.cc index 150141f118..9ff8db312a 100644 --- a/system/btif/src/btif_vc.cc +++ b/system/btif/src/btif_vc.cc @@ -60,10 +60,10 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, public VolumeC address)); } - void OnVolumeStateChanged(const RawAddress& address, uint8_t volume, bool mute, + void OnVolumeStateChanged(const RawAddress& address, uint8_t volume, bool mute, uint8_t flags, bool isAutonomous) override { do_in_jni_thread(Bind(&VolumeControlCallbacks::OnVolumeStateChanged, Unretained(callbacks_), - address, volume, mute, isAutonomous)); + address, volume, mute, flags, isAutonomous)); } void OnGroupVolumeStateChanged(int group_id, uint8_t volume, bool mute, diff --git a/system/btif/src/stack_manager.cc b/system/btif/src/stack_manager.cc index 3af74062d6..61099d65d8 100644 --- a/system/btif/src/stack_manager.cc +++ b/system/btif/src/stack_manager.cc @@ -63,6 +63,7 @@ #include "internal_include/stack_config.h" #include "rust/src/core/ffi/module.h" #include "stack/btm/btm_ble_int.h" +#include "stack/include/ais_api.h" #include "stack/include/smp_api.h" #ifndef BT_STACK_CLEANUP_WAIT_MS @@ -301,6 +302,7 @@ static void event_start_up_stack(bluetooth::core::CoreInterface* interface, RFCOMM_Init(); GAP_Init(); + AIS_Init(); startProfiles(); diff --git a/system/gd/hci/acl_manager/le_impl.h b/system/gd/hci/acl_manager/le_impl.h index 70b9962495..c88a1d62be 100644 --- a/system/gd/hci/acl_manager/le_impl.h +++ b/system/gd/hci/acl_manager/le_impl.h @@ -321,12 +321,18 @@ public: } } + void set_connectability_state(ConnectabilityState state) { + log::debug("{} --> {}", connectability_state_machine_text(connectability_state_), + connectability_state_machine_text(state)); + connectability_state_ = state; + } + // connection canceled by LeAddressManager.OnPause(), will auto reconnect by // LeAddressManager.OnResume() void on_le_connection_canceled_on_pause() { log::assert_that(pause_connection, "Connection must be paused to ack the le address manager"); arm_on_resume_ = true; - connectability_state_ = ConnectabilityState::DISARMED; + set_connectability_state(ConnectabilityState::DISARMED); le_address_manager_->AckPause(this); } @@ -394,7 +400,7 @@ public: const bool in_filter_accept_list = is_device_in_accept_list(remote_address); if (role == hci::Role::CENTRAL) { - connectability_state_ = ConnectabilityState::DISARMED; + set_connectability_state(ConnectabilityState::DISARMED); if (status == ErrorCode::UNKNOWN_CONNECTION && pause_connection) { on_le_connection_canceled_on_pause(); return; @@ -652,9 +658,11 @@ public: } void direct_connect_add(AddressWithType address_with_type) { + log::debug("{}", address_with_type); direct_connections_.insert(address_with_type); if (create_connection_timeout_alarms_.find(address_with_type) != create_connection_timeout_alarms_.end()) { + log::verbose("Timer already added for {}", address_with_type); return; } @@ -672,6 +680,7 @@ public: } void direct_connect_remove(AddressWithType address_with_type) { + log::debug("{}", address_with_type); auto it = create_connection_timeout_alarms_.find(address_with_type); if (it != create_connection_timeout_alarms_.end()) { it->second.Cancel(); @@ -691,6 +700,7 @@ public: return; } + log::debug("Adding device to accept list {}", address_with_type); accept_list.insert(address_with_type); register_with_address_manager(); le_address_manager_->AddDeviceToFilterAcceptList( @@ -752,8 +762,8 @@ public: if (status != ErrorCode::SUCCESS) { log::error("Le connection state machine armed failed status:{}", ErrorCodeText(status)); } - connectability_state_ = (status == ErrorCode::SUCCESS) ? ConnectabilityState::ARMED - : ConnectabilityState::DISARMED; + set_connectability_state((status == ErrorCode::SUCCESS) ? ConnectabilityState::ARMED + : ConnectabilityState::DISARMED); log::info("Le connection state machine armed state:{} status:{}", connectability_state_machine_text(connectability_state_), ErrorCodeText(status)); if (disarmed_while_arming_) { @@ -791,7 +801,7 @@ public: return; } AddressWithType empty(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS); - connectability_state_ = ConnectabilityState::ARMING; + set_connectability_state(ConnectabilityState::ARMING); connecting_le_ = accept_list; uint16_t le_scan_interval = @@ -905,7 +915,7 @@ public: switch (connectability_state_) { case ConnectabilityState::ARMED: log::info("Disarming LE connection state machine with create connection cancel"); - connectability_state_ = ConnectabilityState::DISARMING; + set_connectability_state(ConnectabilityState::DISARMING); le_acl_connection_interface_->EnqueueCommand( LeCreateConnectionCancelBuilder::Create(), handler_->BindOnce(&le_impl::on_create_connection_cancel_complete, @@ -964,6 +974,10 @@ public: return; } + log::verbose("{}, already_in_accept_list: {}, pause_connection {}, state: {}", + address_with_type, already_in_accept_list, pause_connection, + connectability_state_machine_text(connectability_state_)); + switch (connectability_state_) { case ConnectabilityState::ARMED: case ConnectabilityState::ARMING: diff --git a/system/gd/hci/acl_manager/le_impl_test.cc b/system/gd/hci/acl_manager/le_impl_test.cc index e7756ea79f..67c6c8c8ea 100644 --- a/system/gd/hci/acl_manager/le_impl_test.cc +++ b/system/gd/hci/acl_manager/le_impl_test.cc @@ -19,6 +19,7 @@ #include <bluetooth/log.h> #include <gmock/gmock.h> #include <gtest/gtest.h> +#include <log/log.h> #include <chrono> #include <future> @@ -237,6 +238,7 @@ public: class LeImplTest : public ::testing::Test { protected: void SetUp() override { + __android_log_set_minimum_priority(ANDROID_LOG_VERBOSE); thread_ = new Thread("thread", Thread::Priority::NORMAL); handler_ = new Handler(thread_); controller_ = new TestController(); @@ -1422,7 +1424,8 @@ TEST_F(LeImplTest, direct_connection_after_background_connection) { hci::AddressWithType address({0x21, 0x22, 0x23, 0x24, 0x25, 0x26}, AddressType::PUBLIC_DEVICE_ADDRESS); - // arrange: Create background connection + // arrange: Create background connection. Remember that acl_manager adds device background list + le_impl_->add_device_to_background_connection_list(address); le_impl_->create_le_connection(address, true, /* is_direct */ false); hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST); hci_layer_->IncomingEvent( @@ -1455,6 +1458,112 @@ TEST_F(LeImplTest, direct_connection_after_background_connection) { EXPECT_TRUE(direct_create_connection.IsValid()); log::info("Scan Interval {}", direct_create_connection.GetLeScanInterval()); ASSERT_NE(direct_create_connection.GetLeScanInterval(), bg_create_connection.GetLeScanInterval()); + + hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); + sync_handler(); + + // Check state is ARMED + ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_); + + // Simulate timeout on direct connect. Verify background connect is still in place + EXPECT_CALL(mock_le_connection_callbacks_, + OnLeConnectFail(_, ErrorCode::CONNECTION_ACCEPT_TIMEOUT)) + .Times(1); + le_impl_->on_create_connection_timeout(address); + sync_handler(); + cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL); + hci_layer_->IncomingEvent( + LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( + ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL, + AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000, + ClockAccuracy::PPM_30)); + EXPECT_TRUE(cancel_connection.IsValid()); + raw_bg_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION); + bg_create_connection = LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create( + AclCommandView::Create(raw_bg_create_connection))); + EXPECT_TRUE(bg_create_connection.IsValid()); + sync_handler(); + ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty()); + + hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); + sync_handler(); + + // Check state is ARMED + ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_); +} + +TEST_F(LeImplTest, direct_connection_after_direct_connection) { + set_random_device_address_policy(); + + hci::AddressWithType address({0x21, 0x22, 0x23, 0x24, 0x25, 0x26}, + AddressType::PUBLIC_DEVICE_ADDRESS); + + // Create first direct connection + le_impl_->create_le_connection(address, true, /* is_direct */ true); + hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST); + hci_layer_->IncomingEvent( + LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + auto raw_direct_1_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION); + hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); + sync_handler(); + + // Check state is ARMED + ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_); + + log::info("Second direct connect to the same device"); + + // Create second direct connection + le_impl_->create_le_connection(address, true, /* is_direct */ true); + sync_handler(); + + auto cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL); + if (cancel_connection.IsValid()) { + hci_layer_->IncomingEvent( + LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( + ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL, + AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000, + ClockAccuracy::PPM_30)); + } + + auto raw_direct_2_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION); + + // assert + auto direct_1_create_connection = + LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create( + AclCommandView::Create(raw_direct_1_create_connection))); + EXPECT_TRUE(direct_1_create_connection.IsValid()); + auto direct_2_create_connection = + LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create( + AclCommandView::Create(raw_direct_2_create_connection))); + EXPECT_TRUE(direct_2_create_connection.IsValid()); + hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); + sync_handler(); + + log::info("Simulate timeout"); + + EXPECT_CALL(mock_le_connection_callbacks_, + OnLeConnectFail(_, ErrorCode::CONNECTION_ACCEPT_TIMEOUT)) + .Times(1); + le_impl_->on_create_connection_timeout(address); + sync_handler(); + cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL); + EXPECT_TRUE(cancel_connection.IsValid()); + hci_layer_->IncomingEvent( + LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( + ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL, + AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000, + ClockAccuracy::PPM_30)); + sync_handler(); + ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty()); + + hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST); + hci_layer_->IncomingEvent( + LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + hci_layer_->AssertNoQueuedCommand(); + ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_); } } // namespace acl_manager diff --git a/system/gd/hci/acl_manager/round_robin_scheduler.cc b/system/gd/hci/acl_manager/round_robin_scheduler.cc index 77707f8b22..d7fda71edb 100644 --- a/system/gd/hci/acl_manager/round_robin_scheduler.cc +++ b/system/gd/hci/acl_manager/round_robin_scheduler.cc @@ -18,6 +18,9 @@ #include <bluetooth/log.h> +#include <memory> +#include <utility> + #include "hci/acl_manager/acl_fragmenter.h" namespace bluetooth { namespace hci { @@ -49,7 +52,10 @@ void RoundRobinScheduler::Register(ConnectionType connection_type, uint16_t hand acl_queue_handler acl_queue_handler = {connection_type, std::move(queue), false, 0}; acl_queue_handlers_.insert( std::pair<uint16_t, RoundRobinScheduler::acl_queue_handler>(handle, acl_queue_handler)); + log::info("registering acl_queue handle={}, acl_credits={}, le_credits={}", handle, + acl_packet_credits_, le_acl_packet_credits_); if (fragments_to_send_.size() == 0) { + log::info("start round robin"); start_round_robin(); } } @@ -58,6 +64,8 @@ void RoundRobinScheduler::Unregister(uint16_t handle) { log::assert_that(acl_queue_handlers_.count(handle) == 1, "assert failed: acl_queue_handlers_.count(handle) == 1"); auto acl_queue_handler = acl_queue_handlers_.find(handle)->second; + log::info("unregistering acl_queue handle={}, sent_packets={}", handle, + acl_queue_handler.number_of_sent_packets_); // Reclaim outstanding packets if (acl_queue_handler.connection_type_ == ConnectionType::CLASSIC) { acl_packet_credits_ += acl_queue_handler.number_of_sent_packets_; @@ -89,6 +97,7 @@ uint16_t RoundRobinScheduler::GetLeCredits() { return le_acl_packet_credits_; } void RoundRobinScheduler::start_round_robin() { if (acl_packet_credits_ == 0 && le_acl_packet_credits_ == 0) { + log::warn("Both buffers are full"); return; } if (!fragments_to_send_.empty()) { diff --git a/system/gd/hci/hci_layer_fake.cc b/system/gd/hci/hci_layer_fake.cc index eb350acc39..ca13230d31 100644 --- a/system/gd/hci/hci_layer_fake.cc +++ b/system/gd/hci/hci_layer_fake.cc @@ -57,11 +57,26 @@ static std::unique_ptr<AclBuilder> NextAclPacket(uint16_t handle) { return AclBuilder::Create(handle, packet_boundary_flag, broadcast_flag, NextPayload(handle)); } +static void DebugPrintCommandOpcode(std::string prefix, + const std::unique_ptr<CommandBuilder>& command) { + std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>(); + BitInserter it(*packet_bytes); + command->Serialize(it); + PacketView<kLittleEndian> packet_bytes_view(packet_bytes); + auto temp_cmd_view = CommandView::Create(packet_bytes_view); + temp_cmd_view.IsValid(); + auto op_code = temp_cmd_view.GetOpCode(); + + log::info("{} op_code: {}", prefix, OpCodeText(op_code)); +} + void HciLayerFake::EnqueueCommand( std::unique_ptr<CommandBuilder> command, common::ContextualOnceCallback<void(CommandStatusView)> on_status) { std::lock_guard<std::mutex> lock(mutex_); + DebugPrintCommandOpcode(std::string("Sending with command status, "), command); + command_queue_.push(std::move(command)); command_status_callbacks.push_back(std::move(on_status)); @@ -76,6 +91,8 @@ void HciLayerFake::EnqueueCommand( common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) { std::lock_guard<std::mutex> lock(mutex_); + DebugPrintCommandOpcode(std::string("Sending with command complete, "), command); + command_queue_.push(std::move(command)); command_complete_callbacks.push_back(std::move(on_complete)); diff --git a/system/gd/rust/topshim/Cargo.toml b/system/gd/rust/topshim/Cargo.toml index 73a8b37623..bc54e63a70 100644 --- a/system/gd/rust/topshim/Cargo.toml +++ b/system/gd/rust/topshim/Cargo.toml @@ -36,7 +36,7 @@ tokio-stream = "0.1" bitflags ="2.4.0" [build-dependencies] -bindgen = "0.64" +bindgen = "0.69.4" pkg-config = "0.3" [lib] diff --git a/system/gd/rust/topshim/vc/vc_shim.cc b/system/gd/rust/topshim/vc/vc_shim.cc index 4f17a16830..b7f9c80825 100644 --- a/system/gd/rust/topshim/vc/vc_shim.cc +++ b/system/gd/rust/topshim/vc/vc_shim.cc @@ -98,10 +98,10 @@ public: topshim::rust::internal::connection_state_cb(state, address); } - void OnVolumeStateChanged(const RawAddress& address, uint8_t volume, bool mute, + void OnVolumeStateChanged(const RawAddress& address, uint8_t volume, bool mute, uint8_t flags, bool is_autonomous) override { - log::info("address={}, volume={}, mute={}, is_autonomous={}", ADDRESS_TO_LOGGABLE_CSTR(address), - volume, mute, is_autonomous); + log::info("address={}, volume={}, mute={}, flags={}, is_autonomous={}", + ADDRESS_TO_LOGGABLE_CSTR(address), volume, mute, flags, is_autonomous); topshim::rust::internal::volume_state_cb(address, volume, mute, is_autonomous); } diff --git a/system/include/hardware/bt_vc.h b/system/include/hardware/bt_vc.h index 74ed814002..36aa2617ef 100644 --- a/system/include/hardware/bt_vc.h +++ b/system/include/hardware/bt_vc.h @@ -36,7 +36,7 @@ public: /* Callback for the volume change changed on the device */ virtual void OnVolumeStateChanged(const RawAddress& address, uint8_t volume, bool mute, - bool isAutonomous) = 0; + uint8_t flags, bool isAutonomous) = 0; /* Callback for the volume change changed on the group*/ virtual void OnGroupVolumeStateChanged(int group_id, uint8_t volume, bool mute, diff --git a/system/internal_include/bt_target.h b/system/internal_include/bt_target.h index 609dd68c6e..24e1cb32e0 100644 --- a/system/internal_include/bt_target.h +++ b/system/internal_include/bt_target.h @@ -17,8 +17,7 @@ * ******************************************************************************/ -#ifndef BT_TARGET_H -#define BT_TARGET_H +#pragma once #ifndef FALSE #define FALSE false @@ -39,10 +38,6 @@ #define BTUI_OPS_FORMATS (BTA_OP_VCARD21_MASK | BTA_OP_ANY_MASK) #endif -#ifndef BTA_RFC_MTU_SIZE -#define BTA_RFC_MTU_SIZE (L2CAP_MTU_SIZE - L2CAP_MIN_OFFSET - RFCOMM_DATA_OVERHEAD) -#endif - #ifndef BTA_PAN_INCLUDED #define BTA_PAN_INCLUDED TRUE #endif @@ -117,16 +112,6 @@ #define SDP_DATA_BUF_SIZE BT_DEFAULT_BUFFER_SIZE #endif -/* Sends RFCOMM command packets. */ -#ifndef RFCOMM_CMD_BUF_SIZE -#define RFCOMM_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE -#endif - -/* Sends RFCOMM data packets. */ -#ifndef RFCOMM_DATA_BUF_SIZE -#define RFCOMM_DATA_BUF_SIZE BT_DEFAULT_BUFFER_SIZE -#endif - /* Sends L2CAP packets to the peer and HCI messages to the controller. */ #ifndef L2CAP_CMD_BUF_SIZE #define L2CAP_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE @@ -489,72 +474,6 @@ /****************************************************************************** * - * RFCOMM - * - *****************************************************************************/ - -/* The maximum number of ports supported. */ -#ifndef MAX_RFC_PORTS -#define MAX_RFC_PORTS 30 -#endif - -/* The maximum simultaneous links to different devices. */ -#ifndef MAX_BD_CONNECTIONS -#define MAX_BD_CONNECTIONS 16 -#endif - -/* The port receive queue low watermark level, in bytes. */ -#ifndef PORT_RX_LOW_WM -#define PORT_RX_LOW_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_LOW_WM) -#endif - -/* The port receive queue high watermark level, in bytes. */ -#ifndef PORT_RX_HIGH_WM -#define PORT_RX_HIGH_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_HIGH_WM) -#endif - -/* The port receive queue critical watermark level, in bytes. */ -#ifndef PORT_RX_CRITICAL_WM -#define PORT_RX_CRITICAL_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_CRITICAL_WM) -#endif - -/* The port receive queue low watermark level, in number of buffers. */ -#ifndef PORT_RX_BUF_LOW_WM -#define PORT_RX_BUF_LOW_WM 4 -#endif - -/* The port receive queue high watermark level, in number of buffers. */ -#ifndef PORT_RX_BUF_HIGH_WM -#define PORT_RX_BUF_HIGH_WM 10 -#endif - -/* The port receive queue critical watermark level, in number of buffers. */ -#ifndef PORT_RX_BUF_CRITICAL_WM -#define PORT_RX_BUF_CRITICAL_WM 15 -#endif - -/* The port transmit queue high watermark level, in bytes. */ -#ifndef PORT_TX_HIGH_WM -#define PORT_TX_HIGH_WM (BTA_RFC_MTU_SIZE * PORT_TX_BUF_HIGH_WM) -#endif - -/* The port transmit queue critical watermark level, in bytes. */ -#ifndef PORT_TX_CRITICAL_WM -#define PORT_TX_CRITICAL_WM (BTA_RFC_MTU_SIZE * PORT_TX_BUF_CRITICAL_WM) -#endif - -/* The port transmit queue high watermark level, in number of buffers. */ -#ifndef PORT_TX_BUF_HIGH_WM -#define PORT_TX_BUF_HIGH_WM 10 -#endif - -/* The port transmit queue high watermark level, in number of buffers. */ -#ifndef PORT_TX_BUF_CRITICAL_WM -#define PORT_TX_BUF_CRITICAL_WM 15 -#endif - -/****************************************************************************** - * * BNEP * *****************************************************************************/ @@ -766,11 +685,3 @@ #ifndef BTA_EIR_SERVER_NUM_CUSTOM_UUID #define BTA_EIR_SERVER_NUM_CUSTOM_UUID 8 #endif - -/****************************************************************************** - * - * Tracing: Include trace header file here. - * - *****************************************************************************/ - -#endif /* BT_TARGET_H */ diff --git a/system/profile/avrcp/device.cc b/system/profile/avrcp/device.cc index fc0f3cd921..d34f6abbb0 100644 --- a/system/profile/avrcp/device.cc +++ b/system/profile/avrcp/device.cc @@ -1505,8 +1505,8 @@ void Device::SetBrowsedPlayerResponse(uint8_t label, std::shared_ptr<SetBrowsedP current_path_ = std::stack<std::string>(); current_path_.push(root_id); - auto response = - SetBrowsedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR, 0x0000, num_items, 0, ""); + auto response = SetBrowsedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR, 0x0000, num_items, + 0, root_id); send_message(label, true, std::move(response)); } diff --git a/system/rust/src/connection/ffi.rs b/system/rust/src/connection/ffi.rs index 012045f0e3..587ff3b460 100644 --- a/system/rust/src/connection/ffi.rs +++ b/system/rust/src/connection/ffi.rs @@ -56,8 +56,10 @@ mod inner { /// Register Rust callbacks for connection events /// /// # Safety + /// /// `callbacks` must be Send + Sync, since C++ moves it to a different thread and /// invokes it from several others (GD + legacy threads). + #[allow(clippy::missing_safety_doc)] #[cxx_name = "RegisterRustCallbacks"] unsafe fn unchecked_register_rust_callbacks( self: Pin<&mut Self>, diff --git a/system/rust/src/core/ffi/module.cc b/system/rust/src/core/ffi/module.cc index cfee5cf84e..f43e19a1f8 100644 --- a/system/rust/src/core/ffi/module.cc +++ b/system/rust/src/core/ffi/module.cc @@ -53,7 +53,8 @@ namespace { future_t* Start() { auto fut = future_new(); - if (bt_gatt_callbacks == nullptr) { + auto callbacks = bt_gatt_callbacks; + if (callbacks == nullptr) { // We can't crash here since some adapter tests mis-use the stack // startup/cleanup logic and start the stack without GATT, but don't fully // mock out the native layer. @@ -64,7 +65,7 @@ future_t* Start() { return fut; } bluetooth::rust_shim::start( - std::make_unique<bluetooth::gatt::GattServerCallbacks>(*bt_gatt_callbacks->server), + std::make_unique<bluetooth::gatt::GattServerCallbacks>(*callbacks->server), std::make_unique<bluetooth::connection::LeAclManagerShim>(), *fut); return fut; diff --git a/system/stack/Android.bp b/system/stack/Android.bp index 1d6376c90d..d6c88e0dfa 100644 --- a/system/stack/Android.bp +++ b/system/stack/Android.bp @@ -38,6 +38,7 @@ cc_library_static { name: "libbt-stack", defaults: ["fluoride_defaults"], local_include_dirs: [ + "ais", "avct", "avdt", "avrc", @@ -180,6 +181,7 @@ cc_library_static { name: "libbt-stack-core", defaults: ["fluoride_defaults"], local_include_dirs: [ + "ais", "avct", "avdt", "avrc", @@ -213,6 +215,7 @@ cc_library_static { "acl/ble_acl.cc", "acl/btm_acl.cc", "acl/btm_pm.cc", + "ais/ais_ble.cc", "arbiter/acl_arbiter.cc", "btm/ble_scanner_hci_interface.cc", "btm/btm_ble.cc", @@ -517,6 +520,7 @@ cc_fuzz { ":TestMockStackL2cap", ":TestMockStackMetrics", ":TestMockStackSdp", + "ais/*.cc", "eatt/*.cc", "fuzzers/gatt_fuzzer.cc", "gatt/*.cc", @@ -1973,6 +1977,7 @@ cc_test { ":TestMockStackL2cap", ":TestMockStackSdp", ":TestMockStackSmp", + "ais/ais_ble.cc", "arbiter/acl_arbiter.cc", "eatt/eatt.cc", "gatt/att_protocol.cc", diff --git a/system/stack/BUILD.gn b/system/stack/BUILD.gn index 2581035379..68d5136db0 100644 --- a/system/stack/BUILD.gn +++ b/system/stack/BUILD.gn @@ -53,6 +53,7 @@ source_set("nonstandard_codecs") { source_set("stack") { sources = [ + "ais/ais_ble.cc", "a2dp/a2dp_api.cc", "a2dp/a2dp_codec_config.cc", "a2dp/a2dp_ext.cc", @@ -187,6 +188,7 @@ source_set("stack") { include_dirs = [ ".", "include", + "ais", "avct", "btm", "avrc", diff --git a/system/stack/ais/ais_ble.cc b/system/stack/ais/ais_ble.cc new file mode 100644 index 0000000000..f545fc7981 --- /dev/null +++ b/system/stack/ais/ais_ble.cc @@ -0,0 +1,144 @@ +/****************************************************************************** + * + * Copyright 2024 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. + * + ******************************************************************************/ + +#include <bluetooth/log.h> +#include <com_android_bluetooth_flags.h> +#include <string.h> + +#include <array> + +#include "os/system_properties.h" +#include "stack/include/ais_api.h" +#include "stack/include/bt_types.h" +#include "stack/include/gatt_api.h" +#include "types/bluetooth/uuid.h" + +using bluetooth::Uuid; +using bluetooth::log::error; +using bluetooth::log::warn; + +static const char kPropertyAndroidAPILevel[] = "ro.build.version.sdk"; +static const uint32_t kPropertyAndroidAPILevelDefault = 0; + +const Uuid ANDROID_INFORMATION_SERVICE_UUID = + Uuid::FromString(ANDROID_INFORMATION_SERVICE_UUID_STRING); +const Uuid GATT_UUID_AIS_API_LEVEL = Uuid::FromString(GATT_UUID_AIS_API_LEVEL_STRING); + +/* LE AIS attribute handle */ +static uint16_t attr_api_level_handle; + +static uint32_t api_level; + +void ais_request_cback(uint16_t, uint32_t, tGATTS_REQ_TYPE, tGATTS_DATA*); + +static tGATT_CBACK ais_cback = { + .p_conn_cb = nullptr, + .p_cmpl_cb = nullptr, + .p_disc_res_cb = nullptr, + .p_disc_cmpl_cb = nullptr, + .p_req_cb = ais_request_cback, + .p_enc_cmpl_cb = nullptr, + .p_congestion_cb = nullptr, + .p_phy_update_cb = nullptr, + .p_conn_update_cb = nullptr, + .p_subrate_chg_cb = nullptr, +}; + +/** AIS ATT server attribute access request callback */ +void ais_request_cback(uint16_t conn_id, uint32_t trans_id, tGATTS_REQ_TYPE type, + tGATTS_DATA* p_data) { + tGATT_STATUS status = GATT_INVALID_PDU; + tGATTS_RSP rsp_msg = {}; + uint16_t handle = p_data->read_req.handle; + tGATT_VALUE* p_value = &rsp_msg.attr_value; + uint8_t* p = p_value->value; + + if (type == GATTS_REQ_TYPE_READ_CHARACTERISTIC) { + p_value->handle = handle; + + if (handle == attr_api_level_handle) { + if (p_data->read_req.is_long) { + p_value->offset = p_data->read_req.offset; + status = GATT_NOT_LONG; + } else { + UINT32_TO_STREAM(p, api_level); + p_value->len = 4; + status = GATT_SUCCESS; + } + } else { + status = GATT_NOT_FOUND; + } + } else { + warn("Unknown/unexpected LE AIS ATT request: 0x{:02x}", type); + } + + if (GATTS_SendRsp(conn_id, trans_id, status, &rsp_msg) != GATT_SUCCESS) { + warn("Unable to send GATT server response conn_id:{}", conn_id); + } +} + +/******************************************************************************* + * + * Function ais_attr_db_init + * + * Description AIS ATT database initialization. + * + * Returns void. + * + ******************************************************************************/ +void ais_attr_db_init(void) { + if (!com::android::bluetooth::flags::android_os_identifier()) { + return; + } + api_level = bluetooth::os::GetSystemPropertyUint32(kPropertyAndroidAPILevel, + kPropertyAndroidAPILevelDefault); + // Add Android OS identifier if API level is defined. + if (api_level != kPropertyAndroidAPILevelDefault) { + std::array<uint8_t, Uuid::kNumBytes128> tmp; + tmp.fill(0xc5); // any number is fine here + Uuid app_uuid = Uuid::From128BitBE(tmp); + + tGATT_IF gatt_if = GATT_Register(app_uuid, "Ais", &ais_cback, false); + + GATT_StartIf(gatt_if); + + btgatt_db_element_t android_information_service[] = { + { + .uuid = ANDROID_INFORMATION_SERVICE_UUID, + .type = BTGATT_DB_PRIMARY_SERVICE, + }, + { + .uuid = GATT_UUID_AIS_API_LEVEL, + .type = BTGATT_DB_CHARACTERISTIC, + .properties = GATT_CHAR_PROP_BIT_READ, + .permissions = GATT_PERM_READ_IF_ENCRYPTED_OR_DISCOVERABLE, + }}; + if (GATTS_AddService(gatt_if, android_information_service, + sizeof(android_information_service) / sizeof(btgatt_db_element_t)) != + GATT_SERVICE_STARTED) { + error("Unable to add Android Information Server gatt_if:{}", gatt_if); + } + + attr_api_level_handle = android_information_service[1].attribute_handle; + } +} + +/* + * This routine should not be called except once per stack invocation. + */ +void AIS_Init(void) { ais_attr_db_init(); } diff --git a/system/stack/fuzzers/gatt_fuzzer.cc b/system/stack/fuzzers/gatt_fuzzer.cc index a98f674e72..409e62c1da 100644 --- a/system/stack/fuzzers/gatt_fuzzer.cc +++ b/system/stack/fuzzers/gatt_fuzzer.cc @@ -49,6 +49,9 @@ namespace os { bool GetSystemPropertyBool(const std::string& property, bool default_value) { return default_value; } +uint32_t GetSystemPropertyUint32(const std::string& property, uint32_t default_value) { + return default_value; +} } // namespace os } // namespace bluetooth diff --git a/system/stack/gatt/connection_manager.cc b/system/stack/gatt/connection_manager.cc index deddf506f7..ccd902da00 100644 --- a/system/stack/gatt/connection_manager.cc +++ b/system/stack/gatt/connection_manager.cc @@ -366,7 +366,11 @@ bool background_connect_remove(uint8_t app_id, const RawAddress& address) { } bool is_background_connection(const RawAddress& address) { - return bgconn_dev.find(address) != bgconn_dev.end(); + auto it = bgconn_dev.find(address); + if (it == bgconn_dev.end()) { + return false; + } + return it->second.is_in_accept_list; } /** deregister all related background connetion device. */ diff --git a/system/stack/gatt/gatt_api.cc b/system/stack/gatt/gatt_api.cc index bc9fcc622c..dff5e42974 100644 --- a/system/stack/gatt/gatt_api.cc +++ b/system/stack/gatt/gatt_api.cc @@ -41,6 +41,7 @@ #include "stack/btm/btm_dev.h" #include "stack/gatt/connection_manager.h" #include "stack/gatt/gatt_int.h" +#include "stack/include/ais_api.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_uuid16.h" #include "stack/include/l2cap_acl_interface.h" @@ -72,6 +73,9 @@ tGATT_HDL_LIST_ELEM& gatt_add_an_item_to_list(uint16_t s_handle) { return *rit; } +static tGATT_IF GATT_Register_Dynamic(const Uuid& app_uuid128, const std::string& name, + tGATT_CBACK* p_cb_info, bool eatt_support); + /***************************************************************************** * * GATT SERVER API @@ -320,8 +324,10 @@ tGATT_STATUS GATTS_AddService(tGATT_IF gatt_if, btgatt_db_element_t* service, in Uuid* p_uuid = gatts_get_service_uuid(elem.p_db); if (*p_uuid != Uuid::From16Bit(UUID_SERVCLASS_GMCS_SERVER) && *p_uuid != Uuid::From16Bit(UUID_SERVCLASS_GTBS_SERVER)) { - if (com::android::bluetooth::flags::channel_sounding_in_stack() && - *p_uuid == Uuid::From16Bit(UUID_SERVCLASS_RAS)) { + if ((com::android::bluetooth::flags::channel_sounding_in_stack() && + *p_uuid == Uuid::From16Bit(UUID_SERVCLASS_RAS)) || + (com::android::bluetooth::flags::android_os_identifier() && + *p_uuid == ANDROID_INFORMATION_SERVICE_UUID)) { elem.sdp_handle = 0; } else { elem.sdp_handle = gatt_add_sdp_record(*p_uuid, elem.s_hdl, elem.e_hdl); @@ -1216,6 +1222,9 @@ void GATT_SetIdleTimeout(const RawAddress& bd_addr, uint16_t idle_tout, tBT_TRAN ******************************************************************************/ tGATT_IF GATT_Register(const Uuid& app_uuid128, const std::string& name, tGATT_CBACK* p_cb_info, bool eatt_support) { + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + return GATT_Register_Dynamic(app_uuid128, name, p_cb_info, eatt_support); + } tGATT_REG* p_reg; uint8_t i_gatt_if = 0; tGATT_IF gatt_if = 0; @@ -1252,6 +1261,54 @@ tGATT_IF GATT_Register(const Uuid& app_uuid128, const std::string& name, tGATT_C return 0; } +static tGATT_IF GATT_Register_Dynamic(const Uuid& app_uuid128, const std::string& name, + tGATT_CBACK* p_cb_info, bool eatt_support) { + for (auto& [gatt_if, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->app_uuid128 == app_uuid128) { + log::error("Application already registered, uuid={}", app_uuid128.ToString()); + return 0; + } + } + + if (stack_config_get_interface()->get_pts_use_eatt_for_all_services()) { + log::info("PTS: Force to use EATT for servers"); + eatt_support = true; + } + + if (gatt_cb.cl_rcb_map.size() >= GATT_CL_RCB_MAX) { + log::error("Unable to register GATT client, MAX client reached: {}", gatt_cb.cl_rcb_map.size()); + return 0; + } + + uint8_t i_gatt_if = gatt_cb.next_gatt_if; + for (int i = 0; i < GATT_CL_RCB_MAX; i++) { + if (gatt_cb.cl_rcb_map.find(static_cast<tGATT_IF>(i_gatt_if)) == gatt_cb.cl_rcb_map.end()) { + gatt_cb.cl_rcb_map.emplace(i_gatt_if, std::make_unique<tGATT_REG>()); + tGATT_REG* p_reg = gatt_cb.cl_rcb_map[i_gatt_if].get(); + p_reg->app_uuid128 = app_uuid128; + p_reg->gatt_if = (tGATT_IF)i_gatt_if; + p_reg->app_cb = *p_cb_info; + p_reg->in_use = true; + p_reg->eatt_support = eatt_support; + p_reg->name = name; + log::info("Allocated name:{} uuid:{} gatt_if:{} eatt_support:{}", name, + app_uuid128.ToString(), p_reg->gatt_if, eatt_support); + + gatt_cb.next_gatt_if = (tGATT_IF)(i_gatt_if + 1); + if (gatt_cb.next_gatt_if == 0) { + gatt_cb.next_gatt_if = 1; + } + } + i_gatt_if++; + if (i_gatt_if == 0) { + i_gatt_if = 1; + } + } + + log::error("Unable to register GATT client, MAX client reached: {}", gatt_cb.cl_rcb_map.size()); + return 0; +} + /******************************************************************************* * * Function GATT_Deregister @@ -1319,7 +1376,11 @@ void GATT_Deregister(tGATT_IF gatt_if) { connection_manager::on_app_deregistered(gatt_if); } - *p_reg = {}; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + gatt_cb.cl_rcb_map.erase(gatt_if); + } else { + *p_reg = {}; + } } /******************************************************************************* diff --git a/system/stack/gatt/gatt_auth.cc b/system/stack/gatt/gatt_auth.cc index 5d47fc1555..8b893e2354 100644 --- a/system/stack/gatt/gatt_auth.cc +++ b/system/stack/gatt/gatt_auth.cc @@ -23,6 +23,7 @@ ******************************************************************************/ #include <bluetooth/log.h> +#include <com_android_bluetooth_flags.h> #include <string.h> #include "gatt_api.h" @@ -214,9 +215,17 @@ void gatt_notify_enc_cmpl(const RawAddress& bd_addr) { return; } - for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { - if (gatt_cb.cl_rcb[i].in_use && gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb) { - (*gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb)(gatt_cb.cl_rcb[i].gatt_if, bd_addr); + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& [i, p_rcb] : gatt_cb.cl_rcb_map) { + if (p_rcb->app_cb.p_enc_cmpl_cb) { + (*p_rcb->app_cb.p_enc_cmpl_cb)(p_rcb->gatt_if, bd_addr); + } + } + } else { + for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { + if (gatt_cb.cl_rcb[i].in_use && gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb) { + (*gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb)(gatt_cb.cl_rcb[i].gatt_if, bd_addr); + } } } diff --git a/system/stack/gatt/gatt_cl.cc b/system/stack/gatt/gatt_cl.cc index 3975c92098..9d4577eda1 100644 --- a/system/stack/gatt/gatt_cl.cc +++ b/system/stack/gatt/gatt_cl.cc @@ -25,6 +25,7 @@ #define LOG_TAG "bluetooth" #include <bluetooth/log.h> +#include <com_android_bluetooth_flags.h> #include <string.h> #include "gatt_int.h" @@ -696,9 +697,17 @@ void gatt_process_notification(tGATT_TCB& tcb, uint16_t cid, uint8_t op_code, ui // notification/indication // Note: need to do the indication count and start timer first then do // callback - for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { - if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { - tcb.ind_count++; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { + tcb.ind_count++; + } + } + } else { + for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { + if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { + tcb.ind_count++; + } } } @@ -718,10 +727,19 @@ void gatt_process_notification(tGATT_TCB& tcb, uint16_t cid, uint8_t op_code, ui gatt_cl_complete.att_value = value; gatt_cl_complete.cid = cid; - for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { - if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { - conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status, &gatt_cl_complete); + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { + conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status, &gatt_cl_complete); + } + } + } else { + for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { + if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { + conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status, &gatt_cl_complete); + } } } @@ -759,10 +777,19 @@ void gatt_process_notification(tGATT_TCB& tcb, uint16_t cid, uint8_t op_code, ui gatt_cl_complete.att_value = value; gatt_cl_complete.cid = cid; - for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { - if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { - conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status, &gatt_cl_complete); + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { + conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status, &gatt_cl_complete); + } + } + } else { + for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { + if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { + conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status, &gatt_cl_complete); + } } } } diff --git a/system/stack/gatt/gatt_int.h b/system/stack/gatt/gatt_int.h index 998e401371..5ab2bf8454 100644 --- a/system/stack/gatt/gatt_int.h +++ b/system/stack/gatt/gatt_int.h @@ -43,6 +43,7 @@ #define GATT_GET_GATT_IF(conn_id) ((tGATT_IF)((uint8_t)(conn_id))) #define GATT_TRANS_ID_MAX 0x0fffffff /* 4 MSB is reserved */ +#define GATT_CL_RCB_MAX 255 /* Maximum number of cl_rcb */ /* security action for GATT write and read request */ typedef enum : uint8_t { @@ -228,6 +229,7 @@ typedef struct { uint8_t op_code; uint8_t status; uint8_t cback_cnt[GATT_MAX_APPS]; + std::unordered_map<tGATT_IF, uint8_t> cback_cnt_map; uint16_t cid; } tGATT_SR_CMD; @@ -315,6 +317,7 @@ typedef struct { alarm_t* conf_timer; /* peer confirm to indication timer */ uint8_t prep_cnt[GATT_MAX_APPS]; + std::unordered_map<tGATT_IF, uint8_t> prep_cnt_map; uint8_t ind_count; std::deque<tGATT_CMD_Q> cl_cmd_q; @@ -414,6 +417,9 @@ typedef struct { fixed_queue_t* srv_chg_clt_q; /* service change clients queue */ tGATT_REG cl_rcb[GATT_MAX_APPS]; + tGATT_IF next_gatt_if; /* potential next gatt if, should be greater than 0 */ + std::unordered_map<tGATT_IF, std::unique_ptr<tGATT_REG>> cl_rcb_map; + /* list of connection link control blocks. * Since clcbs are also keep in the channels (ATT and EATT) queues while * processing, we want to make sure that references to elements are not @@ -461,6 +467,7 @@ void gatt_set_err_rsp(bool enable, uint8_t req_op_code, uint8_t err_status); /* from gatt_main.cc */ bool gatt_disconnect(tGATT_TCB* p_tcb); +void gatt_cancel_connect(const RawAddress& bd_addr, tBT_TRANSPORT transport); bool gatt_act_connect(tGATT_REG* p_reg, const RawAddress& bd_addr, tBT_TRANSPORT transport, int8_t initiating_phys); bool gatt_act_connect(tGATT_REG* p_reg, const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, diff --git a/system/stack/gatt/gatt_main.cc b/system/stack/gatt/gatt_main.cc index 88ef13fe01..f8d6406610 100644 --- a/system/stack/gatt/gatt_main.cc +++ b/system/stack/gatt/gatt_main.cc @@ -113,6 +113,9 @@ void gatt_init(void) { connection_manager::reset(true); memset(&fixed_reg, 0, sizeof(tL2CAP_FIXED_CHNL_REG)); + // To catch a potential OOB. + gatt_cb.next_gatt_if = 40; + gatt_cb.sign_op_queue = fixed_queue_new(SIZE_MAX); gatt_cb.srv_chg_clt_q = fixed_queue_new(SIZE_MAX); /* First, register fixed L2CAP channel for ATT over BLE */ @@ -235,6 +238,39 @@ bool gatt_connect(const RawAddress& rem_bda, tGATT_TCB* p_tcb, tBT_TRANSPORT tra uint8_t initiating_phys, tGATT_IF gatt_if) { return gatt_connect(rem_bda, BLE_ADDR_PUBLIC, p_tcb, transport, initiating_phys, gatt_if); } + +/******************************************************************************* + * + * Function gatt_cancel_connect + * + * Description This will remove device from allow list and cancel connection + * + * Parameter bd_addr: peer device address. + * transport: transport + * + * + ******************************************************************************/ +void gatt_cancel_connect(const RawAddress& bd_addr, tBT_TRANSPORT transport) { + /* This shall be call only when device is not connected */ + log::debug("{}, transport {}", bd_addr, transport); + + if (bluetooth::common::init_flags::use_unified_connection_manager_is_enabled()) { + // TODO(aryarahul): this might not be necessary now that the connection + // manager handles GATT client closure correctly in GATT_Deregister + bluetooth::connection::GetConnectionManager().stop_all_connections_to_device( + bluetooth::connection::ResolveRawAddress(bd_addr)); + } else { + if (!connection_manager::direct_connect_remove(CONN_MGR_ID_L2CAP, bd_addr)) { + BTM_AcceptlistRemove(bd_addr); + log::info( + "GATT connection manager has no record but removed filter " + "acceptlist gatt_if:{} peer:{}", + static_cast<uint8_t>(CONN_MGR_ID_L2CAP), bd_addr); + } + } + gatt_cleanup_upon_disc(bd_addr, GATT_CONN_TERMINATE_LOCAL_HOST, transport); +} + /******************************************************************************* * * Function gatt_disconnect @@ -269,22 +305,7 @@ bool gatt_disconnect(tGATT_TCB* p_tcb) { } gatt_set_ch_state(p_tcb, GATT_CH_CLOSING); } else { - if (bluetooth::common::init_flags::use_unified_connection_manager_is_enabled()) { - // TODO(aryarahul): this might not be necessary now that the connection - // manager handles GATT client closure correctly in GATT_Deregister - bluetooth::connection::GetConnectionManager().stop_all_connections_to_device( - bluetooth::connection::ResolveRawAddress(p_tcb->peer_bda)); - } else { - if (!connection_manager::direct_connect_remove(CONN_MGR_ID_L2CAP, p_tcb->peer_bda)) { - BTM_AcceptlistRemove(p_tcb->peer_bda); - log::info( - "GATT connection manager has no record but removed filter " - "acceptlist gatt_if:{} peer:{}", - static_cast<uint8_t>(CONN_MGR_ID_L2CAP), p_tcb->peer_bda); - } - } - - gatt_cleanup_upon_disc(p_tcb->peer_bda, GATT_CONN_TERMINATE_LOCAL_HOST, p_tcb->transport); + gatt_cancel_connect(p_tcb->peer_bda, p_tcb->transport); } } else { if ((ch_state == GATT_CH_OPEN) || (ch_state == GATT_CH_CFG)) { @@ -607,13 +628,22 @@ static void gatt_channel_congestion(tGATT_TCB* p_tcb, bool congested) { gatt_cl_send_next_cmd_inq(*p_tcb); } /* notifying all applications for the connection up event */ - for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { - if (p_reg->in_use) { - if (p_reg->app_cb.p_congestion_cb) { + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_congestion_cb) { conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); (*p_reg->app_cb.p_congestion_cb)(conn_id, congested); } } + } else { + for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { + if (p_reg->in_use) { + if (p_reg->app_cb.p_congestion_cb) { + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_congestion_cb)(conn_id, congested); + } + } + } } } @@ -632,11 +662,20 @@ void gatt_notify_phy_updated(tHCI_STATUS status, uint16_t handle, uint8_t tx_phy // TODO: Clean up this status conversion. tGATT_STATUS gatt_status = static_cast<tGATT_STATUS>(status); - for (int i = 0; i < GATT_MAX_APPS; i++) { - tGATT_REG* p_reg = &gatt_cb.cl_rcb[i]; - if (p_reg->in_use && p_reg->app_cb.p_phy_update_cb) { - uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_phy_update_cb)(p_reg->gatt_if, conn_id, tx_phy, rx_phy, gatt_status); + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_phy_update_cb) { + uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_phy_update_cb)(p_reg->gatt_if, conn_id, tx_phy, rx_phy, gatt_status); + } + } + } else { + for (int i = 0; i < GATT_MAX_APPS; i++) { + tGATT_REG* p_reg = &gatt_cb.cl_rcb[i]; + if (p_reg->in_use && p_reg->app_cb.p_phy_update_cb) { + uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_phy_update_cb)(p_reg->gatt_if, conn_id, tx_phy, rx_phy, gatt_status); + } } } } @@ -649,12 +688,22 @@ void gatt_notify_conn_update(const RawAddress& remote, uint16_t interval, uint16 return; } - for (int i = 0; i < GATT_MAX_APPS; i++) { - tGATT_REG* p_reg = &gatt_cb.cl_rcb[i]; - if (p_reg->in_use && p_reg->app_cb.p_conn_update_cb) { - uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_conn_update_cb)(p_reg->gatt_if, conn_id, interval, latency, timeout, - static_cast<tGATT_STATUS>(status)); + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_conn_update_cb) { + uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_conn_update_cb)(p_reg->gatt_if, conn_id, interval, latency, timeout, + static_cast<tGATT_STATUS>(status)); + } + } + } else { + for (int i = 0; i < GATT_MAX_APPS; i++) { + tGATT_REG* p_reg = &gatt_cb.cl_rcb[i]; + if (p_reg->in_use && p_reg->app_cb.p_conn_update_cb) { + uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_conn_update_cb)(p_reg->gatt_if, conn_id, interval, latency, timeout, + static_cast<tGATT_STATUS>(status)); + } } } } @@ -672,12 +721,22 @@ void gatt_notify_subrate_change(uint16_t handle, uint16_t subrate_factor, uint16 return; } - for (int i = 0; i < GATT_MAX_APPS; i++) { - tGATT_REG* p_reg = &gatt_cb.cl_rcb[i]; - if (p_reg->in_use && p_reg->app_cb.p_subrate_chg_cb) { - uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_subrate_chg_cb)(p_reg->gatt_if, conn_id, subrate_factor, latency, cont_num, - timeout, static_cast<tGATT_STATUS>(status)); + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_subrate_chg_cb) { + uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_subrate_chg_cb)(p_reg->gatt_if, conn_id, subrate_factor, latency, + cont_num, timeout, static_cast<tGATT_STATUS>(status)); + } + } + } else { + for (int i = 0; i < GATT_MAX_APPS; i++) { + tGATT_REG* p_reg = &gatt_cb.cl_rcb[i]; + if (p_reg->in_use && p_reg->app_cb.p_subrate_chg_cb) { + uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_subrate_chg_cb)(p_reg->gatt_if, conn_id, subrate_factor, latency, + cont_num, timeout, static_cast<tGATT_STATUS>(status)); + } } } } @@ -927,28 +986,56 @@ static void gatt_send_conn_cback(tGATT_TCB* p_tcb) { } /* notifying all applications for the connection up event */ - for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { - if (!p_reg->in_use) { - continue; - } - if (apps.find(p_reg->gatt_if) != apps.end()) { - gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, true); - } + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (!p_reg->in_use) { + continue; + } - if (com::android::bluetooth::flags::gatt_reconnect_on_bt_on_fix()) { - if (p_reg->direct_connect_request.count(p_tcb->peer_bda) > 0) { + if (apps.find(p_reg->gatt_if) != apps.end()) { gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, true); - log::info("Removing device {} from the direct connect list of gatt_if {}", p_tcb->peer_bda, - p_reg->gatt_if); - p_reg->direct_connect_request.erase(p_tcb->peer_bda); + } + + if (com::android::bluetooth::flags::gatt_reconnect_on_bt_on_fix()) { + if (p_reg->direct_connect_request.count(p_tcb->peer_bda) > 0) { + gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, true); + log::info("Removing device {} from the direct connect list of gatt_if {}", + p_tcb->peer_bda, p_reg->gatt_if); + p_reg->direct_connect_request.erase(p_tcb->peer_bda); + } + } + + if (p_reg->app_cb.p_conn_cb) { + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id, kGattConnected, + GATT_CONN_OK, p_tcb->transport); } } + } else { + for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { + if (!p_reg->in_use) { + continue; + } - if (p_reg->app_cb.p_conn_cb) { - conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id, kGattConnected, - GATT_CONN_OK, p_tcb->transport); + if (apps.find(p_reg->gatt_if) != apps.end()) { + gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, true); + } + + if (com::android::bluetooth::flags::gatt_reconnect_on_bt_on_fix()) { + if (p_reg->direct_connect_request.count(p_tcb->peer_bda) > 0) { + gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, true); + log::info("Removing device {} from the direct connect list of gatt_if {}", + p_tcb->peer_bda, p_reg->gatt_if); + p_reg->direct_connect_request.erase(p_tcb->peer_bda); + } + } + + if (p_reg->app_cb.p_conn_cb) { + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id, kGattConnected, + GATT_CONN_OK, p_tcb->transport); + } } } diff --git a/system/stack/gatt/gatt_sr.cc b/system/stack/gatt/gatt_sr.cc index 6506ec47fa..c85949f02e 100644 --- a/system/stack/gatt/gatt_sr.cc +++ b/system/stack/gatt/gatt_sr.cc @@ -23,6 +23,7 @@ ******************************************************************************/ #include <bluetooth/log.h> +#include <com_android_bluetooth_flags.h> #include <string.h> #include <algorithm> @@ -208,7 +209,7 @@ static void build_read_multi_rsp(tGATT_SR_CMD* p_cmd, uint16_t mtu) { len = std::min((size_t)p_rsp->attr_value.len, mtu - total_len); - if (len == 0) { + if (total_len == mtu && p_rsp->attr_value.len > 0) { log::verbose("Buffer space not enough for this data item, skipping"); break; } @@ -401,14 +402,26 @@ void gatt_process_exec_write_req(tGATT_TCB& tcb, uint16_t cid, uint8_t op_code, trans_id = gatt_sr_enqueue_cmd(tcb, cid, op_code, 0); gatt_sr_copy_prep_cnt_to_cback_cnt(tcb); - for (i = 0; i < GATT_MAX_APPS; i++) { - if (tcb.prep_cnt[i]) { - gatt_if = (tGATT_IF)(i + 1); + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + auto prep_cnt_it = tcb.prep_cnt_map.begin(); + while (prep_cnt_it != tcb.prep_cnt_map.end()) { + gatt_if = i; conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, gatt_if); tGATTS_DATA gatts_data; gatts_data.exec_write = flag; gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_WRITE_EXEC, &gatts_data); - tcb.prep_cnt[i] = 0; + prep_cnt_it = tcb.prep_cnt_map.erase(prep_cnt_it); + } + } else { + for (i = 0; i < GATT_MAX_APPS; i++) { + if (tcb.prep_cnt[i]) { + gatt_if = (tGATT_IF)(i + 1); + conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, gatt_if); + tGATTS_DATA gatts_data; + gatts_data.exec_write = flag; + gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_WRITE_EXEC, &gatts_data); + tcb.prep_cnt[i] = 0; + } } } } else /* nothing needs to be executed , send response now */ @@ -865,12 +878,21 @@ static void gatts_process_mtu_req(tGATT_TCB& tcb, uint16_t cid, uint16_t len, ui tGATTS_DATA gatts_data; gatts_data.mtu = tcb.payload_size; - /* Notify all registered application with new MTU size. Us a transaction ID */ - /* of 0, as no response is allowed from application */ - for (int i = 0; i < GATT_MAX_APPS; i++) { - if (gatt_cb.cl_rcb[i].in_use) { - uint16_t conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, gatt_cb.cl_rcb[i].gatt_if); - gatt_sr_send_req_callback(conn_id, 0, GATTS_REQ_TYPE_MTU, &gatts_data); + /* Notify all registered application with new MTU size. Use a transaction ID */ + /* of 0, as no response is allowed from applications */ + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use) { + uint16_t conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, p_reg->gatt_if); + gatt_sr_send_req_callback(conn_id, 0, GATTS_REQ_TYPE_MTU, &gatts_data); + } + } + } else { + for (int i = 0; i < GATT_MAX_APPS; i++) { + if (gatt_cb.cl_rcb[i].in_use) { + uint16_t conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, gatt_cb.cl_rcb[i].gatt_if); + gatt_sr_send_req_callback(conn_id, 0, GATTS_REQ_TYPE_MTU, &gatts_data); + } } } } diff --git a/system/stack/gatt/gatt_utils.cc b/system/stack/gatt/gatt_utils.cc index f974a6acfa..ef3b888e04 100644 --- a/system/stack/gatt/gatt_utils.cc +++ b/system/stack/gatt/gatt_utils.cc @@ -1034,14 +1034,22 @@ tGATT_REG* gatt_get_regcb(tGATT_IF gatt_if) { uint8_t ii = (uint8_t)gatt_if; tGATT_REG* p_reg = NULL; - if (ii < 1 || ii > GATT_MAX_APPS) { - log::warn("gatt_if out of range = {}", ii); - return NULL; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + auto it = gatt_cb.cl_rcb_map.find(gatt_if); + if (it == gatt_cb.cl_rcb_map.end()) { + log::warn("unknown gatt_if = {}", ii); + return NULL; + } + p_reg = it->second.get(); + } else { + // Index for cl_rcb is always 1 less than gatt_if. + if (ii < 1 || ii > GATT_MAX_APPS) { + log::warn("gatt_if out of range = {}", ii); + return NULL; + } + p_reg = &gatt_cb.cl_rcb[ii - 1]; } - // Index for cl_rcb is always 1 less than gatt_if. - p_reg = &gatt_cb.cl_rcb[ii - 1]; - if (!p_reg->in_use) { log::warn("gatt_if found but not in use."); return NULL; @@ -1315,9 +1323,15 @@ tGATT_TCB* gatt_find_tcb_by_cid(uint16_t lcid) { } void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB& tcb) { - for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { - if (tcb.prep_cnt[i]) { - tcb.sr_cmd.cback_cnt[i] = 1; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& [i, cnt] : tcb.prep_cnt_map) { + tcb.sr_cmd.cback_cnt_map[i] = 1; + } + } else { + for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { + if (tcb.prep_cnt[i]) { + tcb.sr_cmd.cback_cnt[i] = 1; + } } } } @@ -1350,12 +1364,16 @@ tGATT_SR_CMD* gatt_sr_get_cmd_by_trans_id(tGATT_TCB* p_tcb, uint32_t trans_id) { * ******************************************************************************/ bool gatt_sr_is_cback_cnt_zero(tGATT_TCB& tcb) { - for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { - if (tcb.sr_cmd.cback_cnt[i]) { - return false; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + return tcb.sr_cmd.cback_cnt_map.empty(); + } else { + for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { + if (tcb.sr_cmd.cback_cnt[i]) { + return false; + } } + return true; } - return true; } /******************************************************************************* @@ -1368,12 +1386,16 @@ bool gatt_sr_is_cback_cnt_zero(tGATT_TCB& tcb) { * ******************************************************************************/ bool gatt_sr_is_prep_cnt_zero(tGATT_TCB& tcb) { - for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { - if (tcb.prep_cnt[i]) { - return false; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + return tcb.prep_cnt_map.empty(); + } else { + for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { + if (tcb.prep_cnt[i]) { + return false; + } } + return true; } - return true; } /******************************************************************************* @@ -1386,16 +1408,30 @@ bool gatt_sr_is_prep_cnt_zero(tGATT_TCB& tcb) { * ******************************************************************************/ void gatt_sr_reset_cback_cnt(tGATT_TCB& tcb, uint16_t cid) { - for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { if (cid == tcb.att_lcid) { - tcb.sr_cmd.cback_cnt[i] = 0; + tcb.sr_cmd.cback_cnt_map.clear(); } else { EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); if (channel == nullptr) { log::warn("{}, cid 0x{:02x} already disconnected", tcb.peer_bda, cid); return; } - channel->server_outstanding_cmd_.cback_cnt[i] = 0; + channel->server_outstanding_cmd_.cback_cnt_map.clear(); + } + } else { + for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { + if (cid == tcb.att_lcid) { + tcb.sr_cmd.cback_cnt[i] = 0; + } else { + EattChannel* channel = + EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); + if (channel == nullptr) { + log::warn("{}, cid 0x{:02x} already disconnected", tcb.peer_bda, cid); + return; + } + channel->server_outstanding_cmd_.cback_cnt[i] = 0; + } } } } @@ -1482,11 +1518,25 @@ void gatt_sr_update_cback_cnt(tGATT_TCB& tcb, uint16_t cid, tGATT_IF gatt_if, bo if (is_reset_first) { gatt_sr_reset_cback_cnt(tcb, cid); } - if (is_inc) { - sr_cmd_p->cback_cnt[idx]++; + + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + if (is_inc) { + sr_cmd_p->cback_cnt_map[idx]++; + } else { + auto cback_cnt_it = sr_cmd_p->cback_cnt_map.find(idx); + if (cback_cnt_it != sr_cmd_p->cback_cnt_map.end()) { + if ((--cback_cnt_it->second) <= 0) { + sr_cmd_p->cback_cnt_map.erase(cback_cnt_it); + } + } + } } else { - if (sr_cmd_p->cback_cnt[idx]) { - sr_cmd_p->cback_cnt[idx]--; + if (is_inc) { + sr_cmd_p->cback_cnt[idx]++; + } else { + if (sr_cmd_p->cback_cnt[idx]) { + sr_cmd_p->cback_cnt[idx]--; + } } } } @@ -1509,13 +1559,42 @@ void gatt_sr_update_prep_cnt(tGATT_TCB& tcb, tGATT_IF gatt_if, bool is_inc, bool if (is_reset_first) { gatt_sr_reset_prep_cnt(tcb); } - if (is_inc) { - tcb.prep_cnt[idx]++; + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + if (is_inc) { + tcb.prep_cnt_map[gatt_if]++; + } else { + auto prep_cnt_i = tcb.prep_cnt_map.find(gatt_if); + if (prep_cnt_i != tcb.prep_cnt_map.end()) { + if (--prep_cnt_i->second <= 0) { + tcb.prep_cnt_map.erase(prep_cnt_i); + } + } + } } else { - if (tcb.prep_cnt[idx]) { - tcb.prep_cnt[idx]--; + if (is_inc) { + tcb.prep_cnt[idx]++; + } else { + if (tcb.prep_cnt[idx]) { + tcb.prep_cnt[idx]--; + } + } + } +} + +static bool gatt_is_anybody_interested_in_connection(const RawAddress& bda) { + if (connection_manager::is_background_connection(bda)) { + log::debug("{} is in background connection", bda); + return true; + } + + for (size_t i = 1; i <= GATT_MAX_APPS; i++) { + tGATT_REG* p_reg = &gatt_cb.cl_rcb[i - 1]; + if (p_reg->in_use && p_reg->direct_connect_request.count(bda) > 0) { + log::debug("gatt_if {} interested in connection to {}", i, bda); + return true; } } + return false; } /** Cancel LE Create Connection request */ @@ -1535,6 +1614,9 @@ bool gatt_cancel_open(tGATT_IF gatt_if, const RawAddress& bda) { log::info("Removing {} from direct list", bda); p_reg->direct_connect_request.erase(bda); } + if (!gatt_is_anybody_interested_in_connection(bda)) { + gatt_cancel_connect(bda, static_cast<tBT_TRANSPORT>(BT_TRANSPORT_LE)); + } return true; } @@ -1749,20 +1831,39 @@ static void gatt_le_disconnect_complete_notify_user(const RawAddress& bda, tBT_TRANSPORT transport) { tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bda, transport); - for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { - tGATT_REG* p_reg = &gatt_cb.cl_rcb[i]; - if (p_reg->in_use && p_reg->app_cb.p_conn_cb) { - uint16_t conn_id = - p_tcb ? GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if) : GATT_INVALID_CONN_ID; - (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, bda, conn_id, kGattDisconnected, reason, - transport); + if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_conn_cb) { + uint16_t conn_id = + p_tcb ? GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if) : GATT_INVALID_CONN_ID; + (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, bda, conn_id, kGattDisconnected, reason, + transport); + } + + if (com::android::bluetooth::flags::gatt_reconnect_on_bt_on_fix()) { + if (p_reg->direct_connect_request.count(bda) > 0) { + log::info("Removing device {} from the direct connect list of gatt_if {}", bda, + p_reg->gatt_if); + p_reg->direct_connect_request.erase(bda); + } + } } + } else { + for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { + tGATT_REG* p_reg = &gatt_cb.cl_rcb[i]; + if (p_reg->in_use && p_reg->app_cb.p_conn_cb) { + uint16_t conn_id = + p_tcb ? GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if) : GATT_INVALID_CONN_ID; + (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, bda, conn_id, kGattDisconnected, reason, + transport); + } - if (com::android::bluetooth::flags::gatt_reconnect_on_bt_on_fix()) { - if (p_reg->direct_connect_request.count(bda) > 0) { - log::info("Removing device {} from the direct connect list of gatt_if {}", bda, - p_reg->gatt_if); - p_reg->direct_connect_request.erase(bda); + if (com::android::bluetooth::flags::gatt_reconnect_on_bt_on_fix()) { + if (p_reg->direct_connect_request.count(bda) > 0) { + log::info("Removing device {} from the direct connect list of gatt_if {}", bda, + p_reg->gatt_if); + p_reg->direct_connect_request.erase(bda); + } } } } diff --git a/system/stack/hid/hidh_api.cc b/system/stack/hid/hidh_api.cc index 7090a837dc..d0df9997bf 100644 --- a/system/stack/hid/hidh_api.cc +++ b/system/stack/hid/hidh_api.cc @@ -110,7 +110,7 @@ void hidh_get_str_attr(tSDP_DISC_REC* p_rec, uint16_t attr_id, uint16_t max_len, } } -static void hidh_search_callback(const RawAddress& /* bd_addr */, tSDP_RESULT sdp_result) { +static void hidh_search_callback(const RawAddress& bd_addr, tSDP_RESULT sdp_result) { tSDP_DISCOVERY_DB* p_db = hh_cb.p_sdp_db; tSDP_DISC_REC* p_rec; tSDP_DISC_ATTR *p_attr, *p_subattr1, *p_subattr2, *p_repdesc; @@ -120,14 +120,14 @@ static void hidh_search_callback(const RawAddress& /* bd_addr */, tSDP_RESULT sd hh_cb.sdp_busy = false; if (sdp_result != SDP_SUCCESS) { - hh_cb.sdp_cback(sdp_result, 0, NULL); + hh_cb.sdp_cback(bd_addr, sdp_result, 0, NULL); return; } Uuid hid_uuid = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE); p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceUUIDInDb(p_db, hid_uuid, NULL); if (p_rec == NULL) { - hh_cb.sdp_cback(HID_SDP_NO_SERV_UUID, 0, NULL); + hh_cb.sdp_cback(bd_addr, HID_SDP_NO_SERV_UUID, 0, NULL); return; } @@ -142,7 +142,7 @@ static void hidh_search_callback(const RawAddress& /* bd_addr */, tSDP_RESULT sd ((p_subattr2 = p_subattr1->attr_value.v.p_sub_attr) == NULL) || ((p_repdesc = p_subattr2->p_next_attr) == NULL) || (SDP_DISC_ATTR_TYPE(p_repdesc->attr_len_type) != TEXT_STR_DESC_TYPE)) { - hh_cb.sdp_cback(HID_SDP_MANDATORY_MISSING, 0, NULL); + hh_cb.sdp_cback(bd_addr, HID_SDP_MANDATORY_MISSING, 0, NULL); return; } @@ -255,7 +255,7 @@ static void hidh_search_callback(const RawAddress& /* bd_addr */, tSDP_RESULT sd } hh_cb.sdp_rec.p_sdp_layer_rec = p_rec; - hh_cb.sdp_cback(SDP_SUCCESS, attr_mask, &hh_cb.sdp_rec); + hh_cb.sdp_cback(bd_addr, SDP_SUCCESS, attr_mask, &hh_cb.sdp_rec); } /******************************************************************************* diff --git a/system/stack/include/ais_api.h b/system/stack/include/ais_api.h new file mode 100644 index 0000000000..41dad8242b --- /dev/null +++ b/system/stack/include/ais_api.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * + * Copyright 2024 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. + * + ******************************************************************************/ +#ifndef SYSTEM_STACK_INCLUDE_AIS_API_H_ +#define SYSTEM_STACK_INCLUDE_AIS_API_H_ + +#include "types/bluetooth/uuid.h" + +#define ANDROID_INFORMATION_SERVICE_UUID_STRING "e73e0001-ef1b-4e74-8291-2e4f3164f3b5" +/* Android Information Service characteristic */ +#define GATT_UUID_AIS_API_LEVEL_STRING "e73e0002-ef1b-4e74-8291-2e4f3164f3b5" + +extern const bluetooth::Uuid ANDROID_INFORMATION_SERVICE_UUID; +extern const bluetooth::Uuid GATT_UUID_AIS_API_LEVEL; + +/******************************************************************************* + * + * Function AIS_Init + * + * Description Initializes the control blocks used by AIS. + * This routine should not be called except once per + * stack invocation. + * + * Returns Nothing + * + ******************************************************************************/ +void AIS_Init(void); + +#endif // SYSTEM_STACK_INCLUDE_AIS_API_H_ diff --git a/system/stack/include/hidh_api.h b/system/stack/include/hidh_api.h index da7c43356b..f8d55775ce 100644 --- a/system/stack/include/hidh_api.h +++ b/system/stack/include/hidh_api.h @@ -47,8 +47,8 @@ * Type Definitions ****************************************************************************/ -typedef void(tHID_HOST_SDP_CALLBACK)(tSDP_STATUS result, uint16_t attr_mask, - tHID_DEV_SDP_INFO* sdp_rec); +typedef void(tHID_HOST_SDP_CALLBACK)(const RawAddress& bd_add, tSDP_STATUS result, + uint16_t attr_mask, tHID_DEV_SDP_INFO* sdp_rec); /* HID-HOST returns the events in the following table to the application via * tHID_HOST_DEV_CALLBACK diff --git a/system/stack/include/rfcdefs.h b/system/stack/include/rfcdefs.h index 7c5249c6ec..c778492a91 100644 --- a/system/stack/include/rfcdefs.h +++ b/system/stack/include/rfcdefs.h @@ -22,19 +22,35 @@ * ****************************************************************************/ -#ifndef RFCDEFS_H -#define RFCDEFS_H +#pragma once + /* * Server Channel Numbers (SCN) range between 1 and 30, inclusive */ #define RFCOMM_MAX_SCN 30 /* + * The maximum number of ports supported. + */ +#define MAX_RFC_PORTS 30 + +/* + * The maximum simultaneous links to different devices. + */ +#define MAX_BD_CONNECTIONS 16 + +/* * If nothing is negotiated MTU should be 127 */ #define RFCOMM_DEFAULT_MTU 127 /* + * RFCOMM buffer sizes + */ +#define RFCOMM_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE // command packet buffer size +#define RFCOMM_DATA_BUF_SIZE BT_DEFAULT_BUFFER_SIZE // data packet buffer size + +/* * Define used by RFCOMM TS frame types */ #define RFCOMM_SABME 0x2F // Start Asynchronous Balanced Mode (startup command) @@ -235,4 +251,39 @@ #define RFCOMM_MX_RLS 0x50 #define RFCOMM_MX_RLS_LEN 2 -#endif + +/* + * Define RFCOMM port rx and tx queue watermarks + */ +// MTU size used to calculate watermark levels +#define BTA_RFC_MTU_SIZE (L2CAP_MTU_SIZE - L2CAP_MIN_OFFSET - RFCOMM_DATA_OVERHEAD) + +// The port receive queue low watermark level, in number of buffers. +#define PORT_RX_BUF_LOW_WM 4 + +// The port receive queue high watermark level, in number of buffers. +#define PORT_RX_BUF_HIGH_WM 10 + +// The port receive queue critical watermark level, in number of buffers. +#define PORT_RX_BUF_CRITICAL_WM 15 + +// The port receive queue low watermark level, in bytes. +#define PORT_RX_LOW_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_LOW_WM) + +// The port receive queue high watermark level, in bytes. +#define PORT_RX_HIGH_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_HIGH_WM) + +// The port receive queue critical watermark level, in bytes. +#define PORT_RX_CRITICAL_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_CRITICAL_WM) + +// The port transmit queue high watermark level, in number of buffers. +#define PORT_TX_BUF_HIGH_WM 10 + +// The port transmit queue high watermark level, in number of buffers. +#define PORT_TX_BUF_CRITICAL_WM 15 + +// The port transmit queue high watermark level, in bytes. +#define PORT_TX_HIGH_WM (BTA_RFC_MTU_SIZE * PORT_TX_BUF_HIGH_WM) + +// The port transmit queue critical watermark level, in bytes. +#define PORT_TX_CRITICAL_WM (BTA_RFC_MTU_SIZE * PORT_TX_BUF_CRITICAL_WM) diff --git a/system/stack/rfcomm/port_api.cc b/system/stack/rfcomm/port_api.cc index 1eed863a84..b8a8e35b11 100644 --- a/system/stack/rfcomm/port_api.cc +++ b/system/stack/rfcomm/port_api.cc @@ -31,7 +31,6 @@ #include <cstdint> -#include "internal_include/bt_target.h" #include "internal_include/bt_trace.h" #include "os/logging/log_adapter.h" #include "osi/include/allocator.h" @@ -40,6 +39,7 @@ #include "stack/include/bt_types.h" #include "stack/include/bt_uuid16.h" #include "stack/include/btm_log_history.h" +#include "stack/include/rfcdefs.h" #include "stack/rfcomm/rfc_int.h" #include "types/raw_address.h" @@ -925,9 +925,7 @@ int PORT_WriteDataCO(uint16_t handle, int* p_len) { // if(recv(fd, (uint8_t *)(p_buf + 1) + p_buf->offset + p_buf->len, // available, 0) != available) if (!p_port->p_data_co_callback(handle, (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len, - available, DATA_CO_CALLBACK_TYPE_OUTGOING)) - - { + available, DATA_CO_CALLBACK_TYPE_OUTGOING)) { log::error("p_data_co_callback DATA_CO_CALLBACK_TYPE_OUTGOING failed, available:{}", available); mutex_global_unlock(); diff --git a/system/stack/rfcomm/rfc_ts_frames.cc b/system/stack/rfcomm/rfc_ts_frames.cc index e73bab5cf6..3a44afd061 100644 --- a/system/stack/rfcomm/rfc_ts_frames.cc +++ b/system/stack/rfcomm/rfc_ts_frames.cc @@ -28,7 +28,6 @@ #include <cstdint> -#include "internal_include/bt_target.h" #include "os/logging/log_adapter.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/test/gatt/gatt_sr_test.cc b/system/stack/test/gatt/gatt_sr_test.cc index 110c1291c6..29e83725bc 100644 --- a/system/stack/test/gatt/gatt_sr_test.cc +++ b/system/stack/test/gatt/gatt_sr_test.cc @@ -73,6 +73,7 @@ tGATT_STATUS attp_send_sr_msg(tGATT_TCB& tcb, uint16_t cid, BT_HDR* p_msg) { ret void gatt_act_discovery(tGATT_CLCB* p_clcb) {} bool gatt_disconnect(tGATT_TCB* p_tcb) { return false; } +void gatt_cancel_connect(const RawAddress& bd_addr, tBT_TRANSPORT transport) {} tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB* p_tcb) { return GATT_CH_CLOSE; } tGATT_STATUS gatts_db_read_attr_value_by_type(tGATT_TCB& tcb, uint16_t cid, tGATT_SVC_DB* p_db, uint8_t op_code, BT_HDR* p_rsp, uint16_t s_handle, diff --git a/system/stack/test/gatt/mock_gatt_utils_ref.cc b/system/stack/test/gatt/mock_gatt_utils_ref.cc index b4310ccac1..cab85bcfa6 100644 --- a/system/stack/test/gatt/mock_gatt_utils_ref.cc +++ b/system/stack/test/gatt/mock_gatt_utils_ref.cc @@ -50,6 +50,7 @@ void gatt_update_app_use_link_flag(tGATT_IF gatt_if, tGATT_TCB* p_tcb, bool is_a bool check_acl_link) {} void gatts_proc_srv_chg_ind_ack(tGATT_TCB) {} bool gatt_disconnect(tGATT_TCB* p_tcb) { return false; } +void gatt_cancel_connect(const RawAddress& bd_addr, tBT_TRANSPORT transport) {} tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB* p_tcb) { return GATT_CH_CLOSE; } void gatt_set_ch_state(tGATT_TCB* p_tcb, tGATT_CH_STATE ch_state) {} diff --git a/system/test/mock/mock_bta_hh_api.cc b/system/test/mock/mock_bta_hh_api.cc index e201324175..0eecdc6d67 100644 --- a/system/test/mock/mock_bta_hh_api.cc +++ b/system/test/mock/mock_bta_hh_api.cc @@ -72,3 +72,4 @@ void BTA_HhSetReport(uint8_t /* dev_handle */, tBTA_HH_RPT_TYPE /* r_type */, BT_HDR* /* p_data */) { inc_func_call_count(__func__); } +void BTA_HhDump(int /* fd */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_bta_hh_utils.cc b/system/test/mock/mock_bta_hh_utils.cc index b48524f4fb..e45da05966 100644 --- a/system/test/mock/mock_bta_hh_utils.cc +++ b/system/test/mock/mock_bta_hh_utils.cc @@ -38,7 +38,6 @@ namespace bta_hh_utils { struct bta_hh_add_device_to_list bta_hh_add_device_to_list; struct bta_hh_clean_up_kdev bta_hh_clean_up_kdev; struct bta_hh_cleanup_disable bta_hh_cleanup_disable; -struct bta_hh_dev_handle_to_cb_idx bta_hh_dev_handle_to_cb_idx; struct bta_hh_find_cb bta_hh_find_cb; struct bta_hh_get_cb bta_hh_get_cb; struct bta_hh_read_ssr_param bta_hh_read_ssr_param; @@ -67,11 +66,7 @@ void bta_hh_cleanup_disable(tBTA_HH_STATUS status) { inc_func_call_count(__func__); test::mock::bta_hh_utils::bta_hh_cleanup_disable(status); } -uint8_t bta_hh_dev_handle_to_cb_idx(uint8_t dev_handle) { - inc_func_call_count(__func__); - return test::mock::bta_hh_utils::bta_hh_dev_handle_to_cb_idx(dev_handle); -} -uint8_t bta_hh_find_cb(const tAclLinkSpec& link_spec) { +tBTA_HH_DEV_CB* bta_hh_find_cb(const tAclLinkSpec& link_spec) { inc_func_call_count(__func__); return test::mock::bta_hh_utils::bta_hh_find_cb(link_spec); } diff --git a/system/test/mock/mock_bta_hh_utils.h b/system/test/mock/mock_bta_hh_utils.h index 2e587af1dd..a46d616732 100644 --- a/system/test/mock/mock_bta_hh_utils.h +++ b/system/test/mock/mock_bta_hh_utils.h @@ -73,25 +73,14 @@ struct bta_hh_cleanup_disable { }; extern struct bta_hh_cleanup_disable bta_hh_cleanup_disable; -// Name: bta_hh_dev_handle_to_cb_idx -// Params: uint8_t dev_handle -// Return: uint8_t -struct bta_hh_dev_handle_to_cb_idx { - uint8_t return_value{0}; - std::function<uint8_t(uint8_t dev_handle)> body{ - [this](uint8_t /* dev_handle */) { return return_value; }}; - uint8_t operator()(uint8_t dev_handle) { return body(dev_handle); } -}; -extern struct bta_hh_dev_handle_to_cb_idx bta_hh_dev_handle_to_cb_idx; - // Name: bta_hh_find_cb // Params: const tAclLinkSpec& link_spec // Return: uint8_t struct bta_hh_find_cb { - uint8_t return_value{0}; - std::function<uint8_t(const tAclLinkSpec& link_spec)> body{ + tBTA_HH_DEV_CB* return_value{nullptr}; + std::function<tBTA_HH_DEV_CB*(const tAclLinkSpec& link_spec)> body{ [this](const tAclLinkSpec& /* link_spec */) { return return_value; }}; - uint8_t operator()(const tAclLinkSpec& link_spec) { return body(link_spec); } + tBTA_HH_DEV_CB* operator()(const tAclLinkSpec& link_spec) { return body(link_spec); } }; extern struct bta_hh_find_cb bta_hh_find_cb; diff --git a/system/test/mock/mock_stack_ais_ble.cc b/system/test/mock/mock_stack_ais_ble.cc new file mode 100644 index 0000000000..29630207b4 --- /dev/null +++ b/system/test/mock/mock_stack_ais_ble.cc @@ -0,0 +1,20 @@ +/* + * Copyright 2024 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. + */ + +#include "stack/include/ais_api.h" +#include "test/common/mock_functions.h" + +void AIS_Init(void) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_gatt_main.cc b/system/test/mock/mock_stack_gatt_main.cc index d59a56f304..b6476d0e4b 100644 --- a/system/test/mock/mock_stack_gatt_main.cc +++ b/system/test/mock/mock_stack_gatt_main.cc @@ -38,6 +38,9 @@ bool gatt_connect(const RawAddress& /* rem_bda */, tGATT_TCB* /* p_tcb */, inc_func_call_count(__func__); return false; } +void gatt_cancel_connect(const RawAddress& /* bd_addr */, tBT_TRANSPORT /* transport*/) { + inc_func_call_count(__func__); +} bool gatt_disconnect(tGATT_TCB* /* p_tcb */) { inc_func_call_count(__func__); return false; |