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

Commit d0662f4c authored by Łukasz Rymanowski (xWF)'s avatar Łukasz Rymanowski (xWF) Committed by Gerrit Code Review
Browse files

Merge changes Ic9beb4af,Id4b77fd0,Ie541d871 into main

* changes:
  leaudio: Fix race when switching between Sink and Source stream
  test/fake_osi: Improve fake alarms managing
  leaudio: Minor cleanup on suspent_timeout_
parents d119a734 83597fe1
Loading
Loading
Loading
Loading
+43 −38
Original line number Diff line number Diff line
@@ -365,6 +365,36 @@ public:
    }
  }

  void StartSuspendTimeout(void) {
    StopSuspendTimeout();

    /* Group should tie in time to get requested status */
    uint64_t timeoutMs = kAudioSuspentKeepIsoAliveTimeoutMs;
    timeoutMs = osi_property_get_int32(kAudioSuspentKeepIsoAliveTimeoutMsProp, timeoutMs);

    if (stack_config_get_interface()->get_pts_le_audio_disable_ases_before_stopping()) {
      timeoutMs += kAudioDisableTimeoutMs;
    }

    log::debug("Stream suspend_timeout_ started: {} ms", static_cast<int>(timeoutMs));

    alarm_set_on_mloop(
            suspend_timeout_, timeoutMs,
            [](void* data) {
              if (instance) {
                instance->GroupStop(PTR_TO_INT(data));
              }
            },
            INT_TO_PTR(active_group_id_));
  }

  void StopSuspendTimeout(void) {
    if (alarm_is_scheduled(suspend_timeout_)) {
      log::debug("Cancel suspend timeout");
      alarm_cancel(suspend_timeout_);
    }
  }

  void AseInitialStateReadRequest(LeAudioDevice* leAudioDevice) {
    int ases_num = leAudioDevice->ases_.size();
    void* notify_flag_ptr = NULL;
@@ -1292,9 +1322,7 @@ public:
    sink_monitor_notified_status_ = std::nullopt;
    log::info("Group id: {}", active_group_id_);

    if (alarm_is_scheduled(suspend_timeout_)) {
      alarm_cancel(suspend_timeout_);
    }
    StopSuspendTimeout();

    StopAudio();
    ClientAudioInterfaceRelease();
@@ -3921,9 +3949,7 @@ public:

  void Cleanup() {
    StopVbcCloseTimeout();
    if (alarm_is_scheduled(suspend_timeout_)) {
      alarm_cancel(suspend_timeout_);
    }
    StopSuspendTimeout();

    if (active_group_id_ != bluetooth::groups::kGroupUnknown) {
      /* Bluetooth turned off while streaming */
@@ -4037,27 +4063,7 @@ public:
              INT_TO_PTR(active_group_id_));
    }

    /* Group should tie in time to get requested status */
    uint64_t timeoutMs = kAudioSuspentKeepIsoAliveTimeoutMs;
    timeoutMs = osi_property_get_int32(kAudioSuspentKeepIsoAliveTimeoutMsProp, timeoutMs);

    if (stack_config_get_interface()->get_pts_le_audio_disable_ases_before_stopping()) {
      timeoutMs += kAudioDisableTimeoutMs;
    }

    log::debug("Stream suspend_timeout_ started: {} ms", static_cast<int>(timeoutMs));
    if (alarm_is_scheduled(suspend_timeout_)) {
      alarm_cancel(suspend_timeout_);
    }

    alarm_set_on_mloop(
            suspend_timeout_, timeoutMs,
            [](void* data) {
              if (instance) {
                instance->GroupStop(PTR_TO_INT(data));
              }
            },
            INT_TO_PTR(active_group_id_));
    StartSuspendTimeout();
  }

  void OnLocalAudioSourceSuspend() {
@@ -4215,6 +4221,7 @@ public:
            if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
              if (IsDirectionAvailableForCurrentConfiguration(
                          group, bluetooth::le_audio::types::kLeAudioDirectionSink)) {
                StopSuspendTimeout();
                StartSendingAudio(active_group_id_);
              } else {
                log::warn(
@@ -4255,9 +4262,7 @@ public:
          case AudioState::IDLE:
          case AudioState::READY_TO_RELEASE:
            /* Stream is up just restore it */
            if (alarm_is_scheduled(suspend_timeout_)) {
              alarm_cancel(suspend_timeout_);
            }
            StopSuspendTimeout();
            ConfirmLocalAudioSourceStreamingRequest();
            bluetooth::le_audio::MetricsCollector::Get()->OnStreamStarted(
                    active_group_id_, configuration_context_type_);
@@ -4282,8 +4287,6 @@ public:
                                            "r_state: " + ToString(audio_receiver_state_) +
                                                    ", s_state: " + ToString(audio_sender_state_));

    StartVbcCloseTimeout();

    /* Note: This callback is from audio hal driver.
     * Bluetooth peer is a Source for Audio Framework.
     * e.g. Peer is microphone.
@@ -4308,6 +4311,11 @@ public:
    if ((audio_sender_state_ == AudioState::IDLE) ||
        (audio_sender_state_ == AudioState::READY_TO_RELEASE)) {
      OnAudioSuspend();
    } else {
      /* If the local sink direction is used, we want to monitor
       * if back channel is actually needed.
       */
      StartVbcCloseTimeout();
    }

    log::info("OUT: audio_receiver_state_: {},  audio_sender_state_: {}",
@@ -4468,6 +4476,7 @@ public:
            if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
              if (IsDirectionAvailableForCurrentConfiguration(
                          group, bluetooth::le_audio::types::kLeAudioDirectionSource)) {
                StopSuspendTimeout();
                StartReceivingAudio(active_group_id_);
              } else {
                log::warn(
@@ -4507,9 +4516,7 @@ public:
          case AudioState::READY_TO_START:
          case AudioState::READY_TO_RELEASE:
            /* Stream is up just restore it */
            if (alarm_is_scheduled(suspend_timeout_)) {
              alarm_cancel(suspend_timeout_);
            }
            StopSuspendTimeout();
            ConfirmLocalAudioSinkStreamingRequest();
            break;
          case AudioState::RELEASING:
@@ -4604,9 +4611,7 @@ public:
      return false;
    }

    if (alarm_is_scheduled(suspend_timeout_)) {
      alarm_cancel(suspend_timeout_);
    }
    StopSuspendTimeout();

    /* Need to reconfigure stream. At this point pre_configuration_context_type shall be set */

+78 −0
Original line number Diff line number Diff line
@@ -1442,6 +1442,7 @@ protected:
  void SetUp() override {
    __android_log_set_minimum_priority(ANDROID_LOG_VERBOSE);
    init_message_loop_thread();
    reset_mock_function_count_map();
    ON_CALL(controller_, SupportsBleConnectedIsochronousStreamCentral).WillByDefault(Return(true));
    ON_CALL(controller_, SupportsBleConnectedIsochronousStreamPeripheral)
            .WillByDefault(Return(true));
@@ -9914,6 +9915,83 @@ TEST_F(UnicastTest, MicrophoneAttachToCurrentMediaScenario) {
  Mock::VerifyAndClearExpectations(mock_le_audio_source_hal_client_);
}
TEST_F(UnicastTest, SwitchBetweenMicrophoneAndSoundEffectScenario) {
  const RawAddress test_address0 = GetTestAddress(0);
  int group_id = bluetooth::groups::kGroupUnknown;
  /* Scenario:
   * 1. User starts Recording - this creates bidiretional CISes
   * 2. User stops recording  - this starts suspend timeout (500ms)
   * 3. Since user touch the screen it generates touch tone - this shall reuse existing CISes when
   * it happens 500ms before stop
   */
  SetSampleDatabaseEarbudsValid(1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
                                codec_spec_conf::kLeAudioLocationFrontLeft, default_channel_cnt,
                                default_channel_cnt, 0x0024, false /*add_csis*/, true /*add_cas*/,
                                true /*add_pacs*/, default_ase_cnt /*add_ascs_cnt*/, 1 /*set_size*/,
                                0 /*rank*/);
  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
          .Times(1);
  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED))
          .WillOnce(DoAll(SaveArg<1>(&group_id)));
  ConnectLeAudio(test_address0);
  ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown);
  // Audio sessions are started only when device gets active
  EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1);
  EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1);
  LeAudioClient::Get()->GroupSetActive(group_id);
  SyncOnMainLoop();
  // When the local audio source resumes we have no knowledge of recording
  EXPECT_CALL(mock_state_machine_,
              StartStream(_, bluetooth::le_audio::types::LeAudioContextType::LIVE, _, _))
          .Times(1);
  log::info("Start Microphone recording - bidirectional CISes are expected");
  UpdateLocalSinkMetadata(AUDIO_SOURCE_MIC);
  LocalAudioSinkResume();
  ASSERT_EQ(0, get_func_call_count("alarm_set_on_mloop"));
  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);
  Mock::VerifyAndClearExpectations(mock_le_audio_source_hal_client_);
  Mock::VerifyAndClearExpectations(&mock_state_machine_);
  // Verify Data transfer on one audio source cis
  uint8_t cis_count_out = 0;
  uint8_t cis_count_in = 1;
  TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 60);
  log::info("Suspend microphone recording - suspend timeout is not fired");
  LocalAudioSinkSuspend();
  SyncOnMainLoop();
  // VBC and Suspend
  ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop"));
  ASSERT_EQ(0, get_func_call_count("alarm_cancel"));
  log::info("Resume local source with touch tone - expect suspend timeout to be canceled");
  UpdateLocalSourceMetadata(AUDIO_USAGE_ASSISTANCE_SONIFICATION, AUDIO_CONTENT_TYPE_SONIFICATION);
  LocalAudioSourceResume();
  SyncOnMainLoop();
  ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
  auto group = streaming_groups.at(group_id);
  group->PrintDebugState();
  // Verify Data transfer on one audio source and sink cis
  cis_count_out = 1;
  cis_count_in = 0;
  TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 60);
}
/* When a certain context is unavailable and not supported we should stream
 * as UNSPECIFIED for the backwards compatibility.
 * Since UNSPECIFIED is available, put the UNSPECIFIED into the metadata instead
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "osi/include/alarm.h"

struct fake_osi_alarm_set_on_mloop {
  alarm_t* alarm;
  uint64_t interval_ms{0};
  alarm_callback_t cb{};
  void* data{nullptr};
+60 −5
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@

#include "osi/include/osi.h"

#include <bluetooth/log.h>
#include <sys/socket.h>

#include <list>
@@ -335,24 +336,70 @@ alarm_t* alarm_new_periodic(const char* name) {
  inc_func_call_count(__func__);
  return nullptr;
}

// Callback to last set alarm
struct fake_osi_alarm_set_on_mloop fake_osi_alarm_set_on_mloop_;

// Vector of previous osi alarms. Keep it for proper handling alarm_is_scheduler function
static std::vector<struct fake_osi_alarm_set_on_mloop> previous_fake_osi_alarms_;

bool alarm_is_scheduled(const alarm_t* alarm) {
  inc_func_call_count(__func__);
  return fake_osi_alarm_set_on_mloop_.cb != nullptr;

  auto iter =
          find_if(previous_fake_osi_alarms_.begin(), previous_fake_osi_alarms_.end(),
                  [alarm](auto const& a) {
                    bluetooth::log::debug("iter: {} == {} ?", fmt::ptr(a.alarm), fmt::ptr(alarm));
                    return a.alarm == alarm;
                  });
  if (iter != previous_fake_osi_alarms_.end()) {
    return true;
  }

  bluetooth::log::debug(" {} == {} ?", fmt::ptr(fake_osi_alarm_set_on_mloop_.alarm),
                        fmt::ptr(alarm));

  return fake_osi_alarm_set_on_mloop_.alarm == alarm;
}
uint64_t alarm_get_remaining_ms(const alarm_t* alarm) {
  inc_func_call_count(__func__);
  return 0;
}
void alarm_cancel(alarm_t* alarm) {
  inc_func_call_count(__func__);

static void fake_osi_alarm_clear(alarm_t* alarm) {
  if (alarm != nullptr) {
    auto iter = find_if(previous_fake_osi_alarms_.begin(), previous_fake_osi_alarms_.end(),
                        [alarm](auto const& a) { return a.alarm == alarm; });
    if (iter != previous_fake_osi_alarms_.end()) {
      bluetooth::log::debug(" clearing alarm {} ", fmt::ptr(iter->alarm));
      previous_fake_osi_alarms_.erase(iter);
      return;
    }
  }

  if (fake_osi_alarm_set_on_mloop_.alarm == alarm || alarm == nullptr) {
    bluetooth::log::debug(" clearing alarm {} ", fmt::ptr(alarm));
    fake_osi_alarm_set_on_mloop_.alarm = nullptr;
    fake_osi_alarm_set_on_mloop_.interval_ms = 0;
    fake_osi_alarm_set_on_mloop_.cb = nullptr;
    fake_osi_alarm_set_on_mloop_.data = nullptr;
  }
void alarm_cleanup(void) { inc_func_call_count(__func__); }
}

void alarm_cancel(alarm_t* alarm) {
  inc_func_call_count(__func__);
  fake_osi_alarm_clear(alarm);
}

void alarm_cleanup(void) {
  previous_fake_osi_alarms_.clear();
  fake_osi_alarm_clear(nullptr);

  inc_func_call_count(__func__);
}
void alarm_debug_dump(int fd) { inc_func_call_count(__func__); }
void alarm_free(alarm_t* alarm) {
  fake_osi_alarm_clear(alarm);
  uint8_t* ptr = (uint8_t*)alarm;
  delete[] ptr;
  inc_func_call_count(__func__);
@@ -363,6 +410,14 @@ void alarm_set(alarm_t* alarm, uint64_t interval_ms, alarm_callback_t cb, void*

void alarm_set_on_mloop(alarm_t* alarm, uint64_t interval_ms, alarm_callback_t cb, void* data) {
  inc_func_call_count(__func__);

  if (fake_osi_alarm_set_on_mloop_.alarm != nullptr) {
    bluetooth::log::info("Queuing alarm {}", fmt::ptr(fake_osi_alarm_set_on_mloop_.alarm));
    previous_fake_osi_alarms_.push_back(fake_osi_alarm_set_on_mloop_);
  }

  bluetooth::log::info("Adding alarm {}", fmt::ptr(alarm));
  fake_osi_alarm_set_on_mloop_.alarm = alarm;
  fake_osi_alarm_set_on_mloop_.interval_ms = interval_ms;
  fake_osi_alarm_set_on_mloop_.cb = cb;
  fake_osi_alarm_set_on_mloop_.data = data;