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

Commit b07f97b7 authored by Krzysztof Kopyściński's avatar Krzysztof Kopyściński
Browse files

le_audio: Don't set group as inactive when device remains connected

In OnLeAudioDeviceSetStateTimeout, when target state was Idle, and some
of the devices in group reached it, they won't be disconnected. Because
of that, group has still connected devices and shall not be set as
inactive.

Bug: 379000118
Flag: EXEMPT, regression verified with unit test
Test: atest --host --no-bazel-mode bluetooth_le_audio_client_test
Change-Id: I1dfe24ed39ca7d9e9cc016be935957cef134f9fc
parent b62ca748
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -690,7 +690,8 @@ public:
      leAudioDevice = group->GetNextActiveDevice(leAudioDevice);
    } while (leAudioDevice);

    if (recovery) {
    if (recovery && !group->NumOfConnected()) {
      log::info("All devices disconnected, group becomes inactive");
      /* Both devices will  be disconnected soon. Notify upper layer that group
       * is inactive */
      groupSetAndNotifyInactive();
+65 −0
Original line number Diff line number Diff line
@@ -9856,6 +9856,71 @@ TEST_F(UnicastTest, TwoEarbudsStreamingProfileDisconnectStreamStopTimeout) {
  ASSERT_NE(device->GetConnectionState(), DeviceConnectState::DISCONNECTING_AND_RECOVER);
}
TEST_F(UnicastTest, TwoEarbudsStreamingProfileDisconnectForSingleEarbudStreamStopTimeout) {
  uint8_t group_size = 2;
  int group_id = 2;
  // 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; }));
  // First earbud
  const RawAddress test_address0 = GetTestAddress(0);
  ConnectCsisDevice(test_address0, 1 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontLeft,
                    codec_spec_conf::kLeAudioLocationFrontLeft, group_size, group_id, 1 /* rank*/);
  // Second earbud
  const RawAddress test_address1 = GetTestAddress(1);
  ConnectCsisDevice(test_address1, 2 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontRight,
                    codec_spec_conf::kLeAudioLocationFrontRight, group_size, group_id, 2 /* rank*/,
                    true /*connect_through_csis*/);
  // 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();
  /* Use StartStream to generate situation when target state is IDLE, one device is streaming and
   * other one reached IDLE state.
   */
  ON_CALL(mock_state_machine_, StartStream(_, _, _, _))
          .WillByDefault([this](LeAudioDeviceGroup* group,
                                types::LeAudioContextType /* context_type */,
                                types::BidirectionalPair<
                                        types::AudioContexts> /* metadata_context_types */,
                                types::BidirectionalPair<std::vector<uint8_t>> /* ccid_lists */) {
            group->SetTargetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
            auto group_state = group->GetState();
            LeAudioDevice* device = group->GetFirstDevice();
            for (auto& ase : device->ases_) {
              ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING;
              ase.active = true;
            }
            device = group->GetNextDevice(device);
            for (auto& ase : device->ases_) {
              ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE;
              ase.active = false;
            }
            state_machine_callbacks_->OnStateTransitionTimeout(group->group_id_);
            return true;
          });
  // Do not accept direct connect, but expect it to arrive.
  ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, _)).WillByDefault(Return());
  EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(_, _)).Times(1);
  EXPECT_CALL(mock_audio_hal_client_callbacks_, OnGroupStatus(group_id, GroupStatus::INACTIVE))
          .Times(0);
  StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id, AUDIO_SOURCE_INVALID, false,
                 false);
  SyncOnMainLoop();
}
TEST_F(UnicastTest, EarbudsWithStereoSinkMonoSourceSupporting32kHz) {
  const RawAddress test_address0 = GetTestAddress(0);
  int group_id = 0;