From ddcc0a5fed0a771f996b7eef286c2898abea9563 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Tue, 12 Mar 2024 22:51:16 -0400 Subject: [PATCH] sysbta: Sync with r29 * Currently not working on my MTK devices. Investigation ongoing. --- bluetooth/audio/hal/A2dpBits.h | 73 + .../audio/hal/A2dpOffloadAudioProvider.cpp | 75 +- .../audio/hal/A2dpOffloadAudioProvider.h | 11 +- bluetooth/audio/hal/A2dpOffloadCodec.h | 47 + bluetooth/audio/hal/A2dpOffloadCodecAac.cpp | 378 + bluetooth/audio/hal/A2dpOffloadCodecAac.h | 57 + .../audio/hal/A2dpOffloadCodecFactory.cpp | 100 + bluetooth/audio/hal/A2dpOffloadCodecFactory.h | 41 + bluetooth/audio/hal/A2dpOffloadCodecSbc.cpp | 510 + bluetooth/audio/hal/A2dpOffloadCodecSbc.h | 61 + bluetooth/audio/hal/Android.bp | 9 +- .../audio/hal/BluetoothAudioProvider.cpp | 193 +- bluetooth/audio/hal/BluetoothAudioProvider.h | 74 +- .../hal/BluetoothAudioProviderFactory.cpp | 52 +- .../audio/hal/BluetoothAudioProviderFactory.h | 4 + .../audio/hal/HfpOffloadAudioProvider.cpp | 65 + bluetooth/audio/hal/HfpOffloadAudioProvider.h | 46 + .../audio/hal/HfpSoftwareAudioProvider.cpp | 140 + .../audio/hal/HfpSoftwareAudioProvider.h | 59 + .../audio/hal/LeAudioOffloadAudioProvider.cpp | 728 +- .../audio/hal/LeAudioOffloadAudioProvider.h | 123 +- .../audio/hal/bluetooth_audio_system.xml | 2 +- bluetooth/audio/hw/Android.bp | 5 +- bluetooth/audio/hw/audio_bluetooth_hw.cc | 71 +- bluetooth/audio/hw/device_port_proxy.cc | 54 +- bluetooth/audio/hw/device_port_proxy.h | 29 +- bluetooth/audio/hw/device_port_proxy_hidl.cc | 2 +- bluetooth/audio/hw/device_port_proxy_hidl.h | 14 +- bluetooth/audio/hw/stream_apis.cc | 80 +- bluetooth/audio/hw/stream_apis.h | 1 + bluetooth/audio/hw/utils.cc | 4 + bluetooth/audio/hw/utils.h | 1 + bluetooth/audio/hw/utils_unittest.cc | 142 + bluetooth/audio/utils/Android.bp | 93 +- .../aidl_session/BluetoothAudioCodecs.cpp | 161 +- .../utils/aidl_session/BluetoothAudioCodecs.h | 13 +- .../aidl_session/BluetoothAudioSession.cpp | 164 +- .../aidl_session/BluetoothAudioSession.h | 10 +- .../BluetoothAudioSessionControl.h | 22 + ...LeAudioAseConfigurationSettingProvider.cpp | 760 ++ ...thLeAudioAseConfigurationSettingProvider.h | 125 + .../BluetoothLeAudioCodecsProvider.cpp | 555 + .../BluetoothLeAudioCodecsProvider.h | 115 + .../BluetoothLeAudioCodecsProviderTest.cpp | 383 + .../aidl_session/HidlToAidlMiddleware.cpp | 6 +- .../le_audio_codec_capabilities.xml | 77 + .../le_audio_codec_capabilities.xsd | 77 + .../schema/current.txt | 107 + .../schema/last_current.txt | 0 .../schema/last_removed.txt | 0 .../schema/removed.txt | 1 + .../audio_set_configurations.fbs | 91 + .../audio_set_configurations.json | 11382 ++++++++++++++++ .../audio_set_scenarios.fbs | 36 + .../audio_set_scenarios.json | 304 + 55 files changed, 17467 insertions(+), 266 deletions(-) create mode 100644 bluetooth/audio/hal/A2dpBits.h create mode 100644 bluetooth/audio/hal/A2dpOffloadCodec.h create mode 100644 bluetooth/audio/hal/A2dpOffloadCodecAac.cpp create mode 100644 bluetooth/audio/hal/A2dpOffloadCodecAac.h create mode 100644 bluetooth/audio/hal/A2dpOffloadCodecFactory.cpp create mode 100644 bluetooth/audio/hal/A2dpOffloadCodecFactory.h create mode 100644 bluetooth/audio/hal/A2dpOffloadCodecSbc.cpp create mode 100644 bluetooth/audio/hal/A2dpOffloadCodecSbc.h create mode 100644 bluetooth/audio/hal/HfpOffloadAudioProvider.cpp create mode 100644 bluetooth/audio/hal/HfpOffloadAudioProvider.h create mode 100644 bluetooth/audio/hal/HfpSoftwareAudioProvider.cpp create mode 100644 bluetooth/audio/hal/HfpSoftwareAudioProvider.h create mode 100644 bluetooth/audio/hw/utils_unittest.cc create mode 100644 bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp create mode 100644 bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h create mode 100644 bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp create mode 100644 bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h create mode 100644 bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp create mode 100644 bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml create mode 100644 bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd create mode 100644 bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt create mode 100644 bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_current.txt create mode 100644 bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_removed.txt create mode 100644 bluetooth/audio/utils/le_audio_codec_capabilities/schema/removed.txt create mode 100644 bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.fbs create mode 100644 bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json create mode 100644 bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.fbs create mode 100644 bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.json diff --git a/bluetooth/audio/hal/A2dpBits.h b/bluetooth/audio/hal/A2dpBits.h new file mode 100644 index 0000000..f467c95 --- /dev/null +++ b/bluetooth/audio/hal/A2dpBits.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023 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. + */ + +#pragma once + +namespace aidl::android::hardware::bluetooth::audio { + +class A2dpBits { + const uint8_t* cdata_; + uint8_t* data_; + + public: + A2dpBits(const std::vector& vector) : cdata_(vector.data()) {} + + A2dpBits(std::vector& vector) + : cdata_(vector.data()), data_(vector.data()) {} + + struct Range { + const int first, len; + constexpr Range(int first, int last) + : first(first), len(last - first + 1) {} + constexpr Range(int index) : first(index), len(1) {} + }; + + constexpr bool get(int bit) const { + return (cdata_[bit >> 3] >> (7 - (bit & 7))) & 1; + } + + constexpr unsigned get(const Range& range) const { + unsigned v(0); + for (int i = 0; i < range.len; i++) + v |= get(range.first + i) << ((range.len - 1) - i); + return v; + } + + constexpr void set(int bit, int value = 1) { + uint8_t m = 1 << (7 - (bit & 7)); + if (value) + data_[bit >> 3] |= m; + else + data_[bit >> 3] &= ~m; + } + + constexpr void set(const Range& range, int value) { + for (int i = 0; i < range.len; i++) + set(range.first + i, (value >> ((range.len - 1) - i)) & 1); + } + + constexpr int find_active_bit(const Range& range) const { + unsigned v = get(range); + int i = 0; + for (; i < range.len && ((v >> i) & 1) == 0; i++) + ; + return i < range.len && (v ^ (1 << i)) == 0 + ? range.first + (range.len - 1) - i + : -1; + } +}; + +} // namespace aidl::android::hardware::bluetooth::audio diff --git a/bluetooth/audio/hal/A2dpOffloadAudioProvider.cpp b/bluetooth/audio/hal/A2dpOffloadAudioProvider.cpp index 2d0d8c9..ba7a89d 100644 --- a/bluetooth/audio/hal/A2dpOffloadAudioProvider.cpp +++ b/bluetooth/audio/hal/A2dpOffloadAudioProvider.cpp @@ -22,6 +22,10 @@ #include #include +#include "A2dpOffloadCodecAac.h" +#include "A2dpOffloadCodecFactory.h" +#include "A2dpOffloadCodecSbc.h" + namespace aidl { namespace android { namespace hardware { @@ -48,19 +52,44 @@ ndk::ScopedAStatus A2dpOffloadAudioProvider::startSession( const std::shared_ptr& host_if, const AudioConfiguration& audio_config, const std::vector& latency_modes, DataMQDesc* _aidl_return) { - if (audio_config.getTag() != AudioConfiguration::a2dpConfig) { - LOG(WARNING) << __func__ << " - Invalid Audio Configuration=" - << audio_config.toString(); - *_aidl_return = DataMQDesc(); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - if (!BluetoothAudioCodecs::IsOffloadCodecConfigurationValid( - session_type_, audio_config.get())) { + if (audio_config.getTag() == AudioConfiguration::Tag::a2dp) { + auto a2dp_config = audio_config.get(); + A2dpStatus a2dp_status = A2dpStatus::NOT_SUPPORTED_CODEC_TYPE; + + if (a2dp_config.codecId == + A2dpOffloadCodecSbc::GetInstance()->GetCodecId()) { + SbcParameters sbc_parameters; + a2dp_status = A2dpOffloadCodecSbc::GetInstance()->ParseConfiguration( + a2dp_config.configuration, &sbc_parameters); + + } else if (a2dp_config.codecId == + A2dpOffloadCodecAac::GetInstance()->GetCodecId()) { + AacParameters aac_parameters; + a2dp_status = A2dpOffloadCodecAac::GetInstance()->ParseConfiguration( + a2dp_config.configuration, &aac_parameters); + } + if (a2dp_status != A2dpStatus::OK) { + LOG(WARNING) << __func__ << " - Invalid Audio Configuration=" + << audio_config.toString(); + *_aidl_return = DataMQDesc(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + } else if (audio_config.getTag() == AudioConfiguration::Tag::a2dpConfig) { + if (!BluetoothAudioCodecs::IsOffloadCodecConfigurationValid( + session_type_, + audio_config.get())) { + LOG(WARNING) << __func__ << " - Invalid Audio Configuration=" + << audio_config.toString(); + *_aidl_return = DataMQDesc(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + } else { LOG(WARNING) << __func__ << " - Invalid Audio Configuration=" << audio_config.toString(); *_aidl_return = DataMQDesc(); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } + return BluetoothAudioProvider::startSession( host_if, audio_config, latency_modes, _aidl_return); } @@ -73,6 +102,36 @@ ndk::ScopedAStatus A2dpOffloadAudioProvider::onSessionReady( return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus A2dpOffloadAudioProvider::parseA2dpConfiguration( + const CodecId& codec_id, const std::vector& configuration, + CodecParameters* codec_parameters, A2dpStatus* _aidl_return) { + auto codec = A2dpOffloadCodecFactory::GetInstance()->GetCodec(codec_id); + if (!codec) { + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) + << " - CodecId=" << codec_id.toString() << " is not found"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + *_aidl_return = codec->ParseConfiguration(configuration, codec_parameters); + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus A2dpOffloadAudioProvider::getA2dpConfiguration( + const std::vector& remote_a2dp_capabilities, + const A2dpConfigurationHint& hint, + std::optional* _aidl_return) { + *_aidl_return = std::nullopt; + A2dpConfiguration avdtp_configuration; + + if (A2dpOffloadCodecFactory::GetInstance()->GetConfiguration( + remote_a2dp_capabilities, hint, &avdtp_configuration)) + *_aidl_return = + std::make_optional(std::move(avdtp_configuration)); + + return ndk::ScopedAStatus::ok(); +} + } // namespace audio } // namespace bluetooth } // namespace hardware diff --git a/bluetooth/audio/hal/A2dpOffloadAudioProvider.h b/bluetooth/audio/hal/A2dpOffloadAudioProvider.h index e6f188b..7cc6dee 100644 --- a/bluetooth/audio/hal/A2dpOffloadAudioProvider.h +++ b/bluetooth/audio/hal/A2dpOffloadAudioProvider.h @@ -34,7 +34,16 @@ class A2dpOffloadAudioProvider : public BluetoothAudioProvider { const std::shared_ptr& host_if, const AudioConfiguration& audio_config, const std::vector& latency_modes, - DataMQDesc* _aidl_return); + DataMQDesc* _aidl_return) override; + + ndk::ScopedAStatus parseA2dpConfiguration( + const CodecId& codec_id, const std::vector& configuration, + CodecParameters* codec_parameters, A2dpStatus* _aidl_return) override; + + ndk::ScopedAStatus getA2dpConfiguration( + const std::vector& remote_a2dp_capabilities, + const A2dpConfigurationHint& hint, + std::optional* _aidl_return) override; private: ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override; diff --git a/bluetooth/audio/hal/A2dpOffloadCodec.h b/bluetooth/audio/hal/A2dpOffloadCodec.h new file mode 100644 index 0000000..7ed5872 --- /dev/null +++ b/bluetooth/audio/hal/A2dpOffloadCodec.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2023 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. + */ + +#pragma once + +#include +#include +#include + +#include "BluetoothAudioProviderFactory.h" + +namespace aidl::android::hardware::bluetooth::audio { + +class A2dpOffloadCodec { + protected: + A2dpOffloadCodec(const CodecInfo& info) : info(info) {} + virtual ~A2dpOffloadCodec() {} + + public: + const CodecInfo& info; + + const CodecId& GetCodecId() const { return info.id; } + + virtual A2dpStatus ParseConfiguration( + const std::vector& configuration, + CodecParameters* codec_parameters) const = 0; + + virtual bool BuildConfiguration( + const std::vector& remote_capabilities, + const std::optional& hint, + std::vector* configuration) const = 0; +}; + +} // namespace aidl::android::hardware::bluetooth::audio diff --git a/bluetooth/audio/hal/A2dpOffloadCodecAac.cpp b/bluetooth/audio/hal/A2dpOffloadCodecAac.cpp new file mode 100644 index 0000000..0f5533a --- /dev/null +++ b/bluetooth/audio/hal/A2dpOffloadCodecAac.cpp @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2023 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 "A2dpOffloadCodecAac.h" + +#include "A2dpBits.h" + +namespace aidl::android::hardware::bluetooth::audio { + +/** + * AAC Local Capabilities + */ + +enum : bool { + kEnableObjectTypeMpeg2AacLc = true, + kEnableObjectTypeMpeg4AacLc = true, +}; + +enum : bool { + kEnableSamplingFrequency44100 = true, + kEnableSamplingFrequency48000 = true, + kEnableSamplingFrequency88200 = false, + kEnableSamplingFrequency96000 = false, +}; + +enum : bool { + kEnableChannels1 = true, + kEnableChannels2 = true, +}; + +enum : bool { + kEnableVbrSupported = true, +}; + +enum : int { + kBitdepth = 24, +}; + +/** + * AAC Signaling format [A2DP - 4.5] + */ + +// clang-format off + +constexpr A2dpBits::Range kObjectType ( 0, 6 ); +constexpr A2dpBits::Range kDrcEnable ( 7 ); +constexpr A2dpBits::Range kSamplingFrequency ( 8, 19 ); +constexpr A2dpBits::Range kChannels ( 20, 23 ); +constexpr A2dpBits::Range kVbrSupported ( 24 ); +constexpr A2dpBits::Range kBitrate ( 25, 47 ); +constexpr size_t kCapabilitiesSize = 48/8; + +// clang-format on + +enum { + kObjectTypeMpeg2AacLc = kObjectType.first, + kObjectTypeMpeg4AacLc, + kObjectTypeMpeg4AacLtp, + kObjectTypeMpeg4AacScalable, + kObjectTypeMpeg4AacHeV1, + kObjectTypeMpeg4AacHeV2, + kObjectTypeMpeg4AacEldV2 +}; + +enum { + kSamplingFrequency8000 = kSamplingFrequency.first, + kSamplingFrequency11025, + kSamplingFrequency12000, + kSamplingFrequency16000, + kSamplingFrequency22050, + kSamplingFrequency24000, + kSamplingFrequency32000, + kSamplingFrequency44100, + kSamplingFrequency48000, + kSamplingFrequency64000, + kSamplingFrequency88200, + kSamplingFrequency96000 +}; + +enum { kChannels1 = kChannels.first, kChannels2, kChannels51, kChannels71 }; + +/** + * AAC Conversion functions + */ + +static AacParameters::ObjectType GetObjectTypeEnum(int object_type) { + switch (object_type) { + case kObjectTypeMpeg2AacLc: + return AacParameters::ObjectType::MPEG2_AAC_LC; + case kObjectTypeMpeg4AacLc: + default: + return AacParameters::ObjectType::MPEG4_AAC_LC; + } +} + +static int GetSamplingFrequencyBit(int32_t sampling_frequency) { + switch (sampling_frequency) { + case 8000: + return kSamplingFrequency8000; + case 11025: + return kSamplingFrequency11025; + case 12000: + return kSamplingFrequency12000; + case 16000: + return kSamplingFrequency16000; + case 22050: + return kSamplingFrequency22050; + case 24000: + return kSamplingFrequency24000; + case 32000: + return kSamplingFrequency32000; + case 44100: + return kSamplingFrequency44100; + case 48000: + return kSamplingFrequency48000; + case 64000: + return kSamplingFrequency64000; + case 88200: + return kSamplingFrequency88200; + case 96000: + return kSamplingFrequency96000; + default: + return -1; + } +} + +static int32_t GetSamplingFrequencyValue(int sampling_frequency) { + switch (sampling_frequency) { + case kSamplingFrequency8000: + return 8000; + case kSamplingFrequency11025: + return 11025; + case kSamplingFrequency12000: + return 12000; + case kSamplingFrequency16000: + return 16000; + case kSamplingFrequency22050: + return 22050; + case kSamplingFrequency24000: + return 24000; + case kSamplingFrequency32000: + return 32000; + case kSamplingFrequency44100: + return 44100; + case kSamplingFrequency48000: + return 48000; + case kSamplingFrequency64000: + return 64000; + case kSamplingFrequency88200: + return 88200; + case kSamplingFrequency96000: + return 96000; + default: + return 0; + } +} + +static int GetChannelsBit(ChannelMode channel_mode) { + switch (channel_mode) { + case ChannelMode::MONO: + return kChannels1; + case ChannelMode::STEREO: + return kChannels2; + default: + return -1; + } +} + +static ChannelMode GetChannelModeEnum(int channel_mode) { + switch (channel_mode) { + case kChannels1: + return ChannelMode::MONO; + case kChannels2: + return ChannelMode::STEREO; + default: + return ChannelMode::UNKNOWN; + } +} + +/** + * AAC Class implementation + */ + +const A2dpOffloadCodecAac* A2dpOffloadCodecAac::GetInstance() { + static A2dpOffloadCodecAac instance; + return &instance; +} + +A2dpOffloadCodecAac::A2dpOffloadCodecAac() + : A2dpOffloadCodec(info_), + info_({.id = CodecId(CodecId::A2dp::AAC), .name = "AAC"}) { + info_.transport.set(); + auto& a2dp_info = info_.transport.get(); + + /* --- Setup Capabilities --- */ + + a2dp_info.capabilities.resize(kCapabilitiesSize); + std::fill(begin(a2dp_info.capabilities), end(a2dp_info.capabilities), 0); + + auto capabilities = A2dpBits(a2dp_info.capabilities); + + capabilities.set(kObjectTypeMpeg2AacLc, kEnableObjectTypeMpeg2AacLc); + capabilities.set(kObjectTypeMpeg4AacLc, kEnableObjectTypeMpeg4AacLc); + + capabilities.set(kSamplingFrequency44100, kEnableSamplingFrequency44100); + capabilities.set(kSamplingFrequency48000, kEnableSamplingFrequency48000); + capabilities.set(kSamplingFrequency88200, kEnableSamplingFrequency88200); + capabilities.set(kSamplingFrequency96000, kEnableSamplingFrequency96000); + + capabilities.set(kChannels1, kEnableChannels1); + capabilities.set(kChannels2, kEnableChannels2); + + capabilities.set(kVbrSupported, kEnableVbrSupported); + + /* --- Setup Sampling Frequencies --- */ + + auto& sampling_frequency = a2dp_info.samplingFrequencyHz; + + for (auto v : {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, + 64000, 88200, 96000}) + if (capabilities.get(GetSamplingFrequencyBit(int32_t(v)))) + sampling_frequency.push_back(v); + + /* --- Setup Channel Modes --- */ + + auto& channel_modes = a2dp_info.channelMode; + + for (auto v : {ChannelMode::MONO, ChannelMode::STEREO}) + if (capabilities.get(GetChannelsBit(v))) channel_modes.push_back(v); + + /* --- Setup Bitdepth --- */ + + a2dp_info.bitdepth.push_back(kBitdepth); +} + +A2dpStatus A2dpOffloadCodecAac::ParseConfiguration( + const std::vector& configuration, + CodecParameters* codec_parameters, AacParameters* aac_parameters) const { + auto& a2dp_info = info.transport.get(); + + if (configuration.size() != a2dp_info.capabilities.size()) + return A2dpStatus::BAD_LENGTH; + + auto config = A2dpBits(configuration); + auto lcaps = A2dpBits(a2dp_info.capabilities); + + /* --- Check Object Type --- */ + + int object_type = config.find_active_bit(kObjectType); + if (object_type < 0) return A2dpStatus::INVALID_OBJECT_TYPE; + if (!lcaps.get(object_type)) return A2dpStatus::NOT_SUPPORTED_OBJECT_TYPE; + + /* --- Check Sampling Frequency --- */ + + int sampling_frequency = config.find_active_bit(kSamplingFrequency); + if (sampling_frequency < 0) return A2dpStatus::INVALID_SAMPLING_FREQUENCY; + if (!lcaps.get(sampling_frequency)) + return A2dpStatus::NOT_SUPPORTED_SAMPLING_FREQUENCY; + + /* --- Check Channels --- */ + + int channels = config.find_active_bit(kChannels); + if (channels < 0) return A2dpStatus::INVALID_CHANNELS; + if (!lcaps.get(channels)) return A2dpStatus::NOT_SUPPORTED_CHANNELS; + + /* --- Check Bitrate --- */ + + bool vbr = config.get(kVbrSupported); + if (vbr && !lcaps.get(kVbrSupported)) return A2dpStatus::NOT_SUPPORTED_VBR; + + int bitrate = config.get(kBitrate); + if (vbr && lcaps.get(kBitrate) && bitrate > lcaps.get(kBitrate)) + return A2dpStatus::NOT_SUPPORTED_BIT_RATE; + + /* --- Return --- */ + + codec_parameters->channelMode = GetChannelModeEnum(channels); + codec_parameters->samplingFrequencyHz = + GetSamplingFrequencyValue(sampling_frequency); + codec_parameters->bitdepth = kBitdepth; + + codec_parameters->minBitrate = vbr ? 0 : bitrate; + codec_parameters->maxBitrate = bitrate; + + if (aac_parameters) + aac_parameters->object_type = GetObjectTypeEnum(object_type); + + return A2dpStatus::OK; +} + +bool A2dpOffloadCodecAac::BuildConfiguration( + const std::vector& remote_capabilities, + const std::optional& hint, + std::vector* configuration) const { + auto& a2dp_info = info_.transport.get(); + + if (remote_capabilities.size() != a2dp_info.capabilities.size()) return false; + + auto lcaps = A2dpBits(a2dp_info.capabilities); + auto rcaps = A2dpBits(remote_capabilities); + + configuration->resize(a2dp_info.capabilities.size()); + std::fill(begin(*configuration), end(*configuration), 0); + auto config = A2dpBits(*configuration); + + /* --- Select Object Type --- */ + + if (lcaps.get(kObjectTypeMpeg2AacLc) && rcaps.get(kObjectTypeMpeg2AacLc)) + config.set(kObjectTypeMpeg2AacLc); + else if (lcaps.get(kObjectTypeMpeg4AacLc) && rcaps.get(kObjectTypeMpeg4AacLc)) + config.set(kObjectTypeMpeg4AacLc); + else + return false; + + /* --- Select Sampling Frequency --- */ + + auto sf_hint = hint ? GetSamplingFrequencyBit(hint->samplingFrequencyHz) : -1; + + if (sf_hint >= 0 && lcaps.get(sf_hint) && rcaps.get(sf_hint)) + config.set(sf_hint); + else if (lcaps.get(kSamplingFrequency96000) && + rcaps.get(kSamplingFrequency96000)) + config.set(kSamplingFrequency96000); + else if (lcaps.get(kSamplingFrequency88200) && + rcaps.get(kSamplingFrequency88200)) + config.set(kSamplingFrequency88200); + else if (lcaps.get(kSamplingFrequency48000) && + rcaps.get(kSamplingFrequency48000)) + config.set(kSamplingFrequency48000); + else if (lcaps.get(kSamplingFrequency44100) && + rcaps.get(kSamplingFrequency44100)) + config.set(kSamplingFrequency44100); + else + return false; + + /* --- Select Channels --- */ + + auto ch_hint = hint ? GetChannelsBit(hint->channelMode) : -1; + + if (ch_hint >= 0 && lcaps.get(ch_hint) && rcaps.get(ch_hint)) + config.set(ch_hint); + else if (lcaps.get(kChannels2) && rcaps.get(kChannels2)) + config.set(kChannels2); + else if (lcaps.get(kChannels1) && rcaps.get(kChannels1)) + config.set(kChannels1); + else + return false; + + /* --- Select Bitrate --- */ + + if (!hint || hint->minBitrate == 0) + config.set(kVbrSupported, + lcaps.get(kVbrSupported) && rcaps.get(kVbrSupported)); + + int32_t bitrate = lcaps.get(kBitrate); + if (hint && hint->maxBitrate > 0 && bitrate) + bitrate = std::min(hint->maxBitrate, bitrate); + else if (hint && hint->maxBitrate > 0) + bitrate = hint->maxBitrate; + config.set(kBitrate, bitrate); + + return true; +} + +} // namespace aidl::android::hardware::bluetooth::audio diff --git a/bluetooth/audio/hal/A2dpOffloadCodecAac.h b/bluetooth/audio/hal/A2dpOffloadCodecAac.h new file mode 100644 index 0000000..eefa89b --- /dev/null +++ b/bluetooth/audio/hal/A2dpOffloadCodecAac.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2023 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. + */ + +#pragma once + +#include "A2dpOffloadCodec.h" + +namespace aidl::android::hardware::bluetooth::audio { + +struct AacParameters : public CodecParameters { + enum class ObjectType { MPEG2_AAC_LC, MPEG4_AAC_LC }; + + ObjectType object_type; +}; + +class A2dpOffloadCodecAac : public A2dpOffloadCodec { + CodecInfo info_; + + A2dpOffloadCodecAac(); + + A2dpStatus ParseConfiguration(const std::vector& configuration, + CodecParameters* codec_parameters, + AacParameters* aac_parameters) const; + + public: + static const A2dpOffloadCodecAac* GetInstance(); + + A2dpStatus ParseConfiguration( + const std::vector& configuration, + CodecParameters* codec_parameters) const override { + return ParseConfiguration(configuration, codec_parameters, nullptr); + } + + A2dpStatus ParseConfiguration(const std::vector& configuration, + AacParameters* aac_parameters) const { + return ParseConfiguration(configuration, aac_parameters, aac_parameters); + } + + bool BuildConfiguration(const std::vector& remote_capabilities, + const std::optional& hint, + std::vector* configuration) const override; +}; + +} // namespace aidl::android::hardware::bluetooth::audio diff --git a/bluetooth/audio/hal/A2dpOffloadCodecFactory.cpp b/bluetooth/audio/hal/A2dpOffloadCodecFactory.cpp new file mode 100644 index 0000000..73d8fb1 --- /dev/null +++ b/bluetooth/audio/hal/A2dpOffloadCodecFactory.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2023 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 "A2dpOffloadCodecFactory.h" + +#include +#include + +#include "A2dpOffloadCodecAac.h" +#include "A2dpOffloadCodecSbc.h" + +namespace aidl::android::hardware::bluetooth::audio { + +/** + * Local Capabilities Configuration + */ + +enum : bool { + kEnableAac = true, + kEnableSbc = true, +}; + +/** + * Class implementation + */ + +const A2dpOffloadCodecFactory* A2dpOffloadCodecFactory::GetInstance() { + static A2dpOffloadCodecFactory instance; + return &instance; +} + +A2dpOffloadCodecFactory::A2dpOffloadCodecFactory() + : name("Offload"), codecs(ranked_codecs_) { + ranked_codecs_.reserve(kEnableAac + kEnableSbc); + + if (kEnableAac) ranked_codecs_.push_back(A2dpOffloadCodecAac::GetInstance()); + if (kEnableSbc) ranked_codecs_.push_back(A2dpOffloadCodecSbc::GetInstance()); +} + +const A2dpOffloadCodec* A2dpOffloadCodecFactory::GetCodec(CodecId id) const { + auto codec = std::find_if(begin(ranked_codecs_), end(ranked_codecs_), + [&](auto c) { return id == c->info.id; }); + + return codec != end(ranked_codecs_) ? *codec : nullptr; +} + +bool A2dpOffloadCodecFactory::GetConfiguration( + const std::vector& remote_capabilities, + const A2dpConfigurationHint& hint, A2dpConfiguration* configuration) const { + decltype(ranked_codecs_) codecs; + + codecs.reserve(ranked_codecs_.size()); + + auto hinted_codec = + std::find_if(begin(ranked_codecs_), end(ranked_codecs_), + [&](auto c) { return hint.codecId == c->info.id; }); + + if (hinted_codec != end(ranked_codecs_)) codecs.push_back(*hinted_codec); + + std::copy_if(begin(ranked_codecs_), end(ranked_codecs_), + std::back_inserter(codecs), + [&](auto c) { return c != *hinted_codec; }); + + for (auto codec : codecs) { + auto rc = + std::find_if(begin(remote_capabilities), end(remote_capabilities), + [&](auto& rc__) { return codec->info.id == rc__.id; }); + + if ((rc == end(remote_capabilities)) || + !codec->BuildConfiguration(rc->capabilities, hint.codecParameters, + &configuration->configuration)) + continue; + + configuration->id = codec->info.id; + A2dpStatus status = codec->ParseConfiguration(configuration->configuration, + &configuration->parameters); + assert(status == A2dpStatus::OK); + + configuration->remoteSeid = rc->seid; + + return true; + } + + return false; +} + +} // namespace aidl::android::hardware::bluetooth::audio diff --git a/bluetooth/audio/hal/A2dpOffloadCodecFactory.h b/bluetooth/audio/hal/A2dpOffloadCodecFactory.h new file mode 100644 index 0000000..3fb5b1d --- /dev/null +++ b/bluetooth/audio/hal/A2dpOffloadCodecFactory.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023 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. + */ + +#pragma once + +#include "A2dpOffloadCodec.h" + +namespace aidl::android::hardware::bluetooth::audio { + +class A2dpOffloadCodecFactory { + std::vector ranked_codecs_; + + A2dpOffloadCodecFactory(); + + public: + const std::string name; + const std::vector& codecs; + + static const A2dpOffloadCodecFactory* GetInstance(); + + const A2dpOffloadCodec* GetCodec(CodecId id) const; + + bool GetConfiguration(const std::vector&, + const A2dpConfigurationHint& hint, + A2dpConfiguration* configuration) const; +}; + +} // namespace aidl::android::hardware::bluetooth::audio diff --git a/bluetooth/audio/hal/A2dpOffloadCodecSbc.cpp b/bluetooth/audio/hal/A2dpOffloadCodecSbc.cpp new file mode 100644 index 0000000..36d8f72 --- /dev/null +++ b/bluetooth/audio/hal/A2dpOffloadCodecSbc.cpp @@ -0,0 +1,510 @@ +/* + * Copyright (C) 2023 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 "A2dpOffloadCodecSbc.h" + +#include + +#include "A2dpBits.h" + +namespace aidl::android::hardware::bluetooth::audio { + +/** + * SBC Local Capabilities + */ + +enum : bool { + kEnableSamplingFrequency44100 = true, + kEnableSamplingFrequency48000 = true, +}; + +enum : bool { + kEnableChannelModeMono = true, + kEnableChannelModeDualChannel = true, + kEnableChannelModeStereo = true, + kEnableChannelModeJointStereo = true, +}; + +enum : bool { + kEnableBlockLength4 = true, + kEnableBlockLength8 = true, + kEnableBlockLength12 = true, + kEnableBlockLength16 = true, +}; + +enum : bool { + kEnableSubbands4 = true, + kEnableSubbands8 = true, +}; + +enum : bool { + kEnableAllocationMethodSnr = true, + kEnableAllocationMethodLoudness = true, +}; + +enum : uint8_t { + kDefaultMinimumBitpool = 2, + kDefaultMaximumBitpool = 250, +}; + +enum : int { + kBitdepth = 16, +}; + +/** + * SBC Signaling format [A2DP - 4.3] + */ + +// clang-format off + +constexpr A2dpBits::Range kSamplingFrequency ( 0, 3 ); +constexpr A2dpBits::Range kChannelMode ( 4, 7 ); +constexpr A2dpBits::Range kBlockLength ( 8, 11 ); +constexpr A2dpBits::Range kSubbands ( 12, 13 ); +constexpr A2dpBits::Range kAllocationMethod ( 14, 15 ); +constexpr A2dpBits::Range kMinimumBitpool ( 16, 23 ); +constexpr A2dpBits::Range kMaximumBitpool ( 24, 31 ); +constexpr size_t kCapabilitiesSize = 32/8; + +// clang-format on + +enum { + kSamplingFrequency16000 = kSamplingFrequency.first, + kSamplingFrequency32000, + kSamplingFrequency44100, + kSamplingFrequency48000 +}; + +enum { + kChannelModeMono = kChannelMode.first, + kChannelModeDualChannel, + kChannelModeStereo, + kChannelModeJointStereo +}; + +enum { + kBlockLength4 = kBlockLength.first, + kBlockLength8, + kBlockLength12, + kBlockLength16 +}; + +enum { kSubbands8 = kSubbands.first, kSubbands4 }; + +enum { + kAllocationMethodSnr = kAllocationMethod.first, + kAllocationMethodLoudness +}; + +/** + * SBC Conversion functions + */ + +static int GetSamplingFrequencyBit(int32_t sampling_frequency) { + switch (sampling_frequency) { + case 16000: + return kSamplingFrequency16000; + case 32000: + return kSamplingFrequency32000; + case 44100: + return kSamplingFrequency44100; + case 48000: + return kSamplingFrequency48000; + default: + return -1; + } +} + +static int32_t GetSamplingFrequencyValue(int sampling_frequency) { + switch (sampling_frequency) { + case kSamplingFrequency16000: + return 16000; + case kSamplingFrequency32000: + return 32000; + case kSamplingFrequency44100: + return 44100; + case kSamplingFrequency48000: + return 48000; + default: + return 0; + } +} + +static int GetChannelModeBit(ChannelMode channel_mode) { + switch (channel_mode) { + case ChannelMode::STEREO: + return kChannelModeJointStereo | kChannelModeStereo; + case ChannelMode::DUALMONO: + return kChannelModeDualChannel; + case ChannelMode::MONO: + return kChannelModeMono; + default: + return -1; + } +} + +static ChannelMode GetChannelModeEnum(int channel_mode) { + switch (channel_mode) { + case kChannelModeMono: + return ChannelMode::MONO; + case kChannelModeDualChannel: + return ChannelMode::DUALMONO; + case kChannelModeStereo: + case kChannelModeJointStereo: + return ChannelMode::STEREO; + default: + return ChannelMode::UNKNOWN; + } +} + +static int32_t GetBlockLengthValue(int block_length) { + switch (block_length) { + case kBlockLength4: + return 4; + case kBlockLength8: + return 8; + case kBlockLength12: + return 12; + case kBlockLength16: + return 16; + default: + return 0; + } +} + +static int32_t GetSubbandsValue(int subbands) { + switch (subbands) { + case kSubbands4: + return 4; + case kSubbands8: + return 8; + default: + return 0; + } +} + +static SbcParameters::AllocationMethod GetAllocationMethodEnum( + int allocation_method) { + switch (allocation_method) { + case kAllocationMethodSnr: + return SbcParameters::AllocationMethod::SNR; + case kAllocationMethodLoudness: + default: + return SbcParameters::AllocationMethod::LOUDNESS; + } +} + +static int32_t GetSamplingFrequencyValue(const A2dpBits& configuration) { + return GetSamplingFrequencyValue( + configuration.find_active_bit(kSamplingFrequency)); +} + +static int32_t GetBlockLengthValue(const A2dpBits& configuration) { + return GetBlockLengthValue(configuration.find_active_bit(kBlockLength)); +} + +static int32_t GetSubbandsValue(const A2dpBits& configuration) { + return GetSubbandsValue(configuration.find_active_bit(kSubbands)); +} + +static int GetFrameSize(const A2dpBits& configuration, int bitpool) { + const int kSbcHeaderSize = 4; + int subbands = GetSubbandsValue(configuration); + int blocks = GetBlockLengthValue(configuration); + + unsigned bits = + ((4 * subbands) << !configuration.get(kChannelModeMono)) + + ((blocks * bitpool) << configuration.get(kChannelModeDualChannel)) + + ((configuration.get(kChannelModeJointStereo) ? subbands : 0)); + + return kSbcHeaderSize + ((bits + 7) >> 3); +} + +static int GetBitrate(const A2dpBits& configuration, int bitpool) { + int sampling_frequency = GetSamplingFrequencyValue(configuration); + int subbands = GetSubbandsValue(configuration); + int blocks = GetBlockLengthValue(configuration); + int bits = 8 * GetFrameSize(configuration, bitpool); + + return (bits * sampling_frequency) / (blocks * subbands); +} + +static uint8_t GetBitpool(const A2dpBits& configuration, int bitrate) { + int bitpool = 0; + + for (int i = 128; i; i >>= 1) + if (bitrate > GetBitrate(configuration, bitpool + i)) { + bitpool += i; + } + + return std::clamp(bitpool, 2, 250); +} + +/** + * SBC Class implementation + */ + +const A2dpOffloadCodecSbc* A2dpOffloadCodecSbc::GetInstance() { + static A2dpOffloadCodecSbc instance; + return &instance; +} + +A2dpOffloadCodecSbc::A2dpOffloadCodecSbc() + : A2dpOffloadCodec(info_), + info_({.id = CodecId(CodecId::A2dp::SBC), .name = "SBC"}) { + info_.transport.set(); + auto& a2dp_info = info_.transport.get(); + + /* --- Setup Capabilities --- */ + + a2dp_info.capabilities.resize(kCapabilitiesSize); + std::fill(begin(a2dp_info.capabilities), end(a2dp_info.capabilities), 0); + + auto capabilities = A2dpBits(a2dp_info.capabilities); + + capabilities.set(kSamplingFrequency44100, kEnableSamplingFrequency44100); + capabilities.set(kSamplingFrequency48000, kEnableSamplingFrequency48000); + + capabilities.set(kChannelModeMono, kEnableChannelModeMono); + capabilities.set(kChannelModeDualChannel, kEnableChannelModeDualChannel); + capabilities.set(kChannelModeStereo, kEnableChannelModeStereo); + capabilities.set(kChannelModeJointStereo, kEnableChannelModeJointStereo); + + capabilities.set(kBlockLength4, kEnableBlockLength4); + capabilities.set(kBlockLength8, kEnableBlockLength8); + capabilities.set(kBlockLength12, kEnableBlockLength12); + capabilities.set(kBlockLength16, kEnableBlockLength16); + + capabilities.set(kSubbands4, kEnableSubbands4); + capabilities.set(kSubbands8, kEnableSubbands8); + + capabilities.set(kSubbands4, kEnableSubbands4); + capabilities.set(kSubbands8, kEnableSubbands8); + + capabilities.set(kAllocationMethodSnr, kEnableAllocationMethodSnr); + capabilities.set(kAllocationMethodLoudness, kEnableAllocationMethodLoudness); + + capabilities.set(kMinimumBitpool, kDefaultMinimumBitpool); + capabilities.set(kMaximumBitpool, kDefaultMaximumBitpool); + + /* --- Setup Sampling Frequencies --- */ + + auto& sampling_frequency = a2dp_info.samplingFrequencyHz; + + for (auto v : {16000, 32000, 44100, 48000}) + if (capabilities.get(GetSamplingFrequencyBit(int32_t(v)))) + sampling_frequency.push_back(v); + + /* --- Setup Channel Modes --- */ + + auto& channel_modes = a2dp_info.channelMode; + + for (auto v : {ChannelMode::MONO, ChannelMode::DUALMONO, ChannelMode::STEREO}) + if (capabilities.get(GetChannelModeBit(v))) channel_modes.push_back(v); + + /* --- Setup Bitdepth --- */ + + a2dp_info.bitdepth.push_back(kBitdepth); +} + +A2dpStatus A2dpOffloadCodecSbc::ParseConfiguration( + const std::vector& configuration, + CodecParameters* codec_parameters, SbcParameters* sbc_parameters) const { + auto& a2dp_info = info.transport.get(); + + if (configuration.size() != a2dp_info.capabilities.size()) + return A2dpStatus::BAD_LENGTH; + + auto config = A2dpBits(configuration); + auto lcaps = A2dpBits(a2dp_info.capabilities); + + /* --- Check Sampling Frequency --- */ + + int sampling_frequency = config.find_active_bit(kSamplingFrequency); + if (sampling_frequency < 0) return A2dpStatus::INVALID_SAMPLING_FREQUENCY; + if (!lcaps.get(sampling_frequency)) + return A2dpStatus::NOT_SUPPORTED_SAMPLING_FREQUENCY; + + /* --- Check Channel Mode --- */ + + int channel_mode = config.find_active_bit(kChannelMode); + if (channel_mode < 0) return A2dpStatus::INVALID_CHANNEL_MODE; + if (!lcaps.get(channel_mode)) return A2dpStatus::NOT_SUPPORTED_CHANNEL_MODE; + + /* --- Check Block Length --- */ + + int block_length = config.find_active_bit(kBlockLength); + if (block_length < 0) return A2dpStatus::INVALID_BLOCK_LENGTH; + + /* --- Check Subbands --- */ + + int subbands = config.find_active_bit(kSubbands); + if (subbands < 0) return A2dpStatus::INVALID_SUBBANDS; + if (!lcaps.get(subbands)) return A2dpStatus::NOT_SUPPORTED_SUBBANDS; + + /* --- Check Allocation Method --- */ + + int allocation_method = config.find_active_bit(kAllocationMethod); + if (allocation_method < 0) return A2dpStatus::INVALID_ALLOCATION_METHOD; + if (!lcaps.get(allocation_method)) + return A2dpStatus::NOT_SUPPORTED_ALLOCATION_METHOD; + + /* --- Check Bitpool --- */ + + uint8_t min_bitpool = config.get(kMinimumBitpool); + if (min_bitpool < 2 || min_bitpool > 250) + return A2dpStatus::INVALID_MINIMUM_BITPOOL_VALUE; + if (min_bitpool < lcaps.get(kMinimumBitpool)) + return A2dpStatus::NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE; + + uint8_t max_bitpool = config.get(kMaximumBitpool); + if (max_bitpool < 2 || max_bitpool > 250) + return A2dpStatus::INVALID_MAXIMUM_BITPOOL_VALUE; + if (max_bitpool > lcaps.get(kMaximumBitpool)) + return A2dpStatus::NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE; + + /* --- Return --- */ + + codec_parameters->channelMode = GetChannelModeEnum(channel_mode); + codec_parameters->samplingFrequencyHz = + GetSamplingFrequencyValue(sampling_frequency); + codec_parameters->bitdepth = kBitdepth; + + codec_parameters->minBitrate = GetBitrate(config, min_bitpool); + codec_parameters->maxBitrate = GetBitrate(config, max_bitpool); + + if (sbc_parameters) { + sbc_parameters->block_length = GetBlockLengthValue(block_length); + sbc_parameters->subbands = GetSubbandsValue(subbands); + sbc_parameters->allocation_method = + GetAllocationMethodEnum(allocation_method); + sbc_parameters->min_bitpool = min_bitpool; + sbc_parameters->max_bitpool = max_bitpool; + } + + return A2dpStatus::OK; +} + +bool A2dpOffloadCodecSbc::BuildConfiguration( + const std::vector& remote_capabilities, + const std::optional& hint, + std::vector* configuration) const { + auto& a2dp_info = info.transport.get(); + + if (remote_capabilities.size() != a2dp_info.capabilities.size()) return false; + + auto lcaps = A2dpBits(a2dp_info.capabilities); + auto rcaps = A2dpBits(remote_capabilities); + + configuration->resize(a2dp_info.capabilities.size()); + std::fill(begin(*configuration), end(*configuration), 0); + auto config = A2dpBits(*configuration); + + /* --- Select Sampling Frequency --- */ + + auto sf_hint = hint ? GetSamplingFrequencyBit(hint->samplingFrequencyHz) : -1; + + if (sf_hint >= 0 && lcaps.get(sf_hint) && rcaps.get(sf_hint)) + config.set(sf_hint); + else if (lcaps.get(kSamplingFrequency44100) && + rcaps.get(kSamplingFrequency44100)) + config.set(kSamplingFrequency44100); + else if (lcaps.get(kSamplingFrequency48000) && + rcaps.get(kSamplingFrequency48000)) + config.set(kSamplingFrequency48000); + else + return false; + + /* --- Select Channel Mode --- */ + + auto cm_hint = hint ? GetChannelModeBit(hint->channelMode) : -1; + + if (cm_hint >= 0 && lcaps.get(cm_hint) && rcaps.get(cm_hint)) + config.set(cm_hint); + else if (lcaps.get(kChannelModeJointStereo) && + rcaps.get(kChannelModeJointStereo)) + config.set(kChannelModeJointStereo); + else if (lcaps.get(kChannelModeStereo) && rcaps.get(kChannelModeStereo)) + config.set(kChannelModeStereo); + else if (lcaps.get(kChannelModeDualChannel) && + rcaps.get(kChannelModeDualChannel)) + config.set(kChannelModeDualChannel); + else if (lcaps.get(kChannelModeMono) && rcaps.get(kChannelModeMono)) + config.set(kChannelModeMono); + else + return false; + + /* --- Select Block Length --- */ + + if (lcaps.get(kBlockLength16) && rcaps.get(kBlockLength16)) + config.set(kBlockLength16); + else if (lcaps.get(kBlockLength12) && rcaps.get(kBlockLength12)) + config.set(kBlockLength12); + else if (lcaps.get(kBlockLength8) && rcaps.get(kBlockLength8)) + config.set(kBlockLength8); + else if (lcaps.get(kBlockLength4) && rcaps.get(kBlockLength4)) + config.set(kBlockLength4); + else + return false; + + /* --- Select Subbands --- */ + + if (lcaps.get(kSubbands8) && rcaps.get(kSubbands8)) + config.set(kSubbands8); + else if (lcaps.get(kSubbands4) && rcaps.get(kSubbands4)) + config.set(kSubbands4); + else + return false; + + /* --- Select Allocation method --- */ + + if (lcaps.get(kAllocationMethodLoudness) && + rcaps.get(kAllocationMethodLoudness)) + config.set(kAllocationMethodLoudness); + else if (lcaps.get(kAllocationMethodSnr) && rcaps.get(kAllocationMethodSnr)) + config.set(kAllocationMethodSnr); + else + return false; + + /* --- Select Bitpool --- */ + + uint8_t min_bitpool = rcaps.get(kMinimumBitpool); + uint8_t max_bitpool = rcaps.get(kMaximumBitpool); + + if (min_bitpool < 2 || min_bitpool > 250 || max_bitpool < 2 || + max_bitpool > 250 || min_bitpool > max_bitpool) { + min_bitpool = 2; + max_bitpool = 250; + } + + min_bitpool = std::max(min_bitpool, uint8_t(lcaps.get(kMinimumBitpool))); + max_bitpool = std::max(max_bitpool, uint8_t(lcaps.get(kMaximumBitpool))); + + if (hint) { + min_bitpool = + std::max(min_bitpool, GetBitpool(*configuration, hint->minBitrate)); + if (hint->maxBitrate && hint->maxBitrate >= hint->minBitrate) + max_bitpool = + std::min(max_bitpool, GetBitpool(*configuration, hint->maxBitrate)); + } + + config.set(kMinimumBitpool, min_bitpool); + config.set(kMaximumBitpool, max_bitpool); + + return true; +} + +} // namespace aidl::android::hardware::bluetooth::audio diff --git a/bluetooth/audio/hal/A2dpOffloadCodecSbc.h b/bluetooth/audio/hal/A2dpOffloadCodecSbc.h new file mode 100644 index 0000000..c380850 --- /dev/null +++ b/bluetooth/audio/hal/A2dpOffloadCodecSbc.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2023 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. + */ + +#pragma once + +#include "A2dpOffloadCodec.h" + +namespace aidl::android::hardware::bluetooth::audio { + +struct SbcParameters : public CodecParameters { + enum class AllocationMethod { SNR, LOUDNESS }; + + AllocationMethod allocation_method; + int block_length; + int subbands; + int min_bitpool; + int max_bitpool; +}; + +class A2dpOffloadCodecSbc : public A2dpOffloadCodec { + CodecInfo info_; + + A2dpOffloadCodecSbc(); + + A2dpStatus ParseConfiguration(const std::vector& configuration, + CodecParameters* codec_parameters, + SbcParameters* sbc_parameters) const; + + public: + static const A2dpOffloadCodecSbc* GetInstance(); + + A2dpStatus ParseConfiguration( + const std::vector& configuration, + CodecParameters* codec_parameters) const override { + return ParseConfiguration(configuration, codec_parameters, nullptr); + } + + A2dpStatus ParseConfiguration(const std::vector& configuration, + SbcParameters* sbc_parameters) const { + return ParseConfiguration(configuration, sbc_parameters, sbc_parameters); + } + + bool BuildConfiguration(const std::vector& remote_capabilities, + const std::optional& hint, + std::vector* configuration) const override; +}; + +} // namespace aidl::android::hardware::bluetooth::audio diff --git a/bluetooth/audio/hal/Android.bp b/bluetooth/audio/hal/Android.bp index 08e526a..a30754e 100644 --- a/bluetooth/audio/hal/Android.bp +++ b/bluetooth/audio/hal/Android.bp @@ -7,8 +7,13 @@ cc_binary { "BluetoothAudioProvider.cpp", "BluetoothAudioProviderFactory.cpp", "A2dpOffloadAudioProvider.cpp", + "A2dpOffloadCodecAac.cpp", + "A2dpOffloadCodecFactory.cpp", + "A2dpOffloadCodecSbc.cpp", "A2dpSoftwareAudioProvider.cpp", "HearingAidAudioProvider.cpp", + "HfpOffloadAudioProvider.cpp", + "HfpSoftwareAudioProvider.cpp", "LeAudioOffloadAudioProvider.cpp", "LeAudioSoftwareAudioProvider.cpp", "service_system.cpp", @@ -16,6 +21,9 @@ cc_binary { header_libs: [ "libhardware_headers", ], + defaults: [ + "latest_android_hardware_bluetooth_audio_ndk_shared", + ], shared_libs: [ "libbase", "libbinder", @@ -25,7 +33,6 @@ cc_binary { "libhidlbase", "liblog", "libutils", - "android.hardware.bluetooth.audio-V3-ndk", "libbluetooth_audio_session_aidl_system", ], required: [ diff --git a/bluetooth/audio/hal/BluetoothAudioProvider.cpp b/bluetooth/audio/hal/BluetoothAudioProvider.cpp index 2a88959..bdba898 100644 --- a/bluetooth/audio/hal/BluetoothAudioProvider.cpp +++ b/bluetooth/audio/hal/BluetoothAudioProvider.cpp @@ -21,15 +21,39 @@ #include #include +#include "A2dpOffloadCodecFactory.h" + namespace aidl { namespace android { namespace hardware { namespace bluetooth { namespace audio { +struct BluetoothAudioProviderContext { + SessionType session_type; +}; + +static void binderUnlinkedCallbackAidl(void* cookie) { + LOG(INFO) << __func__; + BluetoothAudioProviderContext* ctx = + static_cast(cookie); + delete ctx; +} + +static void binderDiedCallbackAidl(void* cookie) { + LOG(INFO) << __func__; + BluetoothAudioProviderContext* ctx = + static_cast(cookie); + CHECK_NE(ctx, nullptr); + + BluetoothAudioSessionReport::OnSessionEnded(ctx->session_type); +} + BluetoothAudioProvider::BluetoothAudioProvider() { death_recipient_ = ::ndk::ScopedAIBinder_DeathRecipient( AIBinder_DeathRecipient_new(binderDiedCallbackAidl)); + AIBinder_DeathRecipient_setOnUnlinked(death_recipient_.get(), + binderUnlinkedCallbackAidl); } ndk::ScopedAStatus BluetoothAudioProvider::startSession( @@ -39,17 +63,21 @@ ndk::ScopedAStatus BluetoothAudioProvider::startSession( DataMQDesc* _aidl_return) { if (host_if == nullptr) { *_aidl_return = DataMQDesc(); + LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_) + << " Illegal argument"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } latency_modes_ = latencyModes; audio_config_ = std::make_unique(audio_config); stack_iface_ = host_if; - is_binder_died = false; + BluetoothAudioProviderContext* cookie = + new BluetoothAudioProviderContext{session_type_}; AIBinder_linkToDeath(stack_iface_->asBinder().get(), death_recipient_.get(), - this); + cookie); + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_); onSessionReady(_aidl_return); return ndk::ScopedAStatus::ok(); } @@ -60,10 +88,8 @@ ndk::ScopedAStatus BluetoothAudioProvider::endSession() { if (stack_iface_ != nullptr) { BluetoothAudioSessionReport::OnSessionEnded(session_type_); - if (!is_binder_died) { - AIBinder_unlinkToDeath(stack_iface_->asBinder().get(), - death_recipient_.get(), this); - } + AIBinder_unlinkToDeath(stack_iface_->asBinder().get(), + death_recipient_.get(), this); } else { LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << " has NO session"; @@ -77,10 +103,9 @@ ndk::ScopedAStatus BluetoothAudioProvider::endSession() { ndk::ScopedAStatus BluetoothAudioProvider::streamStarted( BluetoothAudioStatus status) { - LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) - << ", status=" << toString(status); - if (stack_iface_ != nullptr) { + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) + << ", status=" << toString(status); BluetoothAudioSessionReport::ReportControlStatus(session_type_, true, status); } else { @@ -108,8 +133,6 @@ ndk::ScopedAStatus BluetoothAudioProvider::streamSuspended( ndk::ScopedAStatus BluetoothAudioProvider::updateAudioConfiguration( const AudioConfiguration& audio_config) { - LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_); - if (stack_iface_ == nullptr || audio_config_ == nullptr) { LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << " has NO session"; @@ -125,13 +148,13 @@ ndk::ScopedAStatus BluetoothAudioProvider::updateAudioConfiguration( audio_config_ = std::make_unique(audio_config); BluetoothAudioSessionReport::ReportAudioConfigChanged(session_type_, *audio_config_); + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) + << " | audio_config=" << audio_config.toString(); return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus BluetoothAudioProvider::setLowLatencyModeAllowed( bool allowed) { - LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_); - if (stack_iface_ == nullptr) { LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << " has NO session"; @@ -143,19 +166,143 @@ ndk::ScopedAStatus BluetoothAudioProvider::setLowLatencyModeAllowed( return ndk::ScopedAStatus::ok(); } -void BluetoothAudioProvider::binderDiedCallbackAidl(void* ptr) { - LOG(ERROR) << __func__ << " - BluetoothAudio Service died"; - auto provider = static_cast(ptr); - if (provider == nullptr) { - LOG(ERROR) << __func__ << ": Null AudioProvider HAL died"; - return; - } - provider->is_binder_died = true; - provider->endSession(); +ndk::ScopedAStatus BluetoothAudioProvider::parseA2dpConfiguration( + [[maybe_unused]] const CodecId& codec_id, + [[maybe_unused]] const std::vector& configuration, + [[maybe_unused]] CodecParameters* codec_parameters, + [[maybe_unused]] A2dpStatus* _aidl_return) { + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) + << " is illegal"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); +} + +ndk::ScopedAStatus BluetoothAudioProvider::getA2dpConfiguration( + [[maybe_unused]] const std::vector& + remote_a2dp_capabilities, + [[maybe_unused]] const A2dpConfigurationHint& hint, + [[maybe_unused]] std::optional* _aidl_return) { + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) + << " is illegal"; + + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); +} + +ndk::ScopedAStatus BluetoothAudioProvider::setCodecPriority( + const ::aidl::android::hardware::bluetooth::audio::CodecId& in_codecId, + int32_t in_priority) { + /* TODO: Implement */ + (void)in_codecId; + (void)in_priority; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +}; + +ndk::ScopedAStatus BluetoothAudioProvider::getLeAudioAseConfiguration( + const std::optional>>& in_remoteSinkAudioCapabilities, + const std::optional>>& in_remoteSourceAudioCapabilities, + const std::vector< + ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + LeAudioConfigurationRequirement>& in_requirements, + std::vector<::aidl::android::hardware::bluetooth::audio:: + IBluetoothAudioProvider::LeAudioAseConfigurationSetting>* + _aidl_return) { + /* TODO: Implement */ + (void)in_remoteSinkAudioCapabilities; + (void)in_remoteSourceAudioCapabilities; + (void)in_requirements; + (void)_aidl_return; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +}; + +ndk::ScopedAStatus BluetoothAudioProvider::getLeAudioAseQosConfiguration( + const ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + LeAudioAseQosConfigurationRequirement& in_qosRequirement, + ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + LeAudioAseQosConfigurationPair* _aidl_return) { + /* TODO: Implement */ + (void)in_qosRequirement; + (void)_aidl_return; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +}; + +ndk::ScopedAStatus BluetoothAudioProvider::getLeAudioAseDatapathConfiguration( + const ::aidl::android::hardware::bluetooth::audio::AudioContext& in_context, + const std::vector<::aidl::android::hardware::bluetooth::audio:: + LeAudioConfiguration::StreamMap>& in_streamMap, + ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + LeAudioDataPathConfigurationPair* _aidl_return) { + /* TODO: Implement */ + (void)in_context; + (void)in_streamMap; + (void)_aidl_return; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +ndk::ScopedAStatus BluetoothAudioProvider::onSinkAseMetadataChanged( + ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + AseState in_state, + int32_t cigId, int32_t cisId, + const std::optional>>& + in_metadata) { + /* TODO: Implement */ + (void)in_state; + (void)cigId; + (void)cisId; + (void)in_metadata; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +}; + +ndk::ScopedAStatus BluetoothAudioProvider::onSourceAseMetadataChanged( + ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + AseState in_state, + int32_t cigId, int32_t cisId, + const std::optional>>& + in_metadata) { + /* TODO: Implement */ + (void)in_state; + (void)cigId; + (void)cisId; + (void)in_metadata; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +}; + +ndk::ScopedAStatus BluetoothAudioProvider::getLeAudioBroadcastConfiguration( + const std::optional>>& in_remoteSinkAudioCapabilities, + const ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + LeAudioBroadcastConfigurationRequirement& in_requirement, + ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + LeAudioBroadcastConfigurationSetting* _aidl_return) { + /* TODO: Implement */ + (void)in_remoteSinkAudioCapabilities; + (void)in_requirement; + (void)_aidl_return; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +}; + +ndk::ScopedAStatus +BluetoothAudioProvider::getLeAudioBroadcastDatapathConfiguration( + const ::aidl::android::hardware::bluetooth::audio::AudioContext& in_context, + const std::vector<::aidl::android::hardware::bluetooth::audio:: + LeAudioBroadcastConfiguration::BroadcastStreamMap>& + in_streamMap, + ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + LeAudioDataPathConfiguration* _aidl_return) { + /* TODO: Implement */ + (void)in_context; + (void)in_streamMap; + (void)_aidl_return; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } } // namespace audio } // namespace bluetooth } // namespace hardware } // namespace android -} // namespace aidl \ No newline at end of file +} // namespace aidl diff --git a/bluetooth/audio/hal/BluetoothAudioProvider.h b/bluetooth/audio/hal/BluetoothAudioProvider.h index dbfff7d..5064869 100644 --- a/bluetooth/audio/hal/BluetoothAudioProvider.h +++ b/bluetooth/audio/hal/BluetoothAudioProvider.h @@ -41,20 +41,86 @@ class BluetoothAudioProvider : public BnBluetoothAudioProvider { ndk::ScopedAStatus startSession( const std::shared_ptr& host_if, const AudioConfiguration& audio_config, - const std::vector& latency_modes, - DataMQDesc* _aidl_return); + const std::vector& latency_modes, DataMQDesc* _aidl_return); ndk::ScopedAStatus endSession(); ndk::ScopedAStatus streamStarted(BluetoothAudioStatus status); ndk::ScopedAStatus streamSuspended(BluetoothAudioStatus status); ndk::ScopedAStatus updateAudioConfiguration( const AudioConfiguration& audio_config); ndk::ScopedAStatus setLowLatencyModeAllowed(bool allowed); + ndk::ScopedAStatus setCodecPriority( + const ::aidl::android::hardware::bluetooth::audio::CodecId& in_codecId, + int32_t in_priority) override; + ndk::ScopedAStatus getLeAudioAseConfiguration( + const std::optional>>& in_remoteSinkAudioCapabilities, + const std::optional>>& in_remoteSourceAudioCapabilities, + const std::vector< + ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + LeAudioConfigurationRequirement>& in_requirements, + std::vector<::aidl::android::hardware::bluetooth::audio:: + IBluetoothAudioProvider::LeAudioAseConfigurationSetting>* + _aidl_return) override; + ndk::ScopedAStatus getLeAudioAseQosConfiguration( + const ::aidl::android::hardware::bluetooth::audio:: + IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement& + in_qosRequirement, + ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + LeAudioAseQosConfigurationPair* _aidl_return) override; + ndk::ScopedAStatus getLeAudioAseDatapathConfiguration( + const ::aidl::android::hardware::bluetooth::audio::AudioContext& + in_context, + const std::vector<::aidl::android::hardware::bluetooth::audio:: + LeAudioConfiguration::StreamMap>& in_streamMap, + ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + LeAudioDataPathConfigurationPair* _aidl_return) override; + ndk::ScopedAStatus onSinkAseMetadataChanged( + ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + AseState in_state, + int32_t cigId, int32_t cisId, + const std::optional>>& + in_metadata) override; + ndk::ScopedAStatus onSourceAseMetadataChanged( + ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + AseState in_state, + int32_t cigId, int32_t cisId, + const std::optional>>& + in_metadata) override; + ndk::ScopedAStatus getLeAudioBroadcastConfiguration( + const std::optional>>& in_remoteSinkAudioCapabilities, + const ::aidl::android::hardware::bluetooth::audio:: + IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement& + in_requirement, + ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + LeAudioBroadcastConfigurationSetting* _aidl_return) override; + ndk::ScopedAStatus getLeAudioBroadcastDatapathConfiguration( + const ::aidl::android::hardware::bluetooth::audio::AudioContext& + in_context, + const std::vector<::aidl::android::hardware::bluetooth::audio:: + LeAudioBroadcastConfiguration::BroadcastStreamMap>& + in_streamMap, + ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider:: + LeAudioDataPathConfiguration* _aidl_return) override; + + ndk::ScopedAStatus parseA2dpConfiguration( + const CodecId& codec_id, const std::vector& configuration, + CodecParameters* codec_parameters, A2dpStatus* _aidl_return); + ndk::ScopedAStatus getA2dpConfiguration( + const std::vector& remote_a2dp_capabilities, + const A2dpConfigurationHint& hint, + std::optional* _aidl_return); virtual bool isValid(const SessionType& sessionType) = 0; protected: virtual ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) = 0; - static void binderDiedCallbackAidl(void* cookie_ptr); ::ndk::ScopedAIBinder_DeathRecipient death_recipient_; @@ -62,9 +128,7 @@ class BluetoothAudioProvider : public BnBluetoothAudioProvider { std::unique_ptr audio_config_ = nullptr; SessionType session_type_; std::vector latency_modes_; - bool is_binder_died = false; }; - } // namespace audio } // namespace bluetooth } // namespace hardware diff --git a/bluetooth/audio/hal/BluetoothAudioProviderFactory.cpp b/bluetooth/audio/hal/BluetoothAudioProviderFactory.cpp index 91731d4..e55a434 100644 --- a/bluetooth/audio/hal/BluetoothAudioProviderFactory.cpp +++ b/bluetooth/audio/hal/BluetoothAudioProviderFactory.cpp @@ -22,9 +22,12 @@ #include #include "A2dpOffloadAudioProvider.h" +#include "A2dpOffloadCodecFactory.h" #include "A2dpSoftwareAudioProvider.h" #include "BluetoothAudioProvider.h" #include "HearingAidAudioProvider.h" +#include "HfpOffloadAudioProvider.h" +#include "HfpSoftwareAudioProvider.h" #include "LeAudioOffloadAudioProvider.h" #include "LeAudioSoftwareAudioProvider.h" @@ -34,6 +37,9 @@ namespace hardware { namespace bluetooth { namespace audio { +static const std::string kLeAudioOffloadProviderName = + "LE_AUDIO_OFFLOAD_HARDWARE_OFFLOAD_PROVIDER"; + BluetoothAudioProviderFactory::BluetoothAudioProviderFactory() {} ndk::ScopedAStatus BluetoothAudioProviderFactory::openProvider( @@ -78,6 +84,15 @@ ndk::ScopedAStatus BluetoothAudioProviderFactory::openProvider( case SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH: provider = ndk::SharedRefBase::make(); break; + case SessionType::HFP_SOFTWARE_ENCODING_DATAPATH: + provider = ndk::SharedRefBase::make(); + break; + case SessionType::HFP_SOFTWARE_DECODING_DATAPATH: + provider = ndk::SharedRefBase::make(); + break; + case SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH: + provider = ndk::SharedRefBase::make(); + break; default: provider = nullptr; break; @@ -135,8 +150,43 @@ ndk::ScopedAStatus BluetoothAudioProviderFactory::getProviderCapabilities( return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus BluetoothAudioProviderFactory::getProviderInfo( + SessionType session_type, std::optional* _aidl_return) { + *_aidl_return = std::nullopt; + + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type); + + if (session_type == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH || + session_type == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) { + auto& provider_info = _aidl_return->emplace(); + + provider_info.name = A2dpOffloadCodecFactory::GetInstance()->name; + for (auto codec : A2dpOffloadCodecFactory::GetInstance()->codecs) + provider_info.codecInfos.push_back(codec->info); + } + + if (session_type == + SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH || + session_type == + SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH || + session_type == + SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) { + std::vector db_codec_info = + BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(session_type); + if (!db_codec_info.empty()) { + auto& provider_info = _aidl_return->emplace(); + provider_info.name = kLeAudioOffloadProviderName; + provider_info.codecInfos = db_codec_info; + *_aidl_return = provider_info; + return ndk::ScopedAStatus::ok(); + } + } + + return ndk::ScopedAStatus::ok(); +} + } // namespace audio } // namespace bluetooth } // namespace hardware } // namespace android -} // namespace aidl \ No newline at end of file +} // namespace aidl diff --git a/bluetooth/audio/hal/BluetoothAudioProviderFactory.h b/bluetooth/audio/hal/BluetoothAudioProviderFactory.h index b38cfd2..1afae64 100644 --- a/bluetooth/audio/hal/BluetoothAudioProviderFactory.h +++ b/bluetooth/audio/hal/BluetoothAudioProviderFactory.h @@ -35,6 +35,10 @@ class BluetoothAudioProviderFactory : public BnBluetoothAudioProviderFactory { ndk::ScopedAStatus getProviderCapabilities( const SessionType session_type, std::vector* _aidl_return) override; + + ndk::ScopedAStatus getProviderInfo( + SessionType in_sessionType, + std::optional* _aidl_return) override; }; } // namespace audio diff --git a/bluetooth/audio/hal/HfpOffloadAudioProvider.cpp b/bluetooth/audio/hal/HfpOffloadAudioProvider.cpp new file mode 100644 index 0000000..7196bb6 --- /dev/null +++ b/bluetooth/audio/hal/HfpOffloadAudioProvider.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2023 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. + */ + +#define LOG_TAG "BTAudioProviderHfpHW" + +#include "HfpOffloadAudioProvider.h" + +#include +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { + +HfpOffloadAudioProvider::HfpOffloadAudioProvider() { + session_type_ = SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH; +} + +bool HfpOffloadAudioProvider::isValid(const SessionType& session_type) { + return (session_type == session_type_); +} + +ndk::ScopedAStatus HfpOffloadAudioProvider::startSession( + const std::shared_ptr& host_if, + const AudioConfiguration& audio_config, + const std::vector& latency_modes, DataMQDesc* _aidl_return) { + if (audio_config.getTag() != AudioConfiguration::hfpConfig) { + LOG(WARNING) << __func__ << " - Invalid Audio Configuration=" + << audio_config.toString(); + *_aidl_return = DataMQDesc(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + return BluetoothAudioProvider::startSession(host_if, audio_config, + latency_modes, _aidl_return); +} + +ndk::ScopedAStatus HfpOffloadAudioProvider::onSessionReady( + DataMQDesc* _aidl_return) { + *_aidl_return = DataMQDesc(); + BluetoothAudioSessionReport::OnSessionStarted( + session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_); + return ndk::ScopedAStatus::ok(); +} + +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/bluetooth/audio/hal/HfpOffloadAudioProvider.h b/bluetooth/audio/hal/HfpOffloadAudioProvider.h new file mode 100644 index 0000000..5526b46 --- /dev/null +++ b/bluetooth/audio/hal/HfpOffloadAudioProvider.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023 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. + */ + +#pragma once + +#include "BluetoothAudioProvider.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { + +class HfpOffloadAudioProvider : public BluetoothAudioProvider { + public: + HfpOffloadAudioProvider(); + + bool isValid(const SessionType& sessionType) override; + + ndk::ScopedAStatus startSession( + const std::shared_ptr& host_if, + const AudioConfiguration& audio_config, + const std::vector& latency_modes, DataMQDesc* _aidl_return); + + private: + ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override; +}; + +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/bluetooth/audio/hal/HfpSoftwareAudioProvider.cpp b/bluetooth/audio/hal/HfpSoftwareAudioProvider.cpp new file mode 100644 index 0000000..0f96046 --- /dev/null +++ b/bluetooth/audio/hal/HfpSoftwareAudioProvider.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2023 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. + */ + +#define LOG_TAG "BTAudioProviderHfpSW" + +#include "HfpSoftwareAudioProvider.h" + +#include +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { + +static constexpr uint32_t kBufferCount = 2; // two frame buffer + +HfpSoftwareOutputAudioProvider::HfpSoftwareOutputAudioProvider() + : HfpSoftwareAudioProvider() { + session_type_ = SessionType::HFP_SOFTWARE_ENCODING_DATAPATH; +} + +HfpSoftwareInputAudioProvider::HfpSoftwareInputAudioProvider() + : HfpSoftwareAudioProvider() { + session_type_ = SessionType::HFP_SOFTWARE_DECODING_DATAPATH; +} + +HfpSoftwareAudioProvider::HfpSoftwareAudioProvider() + : BluetoothAudioProvider(), data_mq_(nullptr) { +} + +bool HfpSoftwareAudioProvider::isValid(const SessionType& sessionType) { + return (sessionType == session_type_); +} + +ndk::ScopedAStatus HfpSoftwareAudioProvider::startSession( + const std::shared_ptr& host_if, + const AudioConfiguration& audio_config, + const std::vector& latency_modes, DataMQDesc* _aidl_return) { + if (audio_config.getTag() != AudioConfiguration::pcmConfig) { + LOG(WARNING) << __func__ << " - Invalid Audio Configuration=" + << audio_config.toString(); + *_aidl_return = DataMQDesc(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + const PcmConfiguration& pcm_config = + audio_config.get(); + if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) { + LOG(WARNING) << __func__ << " - Unsupported PCM Configuration=" + << pcm_config.toString(); + *_aidl_return = DataMQDesc(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + bool isValidConfig = true; + + if (pcm_config.bitsPerSample != 16) { + isValidConfig = false; + } + + if (pcm_config.sampleRateHz != 8000 && pcm_config.sampleRateHz != 16000 && + pcm_config.sampleRateHz != 32000) { + isValidConfig = false; + } + + if (pcm_config.channelMode != ChannelMode::MONO) { + isValidConfig = false; + } + + if (pcm_config.dataIntervalUs != 7500) { + isValidConfig = false; + } + + int bytes_per_sample = pcm_config.bitsPerSample / 8; + + uint32_t data_mq_size = kBufferCount * bytes_per_sample * + (pcm_config.sampleRateHz / 1000) * + pcm_config.dataIntervalUs / 1000; + if (!isValidConfig) { + LOG(ERROR) << __func__ << "Unexpected audio buffer size: " << data_mq_size + << ", SampleRateHz: " << pcm_config.sampleRateHz + << ", ChannelMode: " << toString(pcm_config.channelMode) + << ", BitsPerSample: " + << static_cast(pcm_config.bitsPerSample) + << ", BytesPerSample: " << bytes_per_sample + << ", DataIntervalUs: " << pcm_config.dataIntervalUs + << ", SessionType: " << toString(session_type_); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + LOG(INFO) << __func__ << " - size of audio buffer " << data_mq_size + << " byte(s)"; + + std::unique_ptr temp_data_mq( + new DataMQ(data_mq_size, /* EventFlag */ true)); + if (temp_data_mq == nullptr || !temp_data_mq->isValid()) { + ALOGE_IF(!temp_data_mq, "failed to allocate data MQ"); + ALOGE_IF(temp_data_mq && !temp_data_mq->isValid(), "data MQ is invalid"); + *_aidl_return = DataMQDesc(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + data_mq_ = std::move(temp_data_mq); + + return BluetoothAudioProvider::startSession(host_if, audio_config, + latency_modes, _aidl_return); +} + +ndk::ScopedAStatus HfpSoftwareAudioProvider::onSessionReady( + DataMQDesc* _aidl_return) { + if (data_mq_ == nullptr || !data_mq_->isValid()) { + *_aidl_return = DataMQDesc(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + *_aidl_return = data_mq_->dupeDesc(); + auto desc = data_mq_->dupeDesc(); + BluetoothAudioSessionReport::OnSessionStarted( + session_type_, stack_iface_, &desc, *audio_config_, latency_modes_); + return ndk::ScopedAStatus::ok(); +} + +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/bluetooth/audio/hal/HfpSoftwareAudioProvider.h b/bluetooth/audio/hal/HfpSoftwareAudioProvider.h new file mode 100644 index 0000000..ef51065 --- /dev/null +++ b/bluetooth/audio/hal/HfpSoftwareAudioProvider.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2023 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. + */ + +#pragma once + +#include "BluetoothAudioProvider.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { + +class HfpSoftwareAudioProvider : public BluetoothAudioProvider { + public: + HfpSoftwareAudioProvider(); + + bool isValid(const SessionType& sessionType) override; + + ndk::ScopedAStatus startSession( + const std::shared_ptr& host_if, + const AudioConfiguration& audio_config, + const std::vector& latency_modes, DataMQDesc* _aidl_return); + + private: + // audio data queue for software encoding + std::unique_ptr data_mq_; + + ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override; +}; + +class HfpSoftwareOutputAudioProvider : public HfpSoftwareAudioProvider { + public: + HfpSoftwareOutputAudioProvider(); +}; + +class HfpSoftwareInputAudioProvider : public HfpSoftwareAudioProvider { + public: + HfpSoftwareInputAudioProvider(); +}; + +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/bluetooth/audio/hal/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/hal/LeAudioOffloadAudioProvider.cpp index 0e22e44..cff3b25 100644 --- a/bluetooth/audio/hal/LeAudioOffloadAudioProvider.cpp +++ b/bluetooth/audio/hal/LeAudioOffloadAudioProvider.cpp @@ -28,6 +28,73 @@ namespace hardware { namespace bluetooth { namespace audio { +constexpr uint8_t kLeAudioDirectionSink = 0x01; +constexpr uint8_t kLeAudioDirectionSource = 0x02; + +const std::map + freq_to_support_bitmask_map = { + {CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000, + CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000}, + {CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025, + CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ11025}, + {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000, + CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000}, + {CodecSpecificConfigurationLtv::SamplingFrequency::HZ22050, + CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ22050}, + {CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000, + CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ24000}, + {CodecSpecificConfigurationLtv::SamplingFrequency::HZ32000, + CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ32000}, + {CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000, + CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ48000}, + {CodecSpecificConfigurationLtv::SamplingFrequency::HZ88200, + CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ88200}, + {CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000, + CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ96000}, + {CodecSpecificConfigurationLtv::SamplingFrequency::HZ176400, + CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ176400}, + {CodecSpecificConfigurationLtv::SamplingFrequency::HZ192000, + CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ192000}, + {CodecSpecificConfigurationLtv::SamplingFrequency::HZ384000, + CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ384000}, +}; + +// Helper map from capability's tag to configuration's tag +std::map + cap_to_cfg_tag_map = { + {CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies, + CodecSpecificConfigurationLtv::Tag::samplingFrequency}, + {CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU, + CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU}, + {CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations, + CodecSpecificConfigurationLtv::Tag::frameDuration}, + {CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts, + CodecSpecificConfigurationLtv::Tag::audioChannelAllocation}, + {CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame, + CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame}, +}; + +const std::map + fduration_to_support_fduration_map = { + {CodecSpecificConfigurationLtv::FrameDuration::US7500, + CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500}, + {CodecSpecificConfigurationLtv::FrameDuration::US10000, + CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000}, +}; + +std::map + sampling_freq_map = { + {16000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000}, + {48000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000}, + {96000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000}, +}; + +std::map + frame_duration_map = { + {7500, CodecSpecificConfigurationLtv::FrameDuration::US7500}, + {10000, CodecSpecificConfigurationLtv::FrameDuration::US10000}, +}; + LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider() : LeAudioOffloadAudioProvider() { session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH; @@ -55,24 +122,23 @@ ndk::ScopedAStatus LeAudioOffloadAudioProvider::startSession( const std::shared_ptr& host_if, const AudioConfiguration& audio_config, const std::vector& latency_modes, DataMQDesc* _aidl_return) { - if (audio_config.getTag() != AudioConfiguration::leAudioConfig) { + if (session_type_ == + SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) { + if (audio_config.getTag() != AudioConfiguration::leAudioBroadcastConfig) { + LOG(WARNING) << __func__ << " - Invalid Audio Configuration=" + << audio_config.toString(); + *_aidl_return = DataMQDesc(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + } else if (audio_config.getTag() != AudioConfiguration::leAudioConfig) { LOG(WARNING) << __func__ << " - Invalid Audio Configuration=" << audio_config.toString(); *_aidl_return = DataMQDesc(); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } - const auto& le_audio_config = - audio_config.get(); - if (!BluetoothAudioCodecs::IsOffloadLeAudioConfigurationValid( - session_type_, le_audio_config)) { - LOG(WARNING) << __func__ << " - Unsupported LC3 Offloaded Configuration=" - << le_audio_config.toString(); - *_aidl_return = DataMQDesc(); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - return BluetoothAudioProvider::startSession( - host_if, audio_config, latency_modes, _aidl_return); + return BluetoothAudioProvider::startSession(host_if, audio_config, + latency_modes, _aidl_return); } ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSessionReady( @@ -82,6 +148,644 @@ ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSessionReady( *_aidl_return = DataMQDesc(); return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus LeAudioOffloadAudioProvider::setCodecPriority( + const CodecId& in_codecId, int32_t in_priority) { + codec_priority_map_[in_codecId] = in_priority; + return ndk::ScopedAStatus::ok(); +}; + +bool LeAudioOffloadAudioProvider::isMatchedValidCodec(CodecId cfg_codec, + CodecId req_codec) { + auto priority = codec_priority_map_.find(cfg_codec); + if (priority != codec_priority_map_.end() && priority->second == -1) + return false; + return cfg_codec == req_codec; +} + +bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedContext( + AudioContext setting_context, + const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) { + // If has no metadata, assume match + if (!capabilities.metadata.has_value()) return true; + + for (auto metadata : capabilities.metadata.value()) { + if (!metadata.has_value()) continue; + if (metadata.value().getTag() == MetadataLtv::Tag::preferredAudioContexts) { + // Check all pref audio context to see if anything matched + auto& context = metadata.value() + .get() + .values; + if (setting_context.bitmask & context.bitmask) return true; + } + } + + return false; +} + +bool LeAudioOffloadAudioProvider::isMatchedSamplingFreq( + CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq, + CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies& + capability_freq) { + for (auto [freq, bitmask] : freq_to_support_bitmask_map) + if (cfg_freq == freq) return (capability_freq.bitmask & bitmask); + return false; +} + +bool LeAudioOffloadAudioProvider::isMatchedFrameDuration( + CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration, + CodecSpecificCapabilitiesLtv::SupportedFrameDurations& + capability_fduration) { + for (auto [fduration, bitmask] : fduration_to_support_fduration_map) + if (cfg_fduration == fduration) + return (capability_fduration.bitmask & bitmask); + return false; +} + +bool LeAudioOffloadAudioProvider::isMatchedAudioChannel( + CodecSpecificConfigurationLtv::AudioChannelAllocation& + /*cfg_channel*/, + CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts& + /*capability_channel*/) { + bool isMatched = true; + // TODO: how to match? + return isMatched; +} + +bool LeAudioOffloadAudioProvider::isMatchedCodecFramesPerSDU( + CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU& cfg_frame_sdu, + CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU& + capability_frame_sdu) { + return cfg_frame_sdu.value <= capability_frame_sdu.value; +} + +bool LeAudioOffloadAudioProvider::isMatchedOctetsPerCodecFrame( + CodecSpecificConfigurationLtv::OctetsPerCodecFrame& cfg_octets, + CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame& + capability_octets) { + return cfg_octets.value >= capability_octets.minimum && + cfg_octets.value <= capability_octets.maximum; +} + +bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedCodecConfiguration( + std::vector& codec_cfg, + std::vector codec_capabilities) { + // Convert all codec_cfg into a map of tags -> correct data + std::map + cfg_tag_map; + for (auto codec_cfg_data : codec_cfg) + cfg_tag_map[codec_cfg_data.getTag()] = codec_cfg_data; + + for (auto& codec_capability : codec_capabilities) { + auto cfg = cfg_tag_map.find(cap_to_cfg_tag_map[codec_capability.getTag()]); + // Cannot find tag for the capability: + if (cfg == cfg_tag_map.end()) return false; + + // Matching logic for sampling frequency + if (codec_capability.getTag() == + CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies) { + if (!isMatchedSamplingFreq( + cfg->second + .get(), + codec_capability.get())) + return false; + } else if (codec_capability.getTag() == + CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations) { + if (!isMatchedFrameDuration( + cfg->second + .get(), + codec_capability.get())) + return false; + } else if (codec_capability.getTag() == + CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts) { + if (!isMatchedAudioChannel( + cfg->second.get< + CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>(), + codec_capability.get())) + return false; + } else if (codec_capability.getTag() == CodecSpecificCapabilitiesLtv::Tag:: + supportedMaxCodecFramesPerSDU) { + if (!isMatchedCodecFramesPerSDU( + cfg->second.get< + CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU>(), + codec_capability.get())) + return false; + } else if (codec_capability.getTag() == CodecSpecificCapabilitiesLtv::Tag:: + supportedOctetsPerCodecFrame) { + if (!isMatchedOctetsPerCodecFrame( + cfg->second.get< + CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(), + codec_capability.get())) + return false; + } + } + + return true; +} + +bool LeAudioOffloadAudioProvider::isMatchedAseConfiguration( + LeAudioAseConfiguration setting_cfg, + LeAudioAseConfiguration requirement_cfg) { + // Check matching for codec configuration <=> requirement ASE codec + // Also match if no CodecId requirement + if (requirement_cfg.codecId.has_value()) { + if (!setting_cfg.codecId.has_value()) return false; + if (!isMatchedValidCodec(setting_cfg.codecId.value(), + requirement_cfg.codecId.value())) + return false; + } + + if (setting_cfg.targetLatency != requirement_cfg.targetLatency) return false; + // Ignore PHY requirement + + // Check all codec configuration + std::map + cfg_tag_map; + for (auto cfg : setting_cfg.codecConfiguration) + cfg_tag_map[cfg.getTag()] = cfg; + + for (auto requirement_cfg : requirement_cfg.codecConfiguration) { + // Directly compare CodecSpecificConfigurationLtv + auto cfg = cfg_tag_map.find(requirement_cfg.getTag()); + if (cfg == cfg_tag_map.end()) return false; + + if (cfg->second != requirement_cfg) return false; + } + // Ignore vendor configuration and metadata requirement + + return true; +} + +bool LeAudioOffloadAudioProvider::isMatchedBISConfiguration( + LeAudioBisConfiguration bis_cfg, + const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) { + if (!isMatchedValidCodec(bis_cfg.codecId, capabilities.codecId)) return false; + if (!isCapabilitiesMatchedCodecConfiguration( + bis_cfg.codecConfiguration, capabilities.codecSpecificCapabilities)) + return false; + return true; +} + +void LeAudioOffloadAudioProvider::filterCapabilitiesAseDirectionConfiguration( + std::vector>& + direction_configurations, + const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities, + std::vector>& + valid_direction_configurations) { + for (auto direction_configuration : direction_configurations) { + if (!direction_configuration.has_value()) continue; + if (!direction_configuration.value().aseConfiguration.codecId.has_value()) + continue; + if (!isMatchedValidCodec( + direction_configuration.value().aseConfiguration.codecId.value(), + capabilities.codecId)) + continue; + // Check matching for codec configuration <=> codec capabilities + if (!isCapabilitiesMatchedCodecConfiguration( + direction_configuration.value().aseConfiguration.codecConfiguration, + capabilities.codecSpecificCapabilities)) + continue; + valid_direction_configurations.push_back(direction_configuration); + } +} + +void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration( + std::vector>& + direction_configurations, + const std::optional>>& + requirements, + std::vector>& + valid_direction_configurations) { + for (auto direction_configuration : direction_configurations) { + if (!requirements.has_value()) { + // If there's no requirement, all are valid + valid_direction_configurations.push_back(direction_configuration); + continue; + } + if (!direction_configuration.has_value()) continue; + + for (auto& requirement : requirements.value()) { + if (!requirement.has_value()) continue; + if (!isMatchedAseConfiguration( + direction_configuration.value().aseConfiguration, + requirement.value().aseConfiguration)) + continue; + // Valid if match any requirement. + valid_direction_configurations.push_back(direction_configuration); + break; + } + } +} + +/* Get a new LeAudioAseConfigurationSetting by matching a setting with a + * capabilities. The new setting will have a filtered list of + * AseDirectionConfiguration that matched the capabilities */ +std::optional +LeAudioOffloadAudioProvider::getCapabilitiesMatchedAseConfigurationSettings( + IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting, + const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities, + uint8_t direction) { + // Try to match context in metadata. + if (!isCapabilitiesMatchedContext(setting.audioContext, capabilities)) + return std::nullopt; + + // Get a list of all matched AseDirectionConfiguration + // for the input direction + std::vector>* + direction_configuration = nullptr; + if (direction == kLeAudioDirectionSink) { + if (!setting.sinkAseConfiguration.has_value()) return std::nullopt; + direction_configuration = &setting.sinkAseConfiguration.value(); + } else { + if (!setting.sourceAseConfiguration.has_value()) return std::nullopt; + direction_configuration = &setting.sourceAseConfiguration.value(); + } + std::vector> + valid_direction_configuration; + filterCapabilitiesAseDirectionConfiguration( + *direction_configuration, capabilities, valid_direction_configuration); + if (valid_direction_configuration.empty()) return std::nullopt; + + // Create a new LeAudioAseConfigurationSetting and return + LeAudioAseConfigurationSetting filtered_setting; + filtered_setting.audioContext = setting.audioContext; + filtered_setting.packing = setting.packing; + if (direction == kLeAudioDirectionSink) { + filtered_setting.sinkAseConfiguration = valid_direction_configuration; + } else { + filtered_setting.sourceAseConfiguration = valid_direction_configuration; + } + filtered_setting.flags = setting.flags; + + return filtered_setting; +} + +/* Get a new LeAudioAseConfigurationSetting by matching a setting with a + * requirement. The new setting will have a filtered list of + * AseDirectionConfiguration that matched the requirement */ +std::optional +LeAudioOffloadAudioProvider::getRequirementMatchedAseConfigurationSettings( + IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting, + const IBluetoothAudioProvider::LeAudioConfigurationRequirement& + requirement) { + // Try to match context in metadata. + if (setting.audioContext != requirement.audioContext) return std::nullopt; + + // Check requirement for the correct direction + const std::optional>>* + direction_requirement; + std::vector>* + direction_configuration; + if (setting.sinkAseConfiguration.has_value()) { + direction_configuration = &setting.sinkAseConfiguration.value(); + direction_requirement = &requirement.sinkAseRequirement; + } else { + direction_configuration = &setting.sourceAseConfiguration.value(); + direction_requirement = &requirement.sourceAseRequirement; + } + + std::vector> + valid_direction_configuration; + filterRequirementAseDirectionConfiguration(*direction_configuration, + *direction_requirement, + valid_direction_configuration); + if (valid_direction_configuration.empty()) return std::nullopt; + + // Create a new LeAudioAseConfigurationSetting and return + LeAudioAseConfigurationSetting filtered_setting; + filtered_setting.audioContext = setting.audioContext; + filtered_setting.packing = setting.packing; + if (setting.sinkAseConfiguration.has_value()) + filtered_setting.sinkAseConfiguration = valid_direction_configuration; + else + filtered_setting.sourceAseConfiguration = valid_direction_configuration; + filtered_setting.flags = setting.flags; + + return filtered_setting; +} + +ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration( + const std::optional>>& + in_remoteSinkAudioCapabilities, + const std::optional>>& + in_remoteSourceAudioCapabilities, + const std::vector& + in_requirements, + std::vector* + _aidl_return) { + // Get all configuration settings + std::vector + ase_configuration_settings = + BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings(); + + // Currently won't handle case where both sink and source capabilities + // are passed in. Only handle one of them. + const std::optional>>* + in_remoteAudioCapabilities; + uint8_t direction = 0; + if (in_remoteSinkAudioCapabilities.has_value()) { + direction = kLeAudioDirectionSink; + in_remoteAudioCapabilities = &in_remoteSinkAudioCapabilities; + } else { + direction = kLeAudioDirectionSource; + in_remoteAudioCapabilities = &in_remoteSourceAudioCapabilities; + } + + std::vector + capability_matched_ase_configuration_settings; + // Matching with remote capabilities + for (auto& setting : ase_configuration_settings) { + for (auto& capability : in_remoteAudioCapabilities->value()) { + if (!capability.has_value()) continue; + auto filtered_ase_configuration_setting = + getCapabilitiesMatchedAseConfigurationSettings( + setting, capability.value(), direction); + if (filtered_ase_configuration_setting.has_value()) { + capability_matched_ase_configuration_settings.push_back( + filtered_ase_configuration_setting.value()); + } + } + } + + // Matching with requirements + std::vector result; + for (auto& setting : capability_matched_ase_configuration_settings) { + for (auto& requirement : in_requirements) { + auto filtered_ase_configuration_setting = + getRequirementMatchedAseConfigurationSettings(setting, requirement); + if (filtered_ase_configuration_setting.has_value()) { + result.push_back(filtered_ase_configuration_setting.value()); + } + } + } + + *_aidl_return = result; + return ndk::ScopedAStatus::ok(); +}; + +bool LeAudioOffloadAudioProvider::isMatchedQosRequirement( + LeAudioAseQosConfiguration setting_qos, + AseQosDirectionRequirement requirement_qos) { + if (setting_qos.retransmissionNum != + requirement_qos.preferredRetransmissionNum) + return false; + if (setting_qos.maxTransportLatencyMs > requirement_qos.maxTransportLatencyMs) + return false; + // Ignore other parameters, as they are not populated in the setting_qos + return true; +} + +ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseQosConfiguration( + const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement& + in_qosRequirement, + IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return) { + IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result; + // Get all configuration settings + std::vector + ase_configuration_settings = + BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings(); + + // Direction QoS matching + // Only handle one direction input case + uint8_t direction = 0; + std::optional direction_qos_requirement = + std::nullopt; + if (in_qosRequirement.sinkAseQosRequirement.has_value()) { + direction_qos_requirement = in_qosRequirement.sinkAseQosRequirement.value(); + direction = kLeAudioDirectionSink; + } else if (in_qosRequirement.sourceAseQosRequirement.has_value()) { + direction_qos_requirement = + in_qosRequirement.sourceAseQosRequirement.value(); + direction = kLeAudioDirectionSource; + } + + for (auto& setting : ase_configuration_settings) { + // Context matching + if (setting.audioContext != in_qosRequirement.contextType) continue; + + // Match configuration flags + // Currently configuration flags are not populated, ignore. + + // Get a list of all matched AseDirectionConfiguration + // for the input direction + std::vector>* + direction_configuration = nullptr; + if (direction == kLeAudioDirectionSink) { + if (!setting.sinkAseConfiguration.has_value()) continue; + direction_configuration = &setting.sinkAseConfiguration.value(); + } else { + if (!setting.sourceAseConfiguration.has_value()) continue; + direction_configuration = &setting.sourceAseConfiguration.value(); + } + + for (auto cfg : *direction_configuration) { + if (!cfg.has_value()) continue; + // If no requirement, return the first QoS + if (!direction_qos_requirement.has_value()) { + result.sinkQosConfiguration = cfg.value().qosConfiguration; + result.sourceQosConfiguration = cfg.value().qosConfiguration; + *_aidl_return = result; + return ndk::ScopedAStatus::ok(); + } + + // If has requirement, return the first matched QoS + // Try to match the ASE configuration + // and QoS with requirement + if (!cfg.value().qosConfiguration.has_value()) continue; + if (isMatchedAseConfiguration( + cfg.value().aseConfiguration, + direction_qos_requirement.value().aseConfiguration) && + isMatchedQosRequirement(cfg.value().qosConfiguration.value(), + direction_qos_requirement.value())) { + if (direction == kLeAudioDirectionSink) + result.sinkQosConfiguration = cfg.value().qosConfiguration; + else + result.sourceQosConfiguration = cfg.value().qosConfiguration; + *_aidl_return = result; + return ndk::ScopedAStatus::ok(); + } + } + } + + // No match, return empty QoS + *_aidl_return = result; + return ndk::ScopedAStatus::ok(); +}; + +ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSinkAseMetadataChanged( + IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/, + int32_t /*in_cisId*/, + const std::optional>>& in_metadata) { + (void)in_state; + (void)in_metadata; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +}; + +ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSourceAseMetadataChanged( + IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/, + int32_t /*in_cisId*/, + const std::optional>>& in_metadata) { + (void)in_state; + (void)in_metadata; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +}; + +void LeAudioOffloadAudioProvider::getBroadcastSettings() { + if (!broadcast_settings.empty()) return; + + LOG(INFO) << __func__ << ": Loading broadcast settings from provider info"; + + std::vector db_codec_info = + BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo( + SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH); + broadcast_settings.clear(); + CodecSpecificConfigurationLtv::AudioChannelAllocation default_allocation; + default_allocation.bitmask = + CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER; + + for (auto& codec_info : db_codec_info) { + if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio) + continue; + auto& transport = codec_info.transport.get(); + LeAudioBroadcastConfigurationSetting setting; + // Default setting + setting.numBis = 1; + setting.phy = {Phy::TWO_M}; + // Populate BIS configuration info using codec_info + LeAudioBisConfiguration bis_cfg; + bis_cfg.codecId = codec_info.id; + + CodecSpecificConfigurationLtv::OctetsPerCodecFrame octets; + octets.value = transport.bitdepth[0]; + + bis_cfg.codecConfiguration = { + sampling_freq_map[transport.samplingFrequencyHz[0]], octets, + frame_duration_map[transport.frameDurationUs[0]], default_allocation}; + + // Add information to structure + IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration sub_bis_cfg; + sub_bis_cfg.numBis = 1; + sub_bis_cfg.bisConfiguration = bis_cfg; + IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration sub_cfg; + sub_cfg.bisConfigurations = {sub_bis_cfg}; + setting.subgroupsConfigurations = {sub_cfg}; + + broadcast_settings.push_back(setting); + } + + LOG(INFO) << __func__ + << ": Done loading broadcast settings from provider info"; +} + +/* Get a new LeAudioAseConfigurationSetting by matching a setting with a + * capabilities. The new setting will have a filtered list of + * AseDirectionConfiguration that matched the capabilities */ +std::optional +LeAudioOffloadAudioProvider:: + getCapabilitiesMatchedBroadcastConfigurationSettings( + LeAudioBroadcastConfigurationSetting& setting, + const IBluetoothAudioProvider::LeAudioDeviceCapabilities& + capabilities) { + std::vector + filter_subgroup; + for (auto& sub_cfg : setting.subgroupsConfigurations) { + std::vector + filtered_bis_cfg; + for (auto& bis_cfg : sub_cfg.bisConfigurations) + if (isMatchedBISConfiguration(bis_cfg.bisConfiguration, capabilities)) { + filtered_bis_cfg.push_back(bis_cfg); + } + if (!filtered_bis_cfg.empty()) { + IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration + subgroup_cfg; + subgroup_cfg.bisConfigurations = filtered_bis_cfg; + filter_subgroup.push_back(subgroup_cfg); + } + } + if (filter_subgroup.empty()) return std::nullopt; + + // Create a new LeAudioAseConfigurationSetting and return + LeAudioBroadcastConfigurationSetting filtered_setting(setting); + filtered_setting.subgroupsConfigurations = filter_subgroup; + + return filtered_setting; +} + +ndk::ScopedAStatus +LeAudioOffloadAudioProvider::getLeAudioBroadcastConfiguration( + const std::optional>>& + in_remoteSinkAudioCapabilities, + const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement& + in_requirement, + LeAudioBroadcastConfigurationSetting* _aidl_return) { + getBroadcastSettings(); + _aidl_return = nullptr; + + // Match and filter capability + std::vector filtered_settings; + if (!in_remoteSinkAudioCapabilities.has_value()) { + LOG(WARNING) << __func__ << ": Empty capability"; + return ndk::ScopedAStatus::ok(); + } + for (auto& setting : broadcast_settings) { + for (auto& capability : in_remoteSinkAudioCapabilities.value()) { + if (!capability.has_value()) continue; + auto filtered_setting = + getCapabilitiesMatchedBroadcastConfigurationSettings( + setting, capability.value()); + if (filtered_setting.has_value()) + filtered_settings.push_back(filtered_setting.value()); + } + } + + if (filtered_settings.empty()) { + LOG(WARNING) << __func__ << ": Cannot match any remote capability"; + return ndk::ScopedAStatus::ok(); + } + + // Match and return the first matched requirement + if (in_requirement.subgroupConfigurationRequirements.empty()) { + LOG(INFO) << __func__ << ": Empty requirement"; + *_aidl_return = filtered_settings[0]; + return ndk::ScopedAStatus::ok(); + } + + for (auto& setting : filtered_settings) { + // Further filter out bis configuration + LeAudioBroadcastConfigurationSetting filtered_setting(setting); + filtered_setting.subgroupsConfigurations.clear(); + for (auto& sub_cfg : setting.subgroupsConfigurations) { + bool isMatched = false; + for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) { + // Matching number of BIS + if (sub_req.bisNumPerSubgroup != sub_cfg.bisConfigurations.size()) + continue; + // Currently will ignore quality and context hint. + isMatched = true; + break; + } + if (isMatched) + filtered_setting.subgroupsConfigurations.push_back(sub_cfg); + } + // Return the first match + if (!filtered_setting.subgroupsConfigurations.empty()) { + LOG(INFO) << __func__ << ": Matched requirement"; + *_aidl_return = filtered_setting; + return ndk::ScopedAStatus::ok(); + } + } + + LOG(WARNING) << __func__ << ": Cannot match any requirement"; + return ndk::ScopedAStatus::ok(); +}; } // namespace audio } // namespace bluetooth diff --git a/bluetooth/audio/hal/LeAudioOffloadAudioProvider.h b/bluetooth/audio/hal/LeAudioOffloadAudioProvider.h index 614c794..2785e7f 100644 --- a/bluetooth/audio/hal/LeAudioOffloadAudioProvider.h +++ b/bluetooth/audio/hal/LeAudioOffloadAudioProvider.h @@ -16,7 +16,12 @@ #pragma once +#include + #include "BluetoothAudioProvider.h" +#include "aidl/android/hardware/bluetooth/audio/LeAudioAseConfiguration.h" +#include "aidl/android/hardware/bluetooth/audio/MetadataLtv.h" +#include "aidl/android/hardware/bluetooth/audio/SessionType.h" namespace aidl { namespace android { @@ -24,6 +29,19 @@ namespace hardware { namespace bluetooth { namespace audio { +using LeAudioAseConfigurationSetting = + IBluetoothAudioProvider::LeAudioAseConfigurationSetting; +using AseDirectionRequirement = IBluetoothAudioProvider:: + LeAudioConfigurationRequirement::AseDirectionRequirement; +using AseDirectionConfiguration = IBluetoothAudioProvider:: + LeAudioAseConfigurationSetting::AseDirectionConfiguration; +using AseQosDirectionRequirement = IBluetoothAudioProvider:: + LeAudioAseQosConfigurationRequirement::AseQosDirectionRequirement; +using LeAudioAseQosConfiguration = + IBluetoothAudioProvider::LeAudioAseQosConfiguration; +using LeAudioBroadcastConfigurationSetting = + IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting; + class LeAudioOffloadAudioProvider : public BluetoothAudioProvider { public: LeAudioOffloadAudioProvider(); @@ -33,11 +51,112 @@ class LeAudioOffloadAudioProvider : public BluetoothAudioProvider { ndk::ScopedAStatus startSession( const std::shared_ptr& host_if, const AudioConfiguration& audio_config, - const std::vector& latency_modes, - DataMQDesc* _aidl_return); + const std::vector& latency_modes, DataMQDesc* _aidl_return); + ndk::ScopedAStatus setCodecPriority(const CodecId& in_codecId, + int32_t in_priority) override; + ndk::ScopedAStatus getLeAudioAseConfiguration( + const std::optional>>& + in_remoteSinkAudioCapabilities, + const std::optional>>& + in_remoteSourceAudioCapabilities, + const std::vector< + IBluetoothAudioProvider::LeAudioConfigurationRequirement>& + in_requirements, + std::vector* + _aidl_return) override; + ndk::ScopedAStatus getLeAudioAseQosConfiguration( + const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement& + in_qosRequirement, + IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return) + override; + ndk::ScopedAStatus onSourceAseMetadataChanged( + IBluetoothAudioProvider::AseState in_state, int32_t in_cigId, + int32_t in_cisId, + const std::optional>>& in_metadata) + override; + ndk::ScopedAStatus onSinkAseMetadataChanged( + IBluetoothAudioProvider::AseState in_state, int32_t in_cigId, + int32_t in_cisId, + const std::optional>>& in_metadata) + override; + ndk::ScopedAStatus getLeAudioBroadcastConfiguration( + const std::optional>>& + in_remoteSinkAudioCapabilities, + const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement& + in_requirement, + LeAudioBroadcastConfigurationSetting* _aidl_return) override; private: ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override; + std::map codec_priority_map_; + std::vector broadcast_settings; + + // Private matching function definitions + bool isMatchedValidCodec(CodecId cfg_codec, CodecId req_codec); + bool isCapabilitiesMatchedContext( + AudioContext setting_context, + const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities); + bool isMatchedSamplingFreq( + CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq, + CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies& + capability_freq); + bool isMatchedFrameDuration( + CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration, + CodecSpecificCapabilitiesLtv::SupportedFrameDurations& + capability_fduration); + bool isMatchedAudioChannel( + CodecSpecificConfigurationLtv::AudioChannelAllocation& cfg_channel, + CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts& + capability_channel); + bool isMatchedCodecFramesPerSDU( + CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU& cfg_frame_sdu, + CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU& + capability_frame_sdu); + bool isMatchedOctetsPerCodecFrame( + CodecSpecificConfigurationLtv::OctetsPerCodecFrame& cfg_octets, + CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame& + capability_octets); + bool isCapabilitiesMatchedCodecConfiguration( + std::vector& codec_cfg, + std::vector codec_capabilities); + bool isMatchedAseConfiguration(LeAudioAseConfiguration setting_cfg, + LeAudioAseConfiguration requirement_cfg); + bool isMatchedBISConfiguration( + LeAudioBisConfiguration bis_cfg, + const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities); + void filterCapabilitiesAseDirectionConfiguration( + std::vector>& + direction_configurations, + const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities, + std::vector>& + valid_direction_configurations); + void filterRequirementAseDirectionConfiguration( + std::vector>& + direction_configurations, + const std::optional>>& + requirements, + std::vector>& + valid_direction_configurations); + std::optional + getCapabilitiesMatchedAseConfigurationSettings( + IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting, + const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities, + uint8_t direction); + std::optional + getRequirementMatchedAseConfigurationSettings( + IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting, + const IBluetoothAudioProvider::LeAudioConfigurationRequirement& + requirement); + bool isMatchedQosRequirement(LeAudioAseQosConfiguration setting_qos, + AseQosDirectionRequirement requirement_qos); + std::optional + getCapabilitiesMatchedBroadcastConfigurationSettings( + LeAudioBroadcastConfigurationSetting& setting, + const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities); + void getBroadcastSettings(); }; class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider { diff --git a/bluetooth/audio/hal/bluetooth_audio_system.xml b/bluetooth/audio/hal/bluetooth_audio_system.xml index 8c0e722..1d469e8 100644 --- a/bluetooth/audio/hal/bluetooth_audio_system.xml +++ b/bluetooth/audio/hal/bluetooth_audio_system.xml @@ -1,7 +1,7 @@ android.hardware.bluetooth.audio - 3 + 4 IBluetoothAudioProviderFactory/sysbta diff --git a/bluetooth/audio/hw/Android.bp b/bluetooth/audio/hw/Android.bp index e57aad6..0b4d1d9 100644 --- a/bluetooth/audio/hw/Android.bp +++ b/bluetooth/audio/hw/Android.bp @@ -9,8 +9,11 @@ cc_library_shared { "utils.cc", ], header_libs: ["libhardware_headers"], + defaults: [ + "latest_android_hardware_audio_common_ndk_shared", + "latest_android_hardware_bluetooth_audio_ndk_shared", + ], shared_libs: [ - "android.hardware.bluetooth.audio-V3-ndk", "libbluetooth_audio_session_aidl_system", "libaudioutils", "libbase", diff --git a/bluetooth/audio/hw/audio_bluetooth_hw.cc b/bluetooth/audio/hw/audio_bluetooth_hw.cc index 887c4e3..f85cbb8 100644 --- a/bluetooth/audio/hw/audio_bluetooth_hw.cc +++ b/bluetooth/audio/hw/audio_bluetooth_hw.cc @@ -17,7 +17,6 @@ #define LOG_TAG "BTAudioHw" #include -#include #include #include #include @@ -39,7 +38,8 @@ static int adev_set_parameters(struct audio_hw_device* dev, LOG(VERBOSE) << __func__ << ": ParamsMap=[" << GetAudioParamString(params) << "]"; - if (params.find("A2dpSuspended") == params.end()) { + if (params.find("A2dpSuspended") == params.end() && + params.find("LeAudioSuspended") == params.end()) { return -ENOSYS; } @@ -99,6 +99,67 @@ static int adev_get_mic_mute(const struct audio_hw_device* dev, bool* state) { return -ENOSYS; } +static int adev_create_audio_patch(struct audio_hw_device* device, + unsigned int num_sources, + const struct audio_port_config* sources, + unsigned int num_sinks, + const struct audio_port_config* sinks, + audio_patch_handle_t* handle) { + if (device == nullptr || sources == nullptr || sinks == nullptr || + handle == nullptr || num_sources != 1 || num_sinks == 0 || + num_sinks > AUDIO_PATCH_PORTS_MAX) { + return -EINVAL; + } + if (sources[0].type == AUDIO_PORT_TYPE_DEVICE) { + if (num_sinks != 1 || sinks[0].type != AUDIO_PORT_TYPE_MIX) { + return -EINVAL; + } + } else if (sources[0].type == AUDIO_PORT_TYPE_MIX) { + for (unsigned int i = 0; i < num_sinks; i++) { + if (sinks[i].type != AUDIO_PORT_TYPE_DEVICE) { + return -EINVAL; + } + } + } else { + return -EINVAL; + } + + auto* bluetooth_device = reinterpret_cast(device); + std::lock_guard guard(bluetooth_device->mutex_); + if (*handle == AUDIO_PATCH_HANDLE_NONE) { + *handle = ++bluetooth_device->next_unique_id; + } + + LOG(INFO) << __func__ << ": device=" << std::hex << sinks[0].ext.device.type + << " handle: " << *handle; + return 0; +} + +static int adev_release_audio_patch(struct audio_hw_device* device, + audio_patch_handle_t patch_handle) { + if (device == nullptr) { + return -EINVAL; + } + LOG(INFO) << __func__ << ": patch_handle=" << patch_handle; + return 0; +} + +static int adev_get_audio_port_v7(struct audio_hw_device* device, + struct audio_port_v7* port) { + if (device == nullptr || port == nullptr) { + return -EINVAL; + } + return -ENOSYS; +} + +static int adev_get_audio_port(struct audio_hw_device* device, + struct audio_port* port) { + if (device == nullptr || port == nullptr) { + return -EINVAL; + } + return -ENOSYS; +} + static int adev_dump(const audio_hw_device_t* device, int fd) { return 0; } static int adev_close(hw_device_t* device) { @@ -117,7 +178,7 @@ static int adev_open(const hw_module_t* module, const char* name, if (!adev) return -ENOMEM; adev->common.tag = HARDWARE_DEVICE_TAG; - adev->common.version = AUDIO_DEVICE_API_VERSION_2_0; + adev->common.version = AUDIO_DEVICE_API_VERSION_3_2; adev->common.module = (struct hw_module_t*)module; adev->common.close = adev_close; @@ -138,6 +199,10 @@ static int adev_open(const hw_module_t* module, const char* name, adev->dump = adev_dump; adev->set_master_mute = adev_set_master_mute; adev->get_master_mute = adev_get_master_mute; + adev->create_audio_patch = adev_create_audio_patch; + adev->release_audio_patch = adev_release_audio_patch; + adev->get_audio_port_v7 = adev_get_audio_port_v7; + adev->get_audio_port = adev_get_audio_port; *device = &adev->common; return 0; diff --git a/bluetooth/audio/hw/device_port_proxy.cc b/bluetooth/audio/hw/device_port_proxy.cc index 8b49c4d..3e361b8 100644 --- a/bluetooth/audio/hw/device_port_proxy.cc +++ b/bluetooth/audio/hw/device_port_proxy.cc @@ -34,12 +34,17 @@ namespace bluetooth { namespace audio { namespace aidl { +using ::aidl::android::hardware::audio::common::SinkMetadata; +using ::aidl::android::hardware::audio::common::SourceMetadata; using ::aidl::android::hardware::bluetooth::audio::AudioConfiguration; using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioSessionControl; using ::aidl::android::hardware::bluetooth::audio::ChannelMode; using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration; using ::aidl::android::hardware::bluetooth::audio::PortStatusCallbacks; using ::aidl::android::hardware::bluetooth::audio::PresentationPosition; +using ::aidl::android::media::audio::common::AudioContentType; +using ::aidl::android::media::audio::common::AudioSource; +using ::aidl::android::media::audio::common::AudioUsage; using ::android::base::StringPrintf; using ControlResultCallback = std::function CovertAudioTagFromV7(char* tags_v7) { + std::vector tags; + char tags_copy[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; + strlcpy(tags_copy, tags_v7, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE); + char* tag = strtok(tags_copy, ";"); + + while (tag != NULL) { + tags.push_back(tag); + tag = strtok(NULL, ";"); + } + + return tags; +} + // The maximum time to wait in std::condition_variable::wait_for() constexpr unsigned int kMaxWaitingTimeMs = 4500; @@ -577,7 +596,7 @@ bool BluetoothAudioPortAidl::GetPresentationPosition( } void BluetoothAudioPortAidl::UpdateSourceMetadata( - const source_metadata* source_metadata) const { + const source_metadata_v7* source_metadata) const { if (!in_use()) { LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; return; @@ -586,13 +605,25 @@ void BluetoothAudioPortAidl::UpdateSourceMetadata( << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << ", " << source_metadata->track_count << " track(s)"; - if (source_metadata->track_count == 0) return; + ssize_t track_count = source_metadata->track_count; + if (track_count == 0) return; + SourceMetadata hal_source_metadata; + hal_source_metadata.tracks.resize(track_count); + for (int i = 0; i < track_count; i++) { + hal_source_metadata.tracks[i].usage = + static_cast(source_metadata->tracks[i].base.usage); + hal_source_metadata.tracks[i].contentType = static_cast( + source_metadata->tracks[i].base.content_type); + hal_source_metadata.tracks[i].tags = + std::move(CovertAudioTagFromV7(source_metadata->tracks[i].tags)); + } + BluetoothAudioSessionControl::UpdateSourceMetadata(session_type_, - *source_metadata); + hal_source_metadata); } void BluetoothAudioPortAidl::UpdateSinkMetadata( - const sink_metadata* sink_metadata) const { + const sink_metadata_v7* sink_metadata) const { if (!in_use()) { LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; return; @@ -601,9 +632,20 @@ void BluetoothAudioPortAidl::UpdateSinkMetadata( << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << ", " << sink_metadata->track_count << " track(s)"; - if (sink_metadata->track_count == 0) return; + ssize_t track_count = sink_metadata->track_count; + if (track_count == 0) return; + SinkMetadata hal_sink_metadata; + hal_sink_metadata.tracks.resize(track_count); + for (int i = 0; i < track_count; i++) { + hal_sink_metadata.tracks[i].source = + static_cast(sink_metadata->tracks[i].base.source); + hal_sink_metadata.tracks[i].gain = sink_metadata->tracks[i].base.gain; + hal_sink_metadata.tracks[i].tags = + std::move(CovertAudioTagFromV7(sink_metadata->tracks[i].tags)); + } + BluetoothAudioSessionControl::UpdateSinkMetadata(session_type_, - *sink_metadata); + hal_sink_metadata); } BluetoothStreamState BluetoothAudioPortAidl::GetState() const { return state_; } diff --git a/bluetooth/audio/hw/device_port_proxy.h b/bluetooth/audio/hw/device_port_proxy.h index dab4970..ff3dedd 100644 --- a/bluetooth/audio/hw/device_port_proxy.h +++ b/bluetooth/audio/hw/device_port_proxy.h @@ -16,6 +16,8 @@ #pragma once +#include +#include #include #include #include @@ -93,12 +95,6 @@ class BluetoothAudioPort { return false; } - /*** - * Called by the Audio framework / HAL when the metadata of the stream's - * source has been changed. - ***/ - virtual void UpdateSourceMetadata(const source_metadata*) const {}; - /*** * Return the current BluetoothStreamState ***/ @@ -113,6 +109,8 @@ class BluetoothAudioPort { virtual bool IsA2dp() const { return false; } + virtual bool IsLeAudio() const { return false; } + virtual bool GetPreferredDataIntervalUs(size_t* interval_us) const { return false; }; @@ -146,14 +144,13 @@ class BluetoothAudioPortAidl : public BluetoothAudioPort { bool GetPresentationPosition(uint64_t* delay_ns, uint64_t* byte, timespec* timestamp) const override; - void UpdateSourceMetadata( - const source_metadata* source_metadata) const override; + void UpdateSourceMetadata(const source_metadata_v7* source_metadata) const; /*** * Called by the Audio framework / HAL when the metadata of the stream's * sink has been changed. ***/ - virtual void UpdateSinkMetadata(const sink_metadata* sink_metadata) const; + virtual void UpdateSinkMetadata(const sink_metadata_v7* sink_metadata) const; BluetoothStreamState GetState() const override; @@ -165,6 +162,20 @@ class BluetoothAudioPortAidl : public BluetoothAudioPort { SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH; } + bool IsLeAudio() const override { + return session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH || + session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH || + session_type_ == + SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH || + session_type_ == + SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH || + session_type_ == + SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH || + session_type_ == + SessionType:: + LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH; + } + bool GetPreferredDataIntervalUs(size_t* interval_us) const override; protected: diff --git a/bluetooth/audio/hw/device_port_proxy_hidl.cc b/bluetooth/audio/hw/device_port_proxy_hidl.cc index 0f8aa3d..3aa3a9c 100644 --- a/bluetooth/audio/hw/device_port_proxy_hidl.cc +++ b/bluetooth/audio/hw/device_port_proxy_hidl.cc @@ -486,7 +486,7 @@ bool BluetoothAudioPortHidl::GetPresentationPosition( return retval; } -void BluetoothAudioPortHidl::UpdateSourceMetadata( +void BluetoothAudioPortHidl::UpdateTracksMetadata( const source_metadata* source_metadata) const { if (!in_use()) { LOG(ERROR) << __func__ << ": BluetoothAudioPort is not in use"; diff --git a/bluetooth/audio/hw/device_port_proxy_hidl.h b/bluetooth/audio/hw/device_port_proxy_hidl.h index f37370d..5b32889 100644 --- a/bluetooth/audio/hw/device_port_proxy_hidl.h +++ b/bluetooth/audio/hw/device_port_proxy_hidl.h @@ -55,8 +55,7 @@ class BluetoothAudioPortHidl : public BluetoothAudioPort { bool GetPresentationPosition(uint64_t* delay_ns, uint64_t* bytes, timespec* timestamp) const override; - void UpdateSourceMetadata( - const source_metadata* source_metadata) const override; + void UpdateTracksMetadata(const source_metadata* source_metadata) const; BluetoothStreamState GetState() const override; @@ -69,6 +68,17 @@ class BluetoothAudioPortHidl : public BluetoothAudioPort { SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH; } + bool IsLeAudio() const override { + return session_type_hidl_ == + SessionType_2_1::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH || + session_type_hidl_ == + SessionType_2_1::LE_AUDIO_SOFTWARE_DECODED_DATAPATH || + session_type_hidl_ == + SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH || + session_type_hidl_ == + SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH; + } + bool GetPreferredDataIntervalUs(size_t* interval_us) const override; protected: diff --git a/bluetooth/audio/hw/stream_apis.cc b/bluetooth/audio/hw/stream_apis.cc index 1f449fc..1a10803 100644 --- a/bluetooth/audio/hw/stream_apis.cc +++ b/bluetooth/audio/hw/stream_apis.cc @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -34,6 +33,7 @@ #include "utils.h" using ::android::base::StringPrintf; +using ::android::bluetooth::audio::utils::FrameCount; using ::android::bluetooth::audio::utils::GetAudioParamString; using ::android::bluetooth::audio::utils::ParseAudioParams; @@ -335,7 +335,7 @@ static int out_set_parameters(struct audio_stream* stream, } } - if (params.find("routing") != params.end()) { + if (params.find(AUDIO_PARAMETER_STREAM_ROUTING) != params.end()) { auto routing_param = params.find("routing"); LOG(INFO) << __func__ << ": state=" << out->bluetooth_output_->GetState() << ", stream param '" << routing_param->first.c_str() << "=" @@ -365,8 +365,33 @@ static int out_set_parameters(struct audio_stream* stream, } } - if (params.find("closing") != params.end()) { - if (params["closing"] == "true") { + if (params.find("LeAudioSuspended") != params.end() && + out->bluetooth_output_->IsLeAudio()) { + LOG(INFO) << __func__ << ": LeAudioSuspended found LEAudio=" + << out->bluetooth_output_->IsLeAudio(); + if (params["LeAudioSuspended"] == "true") { + LOG(INFO) << __func__ << ": LeAudioSuspended true, state=" + << out->bluetooth_output_->GetState() + << " stream param standby"; + if (out->bluetooth_output_->GetState() == BluetoothStreamState::STARTED) { + LOG(INFO) << __func__ << ": Stream is started, suspending LE Audio"; + } else if (out->bluetooth_output_->GetState() != + BluetoothStreamState::DISABLED) { + LOG(INFO) << __func__ << ": Stream is disabled, suspending LE Audio"; + } + } else { + LOG(INFO) << __func__ << ": LeAudioSuspended false, state=" + << out->bluetooth_output_->GetState() + << " stream param standby"; + if (out->bluetooth_output_->GetState() == + BluetoothStreamState::DISABLED) { + LOG(INFO) << __func__ << ": Stream is disabled, unsuspending LE Audio"; + } + } + } + + if (params.find(AUDIO_PARAMETER_KEY_CLOSING) != params.end()) { + if (params[AUDIO_PARAMETER_KEY_CLOSING] == "true") { LOG(INFO) << __func__ << ": state=" << out->bluetooth_output_->GetState() << " stream param closing, disallow any writes?"; if (out->bluetooth_output_->GetState() != @@ -378,8 +403,8 @@ static int out_set_parameters(struct audio_stream* stream, } } - if (params.find("exiting") != params.end()) { - if (params["exiting"] == "1") { + if (params.find(AUDIO_PARAMETER_KEY_EXITING) != params.end()) { + if (params[AUDIO_PARAMETER_KEY_EXITING] == "1") { LOG(INFO) << __func__ << ": state=" << out->bluetooth_output_->GetState() << " stream param exiting"; if (out->bluetooth_output_->GetState() != @@ -678,21 +703,32 @@ static int out_get_presentation_position(const struct audio_stream_out* stream, return 0; } -static void out_update_source_metadata( +static void out_update_source_metadata_v7( struct audio_stream_out* stream, - const struct source_metadata* source_metadata) { + const struct source_metadata_v7* source_metadata_v7) { auto* out = reinterpret_cast(stream); std::unique_lock lock(out->mutex_); - if (source_metadata == nullptr || source_metadata->track_count == 0) { + if (source_metadata_v7 == nullptr || source_metadata_v7->track_count == 0) { return; } LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_->GetState() - << ", " << source_metadata->track_count << " track(s)"; - out->bluetooth_output_->UpdateSourceMetadata(source_metadata); -} + << ", " << source_metadata_v7->track_count << " track(s)"; + if (!out->is_aidl) { + struct source_metadata source_metadata; + source_metadata.track_count = source_metadata_v7->track_count; + struct playback_track_metadata playback_track; + playback_track_metadata_from_v7(&playback_track, + source_metadata_v7->tracks); + source_metadata.tracks = &playback_track; -static size_t frame_count(size_t microseconds, uint32_t sample_rate) { - return (microseconds * sample_rate) / 1000000; + static_cast<::android::bluetooth::audio::hidl::BluetoothAudioPortHidl*>( + out->bluetooth_output_.get()) + ->UpdateTracksMetadata(&source_metadata); + } else { + static_cast<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl*>( + out->bluetooth_output_.get()) + ->UpdateSourceMetadata(source_metadata_v7); + } } int adev_open_output_stream(struct audio_hw_device* dev, @@ -740,7 +776,10 @@ int adev_open_output_stream(struct audio_hw_device* dev, out->stream_out_.pause = out_pause; out->stream_out_.resume = out_resume; out->stream_out_.get_presentation_position = out_get_presentation_position; - out->stream_out_.update_source_metadata = out_update_source_metadata; + out->stream_out_.update_source_metadata_v7 = out_update_source_metadata_v7; + /** Fix Coverity Scan Issue @{ */ + out->channel_mask_ = AUDIO_CHANNEL_NONE; + /** @} */ if (!out->bluetooth_output_->LoadAudioConfig(config)) { LOG(ERROR) << __func__ << ": state=" << out->bluetooth_output_->GetState() @@ -782,7 +821,7 @@ int adev_open_output_stream(struct audio_hw_device* dev, } out->frames_count_ = - frame_count(out->preferred_data_interval_us, out->sample_rate_); + FrameCount(out->preferred_data_interval_us, out->sample_rate_); out->frames_rendered_ = 0; out->frames_presented_ = 0; @@ -1182,8 +1221,9 @@ static int in_set_microphone_field_dimension( return -ENOSYS; } -static void in_update_sink_metadata(struct audio_stream_in* stream, - const struct sink_metadata* sink_metadata) { +static void in_update_sink_metadata_v7( + struct audio_stream_in* stream, + const struct sink_metadata_v7* sink_metadata) { LOG(INFO) << __func__; if (sink_metadata == nullptr || sink_metadata->track_count == 0) { return; @@ -1254,7 +1294,7 @@ int adev_open_input_stream(struct audio_hw_device* dev, in->stream_in_.set_microphone_direction = in_set_microphone_direction; in->stream_in_.set_microphone_field_dimension = in_set_microphone_field_dimension; - in->stream_in_.update_sink_metadata = in_update_sink_metadata; + in->stream_in_.update_sink_metadata_v7 = in_update_sink_metadata_v7; if (!in->bluetooth_input_->LoadAudioConfig(config)) { LOG(ERROR) << __func__ << ": state=" << in->bluetooth_input_->GetState() @@ -1277,7 +1317,7 @@ int adev_open_input_stream(struct audio_hw_device* dev, } in->frames_count_ = - frame_count(in->preferred_data_interval_us, in->sample_rate_); + FrameCount(in->preferred_data_interval_us, in->sample_rate_); in->frames_presented_ = 0; BluetoothStreamIn* in_ptr = in.release(); diff --git a/bluetooth/audio/hw/stream_apis.h b/bluetooth/audio/hw/stream_apis.h index 36dd589..d101027 100644 --- a/bluetooth/audio/hw/stream_apis.h +++ b/bluetooth/audio/hw/stream_apis.h @@ -81,6 +81,7 @@ struct BluetoothAudioDevice { std::mutex mutex_; std::list opened_stream_outs_ = std::list(0); + uint32_t next_unique_id = 1; }; struct BluetoothStreamIn { diff --git a/bluetooth/audio/hw/utils.cc b/bluetooth/audio/hw/utils.cc index b3ac7a5..f864fd5 100644 --- a/bluetooth/audio/hw/utils.cc +++ b/bluetooth/audio/hw/utils.cc @@ -57,6 +57,10 @@ std::string GetAudioParamString( return sout.str(); } +size_t FrameCount(uint64_t microseconds, uint32_t sample_rate) { + return (microseconds * sample_rate) / 1000000; +} + } // namespace utils } // namespace audio } // namespace bluetooth diff --git a/bluetooth/audio/hw/utils.h b/bluetooth/audio/hw/utils.h index 817a432..bdd8a9b 100644 --- a/bluetooth/audio/hw/utils.h +++ b/bluetooth/audio/hw/utils.h @@ -42,6 +42,7 @@ std::unordered_map ParseAudioParams( std::string GetAudioParamString( std::unordered_map& params_map); +size_t FrameCount(uint64_t microseconds, uint32_t sample_rate); } // namespace utils } // namespace audio } // namespace bluetooth diff --git a/bluetooth/audio/hw/utils_unittest.cc b/bluetooth/audio/hw/utils_unittest.cc new file mode 100644 index 0000000..1bcd5dd --- /dev/null +++ b/bluetooth/audio/hw/utils_unittest.cc @@ -0,0 +1,142 @@ +/* + * Copyright 2019 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 +#include + +#include "utils.h" + +namespace { + +using ::android::bluetooth::audio::utils::FrameCount; +using ::android::bluetooth::audio::utils::ParseAudioParams; + +class UtilsTest : public testing::Test { + protected: + void SetUp() override {} + void TearDown() override { map_.clear(); } + + std::unordered_map map_; +}; + +TEST_F(UtilsTest, HashMapEmptyParams) { + std::string params = ""; + map_ = ParseAudioParams(params); + // map = {} + EXPECT_TRUE(map_.empty()); +} + +TEST_F(UtilsTest, HashMapDelimitOnly) { + std::string params = ";"; + map_ = ParseAudioParams(params); + // map = {} + EXPECT_TRUE(map_.empty()); +} + +TEST_F(UtilsTest, HashMapNotKeyValuePair) { + std::string params = "key0"; + map_ = ParseAudioParams(params); + // map = {[key0]=""} + EXPECT_EQ(map_.size(), 1); + EXPECT_NE(map_.find("key0"), map_.end()); + EXPECT_EQ(map_["key0"].length(), 0); +} + +TEST_F(UtilsTest, HashMapEmptyValue) { + std::string params = "key0="; + map_ = ParseAudioParams(params); + // map = {[key0]=""} + EXPECT_EQ(map_.size(), 1); + EXPECT_NE(map_.find("key0"), map_.end()); + EXPECT_EQ(map_["key0"].length(), 0); +} + +TEST_F(UtilsTest, HashMapEmptyValueWithDelimit) { + std::string params = "key0=;"; + map_ = ParseAudioParams(params); + // map = {[key0]=""} + EXPECT_EQ(map_.size(), 1); + EXPECT_NE(map_.find("key0"), map_.end()); + EXPECT_EQ(map_["key0"].length(), 0); +} + +TEST_F(UtilsTest, HashMapOneKeyValuePair) { + std::string params = "key0=value0"; + map_ = ParseAudioParams(params); + // map = {[key0]="value0"} + EXPECT_EQ(map_.size(), 1); + EXPECT_EQ(map_["key0"], "value0"); +} + +TEST_F(UtilsTest, HashMapOneKeyValuePairWithDelimit) { + std::string params = "key0=value0;"; + map_ = ParseAudioParams(params); + // map = {[key0]="value0"} + EXPECT_EQ(map_.size(), 1); + EXPECT_EQ(map_["key0"], "value0"); +} + +TEST_F(UtilsTest, HashMapTwoKeyValuePairs) { + std::string params = "key0=value0;key1=value1"; + map_ = ParseAudioParams(params); + // map = {[key0]="value0", [key1]="value1"} + EXPECT_EQ(map_.size(), 2); + EXPECT_EQ(map_["key0"], "value0"); + EXPECT_EQ(map_["key1"], "value1"); +} + +TEST_F(UtilsTest, HashMapEmptyKey) { + std::string params = "=value"; + map_ = ParseAudioParams(params); + // map = {} + EXPECT_TRUE(map_.empty()); +} + +TEST_F(UtilsTest, HashMapEmptyKeyWithDelimit) { + std::string params = "=value;"; + map_ = ParseAudioParams(params); + // map = {} + EXPECT_TRUE(map_.empty()); +} + +TEST_F(UtilsTest, HashMapEquivalentOnly) { + std::string params = "="; + map_ = ParseAudioParams(params); + // map = {} + EXPECT_TRUE(map_.empty()); +} + +TEST_F(UtilsTest, HashMapNoKeyValuePair) { + std::string params = "=;"; + map_ = ParseAudioParams(params); + // map = {} + EXPECT_TRUE(map_.empty()); +} + +TEST_F(UtilsTest, HashMapTwoPairsWithFirstKeyEmpty) { + std::string params = "=value0;key1=value1"; + map_ = ParseAudioParams(params); + // map = {[key1]="value1"} + EXPECT_EQ(map_.size(), 1); + EXPECT_EQ(map_["key1"], "value1"); +} + +TEST_F(UtilsTest, FrameCountTest) { + EXPECT_EQ(FrameCount(120000, 44100), 5292); + EXPECT_EQ(FrameCount(7500, 32000), 240); +} + +} // namespace diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp index c2269f5..7f5baa5 100644 --- a/bluetooth/audio/utils/Android.bp +++ b/bluetooth/audio/utils/Android.bp @@ -29,9 +29,22 @@ cc_library_shared { "aidl_session/BluetoothAudioCodecs.cpp", "aidl_session/BluetoothAudioSession.cpp", "aidl_session/HidlToAidlMiddleware.cpp", + "aidl_session/BluetoothLeAudioCodecsProvider.cpp", + "aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp", ], export_include_dirs: ["aidl_session/"], - header_libs: ["libhardware_headers"], + header_libs: [ + "libhardware_headers", + "libxsdc-utils", + ], + generated_sources: ["le_audio_codec_capabilities_system"], + generated_headers: [ + "le_audio_codec_capabilities_system", + "AIDLLeAudioSetConfigSchemas_h_system", + ], + defaults: [ + "latest_android_hardware_bluetooth_audio_ndk_shared", + ], shared_libs: [ "android.hardware.bluetooth.audio@2.0", "android.hardware.bluetooth.audio@2.1", @@ -40,7 +53,83 @@ cc_library_shared { "libbinder_ndk", "libfmq", "liblog", - "android.hardware.bluetooth.audio-V3-ndk", "libhidlbase", + "libxml2", + "libflatbuffers-cpp", ], } + +xsd_config { + name: "le_audio_codec_capabilities_system", + srcs: ["le_audio_codec_capabilities/le_audio_codec_capabilities.xsd"], + package_name: "aidl.android.hardware.bluetooth.audio.setting", + api_dir: "le_audio_codec_capabilities/schema", + root_elements: ["leAudioOffloadSetting"], +} +genrule { + name: "AIDLLeAudioSetConfigSchemas_h_system", + tools: [ + "flatc", + ], + cmd: "$(location flatc) -I hardware/interfaces/bluetooth/audio/utils/ -o $(genDir) --cpp $(in) ", + srcs: [ + "le_audio_configuration_set/audio_set_configurations.fbs", + "le_audio_configuration_set/audio_set_scenarios.fbs", + ], + out: [ + "audio_set_configurations_generated.h", + "audio_set_scenarios_generated.h", + ], +} +// Binary generation +genrule { + name: "AIDLLeAudioSetScenariosSchema_bfbs_system", + tools: [ + "flatc", + ], + cmd: "$(location flatc) -I device/peter/gsi/bluetooth/audio/utils/ -b --schema -o $(genDir) $(in) ", + srcs: [ + "le_audio_configuration_set/audio_set_scenarios.fbs", + ], + out: [ + "audio_set_scenarios.bfbs", + ], +} +genrule { + name: "AIDLLeAudioSetConfigsSchema_bfbs_system", + tools: [ + "flatc", + ], + cmd: "$(location flatc) -I device/peter/gsi/bluetooth/audio/utils/ -b --schema -o $(genDir) $(in) ", + srcs: [ + "le_audio_configuration_set/audio_set_configurations.fbs", + ], + out: [ + "audio_set_configurations.bfbs", + ], +} +// Add to prebuilt etc +prebuilt_etc { + name: "aidl_audio_set_scenarios_bfbs_system", + src: ":AIDLLeAudioSetScenariosSchema_bfbs_system", + filename: "aidl_audio_set_scenarios.bfbs", + sub_dir: "aidl/le_audio", +} +prebuilt_etc { + name: "aidl_audio_set_scenarios_json_system", + src: "le_audio_configuration_set/audio_set_scenarios.json", + filename: "aidl_audio_set_scenarios.json", + sub_dir: "aidl/le_audio", +} +prebuilt_etc { + name: "aidl_audio_set_configurations_bfbs_system", + src: ":AIDLLeAudioSetConfigsSchema_bfbs", + filename: "aidl_audio_set_configurations.bfbs", + sub_dir: "aidl/le_audio", +} +prebuilt_etc { + name: "aidl_audio_set_configurations_json_system", + src: "le_audio_configuration_set/audio_set_configurations.json", + filename: "aidl_audio_set_configurations.json", + sub_dir: "aidl/le_audio", +} diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp index b858f50..216e169 100644 --- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp +++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp @@ -32,6 +32,9 @@ #include #include +#include "BluetoothLeAudioAseConfigurationSettingProvider.h" +#include "BluetoothLeAudioCodecsProvider.h" + namespace aidl { namespace android { namespace hardware { @@ -39,7 +42,7 @@ namespace bluetooth { namespace audio { static const PcmCapabilities kDefaultSoftwarePcmCapabilities = { - .sampleRateHz = {16000, 24000, 32000, 44100, 48000, 88200, 96000}, + .sampleRateHz = {8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000}, .channelMode = {ChannelMode::MONO, ChannelMode::STEREO}, .bitsPerSample = {16, 24, 32}, .dataIntervalUs = {}, @@ -95,67 +98,8 @@ const std::vector kDefaultOffloadA2dpCodecCapabilities = { {.codecType = CodecType::OPUS, .capabilities = {}}}; std::vector kDefaultOffloadLeAudioCapabilities; - -static const UnicastCapability kInvalidUnicastCapability = { - .codecType = CodecType::UNKNOWN}; - -static const BroadcastCapability kInvalidBroadcastCapability = { - .codecType = CodecType::UNKNOWN}; - -// Default Supported Codecs -// LC3 16_1: sample rate: 16 kHz, frame duration: 7.5 ms, octets per frame: 30 -static const Lc3Capabilities kLc3Capability_16_1 = { - .samplingFrequencyHz = {16000}, - .frameDurationUs = {7500}, - .octetsPerFrame = {30}}; - -// Default Supported Codecs -// LC3 16_2: sample rate: 16 kHz, frame duration: 10 ms, octets per frame: 40 -static const Lc3Capabilities kLc3Capability_16_2 = { - .samplingFrequencyHz = {16000}, - .frameDurationUs = {10000}, - .octetsPerFrame = {40}}; - -// Default Supported Codecs -// LC3 24_2: sample rate: 24 kHz, frame duration: 10 ms, octets per frame: 60 -static const Lc3Capabilities kLc3Capability_24_2 = { - .samplingFrequencyHz = {24000}, - .frameDurationUs = {10000}, - .octetsPerFrame = {60}}; - -// Default Supported Codecs -// LC3 32_2: sample rate: 32 kHz, frame duration: 10 ms, octets per frame: 80 -static const Lc3Capabilities kLc3Capability_32_2 = { - .samplingFrequencyHz = {32000}, - .frameDurationUs = {10000}, - .octetsPerFrame = {80}}; - -// Default Supported Codecs -// LC3 48_4: sample rate: 48 kHz, frame duration: 10 ms, octets per frame: 120 -static const Lc3Capabilities kLc3Capability_48_4 = { - .samplingFrequencyHz = {48000}, - .frameDurationUs = {10000}, - .octetsPerFrame = {120}}; - -static const std::vector supportedLc3CapabilityList = { - kLc3Capability_48_4, kLc3Capability_32_2, kLc3Capability_24_2, - kLc3Capability_16_2, kLc3Capability_16_1}; - -static AudioLocation stereoAudio = static_cast( - static_cast(AudioLocation::FRONT_LEFT) | - static_cast(AudioLocation::FRONT_RIGHT)); -static AudioLocation monoAudio = AudioLocation::UNKNOWN; - -// Stores the supported setting of audio location, connected device, and the -// channel count for each device -std::vector> - supportedDeviceSetting = { - // Stereo, two connected device, one for L one for R - std::make_tuple(stereoAudio, 2, 1), - // Stereo, one connected device for both L and R - std::make_tuple(stereoAudio, 1, 2), - // Mono - std::make_tuple(monoAudio, 1, 1)}; +std::unordered_map> + kDefaultOffloadLeAudioCodecInfoMap; template bool BluetoothAudioCodecs::ContainedInVector( @@ -321,19 +265,6 @@ bool BluetoothAudioCodecs::IsOffloadOpusConfigurationValid( return false; } -bool BluetoothAudioCodecs::IsOffloadLeAudioConfigurationValid( - const SessionType& session_type, const LeAudioConfiguration&) { - if (session_type != - SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH && - session_type != - SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH && - session_type != - SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) { - return false; - } - return true; -} - std::vector BluetoothAudioCodecs::GetSoftwarePcmCapabilities() { return {kDefaultSoftwarePcmCapabilities}; @@ -384,6 +315,8 @@ BluetoothAudioCodecs::GetA2dpOffloadCodecCapabilities( case CodecType::VENDOR: case CodecType::LC3: case CodecType::APTX_ADAPTIVE: + case CodecType::APTX_ADAPTIVE_LE: + case CodecType::APTX_ADAPTIVE_LEX: break; } } @@ -449,6 +382,8 @@ bool BluetoothAudioCodecs::IsOffloadCodecConfigurationValid( } break; case CodecType::APTX_ADAPTIVE: + case CodecType::APTX_ADAPTIVE_LE: + case CodecType::APTX_ADAPTIVE_LEX: case CodecType::LC3: case CodecType::UNKNOWN: case CodecType::VENDOR: @@ -457,19 +392,6 @@ bool BluetoothAudioCodecs::IsOffloadCodecConfigurationValid( return false; } -UnicastCapability composeUnicastLc3Capability( - AudioLocation audioLocation, uint8_t deviceCnt, uint8_t channelCount, - const Lc3Capabilities& capability) { - return { - .codecType = CodecType::LC3, - .supportedChannel = audioLocation, - .deviceCount = deviceCnt, - .channelCountPerDevice = channelCount, - .leAudioCodecCapabilities = - UnicastCapability::LeAudioCodecCapabilities(capability), - }; -} - std::vector BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities( const SessionType& session_type) { @@ -483,37 +405,44 @@ BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities( } if (kDefaultOffloadLeAudioCapabilities.empty()) { - for (auto [audioLocation, deviceCnt, channelCount] : - supportedDeviceSetting) { - for (auto capability : supportedLc3CapabilityList) { - UnicastCapability lc3Capability = composeUnicastLc3Capability( - audioLocation, deviceCnt, channelCount, capability); - UnicastCapability lc3MonoDecodeCapability = - composeUnicastLc3Capability(monoAudio, 1, 1, capability); + auto le_audio_offload_setting = + BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile(); + kDefaultOffloadLeAudioCapabilities = + BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities( + le_audio_offload_setting); + } + return kDefaultOffloadLeAudioCapabilities; +} - // Adds the capability for encode only - kDefaultOffloadLeAudioCapabilities.push_back( - {.unicastEncodeCapability = lc3Capability, - .unicastDecodeCapability = kInvalidUnicastCapability, - .broadcastCapability = kInvalidBroadcastCapability}); - - // Adds the capability for decode only - kDefaultOffloadLeAudioCapabilities.push_back( - {.unicastEncodeCapability = kInvalidUnicastCapability, - .unicastDecodeCapability = lc3Capability, - .broadcastCapability = kInvalidBroadcastCapability}); - - // Adds the capability for the case that encode and decode exist at the - // same time - kDefaultOffloadLeAudioCapabilities.push_back( - {.unicastEncodeCapability = lc3Capability, - .unicastDecodeCapability = lc3MonoDecodeCapability, - .broadcastCapability = kInvalidBroadcastCapability}); - } - } +std::vector BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo( + const SessionType& session_type) { + if (session_type != + SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH && + session_type != + SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH && + session_type != + SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) { + return std::vector(); } - return kDefaultOffloadLeAudioCapabilities; + if (kDefaultOffloadLeAudioCodecInfoMap.empty()) { + auto le_audio_offload_setting = + BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile(); + auto kDefaultOffloadLeAudioCodecInfoMap = + BluetoothLeAudioCodecsProvider::GetLeAudioCodecInfo( + le_audio_offload_setting); + } + auto codec_info_map_iter = + kDefaultOffloadLeAudioCodecInfoMap.find(session_type); + if (codec_info_map_iter == kDefaultOffloadLeAudioCodecInfoMap.end()) + return std::vector(); + return codec_info_map_iter->second; +} + +std::vector +BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings() { + return AudioSetConfigurationProviderJson:: + GetLeAudioAseConfigurationSettings(); } } // namespace audio diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h index ed0598b..057b9a7 100644 --- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h +++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h @@ -18,6 +18,8 @@ #include #include +#include +#include #include #include #include @@ -33,6 +35,9 @@ namespace hardware { namespace bluetooth { namespace audio { +using LeAudioAseConfigurationSetting = + IBluetoothAudioProvider::LeAudioAseConfigurationSetting; + class BluetoothAudioCodecs { public: static std::vector GetSoftwarePcmCapabilities(); @@ -44,11 +49,13 @@ class BluetoothAudioCodecs { static bool IsOffloadCodecConfigurationValid( const SessionType& session_type, const CodecConfiguration& codec_config); - static bool IsOffloadLeAudioConfigurationValid( - const SessionType& session_type, const LeAudioConfiguration&); - static std::vector GetLeAudioOffloadCodecCapabilities(const SessionType& session_type); + static std::vector GetLeAudioOffloadCodecInfo( + const SessionType& session_type); + + static std::vector + GetLeAudioAseConfigurationSettings(); private: template diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp index 3214bf2..3519ace 100644 --- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp +++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "BluetoothAudioSession.h" @@ -94,6 +95,8 @@ const AudioConfiguration BluetoothAudioSession::GetAudioConfig() { case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH: case SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH: return AudioConfiguration(CodecConfiguration{}); + case SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH: + return AudioConfiguration(HfpConfiguration{}); case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH: case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH: return AudioConfiguration(LeAudioConfiguration{}); @@ -114,8 +117,16 @@ void BluetoothAudioSession::ReportAudioConfigChanged( SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) { return; } + std::lock_guard guard(mutex_); + if (audio_config.getTag() != AudioConfiguration::leAudioConfig) { + LOG(ERROR) << __func__ << " invalid audio config type for SessionType =" + << toString(session_type_); + return; + } + audio_config_ = std::make_unique(audio_config); + if (observers_.empty()) { LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_) << " has NO port state observer"; @@ -145,6 +156,7 @@ bool BluetoothAudioSession::IsSessionReady() { session_type_ == SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH || session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH || + session_type_ == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH || (data_mq_ != nullptr && data_mq_->isValid())); return stack_iface_ != nullptr && is_mq_valid && audio_config_ != nullptr; } @@ -266,6 +278,8 @@ bool BluetoothAudioSession::UpdateAudioConfig( bool is_software_session = (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || session_type_ == SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH || + session_type_ == SessionType::HFP_SOFTWARE_ENCODING_DATAPATH || + session_type_ == SessionType::HFP_SOFTWARE_DECODING_DATAPATH || session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH || session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH || session_type_ == @@ -274,23 +288,37 @@ bool BluetoothAudioSession::UpdateAudioConfig( bool is_offload_a2dp_session = (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH || session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH); - bool is_offload_le_audio_session = + bool is_offload_hfp_session = + session_type_ == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH; + bool is_offload_le_audio_unicast_session = (session_type_ == SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH || session_type_ == SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH); + bool is_offload_le_audio_broadcast_session = + (session_type_ == + SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH); auto audio_config_tag = audio_config.getTag(); bool is_software_audio_config = (is_software_session && audio_config_tag == AudioConfiguration::pcmConfig); bool is_a2dp_offload_audio_config = (is_offload_a2dp_session && - audio_config_tag == AudioConfiguration::a2dpConfig); - bool is_le_audio_offload_audio_config = - (is_offload_le_audio_session && + (audio_config_tag == AudioConfiguration::a2dp || + audio_config_tag == AudioConfiguration::a2dpConfig)); + bool is_hfp_offload_audio_config = + (is_offload_hfp_session && + audio_config_tag == AudioConfiguration::hfpConfig); + bool is_le_audio_offload_unicast_audio_config = + (is_offload_le_audio_unicast_session && audio_config_tag == AudioConfiguration::leAudioConfig); + bool is_le_audio_offload_broadcast_audio_config = + (is_offload_le_audio_broadcast_session && + audio_config_tag == AudioConfiguration::leAudioBroadcastConfig); if (!is_software_audio_config && !is_a2dp_offload_audio_config && - !is_le_audio_offload_audio_config) { + !is_hfp_offload_audio_config && + !is_le_audio_offload_unicast_audio_config && + !is_le_audio_offload_broadcast_audio_config) { return false; } audio_config_ = std::make_unique(audio_config); @@ -423,8 +451,21 @@ void BluetoothAudioSession::ReportControlStatus(bool start_resp, } void BluetoothAudioSession::ReportLowLatencyModeAllowedChanged(bool allowed) { + if (session_type_ != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) { + return; + } std::lock_guard guard(mutex_); low_latency_allowed_ = allowed; + // TODO(b/294498919): Remove this after there is API to update latency mode + // after audio session started. If low_latency_allowed_ is true, the session + // can support LOW_LATENCY and FREE LatencyMode. + if (low_latency_allowed_) { + if (std::find(latency_modes_.begin(), latency_modes_.end(), + LatencyMode::LOW_LATENCY) == latency_modes_.end()) { + LOG(INFO) << __func__ << " - insert LOW_LATENCY LatencyMode"; + latency_modes_.push_back(LatencyMode::LOW_LATENCY); + } + } if (observers_.empty()) { LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_) << " has NO port state observer"; @@ -461,23 +502,9 @@ bool BluetoothAudioSession::GetPresentationPosition( void BluetoothAudioSession::UpdateSourceMetadata( const struct source_metadata& source_metadata) { - std::lock_guard guard(mutex_); - if (!IsSessionReady()) { - LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_) - << " has NO session"; - return; - } - ssize_t track_count = source_metadata.track_count; LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << "," << track_count << " track(s)"; - if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || - session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH || - session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH || - session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) { - return; - } - SourceMetadata hal_source_metadata; hal_source_metadata.tracks.resize(track_count); for (int i = 0; i < track_count; i++) { @@ -494,33 +521,14 @@ void BluetoothAudioSession::UpdateSourceMetadata( << toString(hal_source_metadata.tracks[i].contentType) << ", gain=" << hal_source_metadata.tracks[i].gain; } - - auto hal_retval = stack_iface_->updateSourceMetadata(hal_source_metadata); - if (!hal_retval.isOk()) { - LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType=" - << toString(session_type_) << " failed"; - } + UpdateSourceMetadata(hal_source_metadata); } void BluetoothAudioSession::UpdateSinkMetadata( const struct sink_metadata& sink_metadata) { - std::lock_guard guard(mutex_); - if (!IsSessionReady()) { - LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_) - << " has NO session"; - return; - } - ssize_t track_count = sink_metadata.track_count; LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << "," << track_count << " track(s)"; - if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || - session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH || - session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH || - session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) { - return; - } - SinkMetadata hal_sink_metadata; hal_sink_metadata.tracks.resize(track_count); for (int i = 0; i < track_count; i++) { @@ -535,12 +543,57 @@ void BluetoothAudioSession::UpdateSinkMetadata( << ", dest_device_address=" << sink_metadata.tracks[i].dest_device_address; } + UpdateSinkMetadata(hal_sink_metadata); +} + +bool BluetoothAudioSession::UpdateSourceMetadata( + const SourceMetadata& hal_source_metadata) { + std::lock_guard guard(mutex_); + if (!IsSessionReady()) { + LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_) + << " has NO session"; + return false; + } + + if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || + session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH || + session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH || + session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) { + return false; + } + + auto hal_retval = stack_iface_->updateSourceMetadata(hal_source_metadata); + if (!hal_retval.isOk()) { + LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType=" + << toString(session_type_) << " failed"; + return false; + } + return true; +} + +bool BluetoothAudioSession::UpdateSinkMetadata( + const SinkMetadata& hal_sink_metadata) { + std::lock_guard guard(mutex_); + if (!IsSessionReady()) { + LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_) + << " has NO session"; + return false; + } + + if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || + session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH || + session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH || + session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) { + return false; + } auto hal_retval = stack_iface_->updateSinkMetadata(hal_sink_metadata); if (!hal_retval.isOk()) { LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType=" << toString(session_type_) << " failed"; + return false; } + return true; } std::vector BluetoothAudioSession::GetSupportedLatencyModes() { @@ -550,15 +603,32 @@ std::vector BluetoothAudioSession::GetSupportedLatencyModes() { << " has NO session"; return std::vector(); } - if (low_latency_allowed_) return latency_modes_; - std::vector modes; - for (LatencyMode mode : latency_modes_) { - if (mode == LatencyMode::LOW_LATENCY) - // ignore those low latency mode if Bluetooth stack doesn't allow - continue; - modes.push_back(mode); + + std::vector supported_latency_modes; + if (session_type_ == + SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) { + for (LatencyMode mode : latency_modes_) { + if (mode == LatencyMode::LOW_LATENCY) { + // LOW_LATENCY is not supported for LE_HARDWARE_OFFLOAD_ENC sessions + continue; + } + supported_latency_modes.push_back(mode); + } + } else { + for (LatencyMode mode : latency_modes_) { + if (!low_latency_allowed_ && mode == LatencyMode::LOW_LATENCY) { + // ignore LOW_LATENCY mode if Bluetooth stack doesn't allow + continue; + } + if (mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_SOFTWARE || + mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_HARDWARE) { + // DSA_SW and DSA_HW only supported for LE_HARDWARE_OFFLOAD_ENC sessions + continue; + } + supported_latency_modes.push_back(mode); + } } - return modes; + return supported_latency_modes; } void BluetoothAudioSession::SetLatencyMode(const LatencyMode& latency_mode) { diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h index bdfaf36..a655efb 100644 --- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h +++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h @@ -23,12 +23,15 @@ #include #include #include -#include #include #include #include +// To avoid inclusion of hardware/audio.h +struct sink_metadata; +struct source_metadata; + namespace aidl { namespace android { namespace hardware { @@ -183,6 +186,9 @@ class BluetoothAudioSession { bool GetPresentationPosition(PresentationPosition& presentation_position); void UpdateSourceMetadata(const struct source_metadata& source_metadata); void UpdateSinkMetadata(const struct sink_metadata& sink_metadata); + // New versions for AIDL-only clients. + bool UpdateSourceMetadata(const SourceMetadata& hal_source_metadata); + bool UpdateSinkMetadata(const SinkMetadata& hal_sink_metadata); std::vector GetSupportedLatencyModes(); void SetLatencyMode(const LatencyMode& latency_mode); @@ -220,8 +226,10 @@ class BluetoothAudioSession { static inline std::atomic is_aidl_checked = false; static inline std::atomic is_aidl_available = false; + // BEGIN sysbta static inline const std::string kDefaultAudioProviderFactoryInterface = std::string() + IBluetoothAudioProviderFactory::descriptor + "/sysbta"; + // END sysbta }; class BluetoothAudioSessionInstance { diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h index 0782c82..5263222 100644 --- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h +++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h @@ -84,6 +84,8 @@ class BluetoothAudioSessionControl { case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH: case SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH: return AudioConfiguration(CodecConfiguration{}); + case SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH: + return AudioConfiguration(HfpConfiguration{}); case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH: case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH: return AudioConfiguration(LeAudioConfiguration{}); @@ -156,6 +158,26 @@ class BluetoothAudioSessionControl { } } + static bool UpdateSourceMetadata(const SessionType& session_type, + const SourceMetadata& source_metadata) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->UpdateSourceMetadata(source_metadata); + } + return false; + } + + static bool UpdateSinkMetadata(const SessionType& session_type, + const SinkMetadata& sink_metadata) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->UpdateSinkMetadata(sink_metadata); + } + return false; + } + static std::vector GetSupportedLatencyModes( const SessionType& session_type) { std::shared_ptr session_ptr = diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp new file mode 100644 index 0000000..5429a8f --- /dev/null +++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp @@ -0,0 +1,760 @@ +/* + * Copyright (C) 2023 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. + */ + +#define STREAM_TO_UINT8(u8, p) \ + { \ + (u8) = (uint8_t)(*(p)); \ + (p) += 1; \ + } +#define STREAM_TO_UINT16(u16, p) \ + { \ + (u16) = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); \ + (p) += 2; \ + } +#define STREAM_TO_UINT32(u32, p) \ + { \ + (u32) = (((uint32_t)(*(p))) + ((((uint32_t)(*((p) + 1)))) << 8) + \ + ((((uint32_t)(*((p) + 2)))) << 16) + \ + ((((uint32_t)(*((p) + 3)))) << 24)); \ + (p) += 4; \ + } + +#define LOG_TAG "BTAudioAseConfigAidl" + +#include "BluetoothLeAudioAseConfigurationSettingProvider.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { + +/* Internal structure definition */ +std::map>, + std::vector>, + ConfigurationFlags>> + configurations_; + +std::vector ase_configuration_settings_; + +constexpr uint8_t kIsoDataPathHci = 0x00; +constexpr uint8_t kIsoDataPathPlatformDefault = 0x01; +constexpr uint8_t kIsoDataPathDisabled = 0xFF; + +constexpr uint8_t kLeAudioDirectionSink = 0x01; +constexpr uint8_t kLeAudioDirectionSource = 0x02; +constexpr uint8_t kLeAudioDirectionBoth = + kLeAudioDirectionSink | kLeAudioDirectionSource; + +/* Sampling Frequencies */ +constexpr uint8_t kLeAudioSamplingFreq8000Hz = 0x01; +constexpr uint8_t kLeAudioSamplingFreq11025Hz = 0x02; +constexpr uint8_t kLeAudioSamplingFreq16000Hz = 0x03; +constexpr uint8_t kLeAudioSamplingFreq22050Hz = 0x04; +constexpr uint8_t kLeAudioSamplingFreq24000Hz = 0x05; +constexpr uint8_t kLeAudioSamplingFreq32000Hz = 0x06; +constexpr uint8_t kLeAudioSamplingFreq44100Hz = 0x07; +constexpr uint8_t kLeAudioSamplingFreq48000Hz = 0x08; +constexpr uint8_t kLeAudioSamplingFreq88200Hz = 0x09; +constexpr uint8_t kLeAudioSamplingFreq96000Hz = 0x0A; +constexpr uint8_t kLeAudioSamplingFreq176400Hz = 0x0B; +constexpr uint8_t kLeAudioSamplingFreq192000Hz = 0x0C; +constexpr uint8_t kLeAudioSamplingFreq384000Hz = 0x0D; + +/* Frame Durations */ +constexpr uint8_t kLeAudioCodecFrameDur7500us = 0x00; +constexpr uint8_t kLeAudioCodecFrameDur10000us = 0x01; + +/* Audio Allocations */ +constexpr uint32_t kLeAudioLocationNotAllowed = 0x00000000; +constexpr uint32_t kLeAudioLocationFrontLeft = 0x00000001; +constexpr uint32_t kLeAudioLocationFrontRight = 0x00000002; +constexpr uint32_t kLeAudioLocationFrontCenter = 0x00000004; +constexpr uint32_t kLeAudioLocationLowFreqEffects1 = 0x00000008; +constexpr uint32_t kLeAudioLocationBackLeft = 0x00000010; +constexpr uint32_t kLeAudioLocationBackRight = 0x00000020; +constexpr uint32_t kLeAudioLocationFrontLeftOfCenter = 0x00000040; +constexpr uint32_t kLeAudioLocationFrontRightOfCenter = 0x00000080; +constexpr uint32_t kLeAudioLocationBackCenter = 0x00000100; +constexpr uint32_t kLeAudioLocationLowFreqEffects2 = 0x00000200; +constexpr uint32_t kLeAudioLocationSideLeft = 0x00000400; +constexpr uint32_t kLeAudioLocationSideRight = 0x00000800; +constexpr uint32_t kLeAudioLocationTopFrontLeft = 0x00001000; +constexpr uint32_t kLeAudioLocationTopFrontRight = 0x00002000; +constexpr uint32_t kLeAudioLocationTopFrontCenter = 0x00004000; +constexpr uint32_t kLeAudioLocationTopCenter = 0x00008000; +constexpr uint32_t kLeAudioLocationTopBackLeft = 0x00010000; +constexpr uint32_t kLeAudioLocationTopBackRight = 0x00020000; +constexpr uint32_t kLeAudioLocationTopSideLeft = 0x00040000; +constexpr uint32_t kLeAudioLocationTopSideRight = 0x00080000; +constexpr uint32_t kLeAudioLocationTopBackCenter = 0x00100000; +constexpr uint32_t kLeAudioLocationBottomFrontCenter = 0x00200000; +constexpr uint32_t kLeAudioLocationBottomFrontLeft = 0x00400000; +constexpr uint32_t kLeAudioLocationBottomFrontRight = 0x00800000; +constexpr uint32_t kLeAudioLocationFrontLeftWide = 0x01000000; +constexpr uint32_t kLeAudioLocationFrontRightWide = 0x02000000; +constexpr uint32_t kLeAudioLocationLeftSurround = 0x04000000; +constexpr uint32_t kLeAudioLocationRightSurround = 0x08000000; + +constexpr uint32_t kLeAudioLocationAnyLeft = + kLeAudioLocationFrontLeft | kLeAudioLocationBackLeft | + kLeAudioLocationFrontLeftOfCenter | kLeAudioLocationSideLeft | + kLeAudioLocationTopFrontLeft | kLeAudioLocationTopBackLeft | + kLeAudioLocationTopSideLeft | kLeAudioLocationBottomFrontLeft | + kLeAudioLocationFrontLeftWide | kLeAudioLocationLeftSurround; + +constexpr uint32_t kLeAudioLocationAnyRight = + kLeAudioLocationFrontRight | kLeAudioLocationBackRight | + kLeAudioLocationFrontRightOfCenter | kLeAudioLocationSideRight | + kLeAudioLocationTopFrontRight | kLeAudioLocationTopBackRight | + kLeAudioLocationTopSideRight | kLeAudioLocationBottomFrontRight | + kLeAudioLocationFrontRightWide | kLeAudioLocationRightSurround; + +constexpr uint32_t kLeAudioLocationStereo = + kLeAudioLocationFrontLeft | kLeAudioLocationFrontRight; + +/* Octets Per Frame */ +constexpr uint16_t kLeAudioCodecFrameLen30 = 30; +constexpr uint16_t kLeAudioCodecFrameLen40 = 40; +constexpr uint16_t kLeAudioCodecFrameLen60 = 60; +constexpr uint16_t kLeAudioCodecFrameLen80 = 80; +constexpr uint16_t kLeAudioCodecFrameLen100 = 100; +constexpr uint16_t kLeAudioCodecFrameLen120 = 120; + +/* Helper map for matching various sampling frequency notations */ +const std::map + sampling_freq_map = { + {kLeAudioSamplingFreq8000Hz, + CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000}, + {kLeAudioSamplingFreq16000Hz, + CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000}, + {kLeAudioSamplingFreq24000Hz, + CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000}, + {kLeAudioSamplingFreq32000Hz, + CodecSpecificConfigurationLtv::SamplingFrequency::HZ32000}, + {kLeAudioSamplingFreq44100Hz, + CodecSpecificConfigurationLtv::SamplingFrequency::HZ44100}, + {kLeAudioSamplingFreq48000Hz, + CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000}}; + +/* Helper map for matching various frame durations notations */ +const std::map + frame_duration_map = { + {kLeAudioCodecFrameDur7500us, + CodecSpecificConfigurationLtv::FrameDuration::US7500}, + {kLeAudioCodecFrameDur10000us, + CodecSpecificConfigurationLtv::FrameDuration::US10000}}; + +/* Helper map for matching various audio channel allocation notations */ +std::map audio_channel_allocation_map = { + {kLeAudioLocationNotAllowed, + CodecSpecificConfigurationLtv::AudioChannelAllocation::NOT_ALLOWED}, + {kLeAudioLocationFrontLeft, + CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT}, + {kLeAudioLocationFrontRight, + CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT}, + {kLeAudioLocationFrontCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER}, + {kLeAudioLocationLowFreqEffects1, + CodecSpecificConfigurationLtv::AudioChannelAllocation:: + LOW_FREQUENCY_EFFECTS_1}, + {kLeAudioLocationBackLeft, + CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_LEFT}, + {kLeAudioLocationBackRight, + CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_RIGHT}, + {kLeAudioLocationFrontLeftOfCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation:: + FRONT_LEFT_OF_CENTER}, + {kLeAudioLocationFrontRightOfCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation:: + FRONT_RIGHT_OF_CENTER}, + {kLeAudioLocationBackCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_CENTER}, + {kLeAudioLocationLowFreqEffects2, + CodecSpecificConfigurationLtv::AudioChannelAllocation:: + LOW_FREQUENCY_EFFECTS_2}, + {kLeAudioLocationSideLeft, + CodecSpecificConfigurationLtv::AudioChannelAllocation::SIDE_LEFT}, + {kLeAudioLocationSideRight, + CodecSpecificConfigurationLtv::AudioChannelAllocation::SIDE_RIGHT}, + {kLeAudioLocationTopFrontLeft, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_LEFT}, + {kLeAudioLocationTopFrontRight, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_RIGHT}, + {kLeAudioLocationTopFrontCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_CENTER}, + {kLeAudioLocationTopCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_CENTER}, + {kLeAudioLocationTopBackLeft, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_LEFT}, + {kLeAudioLocationTopBackRight, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_RIGHT}, + {kLeAudioLocationTopSideLeft, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_SIDE_LEFT}, + {kLeAudioLocationTopSideRight, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_SIDE_RIGHT}, + {kLeAudioLocationTopBackCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_CENTER}, + {kLeAudioLocationBottomFrontCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation:: + BOTTOM_FRONT_CENTER}, + {kLeAudioLocationBottomFrontLeft, + CodecSpecificConfigurationLtv::AudioChannelAllocation::BOTTOM_FRONT_LEFT}, + {kLeAudioLocationBottomFrontRight, + CodecSpecificConfigurationLtv::AudioChannelAllocation::BOTTOM_FRONT_RIGHT}, + {kLeAudioLocationFrontLeftWide, + CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT_WIDE}, + {kLeAudioLocationFrontRightWide, + CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT_WIDE}, + {kLeAudioLocationLeftSurround, + CodecSpecificConfigurationLtv::AudioChannelAllocation::LEFT_SURROUND}, + {kLeAudioLocationRightSurround, + CodecSpecificConfigurationLtv::AudioChannelAllocation::RIGHT_SURROUND}, +}; + +static const std::vector< + std::pair> + kLeAudioSetConfigs = {{"/vendor/etc/aidl/le_audio/" + "aidl_audio_set_configurations.bfbs", + "/vendor/etc/aidl/le_audio/" + "aidl_audio_set_configurations.json"}}; +static const std::vector< + std::pair> + kLeAudioSetScenarios = {{"/vendor/etc/aidl/le_audio/" + "aidl_audio_set_scenarios.bfbs", + "/vendor/etc/aidl/le_audio/" + "aidl_audio_set_scenarios.json"}}; + +/* Implementation */ + +std::vector +AudioSetConfigurationProviderJson::GetLeAudioAseConfigurationSettings() { + AudioSetConfigurationProviderJson::LoadAudioSetConfigurationProviderJson(); + return ase_configuration_settings_; +} + +void AudioSetConfigurationProviderJson:: + LoadAudioSetConfigurationProviderJson() { + if (configurations_.empty() || ase_configuration_settings_.empty()) { + ase_configuration_settings_.clear(); + configurations_.clear(); + auto loaded = LoadContent(kLeAudioSetConfigs, kLeAudioSetScenarios, + CodecLocation::HOST); + if (!loaded) + LOG(ERROR) << ": Unable to load le audio set configuration files."; + } else + LOG(INFO) << ": Reusing loaded le audio set configuration"; +} + +const le_audio::CodecSpecificConfiguration* +AudioSetConfigurationProviderJson::LookupCodecSpecificParam( + const flatbuffers::Vector>* flat_codec_specific_params, + le_audio::CodecSpecificLtvGenericTypes type) { + auto it = std::find_if( + flat_codec_specific_params->cbegin(), flat_codec_specific_params->cend(), + [&type](const auto& csc) { return (csc->type() == type); }); + return (it != flat_codec_specific_params->cend()) ? *it : nullptr; +} + +void AudioSetConfigurationProviderJson::populateAudioChannelAllocation( + CodecSpecificConfigurationLtv::AudioChannelAllocation& + audio_channel_allocation, + uint32_t audio_location) { + audio_channel_allocation.bitmask = 0; + for (auto [allocation, bitmask] : audio_channel_allocation_map) { + if (audio_location & allocation) + audio_channel_allocation.bitmask |= bitmask; + } +} + +void AudioSetConfigurationProviderJson::populateConfigurationData( + LeAudioAseConfiguration& ase, + const flatbuffers::Vector< + flatbuffers::Offset>* + flat_codec_specific_params) { + uint8_t sampling_frequency = 0; + uint8_t frame_duration = 0; + uint32_t audio_channel_allocation = 0; + uint16_t octets_per_codec_frame = 0; + uint8_t codec_frames_blocks_per_sdu = 0; + + auto param = LookupCodecSpecificParam( + flat_codec_specific_params, + le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_SAMPLING_FREQUENCY); + if (param) { + auto ptr = param->compound_value()->value()->data(); + STREAM_TO_UINT8(sampling_frequency, ptr); + } + + param = LookupCodecSpecificParam( + flat_codec_specific_params, + le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_FRAME_DURATION); + if (param) { + auto ptr = param->compound_value()->value()->data(); + STREAM_TO_UINT8(frame_duration, ptr); + } + + param = LookupCodecSpecificParam( + flat_codec_specific_params, + le_audio:: + CodecSpecificLtvGenericTypes_SUPPORTED_AUDIO_CHANNEL_ALLOCATION); + if (param) { + auto ptr = param->compound_value()->value()->data(); + STREAM_TO_UINT32(audio_channel_allocation, ptr); + } + + param = LookupCodecSpecificParam( + flat_codec_specific_params, + le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_OCTETS_PER_CODEC_FRAME); + if (param) { + auto ptr = param->compound_value()->value()->data(); + STREAM_TO_UINT16(octets_per_codec_frame, ptr); + } + + param = LookupCodecSpecificParam( + flat_codec_specific_params, + le_audio:: + CodecSpecificLtvGenericTypes_SUPPORTED_CODEC_FRAME_BLOCKS_PER_SDU); + if (param) { + auto ptr = param->compound_value()->value()->data(); + STREAM_TO_UINT8(codec_frames_blocks_per_sdu, ptr); + } + + // Make the correct value + ase.codecConfiguration = std::vector(); + + auto sampling_freq_it = sampling_freq_map.find(sampling_frequency); + if (sampling_freq_it != sampling_freq_map.end()) + ase.codecConfiguration.push_back(sampling_freq_it->second); + auto frame_duration_it = frame_duration_map.find(frame_duration); + if (frame_duration_it != frame_duration_map.end()) + ase.codecConfiguration.push_back(frame_duration_it->second); + + CodecSpecificConfigurationLtv::AudioChannelAllocation channel_allocation; + populateAudioChannelAllocation(channel_allocation, audio_channel_allocation); + ase.codecConfiguration.push_back(channel_allocation); + + auto octet_structure = CodecSpecificConfigurationLtv::OctetsPerCodecFrame(); + octet_structure.value = octets_per_codec_frame; + ase.codecConfiguration.push_back(octet_structure); + + auto frame_sdu_structure = + CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU(); + frame_sdu_structure.value = codec_frames_blocks_per_sdu; + ase.codecConfiguration.push_back(frame_sdu_structure); + // TODO: Channel count +} + +void AudioSetConfigurationProviderJson::populateAseConfiguration( + LeAudioAseConfiguration& ase, + const le_audio::AudioSetSubConfiguration* flat_subconfig, + const le_audio::QosConfiguration* qos_cfg) { + // Target latency + switch (qos_cfg->target_latency()) { + case le_audio::AudioSetConfigurationTargetLatency:: + AudioSetConfigurationTargetLatency_BALANCED_RELIABILITY: + ase.targetLatency = + LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY; + break; + case le_audio::AudioSetConfigurationTargetLatency:: + AudioSetConfigurationTargetLatency_HIGH_RELIABILITY: + ase.targetLatency = + LeAudioAseConfiguration::TargetLatency::HIGHER_RELIABILITY; + break; + case le_audio::AudioSetConfigurationTargetLatency:: + AudioSetConfigurationTargetLatency_LOW: + ase.targetLatency = LeAudioAseConfiguration::TargetLatency::LOWER; + break; + default: + ase.targetLatency = LeAudioAseConfiguration::TargetLatency::UNDEFINED; + break; + }; + + ase.targetPhy = Phy::TWO_M; + // Making CodecId + if (flat_subconfig->codec_id()->coding_format() == + (uint8_t)CodecId::Core::LC3) { + ase.codecId = CodecId::Core::LC3; + } else { + auto vendorC = CodecId::Vendor(); + vendorC.codecId = flat_subconfig->codec_id()->vendor_codec_id(); + vendorC.id = flat_subconfig->codec_id()->vendor_company_id(); + ase.codecId = vendorC; + } + // Codec configuration data + populateConfigurationData(ase, flat_subconfig->codec_configuration()); +} + +void AudioSetConfigurationProviderJson::populateAseQosConfiguration( + LeAudioAseQosConfiguration& qos, + const le_audio::QosConfiguration* qos_cfg) { + qos.maxTransportLatencyMs = qos_cfg->max_transport_latency(); + qos.retransmissionNum = qos_cfg->retransmission_number(); +} + +// Parse into AseDirectionConfiguration +AseDirectionConfiguration +AudioSetConfigurationProviderJson::SetConfigurationFromFlatSubconfig( + const le_audio::AudioSetSubConfiguration* flat_subconfig, + const le_audio::QosConfiguration* qos_cfg, CodecLocation location) { + AseDirectionConfiguration direction_conf; + + LeAudioAseConfiguration ase; + LeAudioAseQosConfiguration qos; + LeAudioDataPathConfiguration path; + + // Translate into LeAudioAseConfiguration + populateAseConfiguration(ase, flat_subconfig, qos_cfg); + + // Translate into LeAudioAseQosConfiguration + populateAseQosConfiguration(qos, qos_cfg); + + // Translate location to data path id + switch (location) { + case CodecLocation::ADSP: + path.isoDataPathConfiguration.isTransparent = true; + path.dataPathId = kIsoDataPathPlatformDefault; + break; + case CodecLocation::HOST: + path.isoDataPathConfiguration.isTransparent = true; + path.dataPathId = kIsoDataPathHci; + break; + case CodecLocation::CONTROLLER: + path.isoDataPathConfiguration.isTransparent = false; + path.dataPathId = kIsoDataPathPlatformDefault; + break; + } + + direction_conf.aseConfiguration = ase; + direction_conf.qosConfiguration = qos; + direction_conf.dataPathConfiguration = path; + + return direction_conf; +} + +// Parse into AseDirectionConfiguration and the ConfigurationFlags +// and put them in the given list. +void AudioSetConfigurationProviderJson::processSubconfig( + const le_audio::AudioSetSubConfiguration* subconfig, + const le_audio::QosConfiguration* qos_cfg, + std::vector>& + directionAseConfiguration, + CodecLocation location) { + directionAseConfiguration.push_back( + SetConfigurationFromFlatSubconfig(subconfig, qos_cfg, location)); +} + +void AudioSetConfigurationProviderJson::PopulateAseConfigurationFromFlat( + const le_audio::AudioSetConfiguration* flat_cfg, + std::vector* codec_cfgs, + std::vector* qos_cfgs, + CodecLocation location, + std::vector>& + sourceAseConfiguration, + std::vector>& sinkAseConfiguration, + ConfigurationFlags& /*configurationFlags*/) { + if (flat_cfg == nullptr) { + LOG(ERROR) << "flat_cfg cannot be null"; + return; + } + std::string codec_config_key = flat_cfg->codec_config_name()->str(); + auto* qos_config_key_array = flat_cfg->qos_config_name(); + + constexpr std::string_view default_qos = "QoS_Config_Balanced_Reliability"; + + std::string qos_sink_key(default_qos); + std::string qos_source_key(default_qos); + + /* We expect maximum two QoS settings. First for Sink and second for Source + */ + if (qos_config_key_array->size() > 0) { + qos_sink_key = qos_config_key_array->Get(0)->str(); + if (qos_config_key_array->size() > 1) { + qos_source_key = qos_config_key_array->Get(1)->str(); + } else { + qos_source_key = qos_sink_key; + } + } + + LOG(INFO) << "Audio set config " << flat_cfg->name()->c_str() + << ": codec config " << codec_config_key.c_str() << ", qos_sink " + << qos_sink_key.c_str() << ", qos_source " + << qos_source_key.c_str(); + + // Find the first qos config that match the name + const le_audio::QosConfiguration* qos_sink_cfg = nullptr; + for (auto i = qos_cfgs->begin(); i != qos_cfgs->end(); ++i) { + if ((*i)->name()->str() == qos_sink_key) { + qos_sink_cfg = *i; + break; + } + } + + const le_audio::QosConfiguration* qos_source_cfg = nullptr; + for (auto i = qos_cfgs->begin(); i != qos_cfgs->end(); ++i) { + if ((*i)->name()->str() == qos_source_key) { + qos_source_cfg = *i; + break; + } + } + + // First codec_cfg with the same name + const le_audio::CodecConfiguration* codec_cfg = nullptr; + for (auto i = codec_cfgs->begin(); i != codec_cfgs->end(); ++i) { + if ((*i)->name()->str() == codec_config_key) { + codec_cfg = *i; + break; + } + } + + // Process each subconfig and put it into the correct list + if (codec_cfg != nullptr && codec_cfg->subconfigurations()) { + /* Load subconfigurations */ + for (auto subconfig : *codec_cfg->subconfigurations()) { + if (subconfig->direction() == kLeAudioDirectionSink) { + processSubconfig(subconfig, qos_sink_cfg, sinkAseConfiguration, + location); + } else { + processSubconfig(subconfig, qos_source_cfg, sourceAseConfiguration, + location); + } + } + } else { + if (codec_cfg == nullptr) { + LOG(ERROR) << "No codec config matching key " << codec_config_key.c_str() + << " found"; + } else { + LOG(ERROR) << "Configuration '" << flat_cfg->name()->c_str() + << "' has no valid subconfigurations."; + } + } + + // TODO: Populate information for ConfigurationFlags +} + +bool AudioSetConfigurationProviderJson::LoadConfigurationsFromFiles( + const char* schema_file, const char* content_file, CodecLocation location) { + flatbuffers::Parser configurations_parser_; + std::string configurations_schema_binary_content; + bool ok = flatbuffers::LoadFile(schema_file, true, + &configurations_schema_binary_content); + LOG(INFO) << __func__ << ": Loading file " << schema_file; + if (!ok) return ok; + + /* Load the binary schema */ + ok = configurations_parser_.Deserialize( + (uint8_t*)configurations_schema_binary_content.c_str(), + configurations_schema_binary_content.length()); + if (!ok) return ok; + + /* Load the content from JSON */ + std::string configurations_json_content; + LOG(INFO) << __func__ << ": Loading file " << content_file; + ok = flatbuffers::LoadFile(content_file, false, &configurations_json_content); + if (!ok) return ok; + + /* Parse */ + LOG(INFO) << __func__ << ": Parse JSON content"; + ok = configurations_parser_.Parse(configurations_json_content.c_str()); + if (!ok) return ok; + + /* Import from flatbuffers */ + LOG(INFO) << __func__ << ": Build flat buffer structure"; + auto configurations_root = le_audio::GetAudioSetConfigurations( + configurations_parser_.builder_.GetBufferPointer()); + if (!configurations_root) return false; + + auto flat_qos_configs = configurations_root->qos_configurations(); + if ((flat_qos_configs == nullptr) || (flat_qos_configs->size() == 0)) + return false; + + LOG(DEBUG) << ": Updating " << flat_qos_configs->size() + << " qos config entries."; + std::vector qos_cfgs; + for (auto const& flat_qos_cfg : *flat_qos_configs) { + qos_cfgs.push_back(flat_qos_cfg); + } + + auto flat_codec_configs = configurations_root->codec_configurations(); + if ((flat_codec_configs == nullptr) || (flat_codec_configs->size() == 0)) + return false; + + LOG(DEBUG) << ": Updating " << flat_codec_configs->size() + << " codec config entries."; + std::vector codec_cfgs; + for (auto const& flat_codec_cfg : *flat_codec_configs) { + codec_cfgs.push_back(flat_codec_cfg); + } + + auto flat_configs = configurations_root->configurations(); + if ((flat_configs == nullptr) || (flat_configs->size() == 0)) return false; + + LOG(DEBUG) << ": Updating " << flat_configs->size() << " config entries."; + for (auto const& flat_cfg : *flat_configs) { + // Create 3 vector to use + std::vector> + sourceAseConfiguration; + std::vector> sinkAseConfiguration; + ConfigurationFlags configurationFlags; + PopulateAseConfigurationFromFlat(flat_cfg, &codec_cfgs, &qos_cfgs, location, + sourceAseConfiguration, + sinkAseConfiguration, configurationFlags); + if (sourceAseConfiguration.empty() && sinkAseConfiguration.empty()) + continue; + configurations_[flat_cfg->name()->str()] = std::make_tuple( + sourceAseConfiguration, sinkAseConfiguration, configurationFlags); + } + + return true; +} + +bool AudioSetConfigurationProviderJson::LoadScenariosFromFiles( + const char* schema_file, const char* content_file) { + flatbuffers::Parser scenarios_parser_; + std::string scenarios_schema_binary_content; + bool ok = flatbuffers::LoadFile(schema_file, true, + &scenarios_schema_binary_content); + LOG(INFO) << __func__ << ": Loading file " << schema_file; + if (!ok) return ok; + + /* Load the binary schema */ + ok = scenarios_parser_.Deserialize( + (uint8_t*)scenarios_schema_binary_content.c_str(), + scenarios_schema_binary_content.length()); + if (!ok) return ok; + + /* Load the content from JSON */ + LOG(INFO) << __func__ << ": Loading file " << content_file; + std::string scenarios_json_content; + ok = flatbuffers::LoadFile(content_file, false, &scenarios_json_content); + if (!ok) return ok; + + /* Parse */ + LOG(INFO) << __func__ << ": Parse json content"; + ok = scenarios_parser_.Parse(scenarios_json_content.c_str()); + if (!ok) return ok; + + /* Import from flatbuffers */ + LOG(INFO) << __func__ << ": Build flat buffer structure"; + auto scenarios_root = le_audio::GetAudioSetScenarios( + scenarios_parser_.builder_.GetBufferPointer()); + if (!scenarios_root) return false; + + auto flat_scenarios = scenarios_root->scenarios(); + if ((flat_scenarios == nullptr) || (flat_scenarios->size() == 0)) + return false; + + LOG(INFO) << __func__ << ": Turn flat buffer into structure"; + AudioContext media_context = AudioContext(); + media_context.bitmask = + (AudioContext::ALERTS | AudioContext::INSTRUCTIONAL | + AudioContext::NOTIFICATIONS | AudioContext::EMERGENCY_ALARM | + AudioContext::UNSPECIFIED | AudioContext::MEDIA); + + AudioContext conversational_context = AudioContext(); + conversational_context.bitmask = + (AudioContext::RINGTONE_ALERTS | AudioContext::CONVERSATIONAL); + + AudioContext live_context = AudioContext(); + live_context.bitmask = AudioContext::LIVE_AUDIO; + + AudioContext game_context = AudioContext(); + game_context.bitmask = AudioContext::GAME; + + AudioContext voice_assistants_context = AudioContext(); + voice_assistants_context.bitmask = AudioContext::VOICE_ASSISTANTS; + + LOG(DEBUG) << "Updating " << flat_scenarios->size() << " scenarios."; + for (auto const& scenario : *flat_scenarios) { + LOG(DEBUG) << "Scenario " << scenario->name()->c_str() + << " configs: " << scenario->configurations()->size(); + + if (!scenario->configurations()) continue; + std::string scenario_name = scenario->name()->c_str(); + AudioContext context; + if (scenario_name == "Media") + context = AudioContext(media_context); + else if (scenario_name == "Conversational") + context = AudioContext(conversational_context); + else if (scenario_name == "Live") + context = AudioContext(live_context); + else if (scenario_name == "Game") + context = AudioContext(game_context); + else if (scenario_name == "VoiceAssistants") + context = AudioContext(voice_assistants_context); + + for (auto it = scenario->configurations()->begin(); + it != scenario->configurations()->end(); ++it) { + auto config_name = it->str(); + auto configuration = configurations_.find(config_name); + if (configuration == configurations_.end()) continue; + LOG(DEBUG) << "Getting configuration with name: " << config_name; + auto [source, sink, flags] = configuration->second; + // Each configuration will create a LeAudioAseConfigurationSetting + // with the same {context, packing} + // and different data + LeAudioAseConfigurationSetting setting; + setting.audioContext = context; + // TODO: Packing + setting.sourceAseConfiguration = source; + setting.sinkAseConfiguration = sink; + setting.flags = flags; + // Add to list of setting + LOG(DEBUG) << "Pushing configuration to list: " << config_name; + ase_configuration_settings_.push_back(setting); + } + } + + return true; +} + +bool AudioSetConfigurationProviderJson::LoadContent( + std::vector> + config_files, + std::vector> + scenario_files, + CodecLocation location) { + for (auto [schema, content] : config_files) { + if (!LoadConfigurationsFromFiles(schema, content, location)) return false; + } + + for (auto [schema, content] : scenario_files) { + if (!LoadScenariosFromFiles(schema, content)) return false; + } + return true; +} + +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h new file mode 100644 index 0000000..ce91fca --- /dev/null +++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h @@ -0,0 +1,125 @@ + +/* + * Copyright (C) 2023 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 + +#include +#include +#include +#include +#include +#include + +#include "audio_set_configurations_generated.h" +#include "audio_set_scenarios_generated.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { + +using LeAudioAseConfigurationSetting = + IBluetoothAudioProvider::LeAudioAseConfigurationSetting; +using AseDirectionConfiguration = IBluetoothAudioProvider:: + LeAudioAseConfigurationSetting::AseDirectionConfiguration; +using LeAudioAseQosConfiguration = + IBluetoothAudioProvider::LeAudioAseQosConfiguration; +using LeAudioDataPathConfiguration = + IBluetoothAudioProvider::LeAudioDataPathConfiguration; + +enum class CodecLocation { + HOST, + ADSP, + CONTROLLER, +}; + +class AudioSetConfigurationProviderJson { + public: + static std::vector + GetLeAudioAseConfigurationSettings(); + + private: + static void LoadAudioSetConfigurationProviderJson(); + + static const le_audio::CodecSpecificConfiguration* LookupCodecSpecificParam( + const flatbuffers::Vector>* flat_codec_specific_params, + le_audio::CodecSpecificLtvGenericTypes type); + + static void populateAudioChannelAllocation( + CodecSpecificConfigurationLtv::AudioChannelAllocation& + audio_channel_allocation, + uint32_t audio_location); + + static void populateConfigurationData( + LeAudioAseConfiguration& ase, + const flatbuffers::Vector< + flatbuffers::Offset>* + flat_codec_specific_params); + + static void populateAseConfiguration( + LeAudioAseConfiguration& ase, + const le_audio::AudioSetSubConfiguration* flat_subconfig, + const le_audio::QosConfiguration* qos_cfg); + + static void populateAseQosConfiguration( + LeAudioAseQosConfiguration& qos, + const le_audio::QosConfiguration* qos_cfg); + + static AseDirectionConfiguration SetConfigurationFromFlatSubconfig( + const le_audio::AudioSetSubConfiguration* flat_subconfig, + const le_audio::QosConfiguration* qos_cfg, CodecLocation location); + + static void processSubconfig( + const le_audio::AudioSetSubConfiguration* subconfig, + const le_audio::QosConfiguration* qos_cfg, + std::vector>& + directionAseConfiguration, + CodecLocation location); + + static void PopulateAseConfigurationFromFlat( + const le_audio::AudioSetConfiguration* flat_cfg, + std::vector* codec_cfgs, + std::vector* qos_cfgs, + CodecLocation location, + std::vector>& + sourceAseConfiguration, + std::vector>& + sinkAseConfiguration, + ConfigurationFlags& configurationFlags); + + static bool LoadConfigurationsFromFiles(const char* schema_file, + const char* content_file, + CodecLocation location); + + static bool LoadScenariosFromFiles(const char* schema_file, + const char* content_file); + + static bool LoadContent( + std::vector> + config_files, + std::vector> + scenario_files, + CodecLocation location); +}; + +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp new file mode 100644 index 0000000..b6df67e --- /dev/null +++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp @@ -0,0 +1,555 @@ +/* + * Copyright (C) 2022 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 + +#include "aidl/android/hardware/bluetooth/audio/ChannelMode.h" +#include "aidl/android/hardware/bluetooth/audio/CodecId.h" +#include "aidl_android_hardware_bluetooth_audio_setting_enums.h" +#define LOG_TAG "BTAudioCodecsProviderAidl" + +#include "BluetoothLeAudioCodecsProvider.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { + +static const char* kLeAudioCodecCapabilitiesFile = + "/vendor/etc/le_audio_codec_capabilities.xml"; + +static const AudioLocation kStereoAudio = static_cast( + static_cast(AudioLocation::FRONT_LEFT) | + static_cast(AudioLocation::FRONT_RIGHT)); +static const AudioLocation kMonoAudio = AudioLocation::UNKNOWN; + +static std::vector leAudioCodecCapabilities; + +static bool isInvalidFileContent = false; + +std::optional +BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile() { + if (!leAudioCodecCapabilities.empty() || isInvalidFileContent) { + return std::nullopt; + } + auto le_audio_offload_setting = + setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile); + if (!le_audio_offload_setting.has_value()) { + LOG(ERROR) << __func__ << ": Failed to read " + << kLeAudioCodecCapabilitiesFile; + } + return le_audio_offload_setting; +} + +std::unordered_map> +BluetoothLeAudioCodecsProvider::GetLeAudioCodecInfo( + const std::optional& + le_audio_offload_setting) { + // Load from previous storage if present + if (!session_codecs_map_.empty()) return session_codecs_map_; + + isInvalidFileContent = true; + if (!le_audio_offload_setting.has_value()) return {}; + + // Load scenario, configuration, codec configuration and strategy + LoadConfigurationToMap(le_audio_offload_setting); + if (supported_scenarios_.empty() || configuration_map_.empty() || + codec_configuration_map_.empty() || strategy_configuration_map_.empty()) + return {}; + + // Map each configuration into a CodecInfo + std::unordered_map config_codec_info_map_; + + for (auto& p : configuration_map_) { + // Initialize new CodecInfo for the config + auto config_name = p.first; + if (config_codec_info_map_.count(config_name) == 0) + config_codec_info_map_[config_name] = CodecInfo(); + + // Getting informations from codecConfig and strategyConfig + const auto codec_config_name = p.second.getCodecConfiguration(); + const auto strategy_config_name = p.second.getStrategyConfiguration(); + const auto codec_configuration_map_iter = + codec_configuration_map_.find(codec_config_name); + if (codec_configuration_map_iter == codec_configuration_map_.end()) + continue; + const auto strategy_configuration_map_iter = + strategy_configuration_map_.find(strategy_config_name); + if (strategy_configuration_map_iter == strategy_configuration_map_.end()) + continue; + + const auto& codec_config = codec_configuration_map_iter->second; + const auto codec = codec_config.getCodec(); + const auto& strategy_config = strategy_configuration_map_iter->second; + const auto strategy_config_channel_count = + strategy_config.getChannelCount(); + + // Initiate information + auto& codec_info = config_codec_info_map_[config_name]; + switch (codec) { + case setting::CodecType::LC3: + codec_info.name = "LC3"; + codec_info.id = CodecId::Core::LC3; + break; + default: + codec_info.name = "UNDEFINE"; + codec_info.id = CodecId::Vendor(); + break; + } + codec_info.transport = + CodecInfo::Transport::make(); + + // Mapping codec configuration information + auto& transport = + codec_info.transport.get(); + transport.samplingFrequencyHz.push_back( + codec_config.getSamplingFrequency()); + // Mapping octetsPerCodecFrame to bitdepth for easier comparison. + transport.bitdepth.push_back(codec_config.getOctetsPerCodecFrame()); + transport.frameDurationUs.push_back(codec_config.getFrameDurationUs()); + switch (strategy_config.getAudioLocation()) { + case setting::AudioLocation::MONO: + if (strategy_config_channel_count == 1) + transport.channelMode.push_back(ChannelMode::MONO); + else + transport.channelMode.push_back(ChannelMode::DUALMONO); + break; + case setting::AudioLocation::STEREO: + transport.channelMode.push_back(ChannelMode::STEREO); + break; + default: + transport.channelMode.push_back(ChannelMode::UNKNOWN); + break; + } + } + + // Goes through every scenario, deduplicate configuration + std::set encoding_config, decoding_config, broadcast_config; + for (auto& s : supported_scenarios_) { + if (s.hasEncode()) encoding_config.insert(s.getEncode()); + if (s.hasDecode()) decoding_config.insert(s.getDecode()); + if (s.hasBroadcast()) broadcast_config.insert(s.getBroadcast()); + } + + // Split by session types and add results + const auto encoding_path = + SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH; + const auto decoding_path = + SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH; + const auto broadcast_path = + SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH; + session_codecs_map_ = + std::unordered_map>(); + session_codecs_map_[encoding_path] = std::vector(); + session_codecs_map_[decoding_path] = std::vector(); + session_codecs_map_[broadcast_path] = std::vector(); + session_codecs_map_[encoding_path].reserve(encoding_config.size()); + session_codecs_map_[decoding_path].reserve(decoding_config.size()); + session_codecs_map_[broadcast_path].reserve(broadcast_config.size()); + for (auto& c : encoding_config) + session_codecs_map_[encoding_path].push_back(config_codec_info_map_[c]); + for (auto& c : decoding_config) + session_codecs_map_[decoding_path].push_back(config_codec_info_map_[c]); + for (auto& c : broadcast_config) + session_codecs_map_[broadcast_path].push_back(config_codec_info_map_[c]); + + isInvalidFileContent = session_codecs_map_.empty(); + + return session_codecs_map_; +} + +std::vector +BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities( + const std::optional& + le_audio_offload_setting) { + if (!leAudioCodecCapabilities.empty()) { + return leAudioCodecCapabilities; + } + + isInvalidFileContent = true; + + if (!le_audio_offload_setting.has_value()) { + LOG(ERROR) + << __func__ + << ": input le_audio_offload_setting content need to be non empty"; + return {}; + } + + LoadConfigurationToMap(le_audio_offload_setting); + if (supported_scenarios_.empty() || configuration_map_.empty() || + codec_configuration_map_.empty() || strategy_configuration_map_.empty()) + return {}; + + leAudioCodecCapabilities = + ComposeLeAudioCodecCapabilities(supported_scenarios_); + isInvalidFileContent = leAudioCodecCapabilities.empty(); + + return leAudioCodecCapabilities; +} + +void BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities() { + leAudioCodecCapabilities.clear(); + configuration_map_.clear(); + codec_configuration_map_.clear(); + strategy_configuration_map_.clear(); + session_codecs_map_.clear(); + supported_scenarios_.clear(); +} + +std::vector BluetoothLeAudioCodecsProvider::GetScenarios( + const std::optional& + le_audio_offload_setting) { + std::vector supported_scenarios; + if (le_audio_offload_setting->hasScenarioList()) { + for (const auto& scenario_list : + le_audio_offload_setting->getScenarioList()) { + if (!scenario_list.hasScenario()) { + continue; + } + for (const auto& scenario : scenario_list.getScenario()) { + if (scenario.hasEncode() && scenario.hasDecode()) { + supported_scenarios.push_back(scenario); + } + } + } + } + return supported_scenarios; +} + +void BluetoothLeAudioCodecsProvider::UpdateConfigurationsToMap( + const std::optional& + le_audio_offload_setting) { + if (le_audio_offload_setting->hasConfigurationList()) { + for (const auto& configuration_list : + le_audio_offload_setting->getConfigurationList()) { + if (!configuration_list.hasConfiguration()) { + continue; + } + for (const auto& configuration : configuration_list.getConfiguration()) { + if (configuration.hasName() && configuration.hasCodecConfiguration() && + configuration.hasStrategyConfiguration()) { + configuration_map_.insert( + make_pair(configuration.getName(), configuration)); + } + } + } + } +} + +void BluetoothLeAudioCodecsProvider::UpdateCodecConfigurationsToMap( + const std::optional& + le_audio_offload_setting) { + if (le_audio_offload_setting->hasCodecConfigurationList()) { + for (const auto& codec_configuration_list : + le_audio_offload_setting->getCodecConfigurationList()) { + if (!codec_configuration_list.hasCodecConfiguration()) { + continue; + } + for (const auto& codec_configuration : + codec_configuration_list.getCodecConfiguration()) { + if (IsValidCodecConfiguration(codec_configuration)) { + codec_configuration_map_.insert( + make_pair(codec_configuration.getName(), codec_configuration)); + } + } + } + } +} + +void BluetoothLeAudioCodecsProvider::UpdateStrategyConfigurationsToMap( + const std::optional& + le_audio_offload_setting) { + if (le_audio_offload_setting->hasStrategyConfigurationList()) { + for (const auto& strategy_configuration_list : + le_audio_offload_setting->getStrategyConfigurationList()) { + if (!strategy_configuration_list.hasStrategyConfiguration()) { + continue; + } + for (const auto& strategy_configuration : + strategy_configuration_list.getStrategyConfiguration()) { + if (IsValidStrategyConfiguration(strategy_configuration)) { + strategy_configuration_map_.insert(make_pair( + strategy_configuration.getName(), strategy_configuration)); + } + } + } + } +} + +void BluetoothLeAudioCodecsProvider::LoadConfigurationToMap( + const std::optional& + le_audio_offload_setting) { + ClearLeAudioCodecCapabilities(); + + supported_scenarios_ = GetScenarios(le_audio_offload_setting); + if (supported_scenarios_.empty()) { + LOG(ERROR) << __func__ << ": No scenarios in " + << kLeAudioCodecCapabilitiesFile; + return; + } + + UpdateConfigurationsToMap(le_audio_offload_setting); + if (configuration_map_.empty()) { + LOG(ERROR) << __func__ << ": No configurations in " + << kLeAudioCodecCapabilitiesFile; + return; + } + + UpdateCodecConfigurationsToMap(le_audio_offload_setting); + if (codec_configuration_map_.empty()) { + LOG(ERROR) << __func__ << ": No codec configurations in " + << kLeAudioCodecCapabilitiesFile; + return; + } + + UpdateStrategyConfigurationsToMap(le_audio_offload_setting); + if (strategy_configuration_map_.empty()) { + LOG(ERROR) << __func__ << ": No strategy configurations in " + << kLeAudioCodecCapabilitiesFile; + return; + } +} + +std::vector +BluetoothLeAudioCodecsProvider::ComposeLeAudioCodecCapabilities( + const std::vector& supported_scenarios) { + std::vector le_audio_codec_capabilities; + for (const auto& scenario : supported_scenarios) { + UnicastCapability unicast_encode_capability = + GetUnicastCapability(scenario.getEncode()); + UnicastCapability unicast_decode_capability = + GetUnicastCapability(scenario.getDecode()); + BroadcastCapability broadcast_capability = {.codecType = + CodecType::UNKNOWN}; + + if (scenario.hasBroadcast()) { + broadcast_capability = GetBroadcastCapability(scenario.getBroadcast()); + } + + // At least one capability should be valid + if (unicast_encode_capability.codecType == CodecType::UNKNOWN && + unicast_decode_capability.codecType == CodecType::UNKNOWN && + broadcast_capability.codecType == CodecType::UNKNOWN) { + LOG(ERROR) << __func__ << ": None of the capability is valid."; + continue; + } + + le_audio_codec_capabilities.push_back( + {.unicastEncodeCapability = unicast_encode_capability, + .unicastDecodeCapability = unicast_decode_capability, + .broadcastCapability = broadcast_capability}); + } + return le_audio_codec_capabilities; +} + +UnicastCapability BluetoothLeAudioCodecsProvider::GetUnicastCapability( + const std::string& coding_direction) { + if (coding_direction == "invalid") { + return {.codecType = CodecType::UNKNOWN}; + } + + auto configuration_iter = configuration_map_.find(coding_direction); + if (configuration_iter == configuration_map_.end()) { + return {.codecType = CodecType::UNKNOWN}; + } + + auto codec_configuration_iter = codec_configuration_map_.find( + configuration_iter->second.getCodecConfiguration()); + if (codec_configuration_iter == codec_configuration_map_.end()) { + return {.codecType = CodecType::UNKNOWN}; + } + + auto strategy_configuration_iter = strategy_configuration_map_.find( + configuration_iter->second.getStrategyConfiguration()); + if (strategy_configuration_iter == strategy_configuration_map_.end()) { + return {.codecType = CodecType::UNKNOWN}; + } + + CodecType codec_type = + GetCodecType(codec_configuration_iter->second.getCodec()); + if (codec_type == CodecType::LC3) { + return ComposeUnicastCapability( + codec_type, + GetAudioLocation( + strategy_configuration_iter->second.getAudioLocation()), + strategy_configuration_iter->second.getConnectedDevice(), + strategy_configuration_iter->second.getChannelCount(), + ComposeLc3Capability(codec_configuration_iter->second)); + } else if (codec_type == CodecType::APTX_ADAPTIVE_LE || + codec_type == CodecType::APTX_ADAPTIVE_LEX) { + return ComposeUnicastCapability( + codec_type, + GetAudioLocation( + strategy_configuration_iter->second.getAudioLocation()), + strategy_configuration_iter->second.getConnectedDevice(), + strategy_configuration_iter->second.getChannelCount(), + ComposeAptxAdaptiveLeCapability(codec_configuration_iter->second)); + } + return {.codecType = CodecType::UNKNOWN}; +} + +BroadcastCapability BluetoothLeAudioCodecsProvider::GetBroadcastCapability( + const std::string& coding_direction) { + if (coding_direction == "invalid") { + return {.codecType = CodecType::UNKNOWN}; + } + + auto configuration_iter = configuration_map_.find(coding_direction); + if (configuration_iter == configuration_map_.end()) { + return {.codecType = CodecType::UNKNOWN}; + } + + auto codec_configuration_iter = codec_configuration_map_.find( + configuration_iter->second.getCodecConfiguration()); + if (codec_configuration_iter == codec_configuration_map_.end()) { + return {.codecType = CodecType::UNKNOWN}; + } + + auto strategy_configuration_iter = strategy_configuration_map_.find( + configuration_iter->second.getStrategyConfiguration()); + if (strategy_configuration_iter == strategy_configuration_map_.end()) { + return {.codecType = CodecType::UNKNOWN}; + } + + CodecType codec_type = + GetCodecType(codec_configuration_iter->second.getCodec()); + std::vector> bcastLc3Cap( + 1, std::optional(ComposeLc3Capability(codec_configuration_iter->second))); + + if (codec_type == CodecType::LC3) { + return ComposeBroadcastCapability( + codec_type, + GetAudioLocation( + strategy_configuration_iter->second.getAudioLocation()), + strategy_configuration_iter->second.getChannelCount(), bcastLc3Cap); + } + return {.codecType = CodecType::UNKNOWN}; +} + +template +BroadcastCapability BluetoothLeAudioCodecsProvider::ComposeBroadcastCapability( + const CodecType& codec_type, const AudioLocation& audio_location, + const uint8_t& channel_count, const std::vector& capability) { + return {.codecType = codec_type, + .supportedChannel = audio_location, + .channelCountPerStream = channel_count, + .leAudioCodecCapabilities = std::optional(capability)}; +} + +template +UnicastCapability BluetoothLeAudioCodecsProvider::ComposeUnicastCapability( + const CodecType& codec_type, const AudioLocation& audio_location, + const uint8_t& device_cnt, const uint8_t& channel_count, + const T& capability) { + return { + .codecType = codec_type, + .supportedChannel = audio_location, + .deviceCount = device_cnt, + .channelCountPerDevice = channel_count, + .leAudioCodecCapabilities = + UnicastCapability::LeAudioCodecCapabilities(capability), + }; +} + +Lc3Capabilities BluetoothLeAudioCodecsProvider::ComposeLc3Capability( + const setting::CodecConfiguration& codec_configuration) { + return {.samplingFrequencyHz = {codec_configuration.getSamplingFrequency()}, + .frameDurationUs = {codec_configuration.getFrameDurationUs()}, + .octetsPerFrame = {codec_configuration.getOctetsPerCodecFrame()}}; +} + +AptxAdaptiveLeCapabilities +BluetoothLeAudioCodecsProvider::ComposeAptxAdaptiveLeCapability( + const setting::CodecConfiguration& codec_configuration) { + return {.samplingFrequencyHz = {codec_configuration.getSamplingFrequency()}, + .frameDurationUs = {codec_configuration.getFrameDurationUs()}, + .octetsPerFrame = {codec_configuration.getOctetsPerCodecFrame()}}; +} + +AudioLocation BluetoothLeAudioCodecsProvider::GetAudioLocation( + const setting::AudioLocation& audio_location) { + switch (audio_location) { + case setting::AudioLocation::MONO: + return kMonoAudio; + case setting::AudioLocation::STEREO: + return kStereoAudio; + default: + return AudioLocation::UNKNOWN; + } +} + +CodecType BluetoothLeAudioCodecsProvider::GetCodecType( + const setting::CodecType& codec_type) { + switch (codec_type) { + case setting::CodecType::LC3: + return CodecType::LC3; + case setting::CodecType::APTX_ADAPTIVE_LE: + return CodecType::APTX_ADAPTIVE_LE; + case setting::CodecType::APTX_ADAPTIVE_LEX: + return CodecType::APTX_ADAPTIVE_LEX; + default: + return CodecType::UNKNOWN; + } +} + +bool BluetoothLeAudioCodecsProvider::IsValidCodecConfiguration( + const setting::CodecConfiguration& codec_configuration) { + return codec_configuration.hasName() && codec_configuration.hasCodec() && + codec_configuration.hasSamplingFrequency() && + codec_configuration.hasFrameDurationUs() && + codec_configuration.hasOctetsPerCodecFrame(); +} + +bool BluetoothLeAudioCodecsProvider::IsValidStrategyConfiguration( + const setting::StrategyConfiguration& strategy_configuration) { + if (!strategy_configuration.hasName() || + !strategy_configuration.hasAudioLocation() || + !strategy_configuration.hasConnectedDevice() || + !strategy_configuration.hasChannelCount()) { + return false; + } + if (strategy_configuration.getAudioLocation() == + setting::AudioLocation::STEREO) { + if ((strategy_configuration.getConnectedDevice() == 2 && + strategy_configuration.getChannelCount() == 1) || + (strategy_configuration.getConnectedDevice() == 1 && + strategy_configuration.getChannelCount() == 2)) { + // Stereo + // 1. two connected device, one for L one for R + // 2. one connected device for both L and R + return true; + } else if (strategy_configuration.getConnectedDevice() == 0 && + strategy_configuration.getChannelCount() == 2) { + // Broadcast + return true; + } + } else if (strategy_configuration.getAudioLocation() == + setting::AudioLocation::MONO) { + if (strategy_configuration.getConnectedDevice() == 1 && + strategy_configuration.getChannelCount() == 1) { + // Mono + return true; + } + } + return false; +} + +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h new file mode 100644 index 0000000..5bf67e2 --- /dev/null +++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2022 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. + */ + +#pragma once + +#include +#include + +#include +#include + +#include "aidl/android/hardware/bluetooth/audio/CodecInfo.h" +#include "aidl/android/hardware/bluetooth/audio/SessionType.h" +#include "aidl_android_hardware_bluetooth_audio_setting.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { + +class BluetoothLeAudioCodecsProvider { + public: + static std::optional + ParseFromLeAudioOffloadSettingFile(); + static std::vector + GetLeAudioCodecCapabilities( + const std::optional& + le_audio_offload_setting); + static void ClearLeAudioCodecCapabilities(); + static std::unordered_map> + GetLeAudioCodecInfo(const std::optional& + le_audio_offload_setting); + + private: + static inline std::vector supported_scenarios_; + static inline std::unordered_map + configuration_map_; + static inline std::unordered_map + codec_configuration_map_; + static inline std::unordered_map + strategy_configuration_map_; + static inline std::unordered_map> + session_codecs_map_; + + static std::vector GetScenarios( + const std::optional& + le_audio_offload_setting); + static void UpdateConfigurationsToMap( + const std::optional& + le_audio_offload_setting); + static void UpdateCodecConfigurationsToMap( + const std::optional& + le_audio_offload_setting); + static void UpdateStrategyConfigurationsToMap( + const std::optional& + le_audio_offload_setting); + static void LoadConfigurationToMap( + const std::optional& + le_audio_offload_setting); + + static std::vector + ComposeLeAudioCodecCapabilities( + const std::vector& supported_scenarios); + + static UnicastCapability GetUnicastCapability( + const std::string& coding_direction); + static BroadcastCapability GetBroadcastCapability( + const std::string& coding_direction); + + template + static inline UnicastCapability ComposeUnicastCapability( + const CodecType& codec_type, const AudioLocation& audio_location, + const uint8_t& device_cnt, const uint8_t& channel_count, + const T& capability); + + template + static inline BroadcastCapability ComposeBroadcastCapability( + const CodecType& codec_type, const AudioLocation& audio_location, + const uint8_t& channel_count, const std::vector& capability); + + static inline Lc3Capabilities ComposeLc3Capability( + const setting::CodecConfiguration& codec_configuration); + + static inline AptxAdaptiveLeCapabilities ComposeAptxAdaptiveLeCapability( + const setting::CodecConfiguration& codec_configuration); + + static inline AudioLocation GetAudioLocation( + const setting::AudioLocation& audio_location); + static inline CodecType GetCodecType(const setting::CodecType& codec_type); + + static inline bool IsValidCodecConfiguration( + const setting::CodecConfiguration& codec_configuration); + static inline bool IsValidStrategyConfiguration( + const setting::StrategyConfiguration& strategy_configuration); +}; + +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp new file mode 100644 index 0000000..dba2749 --- /dev/null +++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp @@ -0,0 +1,383 @@ +/* + * Copyright (C) 2022 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 + +#include +#include + +#include "BluetoothLeAudioCodecsProvider.h" + +using aidl::android::hardware::bluetooth::audio::BluetoothLeAudioCodecsProvider; +using aidl::android::hardware::bluetooth::audio:: + LeAudioCodecCapabilitiesSetting; +using aidl::android::hardware::bluetooth::audio::setting::AudioLocation; +using aidl::android::hardware::bluetooth::audio::setting::CodecConfiguration; +using aidl::android::hardware::bluetooth::audio::setting:: + CodecConfigurationList; +using aidl::android::hardware::bluetooth::audio::setting::CodecType; +using aidl::android::hardware::bluetooth::audio::setting::Configuration; +using aidl::android::hardware::bluetooth::audio::setting::ConfigurationList; +using aidl::android::hardware::bluetooth::audio::setting::LeAudioOffloadSetting; +using aidl::android::hardware::bluetooth::audio::setting::Scenario; +using aidl::android::hardware::bluetooth::audio::setting::ScenarioList; +using aidl::android::hardware::bluetooth::audio::setting::StrategyConfiguration; +using aidl::android::hardware::bluetooth::audio::setting:: + StrategyConfigurationList; + +typedef std::tuple, std::vector, + std::vector, + std::vector> + OffloadSetting; + +// Define valid components for each list +// Scenario +static const Scenario kValidScenario(std::make_optional("OneChanStereo_16_1"), + std::make_optional("OneChanStereo_16_1"), + std::nullopt); +static const Scenario kValidBroadcastScenario( + std::nullopt, std::nullopt, std::make_optional("BcastStereo_16_2")); + +// Configuration +static const Configuration kValidConfigOneChanStereo_16_1( + std::make_optional("OneChanStereo_16_1"), std::make_optional("LC3_16k_1"), + std::make_optional("STEREO_ONE_CIS_PER_DEVICE")); +// CodecConfiguration +static const CodecConfiguration kValidCodecLC3_16k_1( + std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3), + std::nullopt, std::make_optional(16000), std::make_optional(7500), + std::make_optional(30), std::nullopt); +// StrategyConfiguration +static const StrategyConfiguration kValidStrategyStereoOneCis( + std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), + std::make_optional(AudioLocation::STEREO), std::make_optional(2), + std::make_optional(1)); +static const StrategyConfiguration kValidStrategyStereoTwoCis( + std::make_optional("STEREO_TWO_CISES_PER_DEVICE"), + std::make_optional(AudioLocation::STEREO), std::make_optional(1), + std::make_optional(2)); +static const StrategyConfiguration kValidStrategyMonoOneCis( + std::make_optional("MONO_ONE_CIS_PER_DEVICE"), + std::make_optional(AudioLocation::MONO), std::make_optional(1), + std::make_optional(1)); +static const StrategyConfiguration kValidStrategyBroadcastStereo( + std::make_optional("BROADCAST_STEREO"), + std::make_optional(AudioLocation::STEREO), std::make_optional(0), + std::make_optional(2)); + +// Define valid test list built from above valid components +// Scenario, Configuration, CodecConfiguration, StrategyConfiguration +static const std::vector kValidScenarioList = {ScenarioList( + std::vector{kValidScenario, kValidBroadcastScenario})}; +static const std::vector kValidConfigurationList = { + ConfigurationList( + std::vector{kValidConfigOneChanStereo_16_1})}; +static const std::vector kValidCodecConfigurationList = + {CodecConfigurationList( + std::vector{kValidCodecLC3_16k_1})}; +static const std::vector + kValidStrategyConfigurationList = { + StrategyConfigurationList(std::vector{ + kValidStrategyStereoOneCis, kValidStrategyStereoTwoCis, + kValidStrategyMonoOneCis, kValidStrategyBroadcastStereo})}; + +class BluetoothLeAudioCodecsProviderTest + : public ::testing::TestWithParam { + public: + static std::vector CreateTestCases( + const std::vector& scenario_lists, + const std::vector& configuration_lists, + const std::vector& codec_configuration_lists, + const std::vector& + strategy_configuration_lists) { + // make each vector in output test_cases has only one element + // to match the input of test params + // normally only one vector in input has multiple elements + // we just split elements in this vector to several vector + std::vector test_cases; + for (const auto& scenario_list : scenario_lists) { + for (const auto& configuration_list : configuration_lists) { + for (const auto& codec_configuration_list : codec_configuration_lists) { + for (const auto& strategy_configuration_list : + strategy_configuration_lists) { + test_cases.push_back(CreateTestCase( + scenario_list, configuration_list, codec_configuration_list, + strategy_configuration_list)); + } + } + } + } + return test_cases; + } + + protected: + void Initialize() { + BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities(); + } + + std::vector RunTestCase() { + auto& [scenario_lists, configuration_lists, codec_configuration_lists, + strategy_configuration_lists] = GetParam(); + LeAudioOffloadSetting le_audio_offload_setting( + scenario_lists, configuration_lists, codec_configuration_lists, + strategy_configuration_lists); + auto le_audio_codec_capabilities = + BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities( + std::make_optional(le_audio_offload_setting)); + return le_audio_codec_capabilities; + } + + private: + static inline OffloadSetting CreateTestCase( + const ScenarioList& scenario_list, + const ConfigurationList& configuration_list, + const CodecConfigurationList& codec_configuration_list, + const StrategyConfigurationList& strategy_configuration_list) { + return std::make_tuple( + std::vector{scenario_list}, + std::vector{configuration_list}, + std::vector{codec_configuration_list}, + std::vector{strategy_configuration_list}); + } +}; + +class GetScenariosTest : public BluetoothLeAudioCodecsProviderTest { + public: + static std::vector CreateInvalidScenarios() { + std::vector invalid_scenario_test_cases; + invalid_scenario_test_cases.push_back(ScenarioList(std::vector{ + Scenario(std::nullopt, std::make_optional("OneChanStereo_16_1"), + std::nullopt)})); + + invalid_scenario_test_cases.push_back(ScenarioList( + std::vector{Scenario(std::make_optional("OneChanStereo_16_1"), + std::nullopt, std::nullopt)})); + + invalid_scenario_test_cases.push_back(ScenarioList(std::vector{ + Scenario(std::nullopt, std::nullopt, std::nullopt)})); + + invalid_scenario_test_cases.push_back( + ScenarioList(std::vector{})); + + return invalid_scenario_test_cases; + } +}; + +TEST_P(GetScenariosTest, InvalidScenarios) { + Initialize(); + auto le_audio_codec_capabilities = RunTestCase(); + ASSERT_TRUE(le_audio_codec_capabilities.empty()); +} + +class UpdateConfigurationsToMapTest + : public BluetoothLeAudioCodecsProviderTest { + public: + static std::vector CreateInvalidConfigurations() { + std::vector invalid_configuration_test_cases; + invalid_configuration_test_cases.push_back( + ConfigurationList(std::vector{ + Configuration(std::nullopt, std::make_optional("LC3_16k_1"), + std::make_optional("STEREO_ONE_CIS_PER_DEVICE"))})); + + invalid_configuration_test_cases.push_back( + ConfigurationList(std::vector{Configuration( + std::make_optional("OneChanStereo_16_1"), std::nullopt, + std::make_optional("STEREO_ONE_CIS_PER_DEVICE"))})); + + invalid_configuration_test_cases.push_back( + ConfigurationList(std::vector{ + Configuration(std::make_optional("OneChanStereo_16_1"), + std::make_optional("LC3_16k_1"), std::nullopt)})); + + invalid_configuration_test_cases.push_back( + ConfigurationList(std::vector{})); + + return invalid_configuration_test_cases; + } +}; + +TEST_P(UpdateConfigurationsToMapTest, InvalidConfigurations) { + Initialize(); + auto le_audio_codec_capabilities = RunTestCase(); + ASSERT_TRUE(le_audio_codec_capabilities.empty()); +} + +class UpdateCodecConfigurationsToMapTest + : public BluetoothLeAudioCodecsProviderTest { + public: + static std::vector + CreateInvalidCodecConfigurations() { + std::vector invalid_codec_configuration_test_cases; + invalid_codec_configuration_test_cases.push_back(CodecConfigurationList( + std::vector{CodecConfiguration( + std::nullopt, std::make_optional(CodecType::LC3), std::nullopt, + std::make_optional(16000), std::make_optional(7500), + std::make_optional(30), std::nullopt)})); + + invalid_codec_configuration_test_cases.push_back(CodecConfigurationList( + std::vector{CodecConfiguration( + std::make_optional("LC3_16k_1"), std::nullopt, std::nullopt, + std::make_optional(16000), std::make_optional(7500), + std::make_optional(30), std::nullopt)})); + + invalid_codec_configuration_test_cases.push_back(CodecConfigurationList( + std::vector{CodecConfiguration( + std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3), + std::nullopt, std::nullopt, std::make_optional(7500), + std::make_optional(30), std::nullopt)})); + + invalid_codec_configuration_test_cases.push_back(CodecConfigurationList( + std::vector{CodecConfiguration( + std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3), + std::nullopt, std::make_optional(16000), std::nullopt, + std::make_optional(30), std::nullopt)})); + + invalid_codec_configuration_test_cases.push_back(CodecConfigurationList( + std::vector{CodecConfiguration( + std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3), + std::nullopt, std::make_optional(16000), std::make_optional(7500), + std::nullopt, std::nullopt)})); + + invalid_codec_configuration_test_cases.push_back( + CodecConfigurationList(std::vector{})); + + return invalid_codec_configuration_test_cases; + } +}; + +TEST_P(UpdateCodecConfigurationsToMapTest, InvalidCodecConfigurations) { + Initialize(); + auto le_audio_codec_capabilities = RunTestCase(); + ASSERT_TRUE(le_audio_codec_capabilities.empty()); +} + +class UpdateStrategyConfigurationsToMapTest + : public BluetoothLeAudioCodecsProviderTest { + public: + static std::vector + CreateInvalidStrategyConfigurations() { + std::vector + invalid_strategy_configuration_test_cases; + invalid_strategy_configuration_test_cases.push_back( + StrategyConfigurationList( + std::vector{StrategyConfiguration( + std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), + std::make_optional(AudioLocation::STEREO), + std::make_optional(2), std::make_optional(2))})); + + invalid_strategy_configuration_test_cases.push_back( + StrategyConfigurationList( + std::vector{StrategyConfiguration( + std::make_optional("MONO_ONE_CIS_PER_DEVICE"), + std::make_optional(AudioLocation::STEREO), + std::make_optional(2), std::make_optional(2))})); + + invalid_strategy_configuration_test_cases.push_back( + StrategyConfigurationList( + std::vector{StrategyConfiguration( + std::nullopt, std::make_optional(AudioLocation::STEREO), + std::make_optional(2), std::make_optional(1))})); + + invalid_strategy_configuration_test_cases.push_back( + StrategyConfigurationList( + std::vector{StrategyConfiguration( + std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), std::nullopt, + std::make_optional(2), std::make_optional(1))})); + + invalid_strategy_configuration_test_cases.push_back( + StrategyConfigurationList( + std::vector{StrategyConfiguration( + std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), + std::make_optional(AudioLocation::STEREO), std::nullopt, + std::make_optional(1))})); + + invalid_strategy_configuration_test_cases.push_back( + StrategyConfigurationList( + std::vector{StrategyConfiguration( + std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), + std::make_optional(AudioLocation::STEREO), + std::make_optional(2), std::nullopt)})); + + invalid_strategy_configuration_test_cases.push_back( + StrategyConfigurationList(std::vector{})); + + return invalid_strategy_configuration_test_cases; + } +}; + +TEST_P(UpdateStrategyConfigurationsToMapTest, InvalidStrategyConfigurations) { + Initialize(); + auto le_audio_codec_capabilities = RunTestCase(); + ASSERT_TRUE(le_audio_codec_capabilities.empty()); +} + +class ComposeLeAudioCodecCapabilitiesTest + : public BluetoothLeAudioCodecsProviderTest { + public: +}; + +TEST_P(ComposeLeAudioCodecCapabilitiesTest, CodecCapabilitiesNotEmpty) { + Initialize(); + auto le_audio_codec_capabilities = RunTestCase(); + ASSERT_TRUE(!le_audio_codec_capabilities.empty()); +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GetScenariosTest); +INSTANTIATE_TEST_SUITE_P( + BluetoothLeAudioCodecsProviderTest, GetScenariosTest, + ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases( + GetScenariosTest::CreateInvalidScenarios(), kValidConfigurationList, + kValidCodecConfigurationList, kValidStrategyConfigurationList))); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UpdateConfigurationsToMapTest); +INSTANTIATE_TEST_SUITE_P( + BluetoothLeAudioCodecsProviderTest, UpdateConfigurationsToMapTest, + ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases( + kValidScenarioList, + UpdateConfigurationsToMapTest::CreateInvalidConfigurations(), + kValidCodecConfigurationList, kValidStrategyConfigurationList))); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( + UpdateCodecConfigurationsToMapTest); +INSTANTIATE_TEST_SUITE_P( + BluetoothLeAudioCodecsProviderTest, UpdateCodecConfigurationsToMapTest, + ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases( + kValidScenarioList, kValidConfigurationList, + UpdateCodecConfigurationsToMapTest::CreateInvalidCodecConfigurations(), + kValidStrategyConfigurationList))); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( + UpdateStrategyConfigurationsToMapTest); +INSTANTIATE_TEST_SUITE_P( + BluetoothLeAudioCodecsProviderTest, UpdateStrategyConfigurationsToMapTest, + ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases( + kValidScenarioList, kValidConfigurationList, + kValidCodecConfigurationList, + UpdateStrategyConfigurationsToMapTest:: + CreateInvalidStrategyConfigurations()))); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( + ComposeLeAudioCodecCapabilitiesTest); +INSTANTIATE_TEST_SUITE_P( + BluetoothLeAudioCodecsProviderTest, ComposeLeAudioCodecCapabilitiesTest, + ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases( + kValidScenarioList, kValidConfigurationList, + kValidCodecConfigurationList, kValidStrategyConfigurationList))); + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp index a4664f1..fd12a6e 100644 --- a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp +++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp @@ -467,6 +467,8 @@ inline AudioConfig_2_1 to_hidl_audio_config_2_1( hidl_audio_config.codecConfig(to_hidl_codec_config_2_0( audio_config.get())); break; + case AudioConfiguration::a2dp: + break; case AudioConfiguration::leAudioConfig: hidl_audio_config.leAudioCodecConfig(to_hidl_leaudio_config_2_1( audio_config.get())); @@ -475,6 +477,8 @@ inline AudioConfig_2_1 to_hidl_audio_config_2_1( hidl_audio_config.leAudioCodecConfig(to_hidl_leaudio_broadcast_config_2_1( audio_config.get())); break; + default: + LOG(FATAL) << __func__ << ": unexpected AudioConfiguration"; } return hidl_audio_config; } @@ -583,7 +587,7 @@ bool HidlToAidlMiddleware_2_0::GetPresentationPosition( *total_bytes_readed = presentation_position.transmittedOctets; if (data_position) *data_position = { - .tv_sec = static_cast<__kernel_old_time_t>( + .tv_sec = static_cast( presentation_position.transmittedOctetsTimestamp.tvSec), .tv_nsec = static_cast( presentation_position.transmittedOctetsTimestamp.tvNSec)}; diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml new file mode 100644 index 0000000..eaace78 --- /dev/null +++ b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd new file mode 100644 index 0000000..03c8ade --- /dev/null +++ b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt new file mode 100644 index 0000000..a882174 --- /dev/null +++ b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt @@ -0,0 +1,107 @@ +// Signature format: 2.0 +package aidl.android.hardware.bluetooth.audio.setting { + + public enum AudioLocation { + method public String getRawName(); + enum_constant public static final aidl.android.hardware.bluetooth.audio.setting.AudioLocation MONO; + enum_constant public static final aidl.android.hardware.bluetooth.audio.setting.AudioLocation STEREO; + } + + public class CodecConfiguration { + ctor public CodecConfiguration(); + method public aidl.android.hardware.bluetooth.audio.setting.CodecType getCodec(); + method public short getCodecFrameBlocksPerSdu(); + method public int getFrameDurationUs(); + method public String getName(); + method public int getOctetsPerCodecFrame(); + method public short getPcmBitDepth(); + method public int getSamplingFrequency(); + method public void setCodec(aidl.android.hardware.bluetooth.audio.setting.CodecType); + method public void setCodecFrameBlocksPerSdu(short); + method public void setFrameDurationUs(int); + method public void setName(String); + method public void setOctetsPerCodecFrame(int); + method public void setPcmBitDepth(short); + method public void setSamplingFrequency(int); + } + + public class CodecConfigurationList { + ctor public CodecConfigurationList(); + method public java.util.List getCodecConfiguration(); + } + + public enum CodecType { + method public String getRawName(); + enum_constant public static final aidl.android.hardware.bluetooth.audio.setting.CodecType APTX_ADAPTIVE_LE; + enum_constant public static final aidl.android.hardware.bluetooth.audio.setting.CodecType APTX_ADAPTIVE_LEX; + enum_constant public static final aidl.android.hardware.bluetooth.audio.setting.CodecType LC3; + } + + public class Configuration { + ctor public Configuration(); + method public String getCodecConfiguration(); + method public String getName(); + method public String getStrategyConfiguration(); + method public void setCodecConfiguration(String); + method public void setName(String); + method public void setStrategyConfiguration(String); + } + + public class ConfigurationList { + ctor public ConfigurationList(); + method public java.util.List getConfiguration(); + } + + public class LeAudioOffloadSetting { + ctor public LeAudioOffloadSetting(); + method public aidl.android.hardware.bluetooth.audio.setting.CodecConfigurationList getCodecConfigurationList(); + method public aidl.android.hardware.bluetooth.audio.setting.ConfigurationList getConfigurationList(); + method public aidl.android.hardware.bluetooth.audio.setting.ScenarioList getScenarioList(); + method public aidl.android.hardware.bluetooth.audio.setting.StrategyConfigurationList getStrategyConfigurationList(); + method public void setCodecConfigurationList(aidl.android.hardware.bluetooth.audio.setting.CodecConfigurationList); + method public void setConfigurationList(aidl.android.hardware.bluetooth.audio.setting.ConfigurationList); + method public void setScenarioList(aidl.android.hardware.bluetooth.audio.setting.ScenarioList); + method public void setStrategyConfigurationList(aidl.android.hardware.bluetooth.audio.setting.StrategyConfigurationList); + } + + public class Scenario { + ctor public Scenario(); + method public String getBroadcast(); + method public String getDecode(); + method public String getEncode(); + method public void setBroadcast(String); + method public void setDecode(String); + method public void setEncode(String); + } + + public class ScenarioList { + ctor public ScenarioList(); + method public java.util.List getScenario(); + } + + public class StrategyConfiguration { + ctor public StrategyConfiguration(); + method public aidl.android.hardware.bluetooth.audio.setting.AudioLocation getAudioLocation(); + method public short getChannelCount(); + method public short getConnectedDevice(); + method public String getName(); + method public void setAudioLocation(aidl.android.hardware.bluetooth.audio.setting.AudioLocation); + method public void setChannelCount(short); + method public void setConnectedDevice(short); + method public void setName(String); + } + + public class StrategyConfigurationList { + ctor public StrategyConfigurationList(); + method public java.util.List getStrategyConfiguration(); + } + + public class XmlParser { + ctor public XmlParser(); + method public static aidl.android.hardware.bluetooth.audio.setting.LeAudioOffloadSetting readLeAudioOffloadSetting(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + } + +} + diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_current.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_current.txt new file mode 100644 index 0000000..e69de29 diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_removed.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_removed.txt new file mode 100644 index 0000000..e69de29 diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/removed.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/removed.txt new file mode 100644 index 0000000..d802177 --- /dev/null +++ b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.fbs b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.fbs new file mode 100644 index 0000000..bde467d --- /dev/null +++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.fbs @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2022 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. + * + */ +namespace aidl.android.hardware.bluetooth.audio.le_audio; +enum CodecSpecificLtvGenericTypes : byte { + SUPPORTED_SAMPLING_FREQUENCY = 0x01, + SUPPORTED_FRAME_DURATION = 0x02, + SUPPORTED_AUDIO_CHANNEL_ALLOCATION = 0x03, + SUPPORTED_OCTETS_PER_CODEC_FRAME = 0x04, + SUPPORTED_CODEC_FRAME_BLOCKS_PER_SDU = 0x05, +} +/// Note: Holds either a single value (when `value_width == 0`) or multiple +/// values if `value.length()` is no-remainder divisible by the non-zero +/// `value_width`. +/// Note: Consider extending it with `flags` field, to hold additional info like +/// IsBitfield, IsRange, etc. if we need these type-specific validations. +table CompoundValue { + value: [ubyte] (required); + value_width: ubyte = 0; +} +table CodecSpecificConfiguration { + name: string; + type: ubyte (key); + compound_value: CompoundValue; +} +struct CodecId { + coding_format: ubyte; + vendor_company_id : ushort; + vendor_codec_id : ushort; +} +enum AudioSetConfigurationStrategy : byte { + MONO_ONE_CIS_PER_DEVICE = 0x00, + STEREO_TWO_CISES_PER_DEVICE = 0x01, + STEREO_ONE_CIS_PER_DEVICE = 0x02, +} +enum AudioSetConfigurationDirection : byte { + SINK = 0x01, + SOURCE = 0x02, +} +enum AudioSetConfigurationTargetLatency : byte { + LOW = 0x01, + BALANCED_RELIABILITY = 0x02, + HIGH_RELIABILITY = 0x03, +} +table AudioSetSubConfiguration { + device_cnt: ubyte; + ase_cnt: ubyte; + direction: AudioSetConfigurationDirection = SINK; + configuration_strategy: AudioSetConfigurationStrategy; + codec_id : CodecId (required); + codec_configuration: [CodecSpecificConfiguration] (required); +} +table CodecConfiguration { + name: string (key, required); + subconfigurations: [AudioSetSubConfiguration] (required); +} +table QosConfiguration { + name: string (key, required); + target_latency: AudioSetConfigurationTargetLatency = BALANCED_RELIABILITY; + retransmission_number: ubyte; + max_transport_latency : ushort; +} +/// Each set configration can contain multiple logical subconfigurations, which +/// all must be configurable with the current set of audio devices. For example, +/// one can define multiple output stream configurations with different +/// qualities, or assign different configurations to each stream direction. +table AudioSetConfiguration { + name: string (key, required); + codec_config_name: string (required); + qos_config_name: [string] (required); +} +table AudioSetConfigurations { + _comments_: [string]; + configurations: [AudioSetConfiguration] (required); + codec_configurations: [CodecConfiguration] (required); + qos_configurations: [QosConfiguration] (required); +} +root_type AudioSetConfigurations; diff --git a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json new file mode 100644 index 0000000..404a48a --- /dev/null +++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json @@ -0,0 +1,11382 @@ +{ + "_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_AUDIO_CHANNEL_ALLOCATION = 3", + " 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", + " ASE Configuration strategies:", + " MONO_ONE_CIS_PER_DEVICE = 0", + " STEREO_TWO_CISES_PER_DEVICE = 1", + " STEREO_ONE_CIS_PER_DEVICE = 2", + " 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": "DualDev_OneChanStereoSnk_16_1_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_16_1_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_16_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_16_1_1", + "codec_config_name": "DualDev_OneChanStereoSnk_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_16_1_2", + "codec_config_name": "DualDev_OneChanStereoSnk_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_16_2_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_16_2_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_16_2_1", + "codec_config_name": "DualDev_OneChanStereoSnk_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_16_2_2", + "codec_config_name": "DualDev_OneChanStereoSnk_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_16_1_Low_Latency", + "codec_config_name": "SingleDev_OneChanStereoSnk_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_16_1_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanStereoSnk_16_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_16_1_1", + "codec_config_name": "SingleDev_OneChanStereoSnk_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_16_1_2", + "codec_config_name": "SingleDev_OneChanStereoSnk_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_16_2_Low_Latency", + "codec_config_name": "SingleDev_OneChanStereoSnk_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_16_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanStereoSnk_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_16_2_1", + "codec_config_name": "SingleDev_OneChanStereoSnk_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_16_2_2", + "codec_config_name": "SingleDev_OneChanStereoSnk_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_1_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_1_Balanced_Reliability", + "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_1_1", + "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_1_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_2_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_2_Balanced_Reliability", + "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_2_1", + "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_2_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_32_1_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSnk_32_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_32_1_1", + "codec_config_name": "SingleDev_OneChanMonoSnk_32_1", + "qos_config_name": [ + "QoS_Config_32_1_1" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_32_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSnk_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_32_2_1", + "codec_config_name": "SingleDev_OneChanMonoSnk_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_16_1_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSnk_16_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_16_1_1", + "codec_config_name": "SingleDev_OneChanMonoSnk_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_16_1_2", + "codec_config_name": "SingleDev_OneChanMonoSnk_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "DualDev_OneChanMonoSnk_16_2_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanMonoSnk_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_16_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSnk_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_16_2_1", + "codec_config_name": "SingleDev_OneChanMonoSnk_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_16_2_2", + "codec_config_name": "SingleDev_OneChanMonoSnk_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_2", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_2", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_2", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_2", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_Low_Latency", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_1", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1", + "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1", + "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1", + "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_2", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_1", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_2", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1", + "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1", + "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", + "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1", + "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_2", + "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1", + "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_2", + "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency", + "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1", + "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_16_1_1" + ] + }, + { + "name": "DualDev_OneChanMonoSrc_16_2_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanStereoSrc_16_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanStereoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_48_4_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSrc_48_4", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_48_3_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSrc_48_3", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_48_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSrc_48_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_48_1_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSrc_48_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_32_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_32_1_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSrc_32_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_24_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSrc_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_24_1_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSrc_24_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_16_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_16_1_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_2", + "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1", + "qos_config_name": [ + "QoS_Config_16_1_2" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency", + "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1", + "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_16_2_1" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_2", + "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_16_2_2" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_24_1_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_24_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_24_1_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_24_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_24_1_Low_Latency", + "codec_config_name": "SingleDev_OneChanStereoSnk_24_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_24_2_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_24_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_24_2_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_24_2_2", + "codec_config_name": "DualDev_OneChanStereoSnk_24_2", + "qos_config_name": [ + "QoS_Config_24_2_2" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_24_2_Low_Latency", + "codec_config_name": "SingleDev_OneChanStereoSnk_24_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_24_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanStereoSnk_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_24_2_2", + "codec_config_name": "SingleDev_OneChanStereoSnk_24_2", + "qos_config_name": [ + "QoS_Config_24_2_2" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_24_2_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_24_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_24_2_Balanced_Reliability", + "codec_config_name": "SingleDev_TwoChanStereoSnk_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_24_2_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_24_2", + "qos_config_name": [ + "QoS_Config_24_2_2" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_24_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSnk_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_24_2_2", + "codec_config_name": "SingleDev_OneChanMonoSnk_24_2", + "qos_config_name": [ + "QoS_Config_24_2_2" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_32_2_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_32_1_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_32_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_32_1_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_32_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_32_2_Low_Latency", + "codec_config_name": "SingleDev_OneChanStereoSnk_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_32_1_Low_Latency", + "codec_config_name": "SingleDev_OneChanStereoSnk_32_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_1", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1", + "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1", + "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency", + "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1", + "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_32_2_1" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_32_2_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_32_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_High_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_48_4", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_1", + "codec_config_name": "DualDev_OneChanStereoSnk_48_4", + "qos_config_name": [ + "QoS_Config_48_4_1" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_2", + "codec_config_name": "DualDev_OneChanStereoSnk_48_4", + "qos_config_name": [ + "QoS_Config_48_4_2" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_3_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_48_3", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_3_High_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_48_3", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_3_2", + "codec_config_name": "DualDev_OneChanStereoSnk_48_3", + "qos_config_name": [ + "QoS_Config_48_3_2" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_2_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_48_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_2_High_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_48_2", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_2_2", + "codec_config_name": "DualDev_OneChanStereoSnk_48_2", + "qos_config_name": [ + "QoS_Config_48_2_2" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_1_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_48_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_1_High_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_48_1", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_1_2", + "codec_config_name": "DualDev_OneChanStereoSnk_48_1", + "qos_config_name": [ + "QoS_Config_48_1_2" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_4_High_Reliability", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_4", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_4_1", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_4", + "qos_config_name": [ + "QoS_Config_48_4_1" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_4_2", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_4", + "qos_config_name": [ + "QoS_Config_48_4_2" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_3_Low_Latency", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_3", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_3_High_Reliability", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_3", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_3_2", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_3", + "qos_config_name": [ + "QoS_Config_48_3_2" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_2_Low_Latency", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_2_High_Reliability", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_2", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_2_2", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_2", + "qos_config_name": [ + "QoS_Config_48_2_2" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_1_Low_Latency", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_1_High_Reliability", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_1", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_1_2", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_1", + "qos_config_name": [ + "QoS_Config_48_1_2" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_High_Reliability", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_1", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4", + "qos_config_name": [ + "QoS_Config_48_4_1" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4", + "qos_config_name": [ + "QoS_Config_48_4_2" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_3_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_3", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_3_High_Reliability", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_3", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_3_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_3", + "qos_config_name": [ + "QoS_Config_48_3_2" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_2_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_2_High_Reliability", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_2", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_2_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_2", + "qos_config_name": [ + "QoS_Config_48_2_2" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_1_Low_Latency", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_1_High_Reliability", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_1", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_1_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_1", + "qos_config_name": [ + "QoS_Config_48_1_2" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_4_High_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSnk_48_4", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_4_1", + "codec_config_name": "SingleDev_OneChanMonoSnk_48_4", + "qos_config_name": [ + "QoS_Config_48_4_1" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_4_2", + "codec_config_name": "SingleDev_OneChanMonoSnk_48_4", + "qos_config_name": [ + "QoS_Config_48_4_2" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_3_High_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSnk_48_3", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_3_2", + "codec_config_name": "SingleDev_OneChanMonoSnk_48_3", + "qos_config_name": [ + "QoS_Config_48_3_2" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_2_High_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSnk_48_2", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_2_2", + "codec_config_name": "SingleDev_OneChanMonoSnk_48_2", + "qos_config_name": [ + "QoS_Config_48_2_2" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_1_High_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSnk_48_1", + "qos_config_name": [ + "QoS_Config_High_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_1_2", + "codec_config_name": "SingleDev_OneChanMonoSnk_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": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_32_2_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_24_2_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_16_2_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_32_2_Balanced_Reliability", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_24_2_Balanced_Reliability", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_16_2_Balanced_Reliability", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_1_OneChanMonoSrc_24_2_Balanced_Reliability", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_1_OneChanMonoSrc_16_2_Balanced_Reliability", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_4_1_OneChanMonoSrc_32_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_4_1_OneChanMonoSrc_24_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_4_1_OneChanMonoSrc_16_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_4_1_OneChanMonoSrc_32_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_32_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_4_1_OneChanMonoSrc_24_2_1_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_24_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_4_1_OneChanMonoSrc_16_2_Balanced_Reliability", + "codec_config_name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_16_2", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1", + "qos_config_name": [ + "QoS_Config_Balanced_Reliability" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Low_Latency", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2", + "qos_config_name": [ + "QoS_Config_Low_Latency" + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Balanced_Reliability", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_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": "DualDev_OneChanStereoSnk_16_2", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_16_1", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_16_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_16_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSrc_16_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SOURCE", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_24_2", + "subconfigurations": [ + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_32_2", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_32_1", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_32_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_32_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanMonoSnk_16_2", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_16_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_16_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2", + "subconfigurations": [ + { + "device_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": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2", + "subconfigurations": [ + { + "device_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": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_cnt": 2, + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1", + "subconfigurations": [ + { + "device_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": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_cnt": 2, + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1", + "subconfigurations": [ + { + "device_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": [ + 3 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 4, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 4, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SOURCE", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SOURCE", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SOURCE", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2", + "subconfigurations": [ + { + "device_cnt": 1, + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1", + "subconfigurations": [ + { + "device_cnt": 1, + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanMonoSrc_16_2", + "subconfigurations": [ + { + "device_cnt": 2, + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_48_4", + "subconfigurations": [ + { + "device_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": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_48_3", + "subconfigurations": [ + { + "device_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": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_48_2", + "subconfigurations": [ + { + "device_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": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_48_1", + "subconfigurations": [ + { + "device_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": [ + 8 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 0 + ] + } + }, + { + "name": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_32_2", + "subconfigurations": [ + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_32_1", + "subconfigurations": [ + { + "device_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": [ + 0 + ] + } + }, + { + "name": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_24_2", + "subconfigurations": [ + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_24_1", + "subconfigurations": [ + { + "device_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": [ + 0 + ] + } + }, + { + "name": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_16_2", + "subconfigurations": [ + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSrc_16_1", + "subconfigurations": [ + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_3", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_2", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_1", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_4", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_3", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_3", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_4", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_3", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_1", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_32_2", + "subconfigurations": [ + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_cnt": 2, + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_24_2", + "subconfigurations": [ + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_cnt": 2, + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_16_2", + "subconfigurations": [ + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_cnt": 2, + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2", + "subconfigurations": [ + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2", + "subconfigurations": [ + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2", + "subconfigurations": [ + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_32_2", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 4, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_24_2", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 4, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_16_2", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 4, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_32_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SOURCE", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_24_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SOURCE", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_16_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SOURCE", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_32_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_24_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_16_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_32_2", + "subconfigurations": [ + { + "device_cnt": 1, + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_24_2", + "subconfigurations": [ + { + "device_cnt": 1, + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_16_2", + "subconfigurations": [ + { + "device_cnt": 1, + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 120, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SOURCE", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SOURCE", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SOURCE", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_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": [ + 0 + ] + } + }, + { + "name": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + }, + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SOURCE", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_24_2", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_24_1", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_24_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_24_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_24_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_24_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_24_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2", + "subconfigurations": [ + { + "device_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": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_cnt": 2, + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2", + "subconfigurations": [ + { + "device_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": [ + 6 + ] + } + }, + { + "name": "frame_duration", + "type": 2, + "compound_value": { + "value": [ + 1 + ] + } + }, + { + "name": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2", + "subconfigurations": [ + { + "device_cnt": 2, + "ase_cnt": 4, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2", + "subconfigurations": [ + { + "device_cnt": 1, + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + }, + { + "device_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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_32_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_TwoChanStereoSnk_32_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 1, + "direction": "SINK", + "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 3, + 0, + 0, + 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 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_32_2", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 0 + ] + } + }, + { + "name": "octets_per_codec_frame", + "type": 4, + "compound_value": { + "value": [ + 80, + 0 + ] + } + }, + { + "name": "codec_frame_blocks_per_sdu", + "type": 5, + "compound_value": { + "value": [ + 1 + ] + } + } + ] + } + ] + }, + { + "name": "SingleDev_OneChanStereoSnk_32_1", + "subconfigurations": [ + { + "device_cnt": 1, + "ase_cnt": 2, + "direction": "SINK", + "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE", + "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": "audio_channel_allocation", + "type": 3, + "compound_value": { + "value": [ + 1, + 0, + 0, + 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 + ] + } + } + ] + } + ] + } + ], + "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 + } + + ] +} diff --git a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.fbs b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.fbs new file mode 100644 index 0000000..e898bdc --- /dev/null +++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.fbs @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022 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. + * + */ +namespace aidl.android.hardware.bluetooth.audio.le_audio; +/// Scenario represents the use case such as "Media", "Conversation", etc. +/// Each scenario can list any number of codec configurations by their names in +/// the order of preference. That means if the first entry does not meet all +/// the current requirements (such as peer device capabilities etc.) next +/// configurations are being checked. +/// +/// The referenced codec configurations are defined by the +/// audio_set_configurations.fbs schema and loaded from a different source file. +/// Multiple scenarios can reference same codec configurations. +table AudioSetScenario { + _comments_: [string]; + name: string (key, required); + configurations: [string] (required); +} +table AudioSetScenarios { + _comments_: [string]; + scenarios: [AudioSetScenario] (required); +} +root_type AudioSetScenarios; diff --git a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.json b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.json new file mode 100644 index 0000000..a28c6cd --- /dev/null +++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.json @@ -0,0 +1,304 @@ +{ + "_comments_": [ + "== Audio Set Scenarios ==", + " Each defined scenario references externally defined audio set", + " configurations, listed in the order of priority." + ], + "scenarios": [ + { + "name": "Conversational", + "configurations": [ + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_2", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_2", + "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1", + "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1", + "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1", + "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_1", + "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_1", + "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_Low_Latency", + "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_1", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_2", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_2", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1", + "DualDev_OneChanMonoSrc_16_2_Balanced_Reliability", + "SingleDev_OneChanStereoSrc_16_2_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_48_4_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_48_2_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_48_3_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_48_1_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_32_2_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_32_1_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_24_2_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_24_1_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_16_2_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_16_1_Balanced_Reliability", + "VND_SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32khz_Server_Prefered_1", + "VND_SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32khz_60oct_R3_L22_1", + "DualDev_OneChanMonoSnk_16_2_Balanced_Reliability", + "SingleDev_OneChanStereoSnk_16_2_Balanced_Reliability", + "SingleDev_TwoChanStereoSnk_16_2_Balanced_Reliability", + "SingleDev_OneChanMonoSnk_16_2_Balanced_Reliability" + ] + }, + { + "name": "Media", + "configurations": [ + "DualDev_OneChanStereoSnk_48_4_High_Reliability", + "DualDev_OneChanStereoSnk_48_4_2", + "DualDev_OneChanStereoSnk_48_2_High_Reliability", + "DualDev_OneChanStereoSnk_48_2_2", + "DualDev_OneChanStereoSnk_48_3_High_Reliability", + "DualDev_OneChanStereoSnk_48_3_2", + "DualDev_OneChanStereoSnk_48_1_High_Reliability", + "DualDev_OneChanStereoSnk_48_1_2", + "DualDev_OneChanStereoSnk_24_2_Balanced_Reliability", + "DualDev_OneChanStereoSnk_24_2_2", + "DualDev_OneChanStereoSnk_16_2_Balanced_Reliability", + "DualDev_OneChanStereoSnk_16_2_2", + "DualDev_OneChanStereoSnk_16_1_Balanced_Reliability", + "DualDev_OneChanStereoSnk_16_1_2", + "SingleDev_OneChanStereoSnk_48_4_High_Reliability", + "SingleDev_OneChanStereoSnk_48_4_2", + "SingleDev_OneChanStereoSnk_48_2_High_Reliability", + "SingleDev_OneChanStereoSnk_48_2_2", + "SingleDev_OneChanStereoSnk_48_3_High_Reliability", + "SingleDev_OneChanStereoSnk_48_3_2", + "SingleDev_OneChanStereoSnk_48_1_High_Reliability", + "SingleDev_OneChanStereoSnk_48_1_2", + "SingleDev_OneChanStereoSnk_24_2_Balanced_Reliability", + "SingleDev_OneChanStereoSnk_24_2_2", + "SingleDev_OneChanStereoSnk_16_2_Balanced_Reliability", + "SingleDev_OneChanStereoSnk_16_2_2", + "SingleDev_OneChanStereoSnk_16_1_Balanced_Reliability", + "SingleDev_OneChanStereoSnk_16_1_2", + "SingleDev_TwoChanStereoSnk_48_4_High_Reliability", + "SingleDev_TwoChanStereoSnk_48_4_2", + "SingleDev_TwoChanStereoSnk_48_4_High_Reliability", + "SingleDev_TwoChanStereoSnk_48_4_2", + "SingleDev_TwoChanStereoSnk_48_2_High_Reliability", + "SingleDev_TwoChanStereoSnk_48_2_2", + "SingleDev_TwoChanStereoSnk_48_3_High_Reliability", + "SingleDev_TwoChanStereoSnk_48_3_2", + "SingleDev_TwoChanStereoSnk_48_1_High_Reliability", + "SingleDev_TwoChanStereoSnk_48_1_2", + "SingleDev_TwoChanStereoSnk_24_2_Balanced_Reliability", + "SingleDev_TwoChanStereoSnk_24_2_2", + "SingleDev_TwoChanStereoSnk_16_2_Balanced_Reliability", + "SingleDev_TwoChanStereoSnk_16_2_2", + "SingleDev_TwoChanStereoSnk_16_1_Balanced_Reliability", + "SingleDev_TwoChanStereoSnk_16_1_2", + "SingleDev_OneChanMonoSnk_48_4_High_Reliability", + "SingleDev_OneChanMonoSnk_48_4_2", + "SingleDev_OneChanMonoSnk_48_2_High_Reliability", + "SingleDev_OneChanMonoSnk_48_2_2", + "SingleDev_OneChanMonoSnk_48_3_High_Reliability", + "SingleDev_OneChanMonoSnk_48_3_2", + "SingleDev_OneChanMonoSnk_48_1_High_Reliability", + "SingleDev_OneChanMonoSnk_48_1_2", + "SingleDev_OneChanMonoSnk_32_2_Balanced_Reliability", + "SingleDev_OneChanMonoSnk_32_2_2", + "SingleDev_OneChanMonoSnk_32_1_Balanced_Reliability", + "SingleDev_OneChanMonoSnk_32_1_2", + "SingleDev_OneChanMonoSnk_24_2_Balanced_Reliability", + "SingleDev_OneChanMonoSnk_24_2_2", + "SingleDev_OneChanMonoSnk_16_2_Balanced_Reliability", + "SingleDev_OneChanMonoSnk_16_2_2", + "SingleDev_OneChanMonoSnk_16_1_Balanced_Reliability", + "SingleDev_OneChanMonoSnk_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", + "DualDev_OneChanMonoSrc_16_2_Balanced_Reliability", + "SingleDev_OneChanStereoSrc_16_2_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_16_2_Balanced_Reliability" + ] + }, + { + "name": "Game", + "configurations": [ + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_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", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency", + "DualDev_OneChanStereoSnk_48_2_Low_Latency", + "DualDev_OneChanStereoSnk_48_3_Low_Latency", + "DualDev_OneChanStereoSnk_48_1_Low_Latency", + "DualDev_OneChanStereoSnk_32_2_Low_Latency", + "DualDev_OneChanStereoSnk_32_1_Low_Latency", + "DualDev_OneChanStereoSnk_24_2_Low_Latency", + "DualDev_OneChanStereoSnk_24_1_Low_Latency", + "DualDev_OneChanStereoSnk_16_2_Low_Latency", + "DualDev_OneChanStereoSnk_16_1_Low_Latency", + "SingleDev_TwoChanStereoSnk_48_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_48_3_Low_Latency", + "SingleDev_TwoChanStereoSnk_48_1_Low_Latency", + "SingleDev_TwoChanStereoSnk_32_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_32_1_Low_Latency", + "SingleDev_TwoChanStereoSnk_24_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_24_1_Low_Latency", + "SingleDev_TwoChanStereoSnk_16_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_16_1_Low_Latency", + "SingleDev_OneChanStereoSnk_48_2_Low_Latency", + "SingleDev_OneChanStereoSnk_48_3_Low_Latency", + "SingleDev_OneChanStereoSnk_48_1_Low_Latency", + "SingleDev_OneChanStereoSnk_32_2_Low_Latency", + "SingleDev_OneChanStereoSnk_32_1_Low_Latency", + "SingleDev_OneChanStereoSnk_24_2_Low_Latency", + "SingleDev_OneChanStereoSnk_24_1_Low_Latency", + "SingleDev_OneChanStereoSnk_16_2_Low_Latency", + "SingleDev_OneChanStereoSnk_16_1_Low_Latency" + ] + }, + { + "name": "VoiceAssistants", + "configurations": [ + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Balanced_Reliability", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Balanced_Reliability", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1", + "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_16_2_Balanced_Reliability", + "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_24_2_Balanced_Reliability", + "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_32_2_Balanced_Reliability", + "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability", + "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability", + "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability", + "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability", + "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability", + "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability", + "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_16_2_Balanced_Reliability", + "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_24_2_Balanced_Reliability", + "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_32_2_Balanced_Reliability", + "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability", + "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability", + "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability", + "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability", + "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability", + "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability", + "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability", + "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability", + "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability" + ] + }, + { + "name": "Live", + "configurations": [ + "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_Balanced_Reliability_1", + "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_R11_L40_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Balanced_Reliability", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Balanced_Reliability", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1", + "SingleDev_OneChanMonoSrc_48_2_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_48_1_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_32_2_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_32_1_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_16_2_Balanced_Reliability", + "SingleDev_OneChanMonoSrc_16_1_Balanced_Reliability" + ] + } + ] +}