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

Commit 634365bb authored by Jakub Tyszkowski's avatar Jakub Tyszkowski Committed by Łukasz Rymanowski
Browse files

LeAudio: Offloader related code encapsulation Part 2

Bug: 295972694
Test: atest bluetooth_le_audio_test bluetooth_le_audio_client_test  bluetooth_test_broadcaster bluetooth_test_broadcaster_state_machine
Change-Id: I772e238c11d5b821b0b49ab1bad0891c551d6a2e
parent eedc7a29
Loading
Loading
Loading
Loading
+71 −0
Original line number Diff line number Diff line
@@ -648,6 +648,77 @@ prebuilt_etc {

// bta unit tests for LE Audio
// ========================================================
cc_test {
    name: "bluetooth_le_audio_codec_manager_test",
    test_suites: ["device-tests"],
    defaults: [
        "bluetooth_gtest_x86_asan_workaround",
        "fluoride_defaults",
        "mts_defaults",
    ],
    host_supported: true,
    target: {
        darwin: {
            enabled: false,
        },
        android: {
            sanitize: {
                misc_undefined: ["bounds"],
            },
            whole_static_libs: [
                "libPlatformProperties",
            ],
        },
    },
    include_dirs: [
        "packages/modules/Bluetooth/system",
        "packages/modules/Bluetooth/system/bta/include",
        "packages/modules/Bluetooth/system/bta/test/common",
        "packages/modules/Bluetooth/system/btif/include",
        "packages/modules/Bluetooth/system/gd",
        "packages/modules/Bluetooth/system/stack/include",
    ],
    srcs: [
        ":TestCommonMockFunctions",
        ":TestMockBtaLeAudioHalVerifier",
        ":TestStubOsi",
        "le_audio/codec_manager.cc",
        "le_audio/codec_manager_test.cc",
        "le_audio/le_audio_set_configuration_provider_json.cc",
        "le_audio/le_audio_types.cc",
        "test/common/btm_api_mock.cc",
        "test/common/mock_controller.cc",
    ],
    data: [
        ":audio_set_configurations_bfbs",
        ":audio_set_configurations_json",
        ":audio_set_scenarios_bfbs",
        ":audio_set_scenarios_json",
    ],
    generated_headers: [
        "LeAudioSetConfigSchemas_h",
    ],
    shared_libs: [
        "android.hardware.bluetooth.audio@2.0",
        "android.hardware.bluetooth.audio@2.1",
        "libcrypto",
        "libhidlbase",
        "liblog", // __android_log_print
    ],
    static_libs: [
        "libbluetooth_gd",
        "libbt-common",
        "libchrome",
        "libevent",
        "libflatbuffers-cpp",
        "libgmock",
        "libosi",
    ],
    sanitize: {
        cfi: false,
    },
}

cc_test {
    name: "bluetooth_le_audio_test",
    test_suites: ["device-tests"],
+45 −48
Original line number Diff line number Diff line
@@ -3398,12 +3398,16 @@ class LeAudioClientImpl : public LeAudioClient {
    ConfirmLocalAudioSourceStreamingRequest();

    if (!LeAudioHalVerifier::SupportsStreamActiveApi()) {
      /* We update the target audio allocation before streamStarted that the
       * offloder would know how to configure offloader encoder. We should check
       * if we need to update the current
       * allocation here as the target allocation and the current allocation is
       * different */
      updateOffloaderIfNeeded(group);
      /* We update the target audio allocation before streamStarted so that the
       * CodecManager would know how to configure the encoder. */
      BidirectionalPair<uint16_t> delays_pair = {
          .sink = group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSink),
          .source =
              group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSource)};
      CodecManager::GetInstance()->UpdateActiveAudioConfig(
          group->stream_conf.stream_params, delays_pair,
          std::bind(&LeAudioSourceAudioHalClient::UpdateAudioConfigToHal,
                    le_audio_source_hal_client_.get(), std::placeholders::_1));
    }

    return true;
@@ -3464,12 +3468,16 @@ class LeAudioClientImpl : public LeAudioClient {
    ConfirmLocalAudioSinkStreamingRequest();

    if (!LeAudioHalVerifier::SupportsStreamActiveApi()) {
      /* We update the target audio allocation before streamStarted that the
       * offloder would know how to configure offloader encoder. We should check
       * if we need to update the current
       * allocation here as the target allocation and the current allocation is
       * different */
      updateOffloaderIfNeeded(group);
      /* We update the target audio allocation before streamStarted so that the
       * CodecManager would know how to configure the encoder. */
      BidirectionalPair<uint16_t> delays_pair = {
          .sink = group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSink),
          .source =
              group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSource)};
      CodecManager::GetInstance()->UpdateActiveAudioConfig(
          group->stream_conf.stream_params, delays_pair,
          std::bind(&LeAudioSourceAudioHalClient::UpdateAudioConfigToHal,
                    le_audio_source_hal_client_.get(), std::placeholders::_1));
    }
  }

@@ -5018,41 +5026,6 @@ class LeAudioClientImpl : public LeAudioClient {
    }
  }

  void updateOffloaderIfNeeded(LeAudioDeviceGroup* group) {
    if (CodecManager::GetInstance()->GetCodecLocation() !=
        le_audio::types::CodecLocation::ADSP) {
      return;
    }

    LOG_INFO("Group %p, group_id %d", group, group->group_id_);

    const auto* stream_conf = &group->stream_conf;

    if (stream_conf->offloader_config.sink.has_changed ||
        stream_conf->offloader_config.sink.is_initial) {
      LOG_INFO("Update sink offloader streams");
      uint16_t remote_delay_ms =
          group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSink);
      CodecManager::GetInstance()->UpdateActiveSourceAudioConfig(
          *stream_conf, remote_delay_ms,
          std::bind(&LeAudioSourceAudioHalClient::UpdateAudioConfigToHal,
                    le_audio_source_hal_client_.get(), std::placeholders::_1));
      group->StreamOffloaderUpdated(le_audio::types::kLeAudioDirectionSink);
    }

    if (stream_conf->offloader_config.source.has_changed ||
        stream_conf->offloader_config.source.is_initial) {
      LOG_INFO("Update source offloader streams");
      uint16_t remote_delay_ms =
          group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSource);
      CodecManager::GetInstance()->UpdateActiveSinkAudioConfig(
          *stream_conf, remote_delay_ms,
          std::bind(&LeAudioSinkAudioHalClient::UpdateAudioConfigToHal,
                    le_audio_sink_hal_client_.get(), std::placeholders::_1));
      group->StreamOffloaderUpdated(le_audio::types::kLeAudioDirectionSource);
    }
  }

  void NotifyUpperLayerGroupTurnedIdleDuringCall(int group_id) {
    if (!osi_property_get_bool(kNotifyUpperLayerAboutGroupBeingInIdleDuringCall,
                               false)) {
@@ -5118,7 +5091,16 @@ class LeAudioClientImpl : public LeAudioClient {
        }

        if (group) {
          updateOffloaderIfNeeded(group);
          BidirectionalPair<uint16_t> delays_pair = {
              .sink =
                  group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSink),
              .source = group->GetRemoteDelay(
                  le_audio::types::kLeAudioDirectionSource)};
          CodecManager::GetInstance()->UpdateActiveAudioConfig(
              group->stream_conf.stream_params, delays_pair,
              std::bind(&LeAudioSourceAudioHalClient::UpdateAudioConfigToHal,
                        le_audio_source_hal_client_.get(),
                        std::placeholders::_1));
          if (reconnection_mode_ ==
              BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS) {
            group->AddToAllowListNotConnectedGroupMembers(gatt_if_);
@@ -5228,6 +5210,17 @@ class LeAudioClientImpl : public LeAudioClient {
    }
  }

  void OnUpdatedCisConfiguration(int group_id, uint8_t direction) {
    LeAudioDeviceGroup* group = aseGroups_.FindById(group_id);
    if (!group) {
      LOG_ERROR("Invalid group_id: %d", group_id);
      return;
    }
    CodecManager::GetInstance()->UpdateCisConfiguration(
        group->cises_, group->stream_conf.stream_params.get(direction),
        direction);
  }

 private:
  tGATT_IF gatt_if_;
  bluetooth::le_audio::LeAudioClientCallbacks* callbacks_;
@@ -5445,6 +5438,10 @@ class CallbacksImpl : public LeAudioGroupStateMachine::Callbacks {
  void OnStateTransitionTimeout(int group_id) override {
    if (instance) instance->OnLeAudioDeviceSetStateTimeout(group_id);
  }

  void OnUpdatedCisConfiguration(int group_id, uint8_t direction) {
    if (instance) instance->OnUpdatedCisConfiguration(group_id, direction);
  }
};

CallbacksImpl stateMachineCallbacksImpl;
+186 −71
Original line number Diff line number Diff line
@@ -39,9 +39,24 @@ using le_audio::set_configurations::AudioSetConfiguration;
using le_audio::set_configurations::AudioSetConfigurations;
using le_audio::set_configurations::SetConfiguration;

typedef struct offloader_stream_maps {
  std::vector<le_audio::stream_map_info> streams_map_target;
  std::vector<le_audio::stream_map_info> streams_map_current;
  bool has_changed;
  bool is_initial;
} offloader_stream_maps_t;
}  // namespace

namespace le_audio {
template <>
offloader_stream_maps_t& types::BidirectionalPair<offloader_stream_maps_t>::get(
    uint8_t direction) {
  ASSERT_LOG(direction < types::kLeAudioDirectionBoth,
             "Unsupported complex direction. Reference to a single complex"
             " direction value is not supported.");
  return (direction == types::kLeAudioDirectionSink) ? sink : source;
}

// The mapping for sampling rate, frame duration, and the QoS config
static std::unordered_map<
    int, std::unordered_map<int, le_audio::broadcaster::BroadcastQosConfig>>
@@ -112,62 +127,43 @@ struct codec_manager_impl {
  }
  CodecLocation GetCodecLocation(void) const { return codec_location_; }

  void UpdateActiveSourceAudioConfig(
      const le_audio::stream_configuration& stream_conf, uint16_t delay_ms,
      std::function<void(const ::le_audio::offload_config& config)>
          update_receiver) {
    if (stream_conf.stream_params.sink.stream_locations.empty()) return;
  void UpdateActiveAudioConfig(
      const types::BidirectionalPair<stream_parameters>& stream_params,
      types::BidirectionalPair<uint16_t> delays_ms,
      std::function<void(const offload_config& config)> update_receiver) {
    if (GetCodecLocation() != le_audio::types::CodecLocation::ADSP) {
      return;
    }

    if (stream_conf.offloader_config.sink.is_initial ||
        LeAudioHalVerifier::SupportsStreamActiveApi()) {
      sink_config.stream_map =
          stream_conf.offloader_config.sink.streams_target_allocation;
    } else {
      sink_config.stream_map =
          stream_conf.offloader_config.sink.streams_current_allocation;
    }
    // TODO: set the default value 16 for now, would change it if we support
    // mode bits_per_sample
    sink_config.bits_per_sample = 16;
    sink_config.sampling_rate =
        stream_conf.stream_params.sink.sample_frequency_hz;
    sink_config.frame_duration =
        stream_conf.stream_params.sink.frame_duration_us;
    sink_config.octets_per_frame =
        stream_conf.stream_params.sink.octets_per_codec_frame;
    sink_config.blocks_per_sdu =
        stream_conf.stream_params.sink.codec_frames_blocks_per_sdu;
    sink_config.peer_delay_ms = delay_ms;
    update_receiver(sink_config);
  }

  void UpdateActiveSinkAudioConfig(
      const le_audio::stream_configuration& stream_conf, uint16_t delay_ms,
      std::function<void(const ::le_audio::offload_config& config)>
          update_receiver) {
    if (stream_conf.stream_params.source.stream_locations.empty()) return;
    for (auto direction : {le_audio::types::kLeAudioDirectionSink,
                           le_audio::types::kLeAudioDirectionSource}) {
      auto& stream_map = offloader_stream_maps.get(direction);
      if (!stream_map.has_changed && !stream_map.is_initial) {
        continue;
      }
      if (stream_params.get(direction).stream_locations.empty()) {
        continue;
      }

    if (stream_conf.offloader_config.source.is_initial ||
        LeAudioHalVerifier::SupportsStreamActiveApi()) {
      source_config.stream_map =
          stream_conf.offloader_config.source.streams_target_allocation;
    } else {
      source_config.stream_map =
          stream_conf.offloader_config.source.streams_current_allocation;
    }
    // TODO: set the default value 16 for now, would change it if we support
    // mode bits_per_sample
    source_config.bits_per_sample = 16;
    source_config.sampling_rate =
        stream_conf.stream_params.source.sample_frequency_hz;
    source_config.frame_duration =
        stream_conf.stream_params.source.frame_duration_us;
    source_config.octets_per_frame =
        stream_conf.stream_params.source.octets_per_codec_frame;
    source_config.blocks_per_sdu =
        stream_conf.stream_params.source.codec_frames_blocks_per_sdu;
    source_config.peer_delay_ms = delay_ms;
    update_receiver(source_config);
      le_audio::offload_config unicast_cfg = {
          .stream_map = (stream_map.is_initial ||
                         LeAudioHalVerifier::SupportsStreamActiveApi())
                            ? stream_map.streams_map_target
                            : stream_map.streams_map_current,
          // TODO: set the default value 16 for now, would change it if we
          // support mode bits_per_sample
          .bits_per_sample = 16,
          .sampling_rate = stream_params.get(direction).sample_frequency_hz,
          .frame_duration = stream_params.get(direction).frame_duration_us,
          .octets_per_frame =
              stream_params.get(direction).octets_per_codec_frame,
          .blocks_per_sdu =
              stream_params.get(direction).codec_frames_blocks_per_sdu,
          .peer_delay_ms = delays_ms.get(direction),
      };
      update_receiver(unicast_cfg);
      stream_map.is_initial = false;
    }
  }

  const AudioSetConfigurations* GetOffloadCodecConfig(
@@ -268,6 +264,119 @@ struct codec_manager_impl {
    update_receiver(broadcast_config);
  }

  void ClearCisConfiguration(uint8_t direction) {
    if (GetCodecLocation() != le_audio::types::CodecLocation::ADSP) {
      return;
    }

    auto& stream_map = offloader_stream_maps.get(direction);
    stream_map.streams_map_target.clear();
    stream_map.streams_map_current.clear();
  }

  static uint32_t AdjustAllocationForOffloader(uint32_t allocation) {
    if ((allocation & codec_spec_conf::kLeAudioLocationAnyLeft) &&
        (allocation & codec_spec_conf::kLeAudioLocationAnyRight)) {
      return codec_spec_conf::kLeAudioLocationStereo;
    }
    if (allocation & codec_spec_conf::kLeAudioLocationAnyLeft) {
      return codec_spec_conf::kLeAudioLocationFrontLeft;
    }
    if (allocation & codec_spec_conf::kLeAudioLocationAnyRight) {
      return codec_spec_conf::kLeAudioLocationFrontRight;
    }
    return 0;
  }

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

    auto available_allocations =
        AdjustAllocationForOffloader(stream_params.audio_channel_allocation);
    if (available_allocations == 0) {
      LOG_ERROR("There is no CIS connected");
      return;
    }

    auto& stream_map = offloader_stream_maps.get(direction);
    if (stream_map.streams_map_target.empty()) {
      stream_map.is_initial = true;
    } else if (stream_map.is_initial ||
               LeAudioHalVerifier::SupportsStreamActiveApi()) {
      /* As multiple CISes phone call case, the target_allocation already have
       * the previous data, but the is_initial flag not be cleared. We need to
       * clear here to avoid make duplicated target allocation stream map. */
      stream_map.streams_map_target.clear();
    }

    stream_map.streams_map_current.clear();
    stream_map.has_changed = true;
    bool all_cises_connected =
        (available_allocations == codec_spec_conf::kLeAudioLocationStereo);

    /* If all the cises are connected as stream started, reset changed_flag that
     * the bt stack wouldn't send another audio configuration for the connection
     * status. */
    if (stream_map.is_initial && all_cises_connected) {
      stream_map.has_changed = false;
    }

    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) {
        uint32_t target_allocation = 0;
        uint32_t current_allocation = 0;
        bool is_active = false;
        for (const auto& s : stream_params.stream_locations) {
          if (s.first == cis_entry.conn_handle) {
            is_active = true;
            target_allocation = AdjustAllocationForOffloader(s.second);
            current_allocation = target_allocation;
            if (!all_cises_connected) {
              /* Tell offloader to mix on this CIS.*/
              current_allocation = codec_spec_conf::kLeAudioLocationStereo;
            }
            break;
          }
        }

        if (target_allocation == 0) {
          /* Take missing allocation for that one .*/
          target_allocation =
              codec_spec_conf::kLeAudioLocationStereo & ~available_allocations;
        }

        LOG_INFO(
            "%s: Cis handle 0x%04x, target allocation  0x%08x, current "
            "allocation 0x%08x, active: %d",
            tag.c_str(), cis_entry.conn_handle, target_allocation,
            current_allocation, is_active);

        if (stream_map.is_initial ||
            LeAudioHalVerifier::SupportsStreamActiveApi()) {
          stream_map.streams_map_target.emplace_back(stream_map_info(
              cis_entry.conn_handle, target_allocation, is_active));
        }
        stream_map.streams_map_current.emplace_back(stream_map_info(
            cis_entry.conn_handle, current_allocation, is_active));
      }
    }
  }

 private:
  void SetCodecLocation(CodecLocation location) {
    if (offload_enable_ == false) return;
@@ -365,7 +474,8 @@ struct codec_manager_impl {
    std::unordered_set<uint8_t> offload_preference_set;

    if (AudioSetConfigurationProvider::Get() == nullptr) {
      LOG(ERROR) << __func__ << " Audio set configuration provider is not available.";
      LOG(ERROR) << __func__
                 << " Audio set configuration provider is not available.";
      return;
    }

@@ -405,8 +515,7 @@ struct codec_manager_impl {

  CodecLocation codec_location_ = CodecLocation::HOST;
  bool offload_enable_ = false;
  le_audio::offload_config sink_config;
  le_audio::offload_config source_config;
  types::BidirectionalPair<offloader_stream_maps_t> offloader_stream_maps;
  std::vector<le_audio::broadcast_offload_config> supported_broadcast_config;
  std::unordered_map<types::LeAudioContextType, AudioSetConfigurations>
      context_type_offload_config_map_;
@@ -456,22 +565,13 @@ types::CodecLocation CodecManager::GetCodecLocation(void) const {
  return pimpl_->codec_manager_impl_->GetCodecLocation();
}

void CodecManager::UpdateActiveSourceAudioConfig(
    const stream_configuration& stream_conf, uint16_t delay_ms,
    std::function<void(const ::le_audio::offload_config& config)>
        update_receiver) {
  if (pimpl_->IsRunning())
    pimpl_->codec_manager_impl_->UpdateActiveSourceAudioConfig(
        stream_conf, delay_ms, update_receiver);
}

void CodecManager::UpdateActiveSinkAudioConfig(
    const stream_configuration& stream_conf, uint16_t delay_ms,
    std::function<void(const ::le_audio::offload_config& config)>
        update_receiver) {
void CodecManager::UpdateActiveAudioConfig(
    const types::BidirectionalPair<stream_parameters>& stream_params,
    types::BidirectionalPair<uint16_t> delays_ms,
    std::function<void(const offload_config& config)> update_receiver) {
  if (pimpl_->IsRunning())
    pimpl_->codec_manager_impl_->UpdateActiveSinkAudioConfig(
        stream_conf, delay_ms, update_receiver);
    pimpl_->codec_manager_impl_->UpdateActiveAudioConfig(
        stream_params, delays_ms, update_receiver);
}

const AudioSetConfigurations* CodecManager::GetOffloadCodecConfig(
@@ -502,4 +602,19 @@ void CodecManager::UpdateBroadcastConnHandle(
  }
}

void 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);
  }
}

void CodecManager::ClearCisConfiguration(uint8_t direction) {
  if (pimpl_->IsRunning()) {
    return pimpl_->codec_manager_impl_->ClearCisConfiguration(direction);
  }
}

}  // namespace le_audio
+20 −9
Original line number Diff line number Diff line
@@ -21,6 +21,17 @@

namespace le_audio {

struct stream_map_info {
  stream_map_info(uint16_t stream_handle, uint32_t audio_channel_allocation,
                  bool is_stream_active)
      : stream_handle(stream_handle),
        audio_channel_allocation(audio_channel_allocation),
        is_stream_active(is_stream_active) {}
  uint16_t stream_handle;
  uint32_t audio_channel_allocation;
  bool is_stream_active;
};

struct offload_config {
  std::vector<stream_map_info> stream_map;
  uint8_t bits_per_sample;
@@ -45,7 +56,6 @@ struct broadcast_offload_config {

class CodecManager {
 public:
  CodecManager();
  virtual ~CodecManager() = default;
  static CodecManager* GetInstance(void) {
    static CodecManager* instance = new CodecManager();
@@ -55,14 +65,14 @@ class CodecManager {
                 offloading_preference);
  void Stop(void);
  virtual types::CodecLocation GetCodecLocation(void) const;
  virtual void UpdateActiveSourceAudioConfig(
      const stream_configuration& stream_conf, uint16_t delay_ms,
      std::function<void(const ::le_audio::offload_config& config)>
          update_receiver);
  virtual void UpdateActiveSinkAudioConfig(
      const stream_configuration& stream_conf, uint16_t delay_ms,
      std::function<void(const ::le_audio::offload_config& config)>
          update_receiver);
  virtual void UpdateCisConfiguration(
      const std::vector<struct types::cis>& cises,
      const stream_parameters& stream_params, uint8_t direction);
  virtual void ClearCisConfiguration(uint8_t direction);
  virtual void UpdateActiveAudioConfig(
      const types::BidirectionalPair<stream_parameters>& stream_params,
      types::BidirectionalPair<uint16_t> delays_ms,
      std::function<void(const offload_config& config)> update_receiver);
  virtual const ::le_audio::set_configurations::AudioSetConfigurations*
  GetOffloadCodecConfig(::le_audio::types::LeAudioContextType ctx_type);
  virtual const ::le_audio::broadcast_offload_config*
@@ -73,6 +83,7 @@ class CodecManager {
          update_receiver);

 private:
  CodecManager();
  struct impl;
  std::unique_ptr<impl> pimpl_;
};
+316 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading