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

Commit 7af879bd authored by Jakub Tyszkowski's avatar Jakub Tyszkowski
Browse files

LeAudio: Do not attach not fully connected group member

AssignCIS is failing during the attach if the device is not considered
fully connected (there are still pending some initial operations like
charateristic reads). We should attach this device later, when fully
initialized and ready. Attach will be triggered when the device changes
state to CONNECTED.

Bug: 364993085
Test: atest bluetooth_le_audio_client_test
Flag: EXEMPT; regression coverred with unit tests; new test added

Change-Id: I90d6119ebb5dbf31c503d65aed9073c7b1a18742
parent 19410862
Loading
Loading
Loading
Loading
+6 −10
Original line number Diff line number Diff line
@@ -1973,16 +1973,6 @@ public:
        return;
      }

      if (leAudioDevice->HaveActiveAse()) {
        /* Do nothing, device is streaming */
        return;
      }

      if (leAudioDevice->GetConnectionState() != DeviceConnectState::CONNECTED) {
        /* Do nothing, wait until device is connected */
        return;
      }

      AttachToStreamingGroupIfNeeded(leAudioDevice);

    } else if (hdl == leAudioDevice->audio_supp_cont_hdls_.val_hdl) {
@@ -3073,6 +3063,12 @@ public:
      return;
    }

    if (leAudioDevice->GetConnectionState() != DeviceConnectState::CONNECTED) {
      /* Do nothing, wait until device is connected */
      log::debug("{} is not yet connected", leAudioDevice->address_);
      return;
    }

    if (leAudioDevice->HaveActiveAse()) {
      log::debug("{} is already configured, nothing to do", leAudioDevice->address_);
      return;
+61 −0
Original line number Diff line number Diff line
@@ -8437,6 +8437,67 @@ TEST_F(UnicastTest, LateStreamConnectBasedOnContextType) {
  SyncOnMainLoop();
}
TEST_F(UnicastTest, LateStreamConnectBasedOnContextTypeNotFullyConnected) {
  uint8_t group_size = 2;
  int group_id = 2;
  /* Scenario
   * 1. Device A is connected
   * 2. Stream creation to Device A has been started
   * 3. Stream is stopped
   * 4. Device B is connected but has ongoing operations of available context types read.
   * 5. Device B sends available context type  read response
   * 6. Make sure AttachToStream was NOT called for Device B since it is not in a CONNECTED state
   * yet
   */
  // Report working CSIS
  ON_CALL(mock_csis_client_module_, IsCsisClientRunning()).WillByDefault(Return(true));
  ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id))
          .WillByDefault(Invoke([&](int group_id) { return group_size; }));
  const RawAddress test_address0 = GetTestAddress(0);
  const RawAddress test_address1 = GetTestAddress(1);
  // First earbud connects
  ConnectCsisDevice(test_address0, 1 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontLeft,
                    codec_spec_conf::kLeAudioLocationFrontLeft, group_size, group_id, 1 /* rank*/);
  // Start streaming
  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();
  StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id);
  auto group = streaming_groups.at(group_id);
  // Stop streaming - simulate suspend timeout passed, alarm executing
  StopStreaming(group_id);
  fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data);
  SyncOnMainLoop();
  // Second earbud connects and is set to Getting Ready state
  ConnectCsisDevice(test_address1, 2 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontRight,
                    codec_spec_conf::kLeAudioLocationFrontRight, group_size, group_id, 2 /* rank*/,
                    true /*connect_through_csis*/);
  auto device1 = group->GetNextDevice(group->GetFirstDevice());
  device1->SetConnectionState(DeviceConnectState::CONNECTED_AUTOCONNECT_GETTING_READY);
  // Resume but block the final streaming state - keep the group in transition
  block_streaming_state_callback = true;
  UpdateLocalSourceMetadata(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC);
  LocalAudioSourceResume(false);
  // Do not expect to attach the device on context update as it is not fully connected
  EXPECT_CALL(mock_state_machine_, AttachToStream(_, _, _)).Times(0);
  InjectAvailableContextTypes(test_address1, 2, types::kLeAudioContextAllRemoteSinkOnly,
                              types::AudioContexts(0), false);
  Mock::VerifyAndClearExpectations(&mock_state_machine_);
  SyncOnMainLoop();
}
TEST_F(UnicastTest, CheckDeviceIsNotAttachedToStreamWhenNotNeeded) {
  uint8_t group_size = 2;
  int group_id = 2;