Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8f4f7fbe authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Expose different offload audio capabilities by project" into tm-qpr-dev

parents d17a96da db060b4f
Loading
Loading
Loading
Loading
+15 −1
Original line number Original line Diff line number Diff line
@@ -40,9 +40,13 @@ cc_library_shared {
        "aidl_session/BluetoothAudioCodecs.cpp",
        "aidl_session/BluetoothAudioCodecs.cpp",
        "aidl_session/BluetoothAudioSession.cpp",
        "aidl_session/BluetoothAudioSession.cpp",
        "aidl_session/HidlToAidlMiddleware.cpp",
        "aidl_session/HidlToAidlMiddleware.cpp",
        "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
    ],
    ],
    export_include_dirs: ["aidl_session/"],
    export_include_dirs: ["aidl_session/"],
    header_libs: ["libhardware_headers"],
    header_libs: [
        "libhardware_headers",
        "libxsdc-utils",
    ],
    shared_libs: [
    shared_libs: [
        "android.hardware.bluetooth.audio@2.0",
        "android.hardware.bluetooth.audio@2.0",
        "android.hardware.bluetooth.audio@2.1",
        "android.hardware.bluetooth.audio@2.1",
@@ -53,5 +57,15 @@ cc_library_shared {
        "liblog",
        "liblog",
        "android.hardware.bluetooth.audio-V2-ndk",
        "android.hardware.bluetooth.audio-V2-ndk",
        "libhidlbase",
        "libhidlbase",
        "libxml2",
    ],
    ],
    generated_sources: ["le_audio_codec_capabilities"],
    generated_headers: ["le_audio_codec_capabilities"],
}

xsd_config {
    name: "le_audio_codec_capabilities",
    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",
}
}
+4 −109
Original line number Original line Diff line number Diff line
@@ -32,6 +32,8 @@
#include <aidl/android/hardware/bluetooth/audio/SbcChannelMode.h>
#include <aidl/android/hardware/bluetooth/audio/SbcChannelMode.h>
#include <android-base/logging.h>
#include <android-base/logging.h>


#include "BluetoothLeAudioCodecsProvider.h"

namespace aidl {
namespace aidl {
namespace android {
namespace android {
namespace hardware {
namespace hardware {
@@ -96,67 +98,6 @@ const std::vector<CodecCapabilities> kDefaultOffloadA2dpCodecCapabilities = {


std::vector<LeAudioCodecCapabilitiesSetting> kDefaultOffloadLeAudioCapabilities;
std::vector<LeAudioCodecCapabilitiesSetting> 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<Lc3Capabilities> supportedLc3CapabilityList = {
    kLc3Capability_48_4, kLc3Capability_32_2, kLc3Capability_24_2,
    kLc3Capability_16_2, kLc3Capability_16_1};

static AudioLocation stereoAudio = static_cast<AudioLocation>(
    static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
    static_cast<uint8_t>(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<std::tuple<AudioLocation, uint8_t, uint8_t>>
    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)};

template <class T>
template <class T>
bool BluetoothAudioCodecs::ContainedInVector(
bool BluetoothAudioCodecs::ContainedInVector(
    const std::vector<T>& vector, const typename identity<T>::type& target) {
    const std::vector<T>& vector, const typename identity<T>::type& target) {
@@ -444,19 +385,6 @@ bool BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
  return false;
  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<LeAudioCodecCapabilitiesSetting>
std::vector<LeAudioCodecCapabilitiesSetting>
BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities(
BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities(
    const SessionType& session_type) {
    const SessionType& session_type) {
@@ -470,41 +398,8 @@ BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities(
  }
  }


  if (kDefaultOffloadLeAudioCapabilities.empty()) {
  if (kDefaultOffloadLeAudioCapabilities.empty()) {
    for (auto [audioLocation, deviceCnt, channelCount] :
    kDefaultOffloadLeAudioCapabilities =
         supportedDeviceSetting) {
        BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities();
      for (auto capability : supportedLc3CapabilityList) {
        UnicastCapability lc3Capability = composeUnicastLc3Capability(
            audioLocation, deviceCnt, channelCount, capability);
        UnicastCapability lc3MonoDecodeCapability =
            composeUnicastLc3Capability(monoAudio, 1, 1, capability);

        // 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(force one active device for decode)
        kDefaultOffloadLeAudioCapabilities.push_back(
            {.unicastEncodeCapability = lc3Capability,
             .unicastDecodeCapability = lc3MonoDecodeCapability,
             .broadcastCapability = kInvalidBroadcastCapability});

        // Adds the capability for the case that encode and decode exist at the
        // same time
        kDefaultOffloadLeAudioCapabilities.push_back(
            {.unicastEncodeCapability = lc3Capability,
             .unicastDecodeCapability = lc3Capability,
             .broadcastCapability = kInvalidBroadcastCapability});
      }
    }
  }
  }


  return kDefaultOffloadLeAudioCapabilities;
  return kDefaultOffloadLeAudioCapabilities;
+312 −0
Original line number Original line Diff line number Diff line
/*
 * 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.
 */

#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<AudioLocation>(
    static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
    static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
static const AudioLocation kMonoAudio = AudioLocation::UNKNOWN;

static std::vector<LeAudioCodecCapabilitiesSetting> leAudioCodecCapabilities;

std::vector<LeAudioCodecCapabilitiesSetting>
BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities() {
  if (!leAudioCodecCapabilities.empty()) {
    return leAudioCodecCapabilities;
  }

  const auto le_audio_offload_setting =
      setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
  if (!le_audio_offload_setting.has_value()) {
    LOG(ERROR) << __func__ << ": Failed to read "
               << kLeAudioCodecCapabilitiesFile;
    return {};
  }

  std::vector<setting::Scenario> 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 {};
  }

  leAudioCodecCapabilities =
      ComposeLeAudioCodecCapabilities(supported_scenarios);
  return leAudioCodecCapabilities;
}

std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
    const std::optional<setting::LeAudioOffloadSetting>&
        le_audio_offload_setting) {
  std::vector<setting::Scenario> 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<setting::LeAudioOffloadSetting>&
        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<setting::LeAudioOffloadSetting>&
        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<setting::LeAudioOffloadSetting>&
        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));
        }
      }
    }
  }
}

std::vector<LeAudioCodecCapabilitiesSetting>
BluetoothLeAudioCodecsProvider::ComposeLeAudioCodecCapabilities(
    const std::vector<setting::Scenario>& supported_scenarios) {
  std::vector<LeAudioCodecCapabilitiesSetting> le_audio_codec_capabilities;
  for (const auto& scenario : supported_scenarios) {
    UnicastCapability unicast_encode_capability =
        GetUnicastCapability(scenario.getEncode());
    UnicastCapability unicast_decode_capability =
        GetUnicastCapability(scenario.getDecode());
    // encode and decode cannot be unknown at the same time
    if (unicast_encode_capability.codecType == CodecType::UNKNOWN &&
        unicast_decode_capability.codecType == CodecType::UNKNOWN) {
      continue;
    }
    BroadcastCapability broadcast_capability = {.codecType =
                                                    CodecType::UNKNOWN};
    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));
  }
  return {.codecType = CodecType::UNKNOWN};
}

template <class T>
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()}};
}

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;
    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.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
+87 −0
Original line number Original line Diff line number Diff line
/*
 * 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 <aidl/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.h>
#include <android-base/logging.h>

#include <unordered_map>

#include "aidl_android_hardware_bluetooth_audio_setting.h"

namespace aidl {
namespace android {
namespace hardware {
namespace bluetooth {
namespace audio {

class BluetoothLeAudioCodecsProvider {
 public:
  static std::vector<LeAudioCodecCapabilitiesSetting>
  GetLeAudioCodecCapabilities();

 private:
  static inline std::unordered_map<std::string, setting::Configuration>
      configuration_map_;
  static inline std::unordered_map<std::string, setting::CodecConfiguration>
      codec_configuration_map_;
  static inline std::unordered_map<std::string, setting::StrategyConfiguration>
      strategy_configuration_map_;

  static std::vector<setting::Scenario> GetScenarios(
      const std::optional<setting::LeAudioOffloadSetting>&
          le_audio_offload_setting);
  static void UpdateConfigurationsToMap(
      const std::optional<setting::LeAudioOffloadSetting>&
          le_audio_offload_setting);
  static void UpdateCodecConfigurationsToMap(
      const std::optional<setting::LeAudioOffloadSetting>&
          le_audio_offload_setting);
  static void UpdateStrategyConfigurationsToMap(
      const std::optional<setting::LeAudioOffloadSetting>&
          le_audio_offload_setting);

  static std::vector<LeAudioCodecCapabilitiesSetting>
  ComposeLeAudioCodecCapabilities(
      const std::vector<setting::Scenario>& supported_scenarios);

  static UnicastCapability GetUnicastCapability(
      const std::string& coding_direction);
  template <class T>
  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);

  static inline Lc3Capabilities ComposeLc3Capability(
      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
+61 −0
Original line number Original line Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>
<!---
  This is an example to configure LE Audio hardware offload supported capability settings
  In the follow list, there would be only one list in this file. Add element into each list as needed.

  codecConfigurationList:
    Supported codec capability along with its parameter setting

  strategyConfigurationList:
     ASE Configuration strategies

  configurationList:
    For each configuration , there are two attributes
      - codecConfiguration
      - strategyConfiguration

  scenarioList:
    There would be only one `scenarios` group
    For each scenario, the are two attributes
      - encode
      - decode
    If a scenario is unidirectional, mark another direction as `invalid`
    The configuration should be chosen from `configurationList`
-->
<leAudioOffloadSetting>
  <scenarioList>
    <!-- encode only -->
    <scenario encode="OneChanMono_16_1" decode="invalid"/>
    <scenario encode="TwoChanStereo_16_1" decode="invalid"/>
    <scenario encode="OneChanStereo_16_1" decode="invalid"/>
    <scenario encode="OneChanMono_16_2" decode="invalid"/>
    <scenario encode="TwoChanStereo_16_2" decode="invalid"/>
    <scenario encode="OneChanStereo_16_2" decode="invalid"/>
    <!-- encode and decode -->
    <scenario encode="OneChanStereo_16_1" decode="OneChanStereo_16_1"/>
    <scenario encode="OneChanStereo_16_1" decode="OneChanMono_16_1"/>
    <scenario encode="TwoChanStereo_16_1" decode="OneChanMono_16_1"/>
    <scenario encode="OneChanMono_16_1" decode="OneChanMono_16_1"/>
    <scenario encode="OneChanStereo_16_2" decode="OneChanStereo_16_2"/>
    <scenario encode="OneChanStereo_16_2" decode="OneChanMono_16_2"/>
    <scenario encode="TwoChanStereo_16_2" decode="OneChanMono_16_2"/>
    <scenario encode="OneChanMono_16_2" decode="OneChanMono_16_2"/>
  </scenarioList>
  <configurationList>
    <configuration name="OneChanMono_16_1" codecConfiguration="LC3_16k_1" strategyConfiguration="MONO_ONE_CIS_PER_DEVICE"/>
    <configuration name="TwoChanStereo_16_1" codecConfiguration="LC3_16k_1" strategyConfiguration="STEREO_TWO_CISES_PER_DEVICE"/>
    <configuration name="OneChanStereo_16_1" codecConfiguration="LC3_16k_1" strategyConfiguration="STEREO_ONE_CIS_PER_DEVICE"/>
    <configuration name="OneChanMono_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="MONO_ONE_CIS_PER_DEVICE"/>
    <configuration name="TwoChanStereo_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="STEREO_TWO_CISES_PER_DEVICE"/>
    <configuration name="OneChanStereo_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="STEREO_ONE_CIS_PER_DEVICE"/>
  </configurationList>
  <codecConfigurationList>
    <codecConfiguration name="LC3_16k_1" codec="LC3" samplingFrequency="16000" frameDurationUs="7500" octetsPerCodecFrame="30"/>
    <codecConfiguration name="LC3_16k_2" codec="LC3" samplingFrequency="16000" frameDurationUs="10000" octetsPerCodecFrame="40"/>
  </codecConfigurationList>
  <strategyConfigurationList>
    <strategyConfiguration name="STEREO_ONE_CIS_PER_DEVICE" audioLocation="STEREO" connectedDevice="2" channelCount="1"/>
    <strategyConfiguration name="STEREO_TWO_CISES_PER_DEVICE" audioLocation="STEREO" connectedDevice="1" channelCount="2"/>
    <strategyConfiguration name="MONO_ONE_CIS_PER_DEVICE" audioLocation="MONO" connectedDevice="1" channelCount="1"/>
  </strategyConfigurationList>
</leAudioOffloadSetting>
Loading