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

Commit aa10506e authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "leaudio: Fix adding back to stream reconnected device"

parents 94bfeecd feaa5ff0
Loading
Loading
Loading
Loading
+59 −4
Original line number Diff line number Diff line
@@ -563,6 +563,40 @@ class UnicastTestNoInit : public Test {
          return true;
        });

    ON_CALL(mock_state_machine_, AttachToStream(_, _))
        .WillByDefault([this](LeAudioDeviceGroup* group,
                              LeAudioDevice* leAudioDevice) {
          if (group->GetState() !=
              types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
            return false;
          }
          auto* stream_conf = &group->stream_conf;
          for (auto& ase : leAudioDevice->ases_) {
            if (!ase.active) continue;

            // And also skip the ase establishment procedure which should
            // be tested as part of the state machine unit tests
            ase.data_path_state =
                types::AudioStreamDataPathState::DATA_PATH_ESTABLISHED;
            ase.cis_conn_hdl = iso_con_counter_++;
            ase.active = true;
            ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING;

            /* Copied from state_machine.cc Enabling->Streaming*/
            if (ase.direction == le_audio::types::kLeAudioDirectionSource) {
              stream_conf->source_streams.emplace_back(
                  std::make_pair(ase.cis_conn_hdl,
                                 *ase.codec_config.audio_channel_allocation));
            } else {
              stream_conf->sink_streams.emplace_back(
                  std::make_pair(ase.cis_conn_hdl,
                                 *ase.codec_config.audio_channel_allocation));
            }
          }

          return true;
        });

    ON_CALL(mock_state_machine_, StartStream(_, _))
        .WillByDefault([this](LeAudioDeviceGroup* group,
                              types::LeAudioContextType context_type) {
@@ -681,8 +715,10 @@ class UnicastTestNoInit : public Test {
              if (ases_pair.sink) {
                ases_pair.sink->data_path_state =
                    types::AudioStreamDataPathState::CIS_ASSIGNED;
                ases_pair.sink->active = false;
              }
              if (ases_pair.source) {
                ases_pair.source->active = false;
                ases_pair.source->data_path_state =
                    types::AudioStreamDataPathState::CIS_ASSIGNED;
              }
@@ -965,7 +1001,8 @@ class UnicastTestNoInit : public Test {
                         uint32_t sink_audio_allocation,
                         uint32_t source_audio_allocation, uint8_t group_size,
                         int group_id, uint8_t rank,
                         bool connect_through_csis = false) {
                         bool connect_through_csis = false,
                         bool new_device = true) {
    SetSampleDatabaseEarbudsValid(conn_id, addr, sink_audio_allocation,
                                  source_audio_allocation, true, /*add_csis*/
                                  true,                          /*add_cas*/
@@ -976,9 +1013,11 @@ class UnicastTestNoInit : public Test {
                OnConnectionState(ConnectionState::CONNECTED, addr))
        .Times(1);

    if (new_device) {
      EXPECT_CALL(mock_client_callbacks_,
                  OnGroupNodeStatus(addr, group_id, GroupNodeStatus::ADDED))
          .Times(1);
    }

    if (connect_through_csis) {
      // Add it the way CSIS would do: add to group and then connect
@@ -2843,6 +2882,22 @@ TEST_F(UnicastTest, TwoEarbuds2ndDisconnect) {
  cis_count_out = 1;
  cis_count_in = 0;
  TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920);

  // Reconnect the disconnected device
  auto rank = 1;
  auto location = codec_spec_conf::kLeAudioLocationFrontLeft;
  if (device->address_ == test_address1) {
    rank = 2;
    location = codec_spec_conf::kLeAudioLocationFrontRight;
  }
  ConnectCsisDevice(device->address_, 3 /*conn_id*/, location, location,
                    group_size, group_id, rank, true /*connect_through_csis*/,
                    false /* New device */);

  // Expect two iso channels to be fed with data
  cis_count_out = 2;
  cis_count_in = 0;
  TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920);
}

}  // namespace
+1 −1
Original line number Diff line number Diff line
@@ -1657,6 +1657,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {

    if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
      /* We are here because of the reconnection of the single device. */
      ase->state = AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING;
      CisCreateForDevice(leAudioDevice);
      return;
    }
@@ -1716,7 +1717,6 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {

        if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
          /* We are here because of the reconnection of the single device. */
          CisCreateForDevice(leAudioDevice);
          return;
        }

+139 −0
Original line number Diff line number Diff line
@@ -2290,5 +2290,144 @@ TEST_F(StateMachineTest, testConfigureDataPathForAdsp) {
  ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
      group, static_cast<types::LeAudioContextType>(context_type)));
}

static void InjectCisDisconnected(LeAudioDeviceGroup* group,
                                  LeAudioDevice* leAudioDevice) {
  bluetooth::hci::iso_manager::cis_disconnected_evt event;

  auto* ase = leAudioDevice->GetFirstActiveAse();
  while (ase) {
    event.reason = 0x08;
    event.cig_id = group->group_id_;
    event.cis_conn_hdl = ase->cis_conn_hdl;
    LeAudioGroupStateMachine::Get()->ProcessHciNotifCisDisconnected(
        group, leAudioDevice, &event);

    ase = leAudioDevice->GetNextActiveAse(ase);
  }
}

static void InjectAclDisconnected(LeAudioDeviceGroup* group,
                                  LeAudioDevice* leAudioDevice) {
  LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected(
      group, leAudioDevice);
}

TEST_F(StateMachineTest, testAttachDeviceToTheStream) {
  const auto context_type = kContextTypeMedia;
  const auto leaudio_group_id = 6;
  const auto num_devices = 2;

  // Prepare multiple fake connected devices in a group
  auto* group =
      PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
  ASSERT_EQ(group->Size(), num_devices);

  PrepareConfigureCodecHandler(group);
  PrepareConfigureQosHandler(group);
  PrepareEnableHandler(group);
  PrepareDisableHandler(group);
  PrepareReleaseHandler(group);

  auto* leAudioDevice = group->GetFirstDevice();
  LeAudioDevice* lastDevice;

  auto expected_devices_written = 0;
  while (leAudioDevice) {
    /* Three Writes:
     * 1: Codec Config
     * 2: Codec QoS
     * 3: Enabling
     */
    lastDevice = leAudioDevice;
    EXPECT_CALL(gatt_queue,
                WriteCharacteristic(leAudioDevice->conn_id_,
                                    leAudioDevice->ctp_hdls_.val_hdl, _,
                                    GATT_WRITE_NO_RSP, _, _))
        .Times(AtLeast(3));
    expected_devices_written++;
    leAudioDevice = group->GetNextDevice(leAudioDevice);
  }
  ASSERT_EQ(expected_devices_written, num_devices);

  EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
  EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2);
  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);

  InjectInitialIdleNotification(group);

  // Start the configuration and stream Media content
  LeAudioGroupStateMachine::Get()->StartStream(
      group, static_cast<types::LeAudioContextType>(context_type));

  // Check if group has transitioned to a proper state
  ASSERT_EQ(group->GetState(),
            types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);

  // Inject CIS and ACL disconnection of first device
  InjectCisDisconnected(group, lastDevice);
  InjectAclDisconnected(group, lastDevice);

  // Check if group keeps streaming
  ASSERT_EQ(group->GetState(),
            types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);

  lastDevice->conn_id_ = 3;
  group->UpdateActiveContextsMap();
  auto* stream_conf = &group->stream_conf;

  /* Second device got reconnect. Try to get it to the stream seamlessly
   * Code take from client.cc
   */
  le_audio::types::AudioLocations sink_group_audio_locations = 0;
  uint8_t sink_num_of_active_ases = 0;

  for (auto [cis_handle, audio_location] : stream_conf->sink_streams) {
    sink_group_audio_locations |= audio_location;
    sink_num_of_active_ases++;
  }

  le_audio::types::AudioLocations source_group_audio_locations = 0;
  uint8_t source_num_of_active_ases = 0;

  for (auto [cis_handle, audio_location] : stream_conf->source_streams) {
    source_group_audio_locations |= audio_location;
    source_num_of_active_ases++;
  }

  for (auto& ent : stream_conf->conf->confs) {
    if (ent.direction == le_audio::types::kLeAudioDirectionSink) {
      /* Sink*/
      if (!lastDevice->ConfigureAses(
              ent, group->GetCurrentContextType(), &sink_num_of_active_ases,
              sink_group_audio_locations, source_group_audio_locations, true)) {
        LOG(INFO) << __func__ << " Could not set sink configuration of "
                  << stream_conf->conf->name;
        return;
      }
    } else {
      /* Source*/
      if (!lastDevice->ConfigureAses(
              ent, group->GetCurrentContextType(), &source_num_of_active_ases,
              sink_group_audio_locations, source_group_audio_locations, true)) {
        LOG(INFO) << __func__ << " Could not set source configuration of "
                  << stream_conf->conf->name;
        return;
      }
    }
  }

  EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
                                              lastDevice->ctp_hdls_.val_hdl, _,
                                              GATT_WRITE_NO_RSP, _, _))
      .Times(AtLeast(3));

  LeAudioGroupStateMachine::Get()->AttachToStream(group, lastDevice);

  // Check if group keeps streaming
  ASSERT_EQ(group->GetState(),
            types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
}

}  // namespace internal
}  // namespace le_audio