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

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

Merge changes I47eca845,Ieb53ce2d,Ia14947d3 into tm-qpr-dev

* changes:
  LeAudio: Add upper tester flag for multiple CCID
  LeAudio: Support multiple contexts in stream metadata
  Broadcaster: Improve broadcast stream metadata
parents 418a4582 49f1bb77
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ cc_library_static {
        "le_audio/state_machine.cc",
        "le_audio/client_parser.cc",
        "le_audio/client_audio.cc",
        "le_audio/le_audio_utils.cc",
        "le_audio/le_audio_set_configuration_provider.cc",
        "le_audio/le_audio_set_configuration_provider_json.cc",
        "le_audio/le_audio_types.cc",
@@ -629,6 +630,7 @@ cc_test {
        "le_audio/client_parser.cc",
        "le_audio/content_control_id_keeper.cc",
        "le_audio/devices.cc",
        "le_audio/le_audio_utils.cc",
        "le_audio/le_audio_client_test.cc",
        "le_audio/le_audio_set_configuration_provider_json.cc",
        "le_audio/le_audio_types.cc",
@@ -772,6 +774,7 @@ cc_test {
        "le_audio/broadcaster/mock_state_machine.cc",
        "le_audio/content_control_id_keeper.cc",
        "le_audio/client_audio.cc",
        "le_audio/le_audio_utils.cc",
        "le_audio/le_audio_types.cc",
        "le_audio/mock_iso_manager.cc",
        "test/common/mock_controller.cc",
+156 −12
Original line number Diff line number Diff line
@@ -20,11 +20,12 @@
#include "bta/include/bta_le_audio_api.h"
#include "bta/include/bta_le_audio_broadcaster_api.h"
#include "bta/le_audio/broadcaster/state_machine.h"
#include "bta/le_audio/content_control_id_keeper.h"
#include "bta/le_audio/le_audio_types.h"
#include "bta/le_audio/le_audio_utils.h"
#include "device/include/controller.h"
#include "embdrv/lc3/include/lc3.h"
#include "gd/common/strings.h"
#include "internal_include/stack_config.h"
#include "osi/include/log.h"
#include "osi/include/properties.h"
#include "stack/include/btm_api_types.h"
@@ -38,7 +39,6 @@ using bluetooth::hci::iso_manager::BigCallbacks;
using bluetooth::le_audio::BasicAudioAnnouncementData;
using bluetooth::le_audio::BroadcastId;
using le_audio::CodecManager;
using le_audio::ContentControlIdKeeper;
using le_audio::broadcaster::BigConfig;
using le_audio::broadcaster::BroadcastCodecWrapper;
using le_audio::broadcaster::BroadcastQosConfig;
@@ -49,6 +49,8 @@ using le_audio::types::CodecLocation;
using le_audio::types::kLeAudioCodingFormatLC3;
using le_audio::types::LeAudioContextType;
using le_audio::types::LeAudioLtvMap;
using le_audio::utils::GetAllCcids;
using le_audio::utils::GetAllowedAudioContextsFromSourceMetadata;

namespace {
class LeAudioBroadcasterImpl;
@@ -165,6 +167,80 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
    return announcement;
  }

  void UpdateStreamingContextTypeOnAllSubgroups(uint16_t context_type_map) {
    LOG_DEBUG("%s context_type_map=%d", __func__, context_type_map);

    auto ccids = GetAllCcids(context_type_map);
    if (ccids.empty()) {
      LOG_WARN("%s No content providers available for context_type_map=%d.",
               __func__, context_type_map);
    }

    std::vector<uint8_t> stream_context_vec(2);
    auto pp = stream_context_vec.data();
    UINT16_TO_STREAM(pp, context_type_map);

    for (auto const& kv_it : broadcasts_) {
      auto& broadcast = kv_it.second;
      if (broadcast->GetState() == BroadcastStateMachine::State::STREAMING) {
        auto announcement = broadcast->GetBroadcastAnnouncement();
        bool broadcast_update = false;

        // Replace context type and CCID list
        for (auto& subgroup : announcement.subgroup_configs) {
          auto subgroup_ltv = LeAudioLtvMap(subgroup.metadata);
          bool subgroup_update = false;

          auto existing_context = subgroup_ltv.Find(
              le_audio::types::kLeAudioMetadataTypeStreamingAudioContext);
          if (existing_context) {
            if (memcmp(stream_context_vec.data(), existing_context->data(),
                       existing_context->size()) != 0) {
              subgroup_ltv.Add(
                  le_audio::types::kLeAudioMetadataTypeStreamingAudioContext,
                  stream_context_vec);
              subgroup_update = true;
            }
          } else {
            subgroup_ltv.Add(
                le_audio::types::kLeAudioMetadataTypeStreamingAudioContext,
                stream_context_vec);
            subgroup_update = true;
          }

          auto existing_ccid_list =
              subgroup_ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList);
          if (existing_ccid_list) {
            if (ccids.empty()) {
              subgroup_ltv.Remove(
                  le_audio::types::kLeAudioMetadataTypeCcidList);
              subgroup_update = true;

            } else if (!std::is_permutation(ccids.begin(), ccids.end(),
                                            existing_ccid_list->begin())) {
              subgroup_ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList,
                               ccids);
              subgroup_update = true;
            }
          } else if (!ccids.empty()) {
            subgroup_ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList,
                             ccids);
            subgroup_update = true;
          }

          if (subgroup_update) {
            subgroup.metadata = subgroup_ltv.Values();
            broadcast_update = true;
          }
        }

        if (broadcast_update) {
          broadcast->UpdateBroadcastAnnouncement(std::move(announcement));
        }
      }
    }
  }

  void UpdateMetadata(uint32_t broadcast_id,
                      std::vector<uint8_t> metadata) override {
    if (broadcasts_.count(broadcast_id) == 0) {
@@ -185,6 +261,43 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
      return;
    }

    uint16_t context_type =
        static_cast<std::underlying_type<LeAudioContextType>::type>(
            LeAudioContextType::MEDIA);

    /* Adds multiple contexts and CCIDs regardless of the incoming audio
     * context. Android has only two CCIDs, one for Media and one for
     * Conversational context. Even though we are not broadcasting
     * Conversational streams, some PTS test cases wants multiple CCIDs.
     */
    if (stack_config_get_interface()
            ->get_pts_force_le_audio_multiple_contexts_metadata()) {
      context_type =
          static_cast<std::underlying_type<LeAudioContextType>::type>(
              LeAudioContextType::MEDIA) |
          static_cast<std::underlying_type<LeAudioContextType>::type>(
              LeAudioContextType::CONVERSATIONAL);
      auto stream_context_vec =
          ltv.Find(le_audio::types::kLeAudioMetadataTypeStreamingAudioContext);
      if (stream_context_vec) {
        auto pp = stream_context_vec.value().data();
        UINT16_TO_STREAM(pp, context_type);
      }
    }

    auto stream_context_vec =
        ltv.Find(le_audio::types::kLeAudioMetadataTypeStreamingAudioContext);
    if (stream_context_vec) {
      auto pp = stream_context_vec.value().data();
      STREAM_TO_UINT16(context_type, pp);
    }

    // Append the CCID list
    auto ccid_vec = GetAllCcids(context_type);
    if (!ccid_vec.empty()) {
      ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList, ccid_vec);
    }

    BasicAudioAnnouncementData announcement =
        prepareAnnouncement(codec_config, std::move(ltv));

@@ -211,6 +324,27 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
    uint16_t context_type =
        static_cast<std::underlying_type<LeAudioContextType>::type>(
            LeAudioContextType::MEDIA);

    /* Adds multiple contexts and CCIDs regardless of the incoming audio
     * context. Android has only two CCIDs, one for Media and one for
     * Conversational context. Even though we are not broadcasting
     * Conversational streams, some PTS test cases wants multiple CCIDs.
     */
    if (stack_config_get_interface()
            ->get_pts_force_le_audio_multiple_contexts_metadata()) {
      context_type =
          static_cast<std::underlying_type<LeAudioContextType>::type>(
              LeAudioContextType::MEDIA) |
          static_cast<std::underlying_type<LeAudioContextType>::type>(
              LeAudioContextType::CONVERSATIONAL);
      auto stream_context_vec =
          ltv.Find(le_audio::types::kLeAudioMetadataTypeStreamingAudioContext);
      if (stream_context_vec) {
        auto pp = stream_context_vec.value().data();
        UINT16_TO_STREAM(pp, context_type);
      }
    }

    auto stream_context_vec =
        ltv.Find(le_audio::types::kLeAudioMetadataTypeStreamingAudioContext);
    if (stream_context_vec) {
@@ -219,12 +353,9 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
    }

    // Append the CCID list
    // TODO: We currently support only one context (and CCID) at a time for both
    //       Unicast and broadcast.
    auto ccid = ContentControlIdKeeper::GetInstance()->GetCcid(context_type);
    if (ccid != -1) {
      ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList,
              {static_cast<uint8_t>(ccid)});
    auto ccid_vec = GetAllCcids(context_type);
    if (!ccid_vec.empty()) {
      ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList, ccid_vec);
    }

    if (CodecManager::GetInstance()->GetCodecLocation() ==
@@ -744,11 +875,24 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
        const source_metadata_t& source_metadata) override {
      LOG_INFO();
      if (!instance) return;
      do_update_metadata_promise.set_value();
      /* TODO: We probably don't want to change stream type or update the
       * advertized metadata on each call. We should rather make sure we get
       * only a single content audio stream from the media frameworks.

      /* TODO: Should we take supported contexts from ASCS? */
      auto supported_context_types = le_audio::types::kLeAudioContextAllTypes;
      auto contexts = GetAllowedAudioContextsFromSourceMetadata(
          source_metadata,
          static_cast<std::underlying_type<LeAudioContextType>::type>(
              supported_context_types));
      if (contexts.any()) {
        /* NOTICE: We probably don't want to change the stream configuration
         * on each metadata change, so just update the context type metadata.
         * Since we are not able to identify individual track streams and
         * they are all mixed inside a single data stream, we will update
         * the metadata of all BIS subgroups with the same combined context.
         */
        instance->UpdateStreamingContextTypeOnAllSubgroups(contexts.to_ulong());
      }

      do_update_metadata_promise.set_value();
    }

   private:
+103 −4
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <hardware/audio.h>

#include <chrono>

@@ -30,6 +31,8 @@
#include "device/include/controller.h"
#include "stack/include/btm_iso_api.h"

using namespace std::chrono_literals;

using le_audio::types::LeAudioContextType;

using testing::_;
@@ -108,6 +111,7 @@ static void cleanup_message_loop_thread() {
namespace le_audio {
namespace broadcaster {
namespace {
static constexpr uint8_t default_ccid = 0xDE;
static constexpr auto default_context =
    static_cast<std::underlying_type<LeAudioContextType>::type>(
        LeAudioContextType::ALERTS);
@@ -203,6 +207,7 @@ class BroadcasterTest : public Test {
                                   base::Bind([]() -> bool { return true; }));

    ContentControlIdKeeper::GetInstance()->Start();
    ContentControlIdKeeper::GetInstance()->SetCcid(0x0004, media_ccid);

    /* Simulate random generator */
    uint8_t random[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
@@ -405,12 +410,29 @@ TEST_F(BroadcasterTest, GetBroadcastAllStates) {

TEST_F(BroadcasterTest, UpdateMetadata) {
  auto broadcast_id = InstantiateBroadcast();

  std::vector<uint8_t> ccid_list;
  EXPECT_CALL(*MockBroadcastStateMachine::GetLastInstance(),
              UpdateBroadcastAnnouncement)
      .Times(1);
      .WillOnce(
          [&](bluetooth::le_audio::BasicAudioAnnouncementData announcement) {
            for (auto subgroup : announcement.subgroup_configs) {
              if (subgroup.metadata.count(
                      types::kLeAudioMetadataTypeCcidList)) {
                ccid_list =
                    subgroup.metadata.at(types::kLeAudioMetadataTypeCcidList);
                break;
              }
            }
          });

  ContentControlIdKeeper::GetInstance()->SetCcid(0x0400, default_ccid);
  LeAudioBroadcaster::Get()->UpdateMetadata(
      broadcast_id, std::vector<uint8_t>({0x02, 0x01, 0x02}));
      broadcast_id,
      std::vector<uint8_t>({0x02, 0x01, 0x02, 0x03, 0x02, 0x04, 0x04}));

  ASSERT_EQ(2u, ccid_list.size());
  ASSERT_NE(0, std::count(ccid_list.begin(), ccid_list.end(), media_ccid));
  ASSERT_NE(0, std::count(ccid_list.begin(), ccid_list.end(), default_ccid));
}

static BasicAudioAnnouncementData prepareAnnouncement(
@@ -444,10 +466,87 @@ static BasicAudioAnnouncementData prepareAnnouncement(
  return announcement;
}

TEST_F(BroadcasterTest, UpdateMetadataFromAudioTrackMetadata) {
  ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
  auto broadcast_id = InstantiateBroadcast();

  LeAudioClientAudioSinkReceiver* audio_receiver;
  EXPECT_CALL(*mock_audio_source_, Start)
      .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true)));

  LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id);
  ASSERT_NE(audio_receiver, nullptr);

  auto sm = MockBroadcastStateMachine::GetLastInstance();
  std::vector<uint8_t> ccid_list;
  std::vector<uint8_t> context_types_map;
  EXPECT_CALL(*sm, UpdateBroadcastAnnouncement)
      .WillOnce(
          [&](bluetooth::le_audio::BasicAudioAnnouncementData announcement) {
            for (auto subgroup : announcement.subgroup_configs) {
              if (subgroup.metadata.count(
                      types::kLeAudioMetadataTypeCcidList)) {
                ccid_list =
                    subgroup.metadata.at(types::kLeAudioMetadataTypeCcidList);
              }
              if (subgroup.metadata.count(
                      types::kLeAudioMetadataTypeStreamingAudioContext)) {
                context_types_map = subgroup.metadata.at(
                    types::kLeAudioMetadataTypeStreamingAudioContext);
              }
            }
          });

  std::map<uint8_t, std::vector<uint8_t>> meta = {};
  BroadcastCodecWrapper codec_config(
      {.coding_format = le_audio::types::kLeAudioCodingFormatLC3,
       .vendor_company_id = le_audio::types::kLeAudioVendorCompanyIdUndefined,
       .vendor_codec_id = le_audio::types::kLeAudioVendorCodecIdUndefined},
      {.num_channels = LeAudioCodecConfiguration::kChannelNumberMono,
       .sample_rate = LeAudioCodecConfiguration::kSampleRate16000,
       .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16,
       .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us},
      32000, 40);
  auto announcement = prepareAnnouncement(codec_config, meta);

  ON_CALL(*sm, GetBroadcastAnnouncement())
      .WillByDefault(ReturnRef(announcement));

  std::promise<void> do_update_metadata_promise;
  struct playback_track_metadata tracks_[] = {
      {AUDIO_USAGE_GAME, AUDIO_CONTENT_TYPE_SONIFICATION, 0},
      {AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, 0},
      {AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING, AUDIO_CONTENT_TYPE_SPEECH,
       0},
      {AUDIO_USAGE_UNKNOWN, AUDIO_CONTENT_TYPE_UNKNOWN, 0}};

  source_metadata_t multitrack_source_metadata = {.track_count = 4,
                                                  .tracks = &tracks_[0]};

  auto do_update_metadata_future = do_update_metadata_promise.get_future();
  audio_receiver->OnAudioMetadataUpdate(std::move(do_update_metadata_promise),
                                        multitrack_source_metadata);
  do_update_metadata_future.wait_for(3s);

  // Verify ccid
  ASSERT_NE(ccid_list.size(), 0u);
  ASSERT_TRUE(std::find(ccid_list.begin(), ccid_list.end(), media_ccid) !=
              ccid_list.end());

  // Verify context type
  ASSERT_NE(context_types_map.size(), 0u);
  uint16_t context_type;
  auto pp = context_types_map.data();
  STREAM_TO_UINT16(context_type, pp);
  ASSERT_NE(context_type &
                static_cast<std::underlying_type<LeAudioContextType>::type>(
                    LeAudioContextType::MEDIA | LeAudioContextType::GAME),
            0);
}

TEST_F(BroadcasterTest, GetMetadata) {
  auto broadcast_id = InstantiateBroadcast();
  bluetooth::le_audio::BroadcastMetadata metadata;
  // bluetooth::le_audio::BasicAudioAnnouncementData announcement;

  static const uint8_t test_adv_sid = 0x14;
  std::optional<bluetooth::le_audio::BroadcastCode> test_broadcast_code =
+1 −0
Original line number Diff line number Diff line
@@ -131,6 +131,7 @@ class MockBroadcastStateMachine
  std::optional<le_audio::broadcaster::BigConfig> big_config_ = std::nullopt;
  le_audio::broadcaster::BroadcastStateMachineConfig cfg;
  le_audio::broadcaster::IBroadcastStateMachineCallbacks* cb;
  void SetExpectedState(BroadcastStateMachine::State state) { SetState(state); }
  void SetExpectedResult(bool result) { result_ = result; }
  void SetExpectedBigConfig(
      std::optional<le_audio::broadcaster::BigConfig> big_cfg) {
+143 −183

File changed.

Preview size limit exceeded, changes collapsed.

Loading