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

Commit 44ab0001 authored by Jack He's avatar Jack He Committed by Android (Google) Code Review
Browse files

Merge changes Ic205348e,Ibfaf9538 into tm-qpr-dev

* changes:
  leaudio: Improve offloader behaviour
  leaudio: Simplify stream configuration
parents 2b829387 e79e4dea
Loading
Loading
Loading
Loading
+58 −121
Original line number Diff line number Diff line
@@ -2241,109 +2241,19 @@ class LeAudioClientImpl : public LeAudioClient {
                                           chan_encoded.size());
  }

  struct le_audio::stream_configuration* GetStreamConfigurationByDirection(
      LeAudioDeviceGroup* group, uint8_t direction) {
    struct le_audio::stream_configuration* stream_conf = &group->stream_conf;
    uint32_t sample_freq_hz = 0;
    uint32_t frame_duration_us = 0;
    uint32_t audio_channel_allocation = 0;
    uint16_t octets_per_frame = 0;
    uint16_t codec_frames_blocks_per_sdu = 0;

    LOG(INFO) << __func__ << " group_id: " << group->group_id_;

    /* This contains pair of cis handle and audio location */
    std::vector<std::pair<uint16_t, uint32_t>> streams;

    for (auto* device = group->GetFirstActiveDevice(); device != nullptr;
         device = group->GetNextActiveDevice(device)) {
      auto* ase = device->GetFirstActiveAseByDirection(direction);

      for (; ase != nullptr;
           ase = device->GetNextActiveAseWithSameDirection(ase)) {
        streams.emplace_back(std::make_pair(
            ase->cis_conn_hdl, *ase->codec_config.audio_channel_allocation));
        audio_channel_allocation |= *ase->codec_config.audio_channel_allocation;
        if (sample_freq_hz == 0) {
          sample_freq_hz = ase->codec_config.GetSamplingFrequencyHz();
        } else {
          LOG_ASSERT(sample_freq_hz ==
                     ase->codec_config.GetSamplingFrequencyHz())
              << __func__ << " sample freq mismatch: " << +sample_freq_hz
              << " != " << ase->codec_config.GetSamplingFrequencyHz();
        }

        if (frame_duration_us == 0) {
          frame_duration_us = ase->codec_config.GetFrameDurationUs();
        } else {
          LOG_ASSERT(frame_duration_us ==
                     ase->codec_config.GetFrameDurationUs())
              << __func__ << " frame duration mismatch: " << +frame_duration_us
              << " != " << ase->codec_config.GetFrameDurationUs();
        }

        if (octets_per_frame == 0) {
          octets_per_frame = *ase->codec_config.octets_per_codec_frame;
        } else {
          LOG_ASSERT(octets_per_frame ==
                     ase->codec_config.octets_per_codec_frame)
              << __func__ << " octets per frame mismatch: " << +octets_per_frame
              << " != " << *ase->codec_config.octets_per_codec_frame;
  const struct le_audio::stream_configuration* GetStreamSinkConfiguration(
      LeAudioDeviceGroup* group) {
    const struct le_audio::stream_configuration* stream_conf =
        &group->stream_conf;
    LOG_INFO("group_id: %d", group->group_id_);
    if (stream_conf->sink_streams.size() == 0) {
      return nullptr;
    }

        if (codec_frames_blocks_per_sdu == 0) {
          codec_frames_blocks_per_sdu =
              *ase->codec_config.codec_frames_blocks_per_sdu;
        } else {
          LOG_ASSERT(codec_frames_blocks_per_sdu ==
                     ase->codec_config.codec_frames_blocks_per_sdu)
              << __func__ << " codec_frames_blocks_per_sdu: "
              << +codec_frames_blocks_per_sdu
              << " != " << *ase->codec_config.codec_frames_blocks_per_sdu;
        }

        LOG(INFO) << __func__ << " Added CIS: " << +ase->cis_conn_hdl
                  << " to stream. Allocation: "
                  << +(*ase->codec_config.audio_channel_allocation)
                  << " sample_freq: " << +sample_freq_hz
                  << " frame_duration: " << +frame_duration_us
                  << " octects per frame: " << +octets_per_frame
                  << " codec_frame_blocks_per_sdu: "
                  << +codec_frames_blocks_per_sdu;
      }
    }

    if (streams.empty()) return nullptr;

    if (direction == le_audio::types::kLeAudioDirectionSource) {
      stream_conf->source_streams = std::move(streams);
      stream_conf->source_sample_frequency_hz = sample_freq_hz;
      stream_conf->source_frame_duration_us = frame_duration_us;
      stream_conf->source_audio_channel_allocation = audio_channel_allocation;
      stream_conf->source_octets_per_codec_frame = octets_per_frame;
      stream_conf->source_codec_frames_blocks_per_sdu =
          codec_frames_blocks_per_sdu;
    } else if (direction == le_audio::types::kLeAudioDirectionSink) {
      stream_conf->sink_streams = std::move(streams);
      stream_conf->sink_sample_frequency_hz = sample_freq_hz;
      stream_conf->sink_frame_duration_us = frame_duration_us;
      stream_conf->sink_audio_channel_allocation = audio_channel_allocation;
      stream_conf->sink_octets_per_codec_frame = octets_per_frame;
      stream_conf->sink_codec_frames_blocks_per_sdu =
          codec_frames_blocks_per_sdu;
    }

    LOG(INFO) << __func__ << " configuration: " << stream_conf->conf->name;

    LOG_INFO("configuration: %s", stream_conf->conf->name.c_str());
    return stream_conf;
  }

  struct le_audio::stream_configuration* GetStreamSinkConfiguration(
      LeAudioDeviceGroup* group) {
    return GetStreamConfigurationByDirection(
        group, le_audio::types::kLeAudioDirectionSink);
  }

  void OnAudioDataReady(const std::vector<uint8_t>& data) {
    if ((active_group_id_ == bluetooth::groups::kGroupUnknown) ||
        (audio_sender_state_ != AudioState::STARTED))
@@ -2641,13 +2551,6 @@ class LeAudioClientImpl : public LeAudioClient {
          lc3_setup_encoder(dt_us, sr_hz, af_hz, lc3_encoder_left_mem);
      lc3_encoder_right =
          lc3_setup_encoder(dt_us, sr_hz, af_hz, lc3_encoder_right_mem);

    } else if (CodecManager::GetInstance()->GetCodecLocation() ==
               le_audio::types::CodecLocation::ADSP) {
      CodecManager::GetInstance()->UpdateActiveSourceAudioConfig(
          *stream_conf, remote_delay_ms,
          std::bind(&LeAudioUnicastClientAudioSource::UpdateAudioConfigToHal,
                    leAudioClientAudioSource, std::placeholders::_1));
    }

    leAudioClientAudioSource->UpdateRemoteDelay(remote_delay_ms);
@@ -2657,10 +2560,15 @@ class LeAudioClientImpl : public LeAudioClient {
    return true;
  }

  struct le_audio::stream_configuration* GetStreamSourceConfiguration(
  const struct le_audio::stream_configuration* GetStreamSourceConfiguration(
      LeAudioDeviceGroup* group) {
    return GetStreamConfigurationByDirection(
        group, le_audio::types::kLeAudioDirectionSource);
    const struct le_audio::stream_configuration* stream_conf =
        &group->stream_conf;
    if (stream_conf->source_streams.size() == 0) {
      return nullptr;
    }
    LOG_INFO("configuration: %s", stream_conf->conf->name.c_str());
    return stream_conf;
  }

  void StartReceivingAudio(int group_id) {
@@ -2702,14 +2610,7 @@ class LeAudioClientImpl : public LeAudioClient {
          lc3_setup_decoder(dt_us, sr_hz, af_hz, lc3_decoder_left_mem);
      lc3_decoder_right =
          lc3_setup_decoder(dt_us, sr_hz, af_hz, lc3_decoder_right_mem);
    } else if (CodecManager::GetInstance()->GetCodecLocation() ==
               le_audio::types::CodecLocation::ADSP) {
      CodecManager::GetInstance()->UpdateActiveSinkAudioConfig(
          *stream_conf, remote_delay_ms,
          std::bind(&LeAudioUnicastClientAudioSink::UpdateAudioConfigToHal,
                    leAudioClientAudioSink, std::placeholders::_1));
    }

    leAudioClientAudioSink->UpdateRemoteDelay(remote_delay_ms);
    leAudioClientAudioSink->ConfirmStreamingRequest();
    audio_receiver_state_ = AudioState::STARTED;
@@ -3600,16 +3501,52 @@ 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->sink_offloader_changed) {
      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(&LeAudioUnicastClientAudioSource::UpdateAudioConfigToHal,
                    leAudioClientAudioSource, std::placeholders::_1));
      group->StreamOffloaderUpdated(le_audio::types::kLeAudioDirectionSink);
    }

    if (stream_conf->source_offloader_changed) {
      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(&LeAudioUnicastClientAudioSink::UpdateAudioConfigToHal,
                    leAudioClientAudioSink, std::placeholders::_1));
      group->StreamOffloaderUpdated(le_audio::types::kLeAudioDirectionSource);
    }
  }

  void StatusReportCb(int group_id, GroupStreamStatus status) {
    LOG(INFO) << __func__ << "status: " << static_cast<int>(status)
              << " audio_sender_state_: " << audio_sender_state_
              << " audio_receiver_state_: " << audio_receiver_state_;
    LOG_INFO("status: %d , audio_sender_state %s, audio_receiver_state %s",
             static_cast<int>(status),
             bluetooth::common::ToString(audio_sender_state_).c_str(),
             bluetooth::common::ToString(audio_receiver_state_).c_str());
    LeAudioDeviceGroup* group = aseGroups_.FindById(group_id);
    switch (status) {
      case GroupStreamStatus::STREAMING:
        LOG_ASSERT(group_id == active_group_id_)
            << __func__ << " invalid group id " << group_id
            << " active_group_id_ " << active_group_id_;
        ASSERT_LOG(group_id == active_group_id_, "invalid group id %d!=%d",
                   group_id, active_group_id_);

        updateOffloaderIfNeeded(group);

        if (audio_sender_state_ == AudioState::READY_TO_START)
          StartSendingAudio(group_id);
        if (audio_receiver_state_ == AudioState::READY_TO_START)
+2 −2
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ struct codec_manager_impl {
          update_receiver) {
    if (stream_conf.sink_streams.empty()) return;

    sink_config.stream_map = std::move(stream_conf.sink_streams);
    sink_config.stream_map = std::move(stream_conf.sink_offloader_streams);
    // TODO: set the default value 16 for now, would change it if we support
    // mode bits_per_sample
    sink_config.bits_per_sample = 16;
@@ -107,7 +107,7 @@ struct codec_manager_impl {
          update_receiver) {
    if (stream_conf.source_streams.empty()) return;

    source_config.stream_map = std::move(stream_conf.source_streams);
    source_config.stream_map = std::move(stream_conf.source_offloader_streams);
    // TODO: set the default value 16 for now, would change it if we support
    // mode bits_per_sample
    source_config.bits_per_sample = 16;
+130 −0
Original line number Diff line number Diff line
@@ -106,9 +106,37 @@ int LeAudioDeviceGroup::NumOfConnected(types::LeAudioContextType context_type) {
      });
}

void LeAudioDeviceGroup::ClearSinksFromConfiguration(void) {
  LOG_INFO("Group %p, group_id %d", this, group_id_);
  stream_conf.sink_streams.clear();
  stream_conf.sink_offloader_streams.clear();
  stream_conf.sink_audio_channel_allocation = 0;
  stream_conf.sink_num_of_channels = 0;
  stream_conf.sink_num_of_devices = 0;
  stream_conf.sink_sample_frequency_hz = 0;
  stream_conf.sink_codec_frames_blocks_per_sdu = 0;
  stream_conf.sink_octets_per_codec_frame = 0;
  stream_conf.sink_frame_duration_us = 0;
}

void LeAudioDeviceGroup::ClearSourcesFromConfiguration(void) {
  LOG_INFO("Group %p, group_id %d", this, group_id_);
  stream_conf.source_streams.clear();
  stream_conf.source_offloader_streams.clear();
  stream_conf.source_audio_channel_allocation = 0;
  stream_conf.source_num_of_channels = 0;
  stream_conf.source_num_of_devices = 0;
  stream_conf.source_sample_frequency_hz = 0;
  stream_conf.source_codec_frames_blocks_per_sdu = 0;
  stream_conf.source_octets_per_codec_frame = 0;
  stream_conf.source_frame_duration_us = 0;
}

void LeAudioDeviceGroup::CigClearCis(void) {
  LOG_INFO("group_id: %d", group_id_);
  cises_.clear();
  ClearSinksFromConfiguration();
  ClearSourcesFromConfiguration();
}

void LeAudioDeviceGroup::Cleanup(void) {
@@ -1592,6 +1620,108 @@ bool LeAudioDeviceGroup::IsMetadataChanged(
  return false;
}

void LeAudioDeviceGroup::StreamOffloaderUpdated(uint8_t direction) {
  if (direction == le_audio::types::kLeAudioDirectionSource) {
    stream_conf.source_offloader_changed = false;
  } else {
    stream_conf.sink_offloader_changed = false;
  }
}

void LeAudioDeviceGroup::CreateStreamVectorForOffloader(uint8_t direction) {
  if (CodecManager::GetInstance()->GetCodecLocation() !=
      le_audio::types::CodecLocation::ADSP) {
    return;
  }

  CisType cis_type;
  std::vector<std::pair<uint16_t, uint32_t>>* streams;
  std::vector<std::pair<uint16_t, uint32_t>>* offloader_streams;
  std::string tag;
  uint32_t available_allocations = 0;
  bool* changed_flag;
  if (direction == le_audio::types::kLeAudioDirectionSource) {
    changed_flag = &stream_conf.source_offloader_changed;
    cis_type = CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE;
    streams = &stream_conf.source_streams;
    offloader_streams = &stream_conf.source_offloader_streams;
    tag = "Source";
    available_allocations = AdjustAllocationForOffloader(
        stream_conf.source_audio_channel_allocation);
  } else {
    changed_flag = &stream_conf.sink_offloader_changed;
    cis_type = CisType::CIS_TYPE_UNIDIRECTIONAL_SINK;
    streams = &stream_conf.sink_streams;
    offloader_streams = &stream_conf.sink_offloader_streams;
    tag = "Sink";
    available_allocations =
        AdjustAllocationForOffloader(stream_conf.sink_audio_channel_allocation);
  }

  if (available_allocations == 0) {
    LOG_ERROR("There is no CIS connected");
    return;
  }

  if (offloader_streams->size() > 0) {
    /* We are here because of the CIS modification during streaming.
     * this makes sense only when downmixing is enabled so we can notify
     * offloader about connected / disconnected CISes. If downmixing is disabled
     * then there is not need to notify offloader as it has all the informations
     * already */
    if (!downmix_fallback_) {
      LOG_INFO("Downmixing disabled - nothing to do");
      return;
    }
  }

  offloader_streams->clear();
  *changed_flag = true;

  bool not_all_cises_connected = false;
  if (available_allocations != codec_spec_conf::kLeAudioLocationStereo) {
    not_all_cises_connected = true;
  }

  /* Note: For the offloader case we simplify allocation to only Left and Right.
   * If we need 2 CISes and only one is connected, the connected one will have
   * allocation set to stereo (left | right) and other one will have allocation
   * set to 0. Offloader in this case shall mix left and right and send it on
   * connected CIS. If there is only single CIS with stereo allocation, it means
   * that peer device support channel count 2 and offloader shall send two
   * channels in the single CIS.
   */

  for (auto& cis_entry : cises_) {
    if ((cis_entry.type == CisType::CIS_TYPE_BIDIRECTIONAL ||
         cis_entry.type == cis_type) &&
        cis_entry.conn_handle != 0) {
      uint32_t allocation = 0;
      for (const auto& s : *streams) {
        if (s.first == cis_entry.conn_handle) {
          allocation = AdjustAllocationForOffloader(s.second);
          if (not_all_cises_connected && downmix_fallback_) {
            /* Tell offloader to mix on this CIS.*/
            allocation = codec_spec_conf::kLeAudioLocationStereo;
          }
          break;
        }
      }

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

      LOG_INFO("%s: Cis handle 0x%04x, allocation  0x%08x", tag.c_str(),
               cis_entry.conn_handle, allocation);
      offloader_streams->emplace_back(
          std::make_pair(cis_entry.conn_handle, allocation));
    }
  }
}

types::LeAudioContextType LeAudioDeviceGroup::GetCurrentContextType(void) {
  return active_context_type_;
}
+11 −1
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include "gatt_api.h"
#include "le_audio_types.h"
#include "osi/include/alarm.h"
#include "osi/include/properties.h"
#include "raw_address.h"

namespace le_audio {
@@ -210,7 +211,9 @@ class LeAudioDeviceGroup {
        pending_update_available_contexts_(std::nullopt),
        target_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE),
        current_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE),
        context_type_(types::LeAudioContextType::UNINITIALIZED) {}
        context_type_(types::LeAudioContextType::UNINITIALIZED) {
    downmix_fallback_ = osi_property_get_bool(kDownmixFallback, false);
  }
  ~LeAudioDeviceGroup(void);

  void AddNode(const std::shared_ptr<LeAudioDevice>& leAudioDevice);
@@ -223,6 +226,8 @@ class LeAudioDeviceGroup {
  bool Activate(types::LeAudioContextType context_type);
  void Deactivate(void);
  void CigClearCis(void);
  void ClearSinksFromConfiguration(void);
  void ClearSourcesFromConfiguration(void);
  void Cleanup(void);
  LeAudioDevice* GetFirstDevice(void);
  LeAudioDevice* GetFirstDeviceWithActiveContext(
@@ -284,6 +289,8 @@ class LeAudioDeviceGroup {
  bool IsContextSupported(types::LeAudioContextType group_context_type);
  bool IsMetadataChanged(types::LeAudioContextType group_context_type,
                         int ccid);
  void CreateStreamVectorForOffloader(uint8_t direction);
  void StreamOffloaderUpdated(uint8_t direction);

  inline types::AseState GetState(void) const { return current_state_; }
  void SetState(types::AseState state) {
@@ -334,6 +341,9 @@ class LeAudioDeviceGroup {
           const set_configurations::AudioSetConfiguration*>
      active_context_to_configuration_map;

  static constexpr char kDownmixFallback[] =
      "persist.bluetooth.leaudio.offloader.downmix_fallback";
  bool downmix_fallback_;
  types::AseState target_state_;
  types::AseState current_state_;
  types::LeAudioContextType context_type_;
+73 −0
Original line number Diff line number Diff line
@@ -772,6 +772,42 @@ class UnicastTestNoInit : public Test {
                  stream_conf->source_num_of_devices++;
                  stream_conf->source_num_of_channels +=
                      ase.codec_config.channel_count;
                  stream_conf->source_audio_channel_allocation |=
                      *ase.codec_config.audio_channel_allocation;

                  if (stream_conf->source_sample_frequency_hz == 0) {
                    stream_conf->source_sample_frequency_hz =
                        ase.codec_config.GetSamplingFrequencyHz();
                  } else {
                    ASSERT_LOG(stream_conf->source_sample_frequency_hz ==
                                   ase.codec_config.GetSamplingFrequencyHz(),
                               "sample freq mismatch: %d!=%d",
                               stream_conf->source_sample_frequency_hz,
                               ase.codec_config.GetSamplingFrequencyHz());
                  }

                  if (stream_conf->source_octets_per_codec_frame == 0) {
                    stream_conf->source_octets_per_codec_frame =
                        *ase.codec_config.octets_per_codec_frame;
                  } else {
                    ASSERT_LOG(stream_conf->source_octets_per_codec_frame ==
                                   *ase.codec_config.octets_per_codec_frame,
                               "octets per frame mismatch: %d!=%d",
                               stream_conf->source_octets_per_codec_frame,
                               *ase.codec_config.octets_per_codec_frame);
                  }

                  if (stream_conf->source_codec_frames_blocks_per_sdu == 0) {
                    stream_conf->source_codec_frames_blocks_per_sdu =
                        *ase.codec_config.codec_frames_blocks_per_sdu;
                  } else {
                    ASSERT_LOG(
                        stream_conf->source_codec_frames_blocks_per_sdu ==
                            *ase.codec_config.codec_frames_blocks_per_sdu,
                        "codec_frames_blocks_per_sdu: %d!=%d",
                        stream_conf->source_codec_frames_blocks_per_sdu,
                        *ase.codec_config.codec_frames_blocks_per_sdu);
                  }

                  LOG_INFO(
                      " Added Source Stream Configuration. CIS Connection "
@@ -800,6 +836,43 @@ class UnicastTestNoInit : public Test {
                  stream_conf->sink_num_of_channels +=
                      ase.codec_config.channel_count;

                  stream_conf->sink_audio_channel_allocation |=
                      *ase.codec_config.audio_channel_allocation;

                  if (stream_conf->sink_sample_frequency_hz == 0) {
                    stream_conf->sink_sample_frequency_hz =
                        ase.codec_config.GetSamplingFrequencyHz();
                  } else {
                    ASSERT_LOG(stream_conf->sink_sample_frequency_hz ==
                                   ase.codec_config.GetSamplingFrequencyHz(),
                               "sample freq mismatch: %d!=%d",
                               stream_conf->sink_sample_frequency_hz,
                               ase.codec_config.GetSamplingFrequencyHz());
                  }

                  if (stream_conf->sink_octets_per_codec_frame == 0) {
                    stream_conf->sink_octets_per_codec_frame =
                        *ase.codec_config.octets_per_codec_frame;
                  } else {
                    ASSERT_LOG(stream_conf->sink_octets_per_codec_frame ==
                                   *ase.codec_config.octets_per_codec_frame,
                               "octets per frame mismatch: %d!=%d",
                               stream_conf->sink_octets_per_codec_frame,
                               *ase.codec_config.octets_per_codec_frame);
                  }

                  if (stream_conf->sink_codec_frames_blocks_per_sdu == 0) {
                    stream_conf->sink_codec_frames_blocks_per_sdu =
                        *ase.codec_config.codec_frames_blocks_per_sdu;
                  } else {
                    ASSERT_LOG(
                        stream_conf->sink_codec_frames_blocks_per_sdu ==
                            *ase.codec_config.codec_frames_blocks_per_sdu,
                        "codec_frames_blocks_per_sdu: %d!=%d",
                        stream_conf->sink_codec_frames_blocks_per_sdu,
                        *ase.codec_config.codec_frames_blocks_per_sdu);
                  }

                  LOG_INFO(
                      " Added Sink Stream Configuration. CIS Connection "
                      "Handle: %d"
Loading