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

Commit b4707b67 authored by Łukasz Rymanowski's avatar Łukasz Rymanowski Committed by Gerrit Code Review
Browse files

Merge "laudio: Improve removing and disconnecting leaudio device"

parents 91622504 03e77b40
Loading
Loading
Loading
Loading
+107 −54
Original line number Diff line number Diff line
@@ -1105,10 +1105,37 @@ class LeAudioClientImpl : public LeAudioClient {
      return;
    }

    if (leAudioDevice->conn_id_ != GATT_INVALID_CONN_ID) {
    LOG_INFO("%s, state: %s", ADDRESS_TO_LOGGABLE_CSTR(address),
             bluetooth::common::ToString(leAudioDevice->GetConnectionState())
                 .c_str());
    auto connection_state = leAudioDevice->GetConnectionState();
    switch (connection_state) {
      case DeviceConnectState::REMOVING:
      case DeviceConnectState::PENDING_REMOVAL:
        /* Just return, and let device disconnect */
        return;
      case DeviceConnectState::CONNECTED:
      case DeviceConnectState::CONNECTED_AUTOCONNECT_GETTING_READY:
      case DeviceConnectState::CONNECTED_BY_USER_GETTING_READY:
        /* ACL exist in this case, disconnect and mark as removing */
        Disconnect(address);
        [[fallthrough]];
      case DeviceConnectState::DISCONNECTING:
        /* Remove device from the background connect if it is there */
        BTA_GATTC_CancelOpen(gatt_if_, address, false);
        /* Device is disconnecting, just mark it shall be removed after all. */
        leAudioDevice->SetConnectionState(DeviceConnectState::REMOVING);
        return;
      case DeviceConnectState::CONNECTING_BY_USER:
        BTA_GATTC_CancelOpen(gatt_if_, address, true);
        [[fallthrough]];
      case DeviceConnectState::CONNECTING_AUTOCONNECT:
        /* Cancel background conection */
        BTA_GATTC_CancelOpen(gatt_if_, address, false);
        break;
      case DeviceConnectState::DISCONNECTED:
        /* Do nothing, just remove device  */
        break;
    }

    /* Remove the group assignment if not yet removed. It might happen that the
@@ -1267,24 +1294,27 @@ class LeAudioClientImpl : public LeAudioClient {
    return SerializeAses(leAudioDevice, out);
  }

  void BackgroundConnectIfGroupConnected(LeAudioDevice* leAudioDevice) {
  void BackgroundConnectIfNeeded(LeAudioDevice* leAudioDevice) {
    DLOG(INFO) << __func__ << ADDRESS_TO_LOGGABLE_STR(leAudioDevice->address_);
    auto group = aseGroups_.FindById(leAudioDevice->group_id_);
    if (!group) {
      DLOG(INFO) << __func__ << " Device is not yet part of the group. ";
      LOG_INFO(" Device %s is not yet part of the group %d. ",
               ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_),
               leAudioDevice->group_id_);
      return;
    }

    if (!group->IsAnyDeviceConnected()) {
      DLOG(INFO) << __func__ << " group: " << leAudioDevice->group_id_
                 << " is not connected";
    if (!leAudioDevice->autoconnect_flag_ && !group->IsAnyDeviceConnected()) {
      LOG_DEBUG("Device %s not in the background connect",
                ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
      return;
    }

    DLOG(INFO) << __func__ << " Add "
               << ADDRESS_TO_LOGGABLE_STR(leAudioDevice->address_)
               << " to background connect to connected group: "
               << leAudioDevice->group_id_;
    LOG_INFO(
        "Add %s added to background connect. autoconnect flag: %d "
        "group_connected: %d",
        ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_),
        leAudioDevice->group_id_, group->IsAnyDeviceConnected());

    leAudioDevice->SetConnectionState(
        DeviceConnectState::CONNECTING_AUTOCONNECT);
@@ -1302,28 +1332,31 @@ class LeAudioClientImpl : public LeAudioClient {
      return;
    }

    /* cancel pending direct connect */
    if (leAudioDevice->GetConnectionState() ==
        DeviceConnectState::CONNECTING_BY_USER) {
      BTA_GATTC_CancelOpen(gatt_if_, address, true);
    }

    /* Removes all registrations for connection */
    BTA_GATTC_CancelOpen(0, address, false);
    auto connection_state = leAudioDevice->GetConnectionState();
    LOG_INFO("%s, state: %s", ADDRESS_TO_LOGGABLE_CSTR(address),
             bluetooth::common::ToString(connection_state).c_str());

    if (leAudioDevice->conn_id_ != GATT_INVALID_CONN_ID) {
    switch (connection_state) {
      case DeviceConnectState::CONNECTING_BY_USER:
        /* Timeout happen on the Java layer. Device probably not in the range.
         * Cancel just direct connection and keep background if it is there.
         */
        BTA_GATTC_CancelOpen(gatt_if_, address, true);
        break;
      case DeviceConnectState::CONNECTED: {
        /* User is disconnecting the device, we shall remove the autoconnect
         * flag for this device and all others
         */
        LOG_INFO("Removing autoconnect flag for group_id %d",
                 leAudioDevice->group_id_);

      auto group = aseGroups_.FindById(leAudioDevice->group_id_);

        if (leAudioDevice->autoconnect_flag_) {
          /* Removes device from background connect */
          BTA_GATTC_CancelOpen(gatt_if_, address, false);
          btif_storage_set_leaudio_autoconnect(address, false);
          leAudioDevice->autoconnect_flag_ = false;
        }
        auto group = aseGroups_.FindById(leAudioDevice->group_id_);

        if (group) {
          /* Remove devices from auto connect mode */
@@ -1346,14 +1379,34 @@ class LeAudioClientImpl : public LeAudioClient {
          groupStateMachine_->StopStream(group);
          return;
        }
      }
        [[fallthrough]];
      case DeviceConnectState::CONNECTED_BY_USER_GETTING_READY:
        /* Timeout happen on the Java layer before native got ready with the
         * device */
        DisconnectDevice(leAudioDevice);
        return;
      case DeviceConnectState::CONNECTED_AUTOCONNECT_GETTING_READY:
        /* Java is not aware about autoconnect actions,
         * therefore this should not happen.
         */
        LOG_WARN("Should not happen - disconnect device");
        DisconnectDevice(leAudioDevice);
        return;
      case DeviceConnectState::DISCONNECTED:
      case DeviceConnectState::DISCONNECTING:
      case DeviceConnectState::CONNECTING_AUTOCONNECT:
      case DeviceConnectState::PENDING_REMOVAL:
      case DeviceConnectState::REMOVING:
        LOG_WARN("%s, invalid state %s", ADDRESS_TO_LOGGABLE_CSTR(address),
                 bluetooth::common::ToString(connection_state).c_str());
        break;
    }

    /* If this is a device which is a part of the group which is connected,
     * lets start backgroup connect
     */
    BackgroundConnectIfGroupConnected(leAudioDevice);
    BackgroundConnectIfNeeded(leAudioDevice);
  }

  void DisconnectDevice(LeAudioDevice* leAudioDevice,
+1 −1
Original line number Diff line number Diff line
@@ -2157,7 +2157,7 @@ void LeAudioDeviceGroup::Dump(int fd, int active_group_id) {

/* LeAudioDevice Class methods implementation */
void LeAudioDevice::SetConnectionState(DeviceConnectState state) {
  LOG_DEBUG(" %s --> %s",
  LOG_DEBUG("%s, %s --> %s", ADDRESS_TO_LOGGABLE_CSTR(address_),
            bluetooth::common::ToString(connection_state_).c_str(),
            bluetooth::common::ToString(state).c_str());
  connection_state_ = state;
+212 −1
Original line number Diff line number Diff line
@@ -2266,7 +2266,7 @@ class UnicastTestNoInit : public Test {
  gatt::MockBtaGattQueue mock_gatt_queue_;
  tBTA_GATTC_CBACK* gatt_callback;
  const uint8_t gatt_if = 0xfe;
  uint8_t global_conn_id = 1;
  uint16_t global_conn_id = 1;
  le_audio::LeAudioGroupStateMachine::Callbacks* state_machine_callbacks_;
  std::map<int, LeAudioDeviceGroup*> streaming_groups;

@@ -3164,6 +3164,217 @@ TEST_F(UnicastTest, RemoveTwoEarbudsCsisGrouped) {
  Mock::VerifyAndClearExpectations(&mock_btif_storage_);
}

TEST_F(UnicastTest, RemoveDeviceWhenConnected) {
  const RawAddress test_address0 = GetTestAddress(0);
  int group_id = bluetooth::groups::kGroupUnknown;
  uint16_t conn_id = 1;

  SetSampleDatabaseEarbudsValid(
      conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt,
      default_channel_cnt, 0x0004,
      /* source sample freq 16khz */ 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)));
  EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true))
      .Times(1);
  ConnectLeAudio(test_address0);
  ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown);

  Mock::VerifyAndClearExpectations(&mock_btif_storage_);
  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);

  EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, false))
      .Times(1);
  EXPECT_CALL(mock_gatt_queue_, Clean(conn_id)).Times(AtLeast(1));
  EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1);

  LeAudioClient::Get()->RemoveDevice(test_address0);
  SyncOnMainLoop();

  Mock::VerifyAndClearExpectations(&mock_btif_storage_);
  Mock::VerifyAndClearExpectations(&mock_gatt_queue_);
  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);
}

TEST_F(UnicastTest, RemoveDeviceWhenConnecting) {
  const RawAddress test_address0 = GetTestAddress(0);
  uint16_t conn_id = 1;

  /* Prepare  mock to not inject connect event so the device can stay in
   * CONNECTING state*/
  ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, _))
      .WillByDefault(DoAll(Return()));

  SetSampleDatabaseEarbudsValid(
      conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt,
      default_channel_cnt, 0x0004,
      /* source sample freq 16khz */ 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(0);
  ConnectLeAudio(test_address0);

  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);

  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, true))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false))
      .Times(1);

  LeAudioClient::Get()->RemoveDevice(test_address0);
  SyncOnMainLoop();

  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);
}

TEST_F(UnicastTest, RemoveDeviceWhenGettingConnectionReady) {
  const RawAddress test_address0 = GetTestAddress(0);
  uint16_t conn_id = 1;

  /* Prepare  mock to not inject Service Search Complete*/
  ON_CALL(mock_gatt_interface_, ServiceSearchRequest(_, _))
      .WillByDefault(DoAll(Return()));

  SetSampleDatabaseEarbudsValid(
      conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt,
      default_channel_cnt, 0x0004,
      /* source sample freq 16khz */ 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(0);
  ConnectLeAudio(test_address0);

  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);

  EXPECT_CALL(mock_gatt_queue_, Clean(conn_id)).Times(AtLeast(1));
  EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1);
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false))
      .Times(1);

  LeAudioClient::Get()->RemoveDevice(test_address0);
  SyncOnMainLoop();

  Mock::VerifyAndClearExpectations(&mock_btif_storage_);
  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);
}

TEST_F(UnicastTest, DisconnectDeviceWhenConnected) {
  const RawAddress test_address0 = GetTestAddress(0);
  int group_id = bluetooth::groups::kGroupUnknown;
  uint16_t conn_id = 1;

  SetSampleDatabaseEarbudsValid(
      conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt,
      default_channel_cnt, 0x0004,
      /* source sample freq 16khz */ 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)));
  EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true))
      .Times(1);
  ConnectLeAudio(test_address0);
  ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown);

  Mock::VerifyAndClearExpectations(&mock_btif_storage_);
  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);

  EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, false))
      .Times(1);
  EXPECT_CALL(mock_gatt_queue_, Clean(conn_id)).Times(AtLeast(1));
  EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1);

  LeAudioClient::Get()->Disconnect(test_address0);
  SyncOnMainLoop();

  Mock::VerifyAndClearExpectations(&mock_btif_storage_);
  Mock::VerifyAndClearExpectations(&mock_gatt_queue_);
  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);
}

TEST_F(UnicastTest, DisconnectDeviceWhenConnecting) {
  const RawAddress test_address0 = GetTestAddress(0);
  uint16_t conn_id = 1;

  /* Prepare  mock to not inject connect event so the device can stay in
   * CONNECTING state*/
  ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, _))
      .WillByDefault(DoAll(Return()));

  SetSampleDatabaseEarbudsValid(
      conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt,
      default_channel_cnt, 0x0004,
      /* source sample freq 16khz */ 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(0);
  ConnectLeAudio(test_address0);

  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);

  /* Prepare on call mock on Close - to not trigger Inject Disconnection, as it
   * is done in default mock.
   */
  ON_CALL(mock_gatt_interface_, Close(_)).WillByDefault(DoAll(Return()));
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, true))
      .Times(1);

  LeAudioClient::Get()->Disconnect(test_address0);

  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);
}

TEST_F(UnicastTest, DisconnectDeviceWhenGettingConnectionReady) {
  const RawAddress test_address0 = GetTestAddress(0);
  uint16_t conn_id = global_conn_id;

  /* Prepare  mock to not inject Service Search Complete*/
  ON_CALL(mock_gatt_interface_, ServiceSearchRequest(_, _))
      .WillByDefault(DoAll(Return()));

  SetSampleDatabaseEarbudsValid(
      conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt,
      default_channel_cnt, 0x0004,
      /* source sample freq 16khz */ 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(0);
  ConnectLeAudio(test_address0);

  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);

  EXPECT_CALL(mock_gatt_queue_, Clean(conn_id)).Times(AtLeast(1));
  EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1);
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false))
      .Times(0);

  LeAudioClient::Get()->Disconnect(test_address0);
}

TEST_F(UnicastTest, RemoveWhileStreaming) {
  const RawAddress test_address0 = GetTestAddress(0);
  int group_id = bluetooth::groups::kGroupUnknown;