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

Commit 5e077fd4 authored by Grzegorz Kolodziejczyk's avatar Grzegorz Kolodziejczyk Committed by Gerrit Code Review
Browse files

Merge "Add Audio Active State to Public Broadcast Announcement" into main

parents 6c75e7fa 5afd1dfe
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1205,6 +1205,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)