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

Commit da676c60 authored by Łukasz Rymanowski's avatar Łukasz Rymanowski Committed by Patty Huang
Browse files

leaudio: Allow to configure AF for more than 16kHz for Microphone

With this patch, if LeAudio group supports more than 16kHz for the
Microphone in the CONVERSATIONAL scenario, bluetooth stack will
configure Audio Framework to receive best possible sample frequency.

Bug: 230550335
Test: atest --host bluetooth_le_audio_test
bluetooth_le_audio_client_test
Sponsor: @jpawlowski

Change-Id: I653f0fa414fbaf783e65e99210e47ab38dc6a700
(cherry picked from commit c6365d8b)
Merged-In: I653f0fa414fbaf783e65e99210e47ab38dc6a700
parent 70b8404b
Loading
Loading
Loading
Loading
+48 −10
Original line number Diff line number Diff line
@@ -684,6 +684,52 @@ class LeAudioClientImpl : public LeAudioClient {
    // TODO Implement
  }

  void StartAudioSession(LeAudioDeviceGroup* group,
                          LeAudioCodecConfiguration* source_config,
                          LeAudioCodecConfiguration* sink_config) {
    /* This function is called when group is not yet set to active.
     * This is why we don't have to check if session is started already.
     * Just check if it is acquired.
     */
    ASSERT_LOG(active_group_id_ == bluetooth::groups::kGroupUnknown,
               "Active group is not set.");
    ASSERT_LOG(audio_source_instance_, "Source session not acquired");
    ASSERT_LOG(audio_sink_instance_, "Sink session not acquired");

    /* We assume that peer device always use same frame duration */
    uint32_t frame_duration_us = 0;
    if (!source_config->IsInvalid()) {
      frame_duration_us = source_config->data_interval_us;
    } else if (!sink_config->IsInvalid()) {
      frame_duration_us = sink_config->data_interval_us;
    } else {
      ASSERT_LOG(true, "Both configs are invalid");
    }

    audio_framework_source_config.data_interval_us = frame_duration_us;
    leAudioClientAudioSource->Start(audio_framework_source_config,
                                    audioSinkReceiver);

    /* We use same frame duration for sink/source */
    audio_framework_sink_config.data_interval_us = frame_duration_us;

    /* If group supports more than 16kHz for the microphone in converstional
     * case let's use that also for Audio Framework.
     */
    std::optional<LeAudioCodecConfiguration> sink_configuration =
        group->GetCodecConfigurationByDirection(
            LeAudioContextType::CONVERSATIONAL,
            le_audio::types::kLeAudioDirectionSource);
    if (sink_configuration &&
        sink_configuration->sample_rate >
            bluetooth::audio::le_audio::kSampleRate16000) {
      audio_framework_sink_config.sample_rate = sink_configuration->sample_rate;
    }

    leAudioClientAudioSink->Start(audio_framework_sink_config,
                                  audioSourceReceiver);
  }

  void GroupSetActive(const int group_id) override {
    DLOG(INFO) << __func__ << " group_id: " << group_id;

@@ -752,16 +798,8 @@ class LeAudioClientImpl : public LeAudioClient {

    if (active_group_id_ == bluetooth::groups::kGroupUnknown) {
      /* Expose audio sessions if there was no previous active group */
      audio_framework_source_config.data_interval_us =
          current_source_codec_config.data_interval_us;
      leAudioClientAudioSource->Start(audio_framework_source_config,
                                      audioSinkReceiver);

      audio_framework_sink_config.data_interval_us =
          current_source_codec_config.data_interval_us;

      leAudioClientAudioSink->Start(audio_framework_sink_config,
                                    audioSourceReceiver);
      StartAudioSession(group, &current_source_codec_config,
                         &current_sink_codec_config);
    } else {
      /* In case there was an active group. Stop the stream */
      GroupStop(active_group_id_);
+7 −0
Original line number Diff line number Diff line
@@ -96,6 +96,13 @@ struct LeAudioCodecConfiguration {
             (data_interval_us == other.data_interval_us));
  }

  bool operator==(const LeAudioCodecConfiguration& other) const {
    return ((num_channels == other.num_channels) &&
            (sample_rate == other.sample_rate) &&
            (bits_per_sample == other.bits_per_sample) &&
            (data_interval_us == other.data_interval_us));
  }

  bool IsInvalid() {
    return (num_channels == 0) || (sample_rate == 0) ||
           (bits_per_sample == 0) || (data_interval_us == 0);
+100 −54
Original line number Diff line number Diff line
@@ -1032,7 +1032,9 @@ class UnicastTestNoInit : public Test {
                         bool connect_through_csis = false,
                         bool new_device = true) {
    SetSampleDatabaseEarbudsValid(conn_id, addr, sink_audio_allocation,
                                  source_audio_allocation, true, /*add_csis*/
                                  source_audio_allocation,
                                  0x0004, /* source sample freq 16khz */
                                  true,   /*add_csis*/
                                  true,   /*add_cas*/
                                  true,   /*add_pacs*/
                                  true,   /*add_ascs*/
@@ -1066,8 +1068,9 @@ class UnicastTestNoInit : public Test {
  void ConnectNonCsisDevice(const RawAddress& addr, uint16_t conn_id,
                            uint32_t sink_audio_allocation,
                            uint32_t source_audio_allocation) {
    SetSampleDatabaseEarbudsValid(conn_id, addr, sink_audio_allocation,
                                  source_audio_allocation, false, /*add_csis*/
    SetSampleDatabaseEarbudsValid(
        conn_id, addr, sink_audio_allocation, source_audio_allocation, 0x0004,
        /* source sample freq 16khz */ false, /*add_csis*/
        true,                                 /*add_cas*/
        true,                                 /*add_pacs*/
        true,                                 /*add_ascs*/
@@ -1358,6 +1361,7 @@ class UnicastTestNoInit : public Test {
  void SetSampleDatabaseEarbudsValid(uint16_t conn_id, RawAddress addr,
                                     uint32_t sink_audio_allocation,
                                     uint32_t source_audio_allocation,
                                     uint16_t sample_freq_mask = 0x0004,
                                     bool add_csis = true, bool add_cas = true,
                                     bool add_pacs = true, bool add_ascs = true,
                                     uint8_t set_size = 2, uint8_t rank = 1) {
@@ -1438,10 +1442,14 @@ class UnicastTestNoInit : public Test {
      src_allocation[2] = (uint8_t)(source_audio_allocation >> 16);
      src_allocation[3] = (uint8_t)(source_audio_allocation >> 24);

      uint8_t sample_freq[2];
      sample_freq[0] = (uint8_t)(sample_freq_mask);
      sample_freq[1] = (uint8_t)(sample_freq_mask >> 8);

      // Set pacs default read values
      ON_CALL(*peer_devices.at(conn_id)->pacs, OnReadCharacteristic(_, _, _))
          .WillByDefault(
              [this, conn_id, snk_allocation, src_allocation](
              [this, conn_id, snk_allocation, src_allocation, sample_freq](
                  uint16_t handle, GATT_READ_OP_CB cb, void* cb_data) {
                auto& pacs = peer_devices.at(conn_id)->pacs;
                std::vector<uint8_t> value;
@@ -1459,8 +1467,8 @@ class UnicastTestNoInit : public Test {
                      0x10,
                      0x03,
                      0x01,
                      0x04,
                      0x00,
                      sample_freq[0],
                      sample_freq[1],
                      0x02,
                      0x02,
                      0x03,
@@ -1471,7 +1479,7 @@ class UnicastTestNoInit : public Test {
                      0x04,
                      0x1E,
                      0x00,
                      0x28,
                      0x78,
                      0x00,
                      // Metadata Length
                      0x00,
@@ -1524,8 +1532,8 @@ class UnicastTestNoInit : public Test {
                      0x10,
                      0x03,
                      0x01,
                      0x04,
                      0x00,
                      sample_freq[0],
                      sample_freq[1],
                      0x02,
                      0x02,
                      0x03,
@@ -1536,7 +1544,7 @@ class UnicastTestNoInit : public Test {
                      0x04,
                      0x1E,
                      0x00,
                      0x28,
                      0x78,
                      0x00,
                      // Metadata Length
                      0x00,
@@ -1850,7 +1858,8 @@ TEST_F(UnicastTest, ConnectOneEarbudNoPacs) {
  const RawAddress test_address0 = GetTestAddress(0);
  SetSampleDatabaseEarbudsValid(
      1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, true, /*add_csis*/
      codec_spec_conf::kLeAudioLocationStereo, 0x0004,
      /* source sample freq 16khz */ true, /*add_csis*/
      true,                                /*add_cas*/
      false,                               /*add_pacs*/
      true /*add_ascs*/);
@@ -1865,7 +1874,8 @@ TEST_F(UnicastTest, ConnectOneEarbudNoAscs) {
  const RawAddress test_address0 = GetTestAddress(0);
  SetSampleDatabaseEarbudsValid(
      1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, true, /*add_csis*/
      codec_spec_conf::kLeAudioLocationStereo, 0x0004,
      /* source sample freq 16khz */ true, /*add_csis*/
      true,                                /*add_cas*/
      true,                                /*add_pacs*/
      false /*add_ascs*/);
@@ -1881,7 +1891,8 @@ TEST_F(UnicastTest, ConnectOneEarbudNoCas) {
  uint16_t conn_id = 1;
  SetSampleDatabaseEarbudsValid(
      conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, true, /*add_csis*/
      codec_spec_conf::kLeAudioLocationStereo, 0x0004,
      /* source sample freq 16khz */ true, /*add_csis*/
      false,                               /*add_cas*/
      true,                                /*add_pacs*/
      true /*add_ascs*/);
@@ -1896,7 +1907,8 @@ TEST_F(UnicastTest, ConnectOneEarbudNoCsis) {
  const RawAddress test_address0 = GetTestAddress(0);
  SetSampleDatabaseEarbudsValid(
      1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, false, /*add_csis*/
      codec_spec_conf::kLeAudioLocationStereo, 0x0004,
      /* source sample freq 16khz */ false, /*add_csis*/
      true,                                 /*add_cas*/
      true,                                 /*add_pacs*/
      true /*add_ascs*/);
@@ -2039,7 +2051,8 @@ TEST_F(UnicastTestNoInit, LoadStoredEarbudsCsisGrouped) {
  const RawAddress test_address0 = GetTestAddress(0);
  SetSampleDatabaseEarbudsValid(
      1, test_address0, codec_spec_conf::kLeAudioLocationFrontLeft,
      codec_spec_conf::kLeAudioLocationFrontLeft, true, /*add_csis*/
      codec_spec_conf::kLeAudioLocationFrontLeft, 0x0004,
      /* source sample freq 16khz */ true, /*add_csis*/
      true,                                /*add_cas*/
      true,                                /*add_pacs*/
      true,                                /*add_ascs*/
@@ -2048,7 +2061,8 @@ TEST_F(UnicastTestNoInit, LoadStoredEarbudsCsisGrouped) {
  const RawAddress test_address1 = GetTestAddress(1);
  SetSampleDatabaseEarbudsValid(
      2, test_address1, codec_spec_conf::kLeAudioLocationFrontRight,
      codec_spec_conf::kLeAudioLocationFrontRight, true, /*add_csis*/
      codec_spec_conf::kLeAudioLocationFrontRight, 0x0004,
      /* source sample freq 16khz */ true, /*add_csis*/
      true,                                /*add_cas*/
      true,                                /*add_pacs*/
      true,                                /*add_ascs*/
@@ -2134,7 +2148,8 @@ TEST_F(UnicastTestNoInit, LoadStoredEarbudsCsisGroupedDifferently) {
  const RawAddress test_address0 = GetTestAddress(0);
  SetSampleDatabaseEarbudsValid(
      1, test_address0, codec_spec_conf::kLeAudioLocationFrontLeft,
      codec_spec_conf::kLeAudioLocationFrontLeft, true, /*add_csis*/
      codec_spec_conf::kLeAudioLocationFrontLeft, 0x0004,
      /* source sample freq 16khz */ true, /*add_csis*/
      true,                                /*add_cas*/
      true,                                /*add_pacs*/
      true,                                /*add_ascs*/
@@ -2149,7 +2164,8 @@ TEST_F(UnicastTestNoInit, LoadStoredEarbudsCsisGroupedDifferently) {
  const RawAddress test_address1 = GetTestAddress(1);
  SetSampleDatabaseEarbudsValid(
      2, test_address1, codec_spec_conf::kLeAudioLocationFrontRight,
      codec_spec_conf::kLeAudioLocationFrontRight, true, /*add_csis*/
      codec_spec_conf::kLeAudioLocationFrontRight, 0x0004,
      /* source sample freq 16khz */ true, /*add_csis*/
      true,                                /*add_cas*/
      true,                                /*add_pacs*/
      true,                                /*add_ascs*/
@@ -2469,9 +2485,9 @@ TEST_F(UnicastTest, RemoveWhileStreaming) {

  SetSampleDatabaseEarbudsValid(
      1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, false /*add_csis*/,
      true /*add_cas*/, true /*add_pacs*/, true /*add_ascs*/, 1 /*set_size*/,
      0 /*rank*/);
      codec_spec_conf::kLeAudioLocationStereo, 0x0004,
      /* source sample freq 16khz */ false /*add_csis*/, true /*add_cas*/,
      true /*add_pacs*/, true /*add_ascs*/, 1 /*set_size*/, 0 /*rank*/);
  EXPECT_CALL(mock_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
      .Times(1);
@@ -2534,9 +2550,9 @@ TEST_F(UnicastTest, SpeakerStreaming) {

  SetSampleDatabaseEarbudsValid(
      1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, false /*add_csis*/,
      true /*add_cas*/, true /*add_pacs*/, true /*add_ascs*/, 1 /*set_size*/,
      0 /*rank*/);
      codec_spec_conf::kLeAudioLocationStereo, 0x0004,
      /* source sample freq 16khz */ false /*add_csis*/, true /*add_cas*/,
      true /*add_pacs*/, true /*add_ascs*/, 1 /*set_size*/, 0 /*rank*/);
  EXPECT_CALL(mock_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
      .Times(1);
@@ -2594,9 +2610,9 @@ TEST_F(UnicastTest, SpeakerStreamingAutonomousRelease) {

  SetSampleDatabaseEarbudsValid(
      1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, false /*add_csis*/,
      true /*add_cas*/, true /*add_pacs*/, true /*add_ascs*/, 1 /*set_size*/,
      0 /*rank*/);
      codec_spec_conf::kLeAudioLocationStereo, 0x0004,
      /* source sample freq 16khz */ false /*add_csis*/, true /*add_cas*/,
      true /*add_pacs*/, true /*add_ascs*/, 1 /*set_size*/, 0 /*rank*/);
  EXPECT_CALL(mock_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
      .Times(1);
@@ -3008,5 +3024,35 @@ TEST_F(UnicastTest, TwoEarbudsStreamingProfileDisconnect) {
  Mock::VerifyAndClearExpectations(&mock_client_callbacks_);
}

TEST_F(UnicastTest, TwoEarbudsWithSourceSupporting32kHz) {
  const RawAddress test_address0 = GetTestAddress(0);
  int group_id = 0;
  SetSampleDatabaseEarbudsValid(
      1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, 0x0024,
      /* source sample freq 32/16khz */ true, /*add_csis*/
      true,                                   /*add_cas*/
      true,                                   /*add_pacs*/
      true /*add_ascs*/);
  EXPECT_CALL(mock_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
      .Times(1);
  ConnectLeAudio(test_address0);

  // LeAudioCodecConfiguration received_af_sink_config;
  const LeAudioCodecConfiguration expected_af_sink_config = {
      .num_channels = 2,
      .sample_rate = bluetooth::audio::le_audio::kSampleRate32000,
      .bits_per_sample = bluetooth::audio::le_audio::kBitsPerSample16,
      .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us,
  };

  // Audio sessions are started only when device gets active
  EXPECT_CALL(*mock_unicast_audio_source_, Start(_, _)).Times(1);
  EXPECT_CALL(*mock_audio_sink_, Start(expected_af_sink_config, _)).Times(1);
  LeAudioClient::Get()->GroupSetActive(group_id);
  SyncOnMainLoop();
}

}  // namespace
}  // namespace le_audio