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

Commit 5afd1dfe authored by Michal Belusiak's avatar Michal Belusiak
Browse files

Add Audio Active State to Public Broadcast Announcement

Bug: 273864658
Bug: 347204335
Test: atest --host bluetooth_test_broadcaster --no-bazel-mode
Change-Id: Id86063aa74038d1fb47c5c94fd69477a02bd6310
parent 8b308200
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1202,6 +1202,7 @@ cc_test {
        "libbt_shim_ffi",
        "libchrome",
        "libevent",
        "libflagtest",
        "libflatbuffers-cpp",
        "libgmock",
        "libgtest",
+90 −20
Original line number Diff line number Diff line
@@ -84,19 +84,14 @@ std::mutex instance_mutex;
 * for test purposes.
 */
class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
  enum class AudioDataPathState {
    INACTIVE,
    ACTIVE,
    SUSPENDED,
  };
  enum class AudioState { SUSPENDED, ACTIVE };

public:
  LeAudioBroadcasterImpl(
      bluetooth::le_audio::LeAudioBroadcasterCallbacks* callbacks_)
  LeAudioBroadcasterImpl(bluetooth::le_audio::LeAudioBroadcasterCallbacks* callbacks_)
      : callbacks_(callbacks_),
        current_phy_(PHY_LE_2M),
        audio_data_path_state_(AudioDataPathState::INACTIVE),
        le_audio_source_hal_client_(nullptr) {
        le_audio_source_hal_client_(nullptr),
        audio_state_(AudioState::SUSPENDED) {
    log::info("");

    /* Register State machine callbacks */
@@ -146,6 +141,7 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
          le_audio_source_hal_client_.get(), false);
      le_audio_source_hal_client_.reset();
    }
    audio_state_ = AudioState::SUSPENDED;
  }

  void Stop() {
@@ -329,6 +325,46 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
    }
  }

  void UpdateAudioActiveStateInPublicAnnouncement() {
    for (auto const& kv_it : broadcasts_) {
      auto& broadcast = kv_it.second;

      bool audio_active_state = (audio_state_ == AudioState::ACTIVE) &&
                                (broadcast->GetState() == BroadcastStateMachine::State::STREAMING);

      log::info("broadcast_id={}, audio_active_state={}", broadcast->GetBroadcastId(),
                audio_active_state);

      auto updateLtv = [](bool audio_active_state, LeAudioLtvMap& ltv) -> bool {
        auto existing_audio_active_state =
                ltv.Find(bluetooth::le_audio::types::kLeAudioMetadataTypeAudioActiveState);

        if (existing_audio_active_state && !existing_audio_active_state->empty()) {
          if (audio_active_state != static_cast<bool>(existing_audio_active_state->at(0))) {
            ltv.Add(bluetooth::le_audio::types::kLeAudioMetadataTypeAudioActiveState,
                    audio_active_state);
            return true;
          }
        } else {
          ltv.Add(bluetooth::le_audio::types::kLeAudioMetadataTypeAudioActiveState,
                  audio_active_state);
          return true;
        }

        return false;
      };

      auto public_announcement = broadcast->GetPublicBroadcastAnnouncement();
      auto public_ltv = LeAudioLtvMap(public_announcement.metadata);

      if (updateLtv(audio_active_state, public_ltv)) {
        public_announcement.metadata = public_ltv.Values();
        broadcast->UpdatePublicBroadcastAnnouncement(
                broadcast->GetBroadcastId(), broadcast->GetBroadcastName(), public_announcement);
      }
    }
  }

  void UpdateMetadata(
      uint32_t broadcast_id, const std::string& broadcast_name,
      const std::vector<uint8_t>& public_metadata,
@@ -410,6 +446,16 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
        log::error("Invalid public metadata provided.");
        return;
      }

      if (com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) {
        // Append the Audio Active State
        bool audio_active_state =
                (audio_state_ == AudioState::ACTIVE) &&
                (broadcasts_[broadcast_id]->GetState() == BroadcastStateMachine::State::STREAMING);
        public_ltv.Add(bluetooth::le_audio::types::kLeAudioMetadataTypeAudioActiveState,
                       audio_active_state);
      }

      PublicBroadcastAnnouncementData pb_announcement =
          preparePublicAnnouncement(broadcasts_[broadcast_id]
                                        ->GetPublicBroadcastAnnouncement()
@@ -483,6 +529,11 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
                                       false);
        return;
      }

      if (com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) {
        // Append the Audio Active State
        public_ltv.Add(bluetooth::le_audio::types::kLeAudioMetadataTypeAudioActiveState, false);
      }
      // Prepare public features byte
      // bit 0 Encryption broadcast stream encrypted or not
      // bit 1 Standard quality audio configuration present or not
@@ -660,6 +711,7 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
    if (broadcasts_.count(broadcast_id) != 0) {
      log::info("Stopping AudioHalClient");
      if (le_audio_source_hal_client_) le_audio_source_hal_client_->Stop();
      audio_state_ = AudioState::SUSPENDED;
      broadcasts_[broadcast_id]->SetMuted(true);
      broadcasts_[broadcast_id]->ProcessMessage(
          BroadcastStateMachine::Message::SUSPEND, nullptr);
@@ -731,6 +783,7 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
    log::info("Stopping AudioHalClient, broadcast_id={}", broadcast_id);

    if (le_audio_source_hal_client_) le_audio_source_hal_client_->Stop();
    audio_state_ = AudioState::SUSPENDED;
    broadcasts_[broadcast_id]->SetMuted(true);
    broadcasts_[broadcast_id]->ProcessMessage(
        BroadcastStateMachine::Message::STOP, nullptr);
@@ -976,13 +1029,15 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {

      switch (state) {
        case BroadcastStateMachine::State::STOPPED:
          /* Pass through */
          break;
        case BroadcastStateMachine::State::CONFIGURING:
          /* Pass through */
          break;
        case BroadcastStateMachine::State::CONFIGURED:
          /* Pass through */
          if (com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) {
            instance->UpdateAudioActiveStateInPublicAnnouncement();
          }
          break;
        case BroadcastStateMachine::State::STOPPING:
          /* Nothing to do here? */
          break;
        case BroadcastStateMachine::State::STREAMING:
          if (getStreamerCount() == 1) {
@@ -1004,7 +1059,9 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
                return;
              }

              instance->audio_data_path_state_ = AudioDataPathState::ACTIVE;
              if (com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) {
                instance->UpdateAudioActiveStateInPublicAnnouncement();
              }
            }
          }
          break;
@@ -1269,8 +1326,15 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
    virtual void OnAudioSuspend(void) override {
      log::info("");
      /* TODO: Should we suspend all broadcasts - remove BIGs? */
      if (instance)
        instance->audio_data_path_state_ = AudioDataPathState::SUSPENDED;
      if (!instance) {
        return;
      }

      instance->audio_state_ = AudioState::SUSPENDED;

      if (com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) {
        instance->UpdateAudioActiveStateInPublicAnnouncement();
      }
    }

    virtual void OnAudioResume(void) override {
@@ -1278,7 +1342,7 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
      if (!instance) return;

      /* TODO: Should we resume all broadcasts - recreate BIGs? */
      instance->audio_data_path_state_ = AudioDataPathState::ACTIVE;
      instance->audio_state_ = AudioState::ACTIVE;

      if (!IsAnyoneStreaming()) {
        instance->le_audio_source_hal_client_->CancelStreamingRequest();
@@ -1286,6 +1350,10 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {
      }

      instance->le_audio_source_hal_client_->ConfirmStreamingRequest();

      if (com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) {
        instance->UpdateAudioActiveStateInPublicAnnouncement();
      }
    }

    virtual void OnAudioMetadataUpdate(
@@ -1320,10 +1388,12 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks {

  /* Some BIG params are set globally */
  uint8_t current_phy_;
  AudioDataPathState audio_data_path_state_;
  std::unique_ptr<LeAudioSourceAudioHalClient> le_audio_source_hal_client_;
  std::vector<BroadcastId> available_broadcast_ids_;

  // Current state of audio playback
  AudioState audio_state_;

  // Flag to track iso state
  bool is_iso_running_ = false;
};
+101 −1
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@
 */

#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
#include <flag_macros.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <hardware/audio.h>
@@ -36,6 +38,8 @@
#include "test/mock/mock_main_shim_entry.h"
#include "test/mock/mock_stack_btm_iso.h"

#define TEST_BT com::android::bluetooth::flags

using namespace std::chrono_literals;

using bluetooth::le_audio::types::AudioContexts;
@@ -201,6 +205,10 @@ static const std::vector<uint8_t> default_public_metadata = {
    5,   bluetooth::le_audio::types::kLeAudioMetadataTypeProgramInfo,
    0x1, 0x2,
    0x3, 0x4};
static const std::vector<uint8_t> audio_active_state_false = {
        2, bluetooth::le_audio::types::kLeAudioMetadataTypeAudioActiveState, 0x00};
static const std::vector<uint8_t> audio_active_state_true = {
        2, bluetooth::le_audio::types::kLeAudioMetadataTypeAudioActiveState, 0x01};
// bit 0: encrypted, bit 1: standard quality present
static const uint8_t test_public_broadcast_features = 0x3;

@@ -736,11 +744,19 @@ TEST_F(BroadcasterTest, UpdateMetadata) {
      broadcast_id, test_broadcast_name, default_public_metadata,
      {std::vector<uint8_t>({0x02, 0x01, 0x02, 0x03, 0x02, 0x04, 0x04})});

  std::vector<uint8_t> public_metadata(default_public_metadata);
  public_metadata.insert(public_metadata.end(), audio_active_state_false.begin(),
                         audio_active_state_false.end());

  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));
  ASSERT_EQ(expected_broadcast_name, test_broadcast_name);
  if (!com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) {
    ASSERT_EQ(expected_public_meta, default_public_metadata);
  } else {
    ASSERT_EQ(expected_public_meta, public_metadata);
  }
}

static BasicAudioAnnouncementData prepareAnnouncement(
@@ -1185,6 +1201,90 @@ TEST_F(BroadcasterTest, VendorCodecConfig) {
             subgroup.bis_configs.at(1).vendor_codec_specific_params->size()));
}

TEST_F_WITH_FLAGS(BroadcasterTest, AudioActiveState,
                  REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT,
                                                      leaudio_big_depends_on_audio_state))) {
  std::vector<uint8_t> updated_public_meta;
  PublicBroadcastAnnouncementData pb_announcement;

  std::vector<uint8_t> public_metadata_audio_false(default_public_metadata);
  public_metadata_audio_false.insert(public_metadata_audio_false.end(),
                                     audio_active_state_false.begin(),
                                     audio_active_state_false.end());
  std::vector<uint8_t> public_metadata_audio_true(default_public_metadata);
  public_metadata_audio_true.insert(public_metadata_audio_true.end(),
                                    audio_active_state_true.begin(), audio_active_state_true.end());

  // Add Audio Actie State while broadcast created
  auto broadcast_id = InstantiateBroadcast();
  auto sm = MockBroadcastStateMachine::GetLastInstance();
  pb_announcement = sm->GetPublicBroadcastAnnouncement();
  auto created_public_meta = types::LeAudioLtvMap(pb_announcement.metadata).RawPacket();
  ASSERT_EQ(created_public_meta, public_metadata_audio_false);

  ON_CALL(*sm, UpdatePublicBroadcastAnnouncement(broadcast_id, _, _))
          .WillByDefault(
                  [&](uint32_t broadcast_id, const std::string& broadcast_name,
                      const bluetooth::le_audio::PublicBroadcastAnnouncementData& announcement) {
                    pb_announcement = announcement;
                    updated_public_meta = types::LeAudioLtvMap(announcement.metadata).RawPacket();
                  });
  ON_CALL(*sm, GetPublicBroadcastAnnouncement()).WillByDefault(ReturnRef(pb_announcement));

  LeAudioSourceAudioHalClient::Callbacks* 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);

  // Update to true Audio Active State while audio resumed
  EXPECT_CALL(*sm, UpdatePublicBroadcastAnnouncement);
  audio_receiver->OnAudioResume();
  ASSERT_EQ(updated_public_meta, public_metadata_audio_true);

  // No update Audio Active State if the same value
  EXPECT_CALL(*sm, UpdatePublicBroadcastAnnouncement).Times(0);
  audio_receiver->OnAudioResume();

  // Updated to false Audio Active State while audio suspended
  EXPECT_CALL(*sm, UpdatePublicBroadcastAnnouncement);
  audio_receiver->OnAudioSuspend();
  ASSERT_EQ(updated_public_meta, public_metadata_audio_false);

  // No update Audio Active State if the same value
  EXPECT_CALL(*sm, UpdatePublicBroadcastAnnouncement).Times(0);
  audio_receiver->OnAudioSuspend();

  // Update to false Audio Active State while metada updated
  EXPECT_CALL(*sm, UpdatePublicBroadcastAnnouncement);
  LeAudioBroadcaster::Get()->UpdateMetadata(
          broadcast_id, test_broadcast_name, default_public_metadata,
          {std::vector<uint8_t>({0x02, 0x01, 0x02, 0x03, 0x02, 0x04, 0x04})});
  ASSERT_EQ(updated_public_meta, public_metadata_audio_false);

  // Update to true Audio Active State while audio resumed
  EXPECT_CALL(*sm, UpdatePublicBroadcastAnnouncement);
  audio_receiver->OnAudioResume();
  ASSERT_EQ(updated_public_meta, public_metadata_audio_true);

  // Update to true Audio Active State while metada updated
  EXPECT_CALL(*sm, UpdatePublicBroadcastAnnouncement);
  LeAudioBroadcaster::Get()->UpdateMetadata(
          broadcast_id, test_broadcast_name, default_public_metadata,
          {std::vector<uint8_t>({0x02, 0x01, 0x02, 0x03, 0x02, 0x04, 0x04})});
  ASSERT_EQ(updated_public_meta, public_metadata_audio_true);

  // Updated to false Audio Active State while broadcast suspended
  EXPECT_CALL(*sm, UpdatePublicBroadcastAnnouncement);
  LeAudioBroadcaster::Get()->SuspendAudioBroadcast(broadcast_id);
  ASSERT_EQ(updated_public_meta, public_metadata_audio_false);

  // No update to true Audio Active State while audio resumed when not in
  // streaming state
  EXPECT_CALL(*sm, UpdatePublicBroadcastAnnouncement).Times(0);
  audio_receiver->OnAudioResume();
}

// TODO: Add tests for:
// ToRawPacket(BasicAudioAnnouncementData const& in, std::vector<uint8_t>& data)