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

Commit 76ff3876 authored by Łukasz Rymanowski (xWF)'s avatar Łukasz Rymanowski (xWF) Committed by Gerrit Code Review
Browse files

Merge "codec_manager: Feed offloader with Mono configuration" into main

parents d4a7e3c8 60877998
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -807,7 +807,7 @@ cc_test {
        "liblog", // __android_log_print
    ],
    static_libs: [
        "bluetooth_flags_c_lib",
        "bluetooth_flags_c_lib_for_test",
        "libbluetooth-types",
        "libbluetooth_crypto_toolbox",
        "libbluetooth_gd",
+64 −8
Original line number Diff line number Diff line
@@ -168,9 +168,12 @@ public:
                           bluetooth::le_audio::types::kLeAudioDirectionSource}) {
      auto& stream_map = offloader_stream_maps.get(direction);
      if (!stream_map.has_changed && !stream_map.is_initial) {
        log::warn("unexpected call for direction {}, stream_map.has_changed {}", direction,
                  stream_map.has_changed, stream_map.is_initial);
        continue;
      }
      if (stream_params.get(direction).stream_locations.empty()) {
        log::warn("unexpected call, stream is empty for direction {}, ", direction);
        continue;
      }

@@ -675,7 +678,7 @@ public:
    stream_map.streams_map_current.clear();
  }

  static uint32_t AdjustAllocationForOffloader(uint32_t allocation) {
  static int AdjustAllocationForOffloader(uint32_t allocation) {
    if ((allocation & codec_spec_conf::kLeAudioLocationAnyLeft) &&
        (allocation & codec_spec_conf::kLeAudioLocationAnyRight)) {
      return codec_spec_conf::kLeAudioLocationStereo;
@@ -686,20 +689,70 @@ public:
    if (allocation & codec_spec_conf::kLeAudioLocationAnyRight) {
      return codec_spec_conf::kLeAudioLocationFrontRight;
    }
    return 0;

    if (allocation == codec_spec_conf::kLeAudioLocationMonoAudio) {
      return codec_spec_conf::kLeAudioLocationMonoAudio;
    }

    return -1;
  }

  void UpdateCisConfiguration(const std::vector<struct types::cis>& cises,
  bool UpdateCisMonoConfiguration(const std::vector<struct types::cis>& cises, uint8_t direction) {
    if (!LeAudioHalVerifier::SupportsStreamActiveApi() ||
        !com::android::bluetooth::flags::leaudio_mono_location_errata()) {
      log::error(
              "SupportsStreamActiveApi() not supported or leaudio_mono_location_errata flag is not "
              "enabled. Mono stream cannot be enabled");
      return false;
    }

    auto& stream_map = offloader_stream_maps.get(direction);

    stream_map.has_changed = true;
    stream_map.streams_map_target.clear();
    stream_map.streams_map_current.clear();

    const std::string tag =
            types::BidirectionalPair<std::string>({.sink = "Sink", .source = "Source"})
                    .get(direction);

    constexpr types::BidirectionalPair<types::CisType> cis_types = {
            .sink = types::CisType::CIS_TYPE_UNIDIRECTIONAL_SINK,
            .source = types::CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE};
    auto cis_type = cis_types.get(direction);

    for (auto const& cis_entry : cises) {
      if ((cis_entry.type == types::CisType::CIS_TYPE_BIDIRECTIONAL ||
           cis_entry.type == cis_type) &&
          cis_entry.conn_handle != 0) {
        bool is_active = cis_entry.addr != RawAddress::kEmpty;
        log::info("{}: {}, Cis handle {:#x}, allocation  {:#x}, active: {}", tag, cis_entry.addr,
                  cis_entry.conn_handle, codec_spec_conf::kLeAudioLocationMonoAudio, is_active);
        stream_map.streams_map_target.emplace_back(stream_map_info(
                cis_entry.conn_handle, codec_spec_conf::kLeAudioLocationMonoAudio, is_active));
        stream_map.streams_map_current.emplace_back(stream_map_info(
                cis_entry.conn_handle, codec_spec_conf::kLeAudioLocationMonoAudio, is_active));
      }
    }

    return true;
  }

  bool UpdateCisConfiguration(const std::vector<struct types::cis>& cises,
                              const stream_parameters& stream_params, uint8_t direction) {
    if (GetCodecLocation() != bluetooth::le_audio::types::CodecLocation::ADSP) {
      return;
      return false;
    }

    auto available_allocations =
            AdjustAllocationForOffloader(stream_params.audio_channel_allocation);
    if (available_allocations == 0) {
      log::error("There is no CIS connected");
      return;
    if (available_allocations == -1) {
      log::error("Unsupported allocation {:#x}", stream_params.audio_channel_allocation);
      return false;
    }

    if (available_allocations == codec_spec_conf::kLeAudioLocationMonoAudio) {
      return UpdateCisMonoConfiguration(cises, direction);
    }

    auto& stream_map = offloader_stream_maps.get(direction);
@@ -770,6 +823,8 @@ public:
                stream_map_info(cis_entry.conn_handle, current_allocation, is_active));
      }
    }

    return true;
  }

private:
@@ -1233,12 +1288,13 @@ void CodecManager::UpdateBroadcastConnHandle(
  }
}

void CodecManager::UpdateCisConfiguration(const std::vector<struct types::cis>& cises,
bool CodecManager::UpdateCisConfiguration(const std::vector<struct types::cis>& cises,
                                          const stream_parameters& stream_params,
                                          uint8_t direction) {
  if (pimpl_->IsRunning()) {
    return pimpl_->codec_manager_impl_->UpdateCisConfiguration(cises, stream_params, direction);
  }
  return false;
}

void CodecManager::ClearCisConfiguration(uint8_t direction) {
+1 −1
Original line number Diff line number Diff line
@@ -104,7 +104,7 @@ public:
  void Stop(void);
  virtual types::CodecLocation GetCodecLocation(void) const;
  virtual bool IsDualBiDirSwbSupported(void) const;
  virtual void UpdateCisConfiguration(const std::vector<struct types::cis>& cises,
  virtual bool UpdateCisConfiguration(const std::vector<struct types::cis>& cises,
                                      const stream_parameters& stream_params, uint8_t direction);
  virtual void ClearCisConfiguration(uint8_t direction);
  virtual bool IsUsingCodecExtensibility() const;
+137 −0
Original line number Diff line number Diff line
@@ -269,10 +269,17 @@ static constexpr char kPropLeAudioOffloadDisabled[] = "persist.bluetooth.leaudio
static constexpr char kPropLeAudioBidirSwbSupported[] =
        "bluetooth.leaudio.dual_bidirection_swb.supported";

RawAddress GetTestAddress(uint8_t index) {
  EXPECT_LT(index, UINT8_MAX);
  RawAddress result = {{0xC0, 0xDE, 0xC0, 0xDE, 0x00, index}};
  return result;
}

class CodecManagerTestBase : public Test {
public:
  virtual void SetUp() override {
    __android_log_set_minimum_priority(ANDROID_LOG_VERBOSE);
    com::android::bluetooth::flags::provider_->reset_flags();
    set_mock_offload_capabilities(offload_capabilities_none);

    bluetooth::legacy::hci::testing::SetMock(legacy_hci_mock_);
@@ -506,6 +513,136 @@ TEST_F(CodecManagerTestAdsp, testStreamConfigurationAdspDownMix) {
  }
}

TEST_F(CodecManagerTestAdsp, testStreamConfigurationMono) {
  com::android::bluetooth::flags::provider_->leaudio_mono_location_errata(true);
  const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference(0);
  codec_manager->Start(offloading_preference);

  // Current CIS configuration for two earbuds
  std::vector<struct types::cis> cises{
          {
                  .id = 0x00,
                  .type = types::CisType::CIS_TYPE_BIDIRECTIONAL,
                  .conn_handle = 96,
                  .addr = RawAddress::kEmpty,  // Disconnected
          },
          {
                  .id = 0x01,
                  .type = types::CisType::CIS_TYPE_BIDIRECTIONAL,
                  .conn_handle = 97,
                  .addr = GetTestAddress(1),
          },
  };

  // Stream parameters
  types::BidirectionalPair<stream_parameters> stream_params{
          .sink =
                  {
                          .sample_frequency_hz = 16000,
                          .frame_duration_us = 10000,
                          .octets_per_codec_frame = 40,
                          .audio_channel_allocation = codec_spec_conf::kLeAudioLocationMonoAudio,
                          .codec_frames_blocks_per_sdu = 1,
                          .num_of_channels = 1,
                          .num_of_devices = 1,
                          .stream_locations =
                                  {
                                          std::pair<uint16_t, uint32_t>{
                                                  97 /*conn_handle*/,
                                                  codec_spec_conf::kLeAudioLocationMonoAudio},
                                  },
                  },
          .source =
                  {
                          .sample_frequency_hz = 16000,
                          .frame_duration_us = 10000,
                          .octets_per_codec_frame = 40,
                          .audio_channel_allocation = codec_spec_conf::kLeAudioLocationMonoAudio,
                          .codec_frames_blocks_per_sdu = 1,
                          .num_of_channels = 1,
                          .num_of_devices = 1,
                          {
                                  std::pair<uint16_t, uint32_t>{
                                          97 /*conn_handle*/,
                                          codec_spec_conf::kLeAudioLocationMonoAudio},
                          },
                  },
  };

  ASSERT_TRUE(
          codec_manager->UpdateCisConfiguration(cises, stream_params.sink, kLeAudioDirectionSink));
  ASSERT_TRUE(codec_manager->UpdateCisConfiguration(cises, stream_params.source,
                                                    kLeAudioDirectionSource));

  // Verify the offloader config content
  types::BidirectionalPair<std::optional<offload_config>> out_offload_configs;
  codec_manager->UpdateActiveAudioConfig(
          stream_params, {.sink = 44, .source = 44},
          [&out_offload_configs](const offload_config& config, uint8_t direction) {
            out_offload_configs.get(direction) = config;
          });

  // Expect the same configuration for sink and source
  ASSERT_TRUE(out_offload_configs.sink.has_value());
  ASSERT_TRUE(out_offload_configs.source.has_value());
  for (auto direction : {bluetooth::le_audio::types::kLeAudioDirectionSink,
                         bluetooth::le_audio::types::kLeAudioDirectionSource}) {
    uint32_t allocation = 0;
    auto& config = out_offload_configs.get(direction).value();
    ASSERT_EQ(2lu, config.stream_map.size());
    for (const auto& info : config.stream_map) {
      if (info.stream_handle == 96) {
        ASSERT_EQ(codec_spec_conf::kLeAudioLocationMonoAudio, info.audio_channel_allocation);
        // The disconnected should be inactive
        ASSERT_FALSE(info.is_stream_active);

      } else if (info.stream_handle == 97) {
        ASSERT_EQ(codec_spec_conf::kLeAudioLocationMonoAudio, info.audio_channel_allocation);
        // The connected should be active
        ASSERT_TRUE(info.is_stream_active);

      } else {
        ASSERT_EQ(97, info.stream_handle);
      }
      allocation |= info.audio_channel_allocation;
    }

    ASSERT_EQ(16, config.bits_per_sample);
    ASSERT_EQ(16000u, config.sampling_rate);
    ASSERT_EQ(10000u, config.frame_duration);
    ASSERT_EQ(40u, config.octets_per_frame);
    ASSERT_EQ(1, config.blocks_per_sdu);
    ASSERT_EQ(44, config.peer_delay_ms);
    ASSERT_EQ(codec_spec_conf::kLeAudioLocationMonoAudio, allocation);
  }

  // Clear the CIS configuration map (no active CISes).
  codec_manager->ClearCisConfiguration(kLeAudioDirectionSink);
  codec_manager->ClearCisConfiguration(kLeAudioDirectionSource);
  out_offload_configs.sink = std::nullopt;
  out_offload_configs.source = std::nullopt;
  codec_manager->UpdateActiveAudioConfig(
          stream_params, {.sink = 44, .source = 44},
          [&out_offload_configs](const offload_config& config, uint8_t direction) {
            out_offload_configs.get(direction) = config;
          });

  // Expect sink & source configurations with empty CIS channel allocation map.
  ASSERT_TRUE(out_offload_configs.sink.has_value());
  ASSERT_TRUE(out_offload_configs.source.has_value());
  for (auto direction : {bluetooth::le_audio::types::kLeAudioDirectionSink,
                         bluetooth::le_audio::types::kLeAudioDirectionSource}) {
    auto& config = out_offload_configs.get(direction).value();
    ASSERT_EQ(0lu, config.stream_map.size());
    ASSERT_EQ(16, config.bits_per_sample);
    ASSERT_EQ(16000u, config.sampling_rate);
    ASSERT_EQ(10000u, config.frame_duration);
    ASSERT_EQ(40u, config.octets_per_frame);
    ASSERT_EQ(1, config.blocks_per_sdu);
    ASSERT_EQ(44, config.peer_delay_ms);
  }
}

TEST_F(CodecManagerTestAdsp, test_capabilities_none) {
  const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference(0);
  codec_manager->Start(offloading_preference);
+2 −1
Original line number Diff line number Diff line
@@ -160,12 +160,13 @@ void CodecManager::Stop() {
  mock_codec_manager_pimpl_ = nullptr;
}

void CodecManager::UpdateCisConfiguration(const std::vector<struct types::cis>& cises,
bool CodecManager::UpdateCisConfiguration(const std::vector<struct types::cis>& cises,
                                          const stream_parameters& stream_params,
                                          uint8_t direction) {
  if (pimpl_) {
    return pimpl_->UpdateCisConfiguration(cises, stream_params, direction);
  }
  return false;
}

void CodecManager::ClearCisConfiguration(uint8_t direction) {
Loading