summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--flags/Android.bp1
-rw-r--r--flags/BUILD.gn1
-rw-r--r--flags/active_device_manager.aconfig9
-rw-r--r--flags/bta_dm.aconfig14
-rw-r--r--flags/btif_dm.aconfig21
-rw-r--r--flags/hfp.aconfig10
-rw-r--r--flags/pairing.aconfig10
-rw-r--r--flags/security.aconfig7
-rw-r--r--framework/tests/bumble/src/android/bluetooth/DckGattTest.kt2
-rw-r--r--framework/tests/bumble/src/android/bluetooth/pairing/PairingTest.java4
-rw-r--r--framework/tests/util/src/Permissions.kt2
-rw-r--r--system/bta/dm/bta_dm_disc.cc9
-rw-r--r--system/bta/dm/bta_dm_disc_legacy.cc11
-rw-r--r--system/bta/hearing_aid/hearing_aid.cc12
-rw-r--r--system/bta/hf_client/bta_hf_client_at.cc2
-rw-r--r--system/bta/le_audio/client.cc23
-rw-r--r--system/bta/le_audio/devices_test.cc110
-rw-r--r--system/bta/le_audio/le_audio_client_test.cc257
-rw-r--r--system/bta/le_audio/le_audio_types.cc4
-rw-r--r--system/bta/le_audio/mock_codec_interface.cc24
-rw-r--r--system/bta/le_audio/mock_codec_interface.h4
-rw-r--r--system/bta/le_audio/state_machine_test.cc161
-rw-r--r--system/btif/include/btif_av.h2
-rw-r--r--system/btif/include/btif_rc.h2
-rw-r--r--system/btif/src/btif_av.cc137
-rw-r--r--system/btif/src/btif_dm.cc48
-rw-r--r--system/gd/rust/linux/stack/src/bluetooth_media.rs23
-rw-r--r--system/gd/rust/topshim/btav_sink/btav_sink_shim.cc2
-rw-r--r--system/log/src/vlog_android.cc3
-rw-r--r--system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc361
-rw-r--r--system/stack/btm/btm_sco_hfp_hal_linux.cc6
-rw-r--r--system/stack/smp/smp_act.cc7
32 files changed, 1016 insertions, 273 deletions
diff --git a/flags/Android.bp b/flags/Android.bp
index f2e05999cf..02c5381966 100644
--- a/flags/Android.bp
+++ b/flags/Android.bp
@@ -10,6 +10,7 @@ aconfig_declarations {
// LINT.IfChange
srcs: [
"a2dp.aconfig",
+ "active_device_manager.aconfig",
"asha.aconfig",
"audio_routing.aconfig",
"avrcp.aconfig",
diff --git a/flags/BUILD.gn b/flags/BUILD.gn
index 319b1b8d14..6e42632f8a 100644
--- a/flags/BUILD.gn
+++ b/flags/BUILD.gn
@@ -4,6 +4,7 @@ aconfig("bluetooth_flags_c_lib") {
# LINT.IfChange
sources = [
"a2dp.aconfig",
+ "active_device_manager.aconfig",
"asha.aconfig",
"audio_routing.aconfig",
"avrcp.aconfig",
diff --git a/flags/active_device_manager.aconfig b/flags/active_device_manager.aconfig
new file mode 100644
index 0000000000..4995951d37
--- /dev/null
+++ b/flags/active_device_manager.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.bluetooth.flags"
+container: "com.android.btservices"
+
+flag {
+ name: "fallback_when_wired_audio_disconnected"
+ namespace: "bluetooth"
+ description: "Fallback to other connected device when wired audio device disconnects"
+ bug: "348124361"
+}
diff --git a/flags/bta_dm.aconfig b/flags/bta_dm.aconfig
index 30264909db..8868063d53 100644
--- a/flags/bta_dm.aconfig
+++ b/flags/bta_dm.aconfig
@@ -9,20 +9,6 @@ flag {
}
flag {
- name: "connect_hid_after_service_discovery"
- namespace: "bluetooth"
- description: "Don't initiate HID connection before pairing and service discovery"
- bug: "314707251"
-}
-
-flag {
- name: "bta_dm_disc_stuck_in_cancelling_fix"
- namespace: "bluetooth"
- description: "Fix being stuck in BTA_DM_SEARCH_CANCELLING"
- bug: "319890673"
-}
-
-flag {
name: "bta_dm_defer_device_discovery_state_change_until_rnr_complete"
namespace: "bluetooth"
description: "Fix double-sending device discovery state change when canceling RNR"
diff --git a/flags/btif_dm.aconfig b/flags/btif_dm.aconfig
index 670036a9b4..9000dfe30b 100644
--- a/flags/btif_dm.aconfig
+++ b/flags/btif_dm.aconfig
@@ -2,27 +2,6 @@ package: "com.android.bluetooth.flags"
container: "com.android.btservices"
flag {
- name: "ignore_bond_type_for_le"
- namespace: "bluetooth"
- description: "Bond type is not applicable for LE SMP pairing"
- bug: "319695663"
-}
-
-flag {
- name: "reset_pairing_only_for_related_service_discovery"
- namespace: "bluetooth"
- description: "Don't reset the pairing state if service discovery concludes for a different device"
- bug: "321996502"
-}
-
-flag {
- name: "force_bredr_for_sdp_retry"
- namespace: "bluetooth"
- description: "Force BR/EDR transport for retrying SDP service discovery"
- bug: "326656580"
-}
-
-flag {
name: "do_not_replace_existing_cod_with_uncategorized_cod"
namespace: "bluetooth"
description: "Don't replace an existing stored class of device with one determined to be uncategorized"
diff --git a/flags/hfp.aconfig b/flags/hfp.aconfig
index 9c853c6f67..dabe666bfa 100644
--- a/flags/hfp.aconfig
+++ b/flags/hfp.aconfig
@@ -115,3 +115,13 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "ignore_notify_when_already_connected"
+ namespace: "bluetooth"
+ description: "Flag to ignore connect state notification from Native to Java layer when already connected"
+ bug: "346679106"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/pairing.aconfig b/flags/pairing.aconfig
index da3ab5b77d..6cbf08fd5a 100644
--- a/flags/pairing.aconfig
+++ b/flags/pairing.aconfig
@@ -54,3 +54,13 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "pairing_name_discovery_addresss_mismatch"
+ namespace: "bluetooth"
+ description: "Do not abort pairing if name discovery for a another device fails"
+ bug: "349144497"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/security.aconfig b/flags/security.aconfig
index f6ff588ae6..0f1261df2c 100644
--- a/flags/security.aconfig
+++ b/flags/security.aconfig
@@ -30,13 +30,6 @@ flag {
}
flag {
- name: "fix_pairing_failure_reason_from_remote"
- namespace: "bluetooth"
- description: "Correct the pairing failure reason reported from remote"
- bug: "320745565"
-}
-
-flag {
name: "fix_le_oob_pairing_bypass"
namespace: "bluetooth"
description: "Fix oob bypassing bug in SMP"
diff --git a/framework/tests/bumble/src/android/bluetooth/DckGattTest.kt b/framework/tests/bumble/src/android/bluetooth/DckGattTest.kt
index ab3e13ffee..d8864b161c 100644
--- a/framework/tests/bumble/src/android/bluetooth/DckGattTest.kt
+++ b/framework/tests/bumble/src/android/bluetooth/DckGattTest.kt
@@ -250,7 +250,7 @@ public class DckGattTest() {
// Verify correct scan result as prerequisite
val scanResult = scanResultCaptor.firstValue
assertThat(scanResult).isNotNull()
- assertThat(scanResult.device.identityAddress).isEqualTo(TEST_ADDRESS_RANDOM_STATIC)
+ assertThat(scanResult.device.address).isEqualTo(TEST_ADDRESS_RANDOM_STATIC)
// Verify successful GATT connection
val device = scanResult.device
diff --git a/framework/tests/bumble/src/android/bluetooth/pairing/PairingTest.java b/framework/tests/bumble/src/android/bluetooth/pairing/PairingTest.java
index d5002b63c5..aad18d7c51 100644
--- a/framework/tests/bumble/src/android/bluetooth/pairing/PairingTest.java
+++ b/framework/tests/bumble/src/android/bluetooth/pairing/PairingTest.java
@@ -39,7 +39,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.ParcelUuid;
-import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Log;
@@ -47,7 +46,6 @@ import android.util.Log;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.bluetooth.flags.Flags;
import com.android.compatibility.common.util.AdoptShellPermissionsRule;
import io.grpc.stub.StreamObserver;
@@ -306,7 +304,6 @@ public class PairingTest {
* Expectation: Pairing gets cancelled instead of getting timed out
*/
@Test
- @RequiresFlagsEnabled(Flags.FLAG_RESET_PAIRING_ONLY_FOR_RELATED_SERVICE_DISCOVERY)
public void testCancelBondLe_WithGattServiceDiscovery() {
registerIntentActions(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
@@ -357,7 +354,6 @@ public class PairingTest {
* Expectation: Pairing succeeds
*/
@Test
- @RequiresFlagsEnabled(Flags.FLAG_RESET_PAIRING_ONLY_FOR_RELATED_SERVICE_DISCOVERY)
public void testBondLe_WithGattServiceDiscovery() {
registerIntentActions(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
diff --git a/framework/tests/util/src/Permissions.kt b/framework/tests/util/src/Permissions.kt
index ee8b60f224..9e25d30e8b 100644
--- a/framework/tests/util/src/Permissions.kt
+++ b/framework/tests/util/src/Permissions.kt
@@ -64,6 +64,8 @@ object Permissions {
private fun restorePermissions(permissions: Set<String>) {
if (UiAutomation.ALL_PERMISSIONS.equals(permissions)) {
uiAutomation.adoptShellPermissionIdentity()
+ } else if (permissions.size == 0) {
+ uiAutomation.dropShellPermissionIdentity()
} else {
uiAutomation.adoptShellPermissionIdentity(*permissions.map { it }.toTypedArray())
}
diff --git a/system/bta/dm/bta_dm_disc.cc b/system/bta/dm/bta_dm_disc.cc
index b8e24551db..37840398b9 100644
--- a/system/bta/dm/bta_dm_disc.cc
+++ b/system/bta/dm/bta_dm_disc.cc
@@ -617,12 +617,9 @@ static void bta_dm_gatt_disc_complete(uint16_t conn_id, tGATT_STATUS status) {
} else {
bta_dm_discovery_cb.conn_id = GATT_INVALID_CONN_ID;
- if (com::android::bluetooth::flags::bta_dm_disc_stuck_in_cancelling_fix()) {
- log::info(
- "Discovery complete for invalid conn ID. Will pick up next job");
- bta_dm_discovery_set_state(BTA_DM_DISCOVER_IDLE);
- bta_dm_execute_queued_discovery_request();
- }
+ log::info("Discovery complete for invalid conn ID. Will pick up next job");
+ bta_dm_discovery_set_state(BTA_DM_DISCOVER_IDLE);
+ bta_dm_execute_queued_discovery_request();
}
}
diff --git a/system/bta/dm/bta_dm_disc_legacy.cc b/system/bta/dm/bta_dm_disc_legacy.cc
index 853fbc3224..6713ade8c6 100644
--- a/system/bta/dm/bta_dm_disc_legacy.cc
+++ b/system/bta/dm/bta_dm_disc_legacy.cc
@@ -1836,13 +1836,10 @@ static void bta_dm_gatt_disc_complete(uint16_t conn_id, tGATT_STATUS status) {
} else {
bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID;
- if (com::android::bluetooth::flags::bta_dm_disc_stuck_in_cancelling_fix()) {
- log::info(
- "Discovery complete for invalid conn ID. Will pick up next job");
- bta_dm_search_set_state(BTA_DM_SEARCH_IDLE);
- bta_dm_free_sdp_db();
- bta_dm_execute_queued_request();
- }
+ log::info("Discovery complete for invalid conn ID. Will pick up next job");
+ bta_dm_search_set_state(BTA_DM_SEARCH_IDLE);
+ bta_dm_free_sdp_db();
+ bta_dm_execute_queued_request();
}
}
diff --git a/system/bta/hearing_aid/hearing_aid.cc b/system/bta/hearing_aid/hearing_aid.cc
index 223af0966f..2f98063198 100644
--- a/system/bta/hearing_aid/hearing_aid.cc
+++ b/system/bta/hearing_aid/hearing_aid.cc
@@ -1100,7 +1100,17 @@ class HearingAidImpl : public HearingAid {
: BTM_SEC_SERVICE_HEARING_AID_RIGHT;
uint16_t gap_handle = GAP_ConnOpen(
"", service_id, false, &hearingDevice->address, psm, 514 /* MPS */,
- &cfg_info, nullptr, BTM_SEC_NONE /* TODO: request security ? */,
+ &cfg_info, nullptr,
+ /// b/309483354:
+ /// Encryption needs to be explicitly requested at channel
+ /// establishment even though validation is performed in this module
+ /// because of re-connection logic present in the L2CAP module.
+ /// The L2CAP will automatically reconnect the LE-ACL link on
+ /// disconnection when there is a pending channel request,
+ /// which invalidates all encryption checks performed here.
+ com::android::bluetooth::flags::asha_asrc()
+ ? BTM_SEC_IN_ENCRYPT | BTM_SEC_OUT_ENCRYPT
+ : BTM_SEC_NONE,
HearingAidImpl::GapCallbackStatic, BT_TRANSPORT_LE);
if (gap_handle == GAP_INVALID_HANDLE) {
diff --git a/system/bta/hf_client/bta_hf_client_at.cc b/system/bta/hf_client/bta_hf_client_at.cc
index 2d44cb45fd..58daf4a605 100644
--- a/system/bta/hf_client/bta_hf_client_at.cc
+++ b/system/bta/hf_client/bta_hf_client_at.cc
@@ -1920,7 +1920,7 @@ void bta_hf_client_send_at_biev(tBTA_HF_CLIENT_CB* client_cb, int indicator_id,
char buf[32];
tBTA_HF_CLIENT_AT_CMD cmd = BTA_HF_CLIENT_AT_BIEV;
- if ((client_cb->peer_features & BTA_HF_CLIENT_FEAT_HF_IND) == 0) {
+ if ((client_cb->peer_features & BTA_HF_CLIENT_PEER_HF_IND) == 0) {
log::error("peer does not support HF Indicators");
return;
}
diff --git a/system/bta/le_audio/client.cc b/system/bta/le_audio/client.cc
index b865865544..5aa081e8a3 100644
--- a/system/bta/le_audio/client.cc
+++ b/system/bta/le_audio/client.cc
@@ -1160,12 +1160,19 @@ class LeAudioClientImpl : public LeAudioClient {
L2CA_SetEcosystemBaseInterval(frame_duration_us / 1250);
- audio_framework_source_config.data_interval_us = frame_duration_us;
+ // Scale by the codec frame blocks per SDU if set
+ uint8_t codec_frame_blocks_per_sdu =
+ group->stream_conf.stream_params.source.codec_frames_blocks_per_sdu
+ ?: 1;
+ audio_framework_source_config.data_interval_us =
+ frame_duration_us * codec_frame_blocks_per_sdu;
+
le_audio_source_hal_client_->Start(audio_framework_source_config,
audioSinkReceiver, dsa_modes);
/* We use same frame duration for sink/source */
- audio_framework_sink_config.data_interval_us = frame_duration_us;
+ audio_framework_sink_config.data_interval_us =
+ frame_duration_us * codec_frame_blocks_per_sdu;
/* If group supports more than 16kHz for the microphone in converstional
* case let's use that also for Audio Framework.
@@ -3393,6 +3400,12 @@ class LeAudioClientImpl : public LeAudioClient {
right_cis_handle = cis_handle;
}
+ if (stream_params.codec_frames_blocks_per_sdu != 1) {
+ log::error(
+ "Codec Frame Blocks of {} is not supported by the software encoding",
+ +stream_params.codec_frames_blocks_per_sdu);
+ }
+
uint16_t byte_count = stream_params.octets_per_codec_frame;
bool mix_to_mono = (left_cis_handle == 0) || (right_cis_handle == 0);
if (mix_to_mono) {
@@ -3441,6 +3454,12 @@ class LeAudioClientImpl : public LeAudioClient {
return;
}
+ if (stream_params.codec_frames_blocks_per_sdu != 1) {
+ log::error(
+ "Codec Frame Blocks of {} is not supported by the software encoding",
+ +stream_params.codec_frames_blocks_per_sdu);
+ }
+
uint16_t byte_count = stream_params.octets_per_codec_frame;
bool mix_to_mono = (num_channels == 1);
if (mix_to_mono) {
diff --git a/system/bta/le_audio/devices_test.cc b/system/bta/le_audio/devices_test.cc
index 79290fc1cd..ea6f4421a1 100644
--- a/system/bta/le_audio/devices_test.cc
+++ b/system/bta/le_audio/devices_test.cc
@@ -718,12 +718,15 @@ class LeAudioAseConfigurationTest
// configurations
ON_CALL(*mock_codec_manager_, IsDualBiDirSwbSupported)
.WillByDefault(Return(true));
- ON_CALL(*mock_codec_manager_, GetCodecConfig)
- .WillByDefault(Invoke(
- [](const bluetooth::le_audio::CodecManager::
- UnicastConfigurationRequirements& requirements,
- bluetooth::le_audio::CodecManager::UnicastConfigurationVerifier
- verifier) {
+ }
+
+ ON_CALL(*mock_codec_manager_, GetCodecConfig)
+ .WillByDefault(Invoke(
+ [&](const bluetooth::le_audio::CodecManager::
+ UnicastConfigurationRequirements& requirements,
+ bluetooth::le_audio::CodecManager::UnicastConfigurationVerifier
+ verifier) {
+ if (codec_coding_format_ == kLeAudioCodingFormatLC3) {
auto filtered =
*bluetooth::le_audio::AudioSetConfigurationProvider::Get()
->GetConfigurations(requirements.audio_context_type);
@@ -745,18 +748,10 @@ class LeAudioAseConfigurationTest
return std::unique_ptr<AudioSetConfiguration>(nullptr);
}
return std::make_unique<AudioSetConfiguration>(*cfg);
- }));
- } else {
- // Provide a configuration for the vendor codec
- ON_CALL(*mock_codec_manager_, GetCodecConfig)
- .WillByDefault(Invoke(
- [](const bluetooth::le_audio::CodecManager::
- UnicastConfigurationRequirements& requirements,
- bluetooth::le_audio::CodecManager::UnicastConfigurationVerifier
- verifier) {
+ } else {
return MockVendorCodecProvider(requirements);
- }));
- }
+ }
+ }));
ON_CALL(*mock_codec_manager_, CheckCodecConfigIsBiDirSwb)
.WillByDefault(Invoke([](const bluetooth::le_audio::set_configurations::
@@ -1125,7 +1120,8 @@ class LeAudioAseConfigurationTest
}
void TestAsesActive(LeAudioCodecId codec_id, uint8_t sampling_frequency,
- uint8_t frame_duration, uint16_t octets_per_frame) {
+ uint8_t frame_duration, uint16_t octets_per_frame,
+ uint8_t codec_frame_blocks_per_sdu = 1) {
bool active_ase = false;
for (const auto& device : devices_) {
@@ -1144,6 +1140,8 @@ class LeAudioAseConfigurationTest
ASSERT_EQ(core_config.sampling_frequency, sampling_frequency);
ASSERT_EQ(core_config.frame_duration, frame_duration);
ASSERT_EQ(core_config.octets_per_codec_frame, octets_per_frame);
+ ASSERT_EQ(core_config.codec_frames_blocks_per_sdu.value_or(0),
+ codec_frame_blocks_per_sdu);
}
}
}
@@ -1177,7 +1175,8 @@ class LeAudioAseConfigurationTest
}
}
- void TestLc3CodecConfig(LeAudioContextType context_type) {
+ void TestLc3CodecConfig(LeAudioContextType context_type,
+ uint8_t max_codec_frames_per_sdu = 1) {
for (int i = Lc3SettingIdBegin; i < Lc3SettingIdEnd; i++) {
// test each configuration parameter against valid and invalid value
std::array<Lc3SettingId, 2> test_variants = {static_cast<Lc3SettingId>(i),
@@ -1198,7 +1197,7 @@ class LeAudioAseConfigurationTest
frame_duration,
kLeAudioCodecChannelCountSingleChannel |
kLeAudioCodecChannelCountTwoChannel,
- octets_per_frame);
+ octets_per_frame, max_codec_frames_per_sdu);
for (auto& device : devices_) {
/* For simplicity configure both PACs with the same
parameters*/
@@ -1224,7 +1223,8 @@ class LeAudioAseConfigurationTest
group_->Configure(context_type, group_audio_locations));
if (success_expected) {
TestAsesActive(LeAudioCodecIdLc3, sampling_frequency,
- frame_duration, octets_per_frame);
+ frame_duration, octets_per_frame,
+ max_codec_frames_per_sdu);
group_->Deactivate();
}
@@ -2072,6 +2072,74 @@ TEST_P(LeAudioAseConfigurationTest, test_lc3_config_media) {
TestLc3CodecConfig(LeAudioContextType::MEDIA);
}
+TEST_P(LeAudioAseConfigurationTest,
+ test_lc3_config_media_codec_extensibility_fb2) {
+ if (codec_coding_format_ != kLeAudioCodingFormatLC3) GTEST_SKIP();
+
+ bool is_fb2_passed_as_requirement = false;
+ auto max_codec_frames_per_sdu = 2;
+
+ // Mock the configuration provider to give us config with 2 frame blocks per
+ // SDU if it receives the proper PAC entry in the requirements
+ // ON_CALL(*mock_codec_manager_, IsUsingCodecExtensibility)
+ // .WillByDefault(Return(true));
+ ON_CALL(*mock_codec_manager_, GetCodecConfig)
+ .WillByDefault(Invoke([&](const bluetooth::le_audio::CodecManager::
+ UnicastConfigurationRequirements&
+ requirements,
+ bluetooth::le_audio::CodecManager::
+ UnicastConfigurationVerifier verifier) {
+ auto filtered =
+ *bluetooth::le_audio::AudioSetConfigurationProvider::Get()
+ ->GetConfigurations(requirements.audio_context_type);
+ // Filter out the dual bidir SWB configurations
+ if (!bluetooth::le_audio::CodecManager::GetInstance()
+ ->IsDualBiDirSwbSupported()) {
+ filtered.erase(
+ std::remove_if(filtered.begin(), filtered.end(),
+ [](auto const& el) {
+ if (el->confs.source.empty()) return false;
+ return AudioSetConfigurationProvider::Get()
+ ->CheckConfigurationIsDualBiDirSwb(*el);
+ }),
+ filtered.end());
+ }
+ auto cfg = verifier(requirements, &filtered);
+ if (cfg == nullptr) {
+ return std::unique_ptr<AudioSetConfiguration>(nullptr);
+ }
+
+ auto config = *cfg;
+
+ if (requirements.sink_pacs.has_value()) {
+ for (auto const& rec : requirements.sink_pacs.value()) {
+ auto caps = rec.codec_spec_caps.GetAsCoreCodecCapabilities();
+ if (caps.HasSupportedMaxCodecFramesPerSdu()) {
+ if (caps.supported_max_codec_frames_per_sdu.value() ==
+ max_codec_frames_per_sdu) {
+ // Inject the proper Codec Frames Per SDU as the json
+ // configs are conservative and will always give us 1
+ for (auto& entry : config.confs.sink) {
+ entry.codec.params.Add(
+ codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu,
+ (uint8_t)max_codec_frames_per_sdu);
+ }
+ is_fb2_passed_as_requirement = true;
+ }
+ }
+ }
+ }
+ return std::make_unique<AudioSetConfiguration>(config);
+ }));
+
+ AddTestDevice(1, 1);
+
+ TestLc3CodecConfig(LeAudioContextType::MEDIA, max_codec_frames_per_sdu);
+
+ // Make sure the CodecManager mock gets the proper PAC record
+ ASSERT_TRUE(is_fb2_passed_as_requirement);
+}
+
TEST_P(LeAudioAseConfigurationTest, test_unsupported_codec) {
if (codec_coding_format_ == kLeAudioCodingFormatVendorSpecific) GTEST_SKIP();
diff --git a/system/bta/le_audio/le_audio_client_test.cc b/system/bta/le_audio/le_audio_client_test.cc
index 8cd07f856d..a216a4acc4 100644
--- a/system/bta/le_audio/le_audio_client_test.cc
+++ b/system/bta/le_audio/le_audio_client_test.cc
@@ -30,6 +30,7 @@
#include "bta_groups.h"
#include "bta_le_audio_api.h"
#include "bta_le_audio_broadcaster_api.h"
+#include "btif/include/mock_core_callbacks.h"
#include "btif_storage_mock.h"
#include "btm_api_mock.h"
#include "btm_iso_api.h"
@@ -41,6 +42,7 @@
#include "hci/controller_interface_mock.h"
#include "internal_include/stack_config.h"
#include "le_audio/codec_manager.h"
+#include "le_audio/mock_codec_interface.h"
#include "le_audio_health_status.h"
#include "le_audio_set_configuration_provider.h"
#include "le_audio_types.h"
@@ -1156,6 +1158,8 @@ class UnicastTestNoInit : public Test {
stream_conf->stream_params.source
.codec_frames_blocks_per_sdu =
*core_config.codec_frames_blocks_per_sdu;
+ stream_conf->stream_params.source.frame_duration_us =
+ core_config.GetFrameDurationUs();
} else {
log::assert_that(
stream_conf->stream_params.source
@@ -1228,6 +1232,8 @@ class UnicastTestNoInit : public Test {
stream_conf->stream_params.sink
.codec_frames_blocks_per_sdu =
*core_config.codec_frames_blocks_per_sdu;
+ stream_conf->stream_params.sink.frame_duration_us =
+ core_config.GetFrameDurationUs();
} else {
log::assert_that(
stream_conf->stream_params.sink
@@ -2347,6 +2353,25 @@ class UnicastTestNoInit : public Test {
std::move(ascs), std::move(pacs));
}
+ struct SampleDatabaseParameters {
+ uint16_t conn_id;
+ RawAddress addr;
+
+ uint32_t sink_audio_allocation = codec_spec_conf::kLeAudioLocationStereo;
+ uint32_t source_audio_allocation = codec_spec_conf::kLeAudioLocationStereo;
+ uint8_t sink_channel_cnt = 0x03;
+ uint8_t source_channel_cnt = 0x03;
+ uint16_t sample_freq_mask = 0x0004;
+ bool add_csis = true;
+ bool add_cas = true;
+ bool add_pacs = true;
+ int add_ascs_cnt = 1;
+ uint8_t set_size = 2;
+ uint8_t rank = 1;
+ GattStatus gatt_status = GATT_SUCCESS;
+ uint8_t max_supported_codec_frames_per_sdu = 1;
+ };
+
void SetSampleDatabaseEarbudsValid(
uint16_t conn_id, RawAddress addr, uint32_t sink_audio_allocation,
uint32_t source_audio_allocation, uint8_t sink_channel_cnt = 0x03,
@@ -2354,6 +2379,43 @@ class UnicastTestNoInit : public Test {
bool add_csis = true, bool add_cas = true, bool add_pacs = true,
int add_ascs_cnt = 1, uint8_t set_size = 2, uint8_t rank = 1,
GattStatus gatt_status = GATT_SUCCESS) {
+ SetSampleDatabaseEarbudsValid(SampleDatabaseParameters{
+ .conn_id = conn_id,
+ .addr = addr,
+ .sink_audio_allocation = sink_audio_allocation,
+ .source_audio_allocation = source_audio_allocation,
+ .sink_channel_cnt = sink_channel_cnt,
+ .source_channel_cnt = source_channel_cnt,
+ .sample_freq_mask = sample_freq_mask,
+ .add_csis = add_csis,
+ .add_cas = add_cas,
+ .add_pacs = add_pacs,
+ .add_ascs_cnt = add_ascs_cnt,
+ .set_size = set_size,
+ .rank = rank,
+ .gatt_status = gatt_status,
+ .max_supported_codec_frames_per_sdu = 1,
+ });
+ }
+
+ void SetSampleDatabaseEarbudsValid(const SampleDatabaseParameters& params) {
+ auto conn_id = params.conn_id;
+ auto addr = params.addr;
+ auto sink_audio_allocation = params.sink_audio_allocation;
+ auto source_audio_allocation = params.source_audio_allocation;
+ auto sink_channel_cnt = params.sink_channel_cnt;
+ auto source_channel_cnt = params.source_channel_cnt;
+ auto sample_freq_mask = params.sample_freq_mask;
+ auto add_csis = params.add_csis;
+ auto add_cas = params.add_cas;
+ auto add_pacs = params.add_pacs;
+ auto add_ascs_cnt = params.add_ascs_cnt;
+ auto set_size = params.set_size;
+ auto rank = params.rank;
+ auto gatt_status = params.gatt_status;
+ auto max_supported_codec_frames_per_sdu =
+ params.max_supported_codec_frames_per_sdu;
+
auto csis = std::make_unique<NiceMock<MockDeviceWrapper::csis_mock>>();
if (add_csis) {
// attribute handles
@@ -2451,10 +2513,8 @@ class UnicastTestNoInit : public Test {
// Set pacs default read values
ON_CALL(*peer_devices.at(conn_id)->pacs, OnReadCharacteristic(_, _, _))
- .WillByDefault([this, conn_id, snk_allocation, src_allocation,
- sample_freq, sink_channel_cnt, source_channel_cnt,
- gatt_status](uint16_t handle, GATT_READ_OP_CB cb,
- void* cb_data) {
+ .WillByDefault([=, this](uint16_t handle, GATT_READ_OP_CB cb,
+ void* cb_data) {
auto& pacs = peer_devices.at(conn_id)->pacs;
std::vector<uint8_t> value;
if (gatt_status == GATT_SUCCESS) {
@@ -2498,7 +2558,7 @@ class UnicastTestNoInit : public Test {
0x00,
0x00,
// Codec Spec. Caps. Len
- 0x10,
+ 0x13,
0x03, /* sample freq */
0x01,
0x80, /* 48kHz */
@@ -2515,6 +2575,9 @@ class UnicastTestNoInit : public Test {
0x00,
0x78,
0x00,
+ 0x02, /* Max supported codec frames per SDU */
+ 0x05,
+ max_supported_codec_frames_per_sdu,
// Metadata Length
0x00,
};
@@ -2900,6 +2963,8 @@ class UnicastTest : public UnicastTestNoInit {
}
void TearDown() override {
+ MockCodecInterface::ClearMockInstanceHookList();
+
// Clear the default actions before the parent class teardown is called
Mock::VerifyAndClear(&mock_btm_interface_);
Mock::VerifyAndClear(&mock_gatt_interface_);
@@ -10882,4 +10947,186 @@ TEST_F_WITH_FLAGS(UnicastTest, NoContextvalidateStreamingRequest,
Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);
Mock::VerifyAndClearExpectations(mock_le_audio_source_hal_client_);
}
+
+TEST_F(UnicastTest, CodecFrameBlocks2) {
+ auto const max_codec_frames_per_sdu = 2;
+ uint32_t data_len = 1920;
+
+ // Register a on-the-fly hook for codec interface mock mutation to prepare the
+ // codec mock for encoding
+ std::list<MockCodecInterface*> codec_mocks;
+ MockCodecInterface::RegisterMockInstanceHook([&](MockCodecInterface* mock,
+ bool is_destroyed) {
+ if (is_destroyed) {
+ log::debug("Codec Interface Destroyed: {}", (long)mock);
+ codec_mocks.remove(mock);
+ } else {
+ log::debug("Codec Interface Created: {}", (long)mock);
+ ON_CALL(*mock, GetNumOfSamplesPerChannel()).WillByDefault(Return(960));
+ ON_CALL(*mock, GetNumOfBytesPerSample())
+ .WillByDefault(Return(2)); // 16bits samples
+ ON_CALL(*mock, Encode(_, _, _, _, _))
+ .WillByDefault(Return(CodecInterface::Status::STATUS_OK));
+ codec_mocks.push_back(mock);
+ }
+ });
+
+ // Add a frame block PAC passing verifier
+ bool is_fb2_passed_as_requirement = false;
+ ON_CALL(*mock_codec_manager_, GetCodecConfig)
+ .WillByDefault(Invoke([&](const bluetooth::le_audio::CodecManager::
+ UnicastConfigurationRequirements&
+ requirements,
+ bluetooth::le_audio::CodecManager::
+ UnicastConfigurationVerifier verifier) {
+ auto filtered =
+ *bluetooth::le_audio::AudioSetConfigurationProvider::Get()
+ ->GetConfigurations(requirements.audio_context_type);
+ // Filter out the dual bidir SWB configurations
+ if (!bluetooth::le_audio::CodecManager::GetInstance()
+ ->IsDualBiDirSwbSupported()) {
+ filtered.erase(
+ std::remove_if(filtered.begin(), filtered.end(),
+ [](auto const& el) {
+ if (el->confs.source.empty()) return false;
+ return AudioSetConfigurationProvider::Get()
+ ->CheckConfigurationIsDualBiDirSwb(*el);
+ }),
+ filtered.end());
+ }
+ auto cfg = verifier(requirements, &filtered);
+ if (cfg == nullptr) {
+ return std::unique_ptr<set_configurations::AudioSetConfiguration>(
+ nullptr);
+ }
+
+ auto config = *cfg;
+
+ if (requirements.sink_pacs.has_value()) {
+ for (auto const& rec : requirements.sink_pacs.value()) {
+ auto caps = rec.codec_spec_caps.GetAsCoreCodecCapabilities();
+ if (caps.HasSupportedMaxCodecFramesPerSdu()) {
+ if (caps.supported_max_codec_frames_per_sdu.value() ==
+ max_codec_frames_per_sdu) {
+ // Inject the proper Codec Frames Per SDU as the json
+ // configs are conservative and will always give us 1
+ for (auto& entry : config.confs.sink) {
+ entry.codec.params.Add(
+ codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu,
+ (uint8_t)max_codec_frames_per_sdu);
+ }
+ is_fb2_passed_as_requirement = true;
+ }
+ }
+ }
+ }
+ return std::make_unique<set_configurations::AudioSetConfiguration>(
+ config);
+ }));
+
+ types::BidirectionalPair<stream_parameters> codec_manager_stream_params;
+ ON_CALL(*mock_codec_manager_, UpdateActiveAudioConfig)
+ .WillByDefault(Invoke(
+ [&](const types::BidirectionalPair<stream_parameters>& stream_params,
+ types::BidirectionalPair<uint16_t> delays_ms,
+ std::function<void(const offload_config& config,
+ uint8_t direction)>
+ updater) { codec_manager_stream_params = stream_params; }));
+
+ const RawAddress test_address0 = GetTestAddress(0);
+ int group_id = bluetooth::groups::kGroupUnknown;
+
+ SampleDatabaseParameters remote_params{
+ .conn_id = 1,
+ .addr = test_address0,
+ .add_csis = false,
+ .set_size = 0,
+ .rank = 0,
+ .max_supported_codec_frames_per_sdu = 2,
+ };
+ SetSampleDatabaseEarbudsValid(remote_params);
+
+ 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)));
+
+ ConnectLeAudio(test_address0);
+ ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown);
+
+ constexpr int gmcs_ccid = 1;
+ constexpr int gtbs_ccid = 2;
+
+ // 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()->SetCcidInformation(gmcs_ccid, 4 /* Media */);
+ LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */);
+ LeAudioClient::Get()->GroupSetActive(group_id);
+ SyncOnMainLoop();
+
+ types::BidirectionalPair<std::vector<uint8_t>> ccids = {.sink = {gmcs_ccid},
+ .source = {}};
+ EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1);
+
+ block_streaming_state_callback = true;
+
+ UpdateLocalSourceMetadata(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC);
+ LocalAudioSourceResume(false);
+
+ SyncOnMainLoop();
+ Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);
+ Mock::VerifyAndClearExpectations(mock_le_audio_source_hal_client_);
+ ASSERT_TRUE(is_fb2_passed_as_requirement);
+
+ // Verify codec fram blocks per SDU has been applied to the device
+ ASSERT_NE(0lu, streaming_groups.count(group_id));
+ uint8_t device_configured_codec_frame_blocks_per_sdu = 0;
+ auto group = streaming_groups.at(group_id);
+ for (LeAudioDevice* device = group->GetFirstDevice(); device != nullptr;
+ device = group->GetNextDevice(device)) {
+ for (auto& ase : device->ases_) {
+ if (ase.active) {
+ auto cfg = ase.codec_config.GetAsCoreCodecConfig();
+ ASSERT_TRUE(cfg.codec_frames_blocks_per_sdu.has_value());
+ device_configured_codec_frame_blocks_per_sdu =
+ cfg.codec_frames_blocks_per_sdu.value();
+ }
+ }
+ }
+
+ // Verify the configured codec frame blocks per SDU
+ ASSERT_EQ(device_configured_codec_frame_blocks_per_sdu,
+ remote_params.max_supported_codec_frames_per_sdu);
+
+ EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(0);
+ do_in_main_thread(
+ FROM_HERE,
+ base::BindOnce(
+ [](int group_id,
+ bluetooth::le_audio::LeAudioGroupStateMachine::Callbacks*
+ state_machine_callbacks) {
+ state_machine_callbacks->StatusReportCb(
+ group_id, GroupStreamStatus::STREAMING);
+ },
+ group_id, base::Unretained(state_machine_callbacks_)));
+ SyncOnMainLoop();
+ Mock::VerifyAndClearExpectations(&mock_state_machine_);
+
+ // Verify Data transfer on one audio source cis
+ constexpr uint8_t cis_count_out = 1;
+ constexpr uint8_t cis_count_in = 0;
+ TestAudioDataTransfer(
+ group_id, cis_count_out, cis_count_in,
+ data_len * device_configured_codec_frame_blocks_per_sdu);
+
+ ASSERT_NE(codec_mocks.size(), 0ul);
+
+ // Verify that the initially started session was updated with the new params
+ ASSERT_EQ(codec_manager_stream_params.sink.codec_frames_blocks_per_sdu,
+ max_codec_frames_per_sdu);
+}
+
} // namespace bluetooth::le_audio
diff --git a/system/bta/le_audio/le_audio_types.cc b/system/bta/le_audio/le_audio_types.cc
index 67a8a58276..21337cba12 100644
--- a/system/bta/le_audio/le_audio_types.cc
+++ b/system/bta/le_audio/le_audio_types.cc
@@ -133,7 +133,9 @@ uint32_t CodecConfigSetting::GetSamplingFrequencyHz() const {
uint32_t CodecConfigSetting::GetDataIntervalUs() const {
switch (id.coding_format) {
case kLeAudioCodingFormatLC3:
- return params.GetAsCoreCodecConfig().GetFrameDurationUs();
+ return params.GetAsCoreCodecConfig().GetFrameDurationUs() *
+ params.GetAsCoreCodecConfig().codec_frames_blocks_per_sdu.value_or(
+ 1);
default:
log::warn(", invalid codec id: 0x{:02x}", id.coding_format);
return 0;
diff --git a/system/bta/le_audio/mock_codec_interface.cc b/system/bta/le_audio/mock_codec_interface.cc
index 71b26e2bfa..0c8af03767 100644
--- a/system/bta/le_audio/mock_codec_interface.cc
+++ b/system/bta/le_audio/mock_codec_interface.cc
@@ -16,6 +16,11 @@
#include "mock_codec_interface.h"
+#include "le_audio/codec_interface.h"
+
+static std::list<std::function<void(MockCodecInterface*, bool)>>
+ mock_life_listener_list;
+
namespace bluetooth::le_audio {
struct CodecInterface::Impl : public MockCodecInterface {
@@ -31,8 +36,16 @@ struct CodecInterface::Impl : public MockCodecInterface {
CodecInterface::CodecInterface(const types::LeAudioCodecId& codec_id) {
impl = new Impl(codec_id);
+ for (auto& foo : mock_life_listener_list) {
+ foo(impl, false);
+ }
+}
+CodecInterface::~CodecInterface() {
+ for (auto& foo : mock_life_listener_list) {
+ foo(impl, true);
+ }
+ delete impl;
}
-CodecInterface::~CodecInterface() { delete impl; }
bool CodecInterface::IsReady() { return impl->IsReady(); };
CodecInterface::Status CodecInterface::InitEncoder(
const LeAudioCodecConfiguration& pcm_config,
@@ -65,3 +78,12 @@ uint8_t CodecInterface::GetNumOfBytesPerSample() {
return impl->GetNumOfBytesPerSample();
};
} // namespace bluetooth::le_audio
+
+void MockCodecInterface::RegisterMockInstanceHook(
+ std::function<void(MockCodecInterface*, bool)> listener) {
+ mock_life_listener_list.push_back(std::move(listener));
+}
+
+void MockCodecInterface::ClearMockInstanceHookList() {
+ mock_life_listener_list.clear();
+}
diff --git a/system/bta/le_audio/mock_codec_interface.h b/system/bta/le_audio/mock_codec_interface.h
index 974e049779..2b3ecaa958 100644
--- a/system/bta/le_audio/mock_codec_interface.h
+++ b/system/bta/le_audio/mock_codec_interface.h
@@ -24,6 +24,10 @@
class MockCodecInterface {
public:
+ static void RegisterMockInstanceHook(
+ std::function<void(MockCodecInterface*, bool)>);
+ static void ClearMockInstanceHookList();
+
MockCodecInterface() = default;
MockCodecInterface(const MockCodecInterface&) = delete;
MockCodecInterface& operator=(const MockCodecInterface&) = delete;
diff --git a/system/bta/le_audio/state_machine_test.cc b/system/bta/le_audio/state_machine_test.cc
index c23083ec4d..43f08d3fed 100644
--- a/system/bta/le_audio/state_machine_test.cc
+++ b/system/bta/le_audio/state_machine_test.cc
@@ -140,7 +140,7 @@ constexpr uint8_t kCapTypeSupportedSamplingFrequencies = 0x01;
constexpr uint8_t kCapTypeSupportedFrameDurations = 0x02;
constexpr uint8_t kCapTypeAudioChannelCount = 0x03;
constexpr uint8_t kCapTypeSupportedOctetsPerCodecFrame = 0x04;
-// constexpr uint8_t kCapTypeSupportedLc3CodecFramesPerSdu = 0x05;
+constexpr uint8_t kCapTypeSupportedLc3CodecFramesPerSdu = 0x05;
// constexpr uint8_t kCapSamplingFrequency8000Hz = 0x0001;
// constexpr uint8_t kCapSamplingFrequency11025Hz = 0x0002;
@@ -247,6 +247,7 @@ class StateMachineTestBase : public Test {
uint8_t additional_snk_ases = 0;
uint8_t additional_src_ases = 0;
uint8_t channel_count_ = kLeAudioCodecChannelCountSingleChannel;
+ uint8_t codec_frame_blocks_per_sdu_ = 1;
uint16_t sample_freq_ = codec_specific::kCapSamplingFrequency16000Hz |
codec_specific::kCapSamplingFrequency32000Hz;
uint8_t channel_allocations_sink_ =
@@ -407,6 +408,7 @@ class StateMachineTestBase : public Test {
[this](uint8_t cig_id,
bluetooth::hci::iso_manager::cig_create_params p) {
log::debug("CreateCig");
+ last_cig_params_ = p;
auto& group = le_audio_device_groups_[cig_id];
if (group) {
@@ -900,6 +902,7 @@ class StateMachineTestBase : public Test {
uint8_t audio_channel_count_bitfield,
uint16_t supported_octets_per_codec_frame_min,
uint16_t supported_octets_per_codec_frame_max,
+ uint8_t codec_frame_blocks_per_sdu_ = 1,
uint8_t coding_format = codec_specific::kLc3CodingFormat,
uint16_t vendor_company_id = 0x0000, uint16_t vendor_codec_id = 0x0000,
std::vector<uint8_t> metadata = {}) {
@@ -921,6 +924,8 @@ class StateMachineTestBase : public Test {
(uint8_t)(supported_octets_per_codec_frame_max >> 8),
}},
});
+ ltv_map.Add(codec_specific::kCapTypeSupportedLc3CodecFramesPerSdu,
+ (uint8_t)codec_frame_blocks_per_sdu_);
recs.push_back({
.codec_id =
{
@@ -1066,7 +1071,7 @@ class StateMachineTestBase : public Test {
codec_specific::kCapFrameDuration10ms |
codec_specific::kCapFrameDuration7p5ms |
codec_specific::kCapFrameDuration10msPreferred,
- channel_count_, 30, 120);
+ channel_count_, 30, 120, codec_frame_blocks_per_sdu_);
types::hdl_pair handle_pair;
handle_pair.val_hdl = attr_handle++;
@@ -1091,7 +1096,7 @@ class StateMachineTestBase : public Test {
codec_specific::kCapFrameDuration10ms |
codec_specific::kCapFrameDuration7p5ms |
codec_specific::kCapFrameDuration10msPreferred,
- 0b00000001, 30, 120);
+ 0b00000001, 30, 120, codec_frame_blocks_per_sdu_);
types::hdl_pair handle_pair;
handle_pair.val_hdl = attr_handle++;
@@ -1188,7 +1193,7 @@ class StateMachineTestBase : public Test {
codec_configured_state_params.framing =
ascs::kAseParamFramingUnframedSupported;
codec_configured_state_params.preferred_retrans_nb = 0x04;
- codec_configured_state_params.max_transport_latency = 0x0010;
+ codec_configured_state_params.max_transport_latency = 0x0020;
codec_configured_state_params.pres_delay_min = 0xABABAB;
codec_configured_state_params.pres_delay_max = 0xCDCDCD;
codec_configured_state_params.preferred_pres_delay_min =
@@ -1605,6 +1610,7 @@ class StateMachineTestBase : public Test {
gatt::MockBtaGattQueue gatt_queue;
bluetooth::hci::IsoManager* iso_manager_;
+ bluetooth::hci::iso_manager::cig_create_params last_cig_params_;
MockIsoManager* mock_iso_manager_;
bluetooth::le_audio::CodecManager* codec_manager_;
MockCodecManager* mock_codec_manager_;
@@ -1712,6 +1718,153 @@ TEST_F(StateMachineTest, testConfigureCodecSingle) {
ASSERT_EQ(0, get_func_call_count("alarm_cancel"));
}
+TEST_F(StateMachineTest, testConfigureCodecSingleFb2) {
+ codec_frame_blocks_per_sdu_ = 2;
+ bool is_fb2_passed_as_sink_requirement = false;
+ bool is_fb2_passed_as_source_requirement = false;
+
+ ON_CALL(*mock_codec_manager_, GetCodecConfig)
+ .WillByDefault(Invoke([&](const bluetooth::le_audio::CodecManager::
+ UnicastConfigurationRequirements&
+ requirements,
+ bluetooth::le_audio::CodecManager::
+ UnicastConfigurationVerifier verifier) {
+ auto configs =
+ *bluetooth::le_audio::AudioSetConfigurationProvider::Get()
+ ->GetConfigurations(requirements.audio_context_type);
+ // Note: This dual bidir SWB exclusion logic has to match the
+ // CodecManager::GetCodecConfig() implementation.
+ if (!CodecManager::GetInstance()->IsDualBiDirSwbSupported()) {
+ configs.erase(
+ std::remove_if(configs.begin(), configs.end(),
+ [](auto const& el) {
+ if (el->confs.source.empty()) return false;
+ return AudioSetConfigurationProvider::Get()
+ ->CheckConfigurationIsDualBiDirSwb(*el);
+ }),
+ configs.end());
+ }
+
+ auto cfg = verifier(requirements, &configs);
+ if (cfg == nullptr) {
+ return std::unique_ptr<
+ bluetooth::le_audio::set_configurations::AudioSetConfiguration>(
+ nullptr);
+ }
+ auto config = *cfg;
+
+ if (requirements.sink_pacs.has_value()) {
+ for (auto const& rec : requirements.sink_pacs.value()) {
+ auto caps = rec.codec_spec_caps.GetAsCoreCodecCapabilities();
+ if (caps.HasSupportedMaxCodecFramesPerSdu()) {
+ if (caps.supported_max_codec_frames_per_sdu.value() ==
+ codec_frame_blocks_per_sdu_) {
+ // Scale by Codec Frames Per SDU = 2
+ for (auto& entry : config.confs.sink) {
+ entry.codec.params.Add(
+ codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu,
+ (uint8_t)codec_frame_blocks_per_sdu_);
+ entry.qos.maxSdu *= codec_frame_blocks_per_sdu_;
+ entry.qos.sduIntervalUs *= codec_frame_blocks_per_sdu_;
+ entry.qos.max_transport_latency *=
+ codec_frame_blocks_per_sdu_;
+ }
+ is_fb2_passed_as_sink_requirement = true;
+ }
+ }
+ }
+ }
+ if (requirements.source_pacs.has_value()) {
+ for (auto const& rec : requirements.source_pacs.value()) {
+ auto caps = rec.codec_spec_caps.GetAsCoreCodecCapabilities();
+ if (caps.HasSupportedMaxCodecFramesPerSdu()) {
+ if (caps.supported_max_codec_frames_per_sdu.value() ==
+ codec_frame_blocks_per_sdu_) {
+ // Scale by Codec Frames Per SDU = 2
+ for (auto& entry : config.confs.source) {
+ entry.codec.params.Add(
+ codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu,
+ (uint8_t)codec_frame_blocks_per_sdu_);
+ entry.qos.maxSdu *= codec_frame_blocks_per_sdu_;
+ entry.qos.sduIntervalUs *= codec_frame_blocks_per_sdu_;
+ entry.qos.max_transport_latency *=
+ codec_frame_blocks_per_sdu_;
+ }
+ is_fb2_passed_as_source_requirement = true;
+ }
+ }
+ }
+ }
+
+ return std::make_unique<
+ bluetooth::le_audio::set_configurations::AudioSetConfiguration>(
+ config);
+ }));
+
+ /* Device is banded headphones with 1x snk + 0x src ase
+ * (1xunidirectional CIS) with channel count 2 (for stereo
+ */
+ const auto context_type = kContextTypeRingtone;
+ const int leaudio_group_id = 2;
+ channel_count_ = kLeAudioCodecChannelCountSingleChannel |
+ kLeAudioCodecChannelCountTwoChannel;
+
+ /* Prepare the fake connected device group */
+ auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
+
+ /* Since we prepared device with Ringtone context in mind, only one ASE
+ * should have been configured.
+ */
+ auto* leAudioDevice = group->GetFirstDevice();
+ PrepareConfigureCodecHandler(group, 1);
+
+ /* Start the configuration and stream Media content.
+ * Expect 2 times: for Codec Configure & QoS Configure */
+ EXPECT_CALL(gatt_queue,
+ WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
+ GATT_WRITE_NO_RSP, _, _))
+ .Times(2);
+
+ InjectInitialIdleNotification(group);
+
+ EXPECT_CALL(*mock_iso_manager_, CreateCig).Times(1);
+ ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
+ group, context_type,
+ {.sink = types::AudioContexts(context_type),
+ .source = types::AudioContexts(context_type)}));
+
+ /* Check if group has transitioned to a proper state */
+ ASSERT_EQ(group->GetState(),
+ types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
+
+ /* Cancel is called when group goes to streaming. */
+ ASSERT_EQ(0, get_func_call_count("alarm_cancel"));
+
+ ASSERT_TRUE(is_fb2_passed_as_sink_requirement);
+
+ /* Make sure that data interval is based on the codec frame blocks count */
+ auto data_interval = group->GetActiveConfiguration()
+ ->confs.sink.at(0)
+ .codec.GetDataIntervalUs();
+ ASSERT_EQ(data_interval, group->GetActiveConfiguration()
+ ->confs.sink.at(0)
+ .codec.params.GetAsCoreCodecConfig()
+ .GetFrameDurationUs() *
+ codec_frame_blocks_per_sdu_);
+
+ /* Verify CIG parameters */
+ auto channel_count = group->GetActiveConfiguration()
+ ->confs.sink.at(0)
+ .codec.GetChannelCountPerIsoStream();
+ auto frame_octets = group->GetActiveConfiguration()
+ ->confs.sink.at(0)
+ .codec.GetOctectsPerFrame();
+ ASSERT_NE(last_cig_params_.cis_cfgs.size(), 0lu);
+ ASSERT_EQ(last_cig_params_.sdu_itv_mtos, data_interval);
+ ASSERT_EQ(last_cig_params_.cis_cfgs.at(0).max_sdu_size_mtos,
+ codec_frame_blocks_per_sdu_ * channel_count * frame_octets);
+}
+
TEST_F(StateMachineTest, testConfigureCodecMulti) {
const auto context_type = kContextTypeMedia;
const auto leaudio_group_id = 2;
diff --git a/system/btif/include/btif_av.h b/system/btif/include/btif_av.h
index de97fa142f..7d4e0ca269 100644
--- a/system/btif/include/btif_av.h
+++ b/system/btif/include/btif_av.h
@@ -308,8 +308,6 @@ bool btif_av_is_source_enabled(void);
bool btif_av_both_enable(void);
bool btif_av_src_sink_coexist_enabled(void);
bool btif_av_is_sink_enabled(void);
-bool btif_av_is_connected_addr(const RawAddress& peer_address,
- const A2dpType local_a2dp_type);
bool btif_av_peer_is_connected_sink(const RawAddress& peer_address);
bool btif_av_peer_is_connected_source(const RawAddress& peer_address);
bool btif_av_peer_is_sink(const RawAddress& peer_address);
diff --git a/system/btif/include/btif_rc.h b/system/btif/include/btif_rc.h
index a78110d87e..ea2e9f9da1 100644
--- a/system/btif/include/btif_rc.h
+++ b/system/btif/include/btif_rc.h
@@ -27,6 +27,8 @@ uint8_t btif_rc_get_connected_peer_handle(const RawAddress& peer_addr);
void btif_rc_check_handle_pending_play(const RawAddress& peer_addr,
bool bSendToApp);
bool btif_rc_is_connected_peer(const RawAddress& peer_addr);
+void btif_rc_check_pending_cmd(const RawAddress& peer_addr);
+void btif_rc_get_addr_by_handle(uint8_t handle, RawAddress& rc_addr);
void btif_debug_rc_dump(int fd);
#endif // BTIF_RC_H
diff --git a/system/btif/src/btif_av.cc b/system/btif/src/btif_av.cc
index 56ff784492..a9a30a41a1 100644
--- a/system/btif/src/btif_av.cc
+++ b/system/btif/src/btif_av.cc
@@ -71,8 +71,8 @@ using namespace bluetooth;
/*****************************************************************************
* Constants & Macros
*****************************************************************************/
-static const std::string kBtifAvSourceServiceName = "Advanced Audio Source";
-static const std::string kBtifAvSinkServiceName = "Advanced Audio Sink";
+static const char kBtifAvSourceServiceName[] = "Advanced Audio Source";
+static const char kBtifAvSinkServiceName[] = "Advanced Audio Sink";
static constexpr int kDefaultMaxConnectedAudioDevices = 1;
static constexpr tBTA_AV_HNDL kBtaHandleUnknown = 0;
@@ -161,7 +161,7 @@ class BtifAvStateMachine : public bluetooth::common::StateMachine {
class StateIdle : public State {
public:
- StateIdle(BtifAvStateMachine& sm)
+ explicit StateIdle(BtifAvStateMachine& sm)
: State(sm, kStateIdle), peer_(sm.Peer()) {}
void OnEnter() override;
void OnExit() override;
@@ -173,7 +173,7 @@ class BtifAvStateMachine : public bluetooth::common::StateMachine {
class StateOpening : public State {
public:
- StateOpening(BtifAvStateMachine& sm)
+ explicit StateOpening(BtifAvStateMachine& sm)
: State(sm, kStateOpening), peer_(sm.Peer()) {}
void OnEnter() override;
void OnExit() override;
@@ -185,7 +185,7 @@ class BtifAvStateMachine : public bluetooth::common::StateMachine {
class StateOpened : public State {
public:
- StateOpened(BtifAvStateMachine& sm)
+ explicit StateOpened(BtifAvStateMachine& sm)
: State(sm, kStateOpened), peer_(sm.Peer()) {}
void OnEnter() override;
void OnExit() override;
@@ -197,7 +197,7 @@ class BtifAvStateMachine : public bluetooth::common::StateMachine {
class StateStarted : public State {
public:
- StateStarted(BtifAvStateMachine& sm)
+ explicit StateStarted(BtifAvStateMachine& sm)
: State(sm, kStateStarted), peer_(sm.Peer()) {}
void OnEnter() override;
void OnExit() override;
@@ -209,7 +209,7 @@ class BtifAvStateMachine : public bluetooth::common::StateMachine {
class StateClosing : public State {
public:
- StateClosing(BtifAvStateMachine& sm)
+ explicit StateClosing(BtifAvStateMachine& sm)
: State(sm, kStateClosing), peer_(sm.Peer()) {}
void OnEnter() override;
void OnExit() override;
@@ -219,7 +219,7 @@ class BtifAvStateMachine : public bluetooth::common::StateMachine {
BtifAvPeer& peer_;
};
- BtifAvStateMachine(BtifAvPeer& btif_av_peer) : peer_(btif_av_peer) {
+ explicit BtifAvStateMachine(BtifAvPeer& btif_av_peer) : peer_(btif_av_peer) {
state_idle_ = new StateIdle(*this);
state_opening_ = new StateOpening(*this);
state_opened_ = new StateOpened(*this);
@@ -407,7 +407,7 @@ class BtifAvSource {
btav_source_callbacks_t* Callbacks() { return callbacks_; }
bool Enabled() const { return enabled_; }
bool A2dpOffloadEnabled() const { return a2dp_offload_enabled_; }
- // TODO: b/321806163: Remove this method as part of flag cleanup
+ // TODO(b/321806163): Remove this method as part of flag cleanup
void SetInvalidPeerCheck(bool invalid_peer_check) {
invalid_peer_check_ = invalid_peer_check;
}
@@ -651,7 +651,7 @@ class BtifAvSink {
btav_sink_callbacks_t* Callbacks() { return callbacks_; }
bool Enabled() const { return enabled_; }
- // TODO: b/321806163: Remove this method as part of flag cleanup
+ // TODO(b/321806163): Remove this method as part of flag cleanup
void SetInvalidPeerCheck(bool invalid_peer_check) {
invalid_peer_check_ = invalid_peer_check;
}
@@ -839,19 +839,15 @@ static void btif_av_sink_initiate_av_open_timer_timeout(void* data);
static void bta_av_sink_media_callback(const RawAddress& peer_address,
tBTA_AV_EVT event,
tBTA_AV_MEDIA* p_data);
-extern bool btif_av_both_enable(void);
-extern bool btif_av_is_connected_addr(const RawAddress& peer_address,
- const A2dpType local_a2dp_type);
-extern bool btif_av_peer_is_sink(const RawAddress& peer_address);
-extern void btif_rc_check_pending_cmd(const RawAddress& peer_address);
-extern void btif_rc_get_addr_by_handle(uint8_t handle, RawAddress& rc_addr);
static BtifAvPeer* btif_av_source_find_peer(const RawAddress& peer_address) {
return btif_av_source.FindPeer(peer_address);
}
+
static BtifAvPeer* btif_av_sink_find_peer(const RawAddress& peer_address) {
return btif_av_sink.FindPeer(peer_address);
}
+
static BtifAvPeer* btif_av_find_peer(const RawAddress& peer_address,
const A2dpType local_a2dp_type) {
if (com::android::bluetooth::flags::a2dp_concurrent_source_sink()) {
@@ -894,6 +890,7 @@ static BtifAvPeer* btif_av_find_peer(const RawAddress& peer_address,
if (btif_av_sink.Enabled()) return btif_av_sink_find_peer(peer_address);
return nullptr;
}
+
static BtifAvPeer* btif_av_find_active_peer(const A2dpType local_a2dp_type) {
if (com::android::bluetooth::flags::a2dp_concurrent_source_sink()) {
if (btif_av_source.Enabled() && local_a2dp_type == A2dpType::kSource)
@@ -943,7 +940,7 @@ const RawAddress& btif_av_find_by_handle(tBTA_AV_HNDL bta_handle) {
*****************************************************************************/
const char* dump_av_sm_event_name(btif_av_sm_event_t event) {
- switch ((int)event) {
+ switch (static_cast<int>(event)) {
CASE_RETURN_STR(BTA_AV_ENABLE_EVT)
CASE_RETURN_STR(BTA_AV_REGISTER_EVT)
CASE_RETURN_STR(BTA_AV_OPEN_EVT)
@@ -1034,15 +1031,17 @@ void BtifAvEvent::DeepCopy(uint32_t event, const void* p_data,
log::assert_that(data_length >= sizeof(tBTA_AV),
"assert failed: data_length >= sizeof(tBTA_AV)");
const tBTA_AV* av_src = (const tBTA_AV*)p_data;
- tBTA_AV* av_dest = (tBTA_AV*)data_;
+ tBTA_AV* av_dest = reinterpret_cast<tBTA_AV*>(data_);
if (av_src->meta_msg.p_data && av_src->meta_msg.len) {
- av_dest->meta_msg.p_data = (uint8_t*)osi_calloc(av_src->meta_msg.len);
+ av_dest->meta_msg.p_data =
+ reinterpret_cast<uint8_t*>(osi_calloc(av_src->meta_msg.len));
memcpy(av_dest->meta_msg.p_data, av_src->meta_msg.p_data,
av_src->meta_msg.len);
}
if (av_src->meta_msg.p_msg) {
- av_dest->meta_msg.p_msg = (tAVRC_MSG*)osi_calloc(sizeof(tAVRC_MSG));
+ av_dest->meta_msg.p_msg =
+ reinterpret_cast<tAVRC_MSG*>(osi_calloc(sizeof(tAVRC_MSG)));
memcpy(av_dest->meta_msg.p_msg, av_src->meta_msg.p_msg,
sizeof(tAVRC_MSG));
@@ -1051,15 +1050,15 @@ void BtifAvEvent::DeepCopy(uint32_t event, const void* p_data,
if ((p_msg_src->hdr.opcode == AVRC_OP_VENDOR) &&
(p_msg_src->vendor.p_vendor_data && p_msg_src->vendor.vendor_len)) {
- p_msg_dest->vendor.p_vendor_data =
- (uint8_t*)osi_calloc(p_msg_src->vendor.vendor_len);
+ p_msg_dest->vendor.p_vendor_data = reinterpret_cast<uint8_t*>(
+ osi_calloc(p_msg_src->vendor.vendor_len));
memcpy(p_msg_dest->vendor.p_vendor_data,
p_msg_src->vendor.p_vendor_data, p_msg_src->vendor.vendor_len);
}
if ((p_msg_src->hdr.opcode == AVRC_OP_BROWSE) &&
p_msg_src->browse.p_browse_data && p_msg_src->browse.browse_len) {
- p_msg_dest->browse.p_browse_data =
- (uint8_t*)osi_calloc(p_msg_src->browse.browse_len);
+ p_msg_dest->browse.p_browse_data = reinterpret_cast<uint8_t*>(
+ osi_calloc(p_msg_src->browse.browse_len));
memcpy(p_msg_dest->browse.p_browse_data,
p_msg_src->browse.p_browse_data, p_msg_src->browse.browse_len);
}
@@ -1074,8 +1073,9 @@ void BtifAvEvent::DeepCopy(uint32_t event, const void* p_data,
void BtifAvEvent::DeepFree() {
switch (event_) {
case BTA_AV_META_MSG_EVT: {
- tBTA_AV* av = (tBTA_AV*)data_;
- osi_free_and_reset((void**)&av->meta_msg.p_data);
+ tBTA_AV* av = reinterpret_cast<tBTA_AV*>(data_);
+ osi_free(av->meta_msg.p_data);
+ av->meta_msg.p_data = nullptr;
if (av->meta_msg.p_msg) {
if (av->meta_msg.p_msg->hdr.opcode == AVRC_OP_VENDOR) {
@@ -1084,7 +1084,8 @@ void BtifAvEvent::DeepFree() {
if (av->meta_msg.p_msg->hdr.opcode == AVRC_OP_BROWSE) {
osi_free(av->meta_msg.p_msg->browse.p_browse_data);
}
- osi_free_and_reset((void**)&av->meta_msg.p_msg);
+ osi_free(av->meta_msg.p_msg);
+ av->meta_msg.p_msg = nullptr;
}
} break;
@@ -1092,7 +1093,8 @@ void BtifAvEvent::DeepFree() {
break;
}
- osi_free_and_reset((void**)&data_);
+ osi_free(data_);
+ data_ = nullptr;
data_length_ = 0;
}
@@ -1396,7 +1398,7 @@ void BtifAvSource::DispatchSuspendStreamEvent(btif_av_sm_event_t event) {
if (event != BTIF_AV_SUSPEND_STREAM_REQ_EVT &&
event != BTIF_AV_STOP_STREAM_REQ_EVT) {
log::error("Invalid event: {} id: {}", dump_av_sm_event_name(event),
- (int)event);
+ static_cast<int>(event));
return;
}
bool av_stream_idle = true;
@@ -1442,7 +1444,7 @@ void BtifAvSource::CleanupAllPeers() {
void BtifAvSource::RegisterAllBtaHandles() {
for (int peer_id = kPeerIdMin; peer_id < kPeerIdMax; peer_id++) {
- BTA_AvRegister(BTA_AV_CHNL_AUDIO, kBtifAvSourceServiceName.c_str(), peer_id,
+ BTA_AvRegister(BTA_AV_CHNL_AUDIO, kBtifAvSourceServiceName, peer_id,
nullptr, UUID_SERVCLASS_AUDIO_SOURCE);
}
}
@@ -1718,7 +1720,7 @@ void BtifAvSink::CleanupAllPeers() {
void BtifAvSink::RegisterAllBtaHandles() {
for (int peer_id = kPeerIdMin; peer_id < kPeerIdMax; peer_id++) {
- BTA_AvRegister(BTA_AV_CHNL_AUDIO, kBtifAvSinkServiceName.c_str(), peer_id,
+ BTA_AvRegister(BTA_AV_CHNL_AUDIO, kBtifAvSinkServiceName, peer_id,
bta_av_sink_media_callback, UUID_SERVCLASS_AUDIO_SINK);
}
}
@@ -1894,7 +1896,8 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) {
log::error("Source profile doesn't allow connection to peer:{}",
peer_.PeerAddress());
if (btif_av_src_sink_coexist_enabled())
- BTA_AvCloseRc(((tBTA_AV*)p_data)->rc_open.rc_handle);
+ BTA_AvCloseRc(
+ (reinterpret_cast<tBTA_AV*>(p_data))->rc_open.rc_handle);
else
btif_av_source_disconnect(peer_.PeerAddress());
}
@@ -1904,7 +1907,8 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) {
log::error("Sink profile doesn't allow connection to peer:{}",
peer_.PeerAddress());
if (btif_av_src_sink_coexist_enabled())
- BTA_AvCloseRc(((tBTA_AV*)p_data)->rc_open.rc_handle);
+ BTA_AvCloseRc(
+ (reinterpret_cast<tBTA_AV*>(p_data))->rc_open.rc_handle);
else
btif_av_sink_disconnect(peer_.PeerAddress());
}
@@ -1937,12 +1941,12 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) {
}
}
if (event == BTA_AV_RC_OPEN_EVT) {
- btif_rc_handler(event, (tBTA_AV*)p_data);
+ btif_rc_handler(event, reinterpret_cast<tBTA_AV*>(p_data));
}
} break;
case BTA_AV_RC_BROWSE_OPEN_EVT:
- btif_rc_handler(event, (tBTA_AV*)p_data);
+ btif_rc_handler(event, reinterpret_cast<tBTA_AV*>(p_data));
break;
// In case Signalling channel is not down and remote started Streaming
@@ -1957,7 +1961,7 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) {
} break;
case BTA_AV_OPEN_EVT: {
- tBTA_AV* p_bta_data = (tBTA_AV*)p_data;
+ tBTA_AV* p_bta_data = reinterpret_cast<tBTA_AV*>(p_data);
tBTA_AV_STATUS status = p_bta_data->open.status;
bool can_connect = true;
@@ -2070,7 +2074,7 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) {
case BTA_AV_RC_FEAT_EVT:
case BTA_AV_RC_PSM_EVT:
case BTA_AV_REMOTE_RSP_EVT:
- btif_rc_handler(event, (tBTA_AV*)p_data);
+ btif_rc_handler(event, reinterpret_cast<tBTA_AV*>(p_data));
break;
case BTIF_AV_AVRCP_CLOSE_EVT:
@@ -2080,7 +2084,7 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) {
alarm_cancel(peer_.AvOpenOnRcTimer());
if (event == BTA_AV_RC_CLOSE_EVT) {
- btif_rc_handler(event, (tBTA_AV*)p_data);
+ btif_rc_handler(event, reinterpret_cast<tBTA_AV*>(p_data));
}
} break;
@@ -2164,7 +2168,7 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event,
break;
case BTA_AV_OPEN_EVT: {
- tBTA_AV* p_bta_data = (tBTA_AV*)p_data;
+ tBTA_AV* p_bta_data = reinterpret_cast<tBTA_AV*>(p_data);
int av_state;
tBTA_AV_STATUS status = p_bta_data->open.status;
@@ -2372,7 +2376,7 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event,
}
break;
- CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
+ CHECK_RC_EVENT(event, reinterpret_cast<tBTA_AV*>(p_data));
default:
log_counter_metrics_btif(android::bluetooth::CodePathCounterKeyEnum::
@@ -2414,7 +2418,7 @@ void BtifAvStateMachine::StateOpened::OnExit() {
bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event,
void* p_data) {
- tBTA_AV* p_av = (tBTA_AV*)p_data;
+ tBTA_AV* p_av = reinterpret_cast<tBTA_AV*>(p_data);
log::info("state=Opened peer={} event={} flags={} active_peer={}",
peer_.PeerAddress(), BtifAvEvent::EventName(event),
@@ -2434,6 +2438,9 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event,
case BTIF_AV_ACL_DISCONNECTED:
break; // Ignore
+ // Event sent by the Bluetooth Audio HAL to a source A2DP stack
+ // when a stream is ready to play. The stack shall send AVDTP Start to the
+ // remote device to start the stream.
case BTIF_AV_START_STREAM_REQ_EVT: {
log::info("Peer {} : event={} flags={}", peer_.PeerAddress(),
BtifAvEvent::EventName(event), peer_.FlagsToString());
@@ -2449,6 +2456,10 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event,
peer_.SetFlags(BtifAvPeer::kFlagPendingStart);
} break;
+ // Event sent by lower layer to indicate that the AVDTP stream is started.
+ // May be initiated by the remote device to start a stream, in this case the
+ // event is ignored by source A2DP, and the stack shall immediately suspend
+ // the stream.
case BTA_AV_START_EVT: {
log::info(
"Peer {} : event={} status={} suspending={} initiator={} flags={}",
@@ -2475,13 +2486,14 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event,
should_suspend = true;
}
- // If peer is A2DP Source, do ACK commands to audio HAL and start
- // media task
- if (btif_a2dp_on_started(
- peer_.PeerAddress(), &p_av->start,
- peer_.IsSource() ? A2dpType::kSink : A2dpType::kSource)) {
- // Only clear pending flag after acknowledgement
- peer_.ClearFlags(BtifAvPeer::kFlagPendingStart);
+ // Invoke the started handler only when initiator.
+ if (!com::android::bluetooth::flags::a2dp_ignore_started_when_responder() ||
+ peer_.CheckFlags(BtifAvPeer::kFlagPendingStart)) {
+ if (btif_a2dp_on_started(
+ peer_.PeerAddress(), &p_av->start, A2dpType::kSource)) {
+ // Only clear pending flag after acknowledgement
+ peer_.ClearFlags(BtifAvPeer::kFlagPendingStart);
+ }
}
}
@@ -2499,8 +2511,8 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event,
BTIF_AV_SUSPEND_STREAM_REQ_EVT);
}
peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateStarted);
-
- } break;
+ break;
+ }
case BTIF_AV_DISCONNECT_REQ_EVT:
BTA_AvClose(peer_.BtaHandle());
@@ -2604,7 +2616,7 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event,
}
break;
- CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
+ CHECK_RC_EVENT(event, reinterpret_cast<tBTA_AV*>(p_data));
case BTIF_AV_SET_LATENCY_REQ_EVT: {
const btif_av_set_latency_req_t* p_set_latency_req =
@@ -2645,7 +2657,7 @@ void BtifAvStateMachine::StateStarted::OnExit() {
bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event,
void* p_data) {
- tBTA_AV* p_av = (tBTA_AV*)p_data;
+ tBTA_AV* p_av = reinterpret_cast<tBTA_AV*>(p_data);
log::info("state=Started peer={} event={} flags={} active_peer={}",
peer_.PeerAddress(), BtifAvEvent::EventName(event),
@@ -2848,7 +2860,7 @@ bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event,
BTA_AvSetLatency(peer_.BtaHandle(), p_set_latency_req->is_low_latency);
} break;
- CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
+ CHECK_RC_EVENT(event, reinterpret_cast<tBTA_AV*>(p_data));
default:
log::warn("Peer {} : Unhandled event={}", peer_.PeerAddress(),
@@ -2908,12 +2920,12 @@ bool BtifAvStateMachine::StateClosing::ProcessEvent(uint32_t event,
// Handle the RC_CLOSE event for the cleanup
case BTA_AV_RC_CLOSE_EVT:
- btif_rc_handler(event, (tBTA_AV*)p_data);
+ btif_rc_handler(event, reinterpret_cast<tBTA_AV*>(p_data));
break;
// Handle the RC_BROWSE_CLOSE event for testing
case BTA_AV_RC_BROWSE_CLOSE_EVT:
- btif_rc_handler(event, (tBTA_AV*)p_data);
+ btif_rc_handler(event, reinterpret_cast<tBTA_AV*>(p_data));
break;
case BTIF_AV_OFFLOAD_START_REQ_EVT:
@@ -2943,7 +2955,7 @@ bool BtifAvStateMachine::StateClosing::ProcessEvent(uint32_t event,
* interoperate with headsets that do establish AV after AVRCP connection.
*/
static void btif_av_source_initiate_av_open_timer_timeout(void* data) {
- BtifAvPeer* peer = (BtifAvPeer*)data;
+ BtifAvPeer* peer = reinterpret_cast<BtifAvPeer*>(data);
bool device_connected = false;
if (com::android::bluetooth::flags::avrcp_connect_a2dp_delayed() &&
@@ -2980,7 +2992,7 @@ static void btif_av_source_initiate_av_open_timer_timeout(void* data) {
* establishes AVRCP connection without AV connection.
*/
static void btif_av_sink_initiate_av_open_timer_timeout(void* data) {
- BtifAvPeer* peer = (BtifAvPeer*)data;
+ BtifAvPeer* peer = reinterpret_cast<BtifAvPeer*>(data);
log::verbose("Peer {}", peer->PeerAddress());
@@ -3296,7 +3308,7 @@ static void btif_av_handle_bta_av_event(uint8_t peer_sep,
RawAddress peer_address = RawAddress::kEmpty;
tBTA_AV_HNDL bta_handle = kBtaHandleUnknown;
tBTA_AV_EVT event = btif_av_event.Event();
- tBTA_AV* p_data = (tBTA_AV*)btif_av_event.Data();
+ tBTA_AV* p_data = reinterpret_cast<tBTA_AV*>(btif_av_event.Data());
std::string msg;
log::verbose("peer_sep={} event={}", peer_stream_endpoint_text(peer_sep),
@@ -3406,8 +3418,9 @@ static void btif_av_handle_bta_av_event(uint8_t peer_sep,
peer_address = btif_av_sink.ActivePeer();
}
break;
- } else
+ } else {
FALLTHROUGH_INTENDED;
+ }
}
case BTA_AV_OFFLOAD_START_RSP_EVT: {
// TODO: Might be wrong - this code will be removed once those
@@ -3530,7 +3543,8 @@ static void bta_av_sink_media_callback(const RawAddress& peer_address,
int state = peer->StateMachine().StateId();
if ((state == BtifAvStateMachine::kStateStarted) ||
(state == BtifAvStateMachine::kStateOpened)) {
- uint8_t queue_len = btif_a2dp_sink_enqueue_buf((BT_HDR*)p_data);
+ uint8_t queue_len =
+ btif_a2dp_sink_enqueue_buf(reinterpret_cast<BT_HDR*>(p_data));
log::verbose("Packets in Sink queue {}", queue_len);
}
}
@@ -3542,7 +3556,8 @@ static void bta_av_sink_media_callback(const RawAddress& peer_address,
log::verbose("address={}", p_data->avk_config.bd_addr);
// Update the codec info of the A2DP Sink decoder
- btif_a2dp_sink_update_decoder((uint8_t*)(p_data->avk_config.codec_info));
+ btif_a2dp_sink_update_decoder(
+ reinterpret_cast<uint8_t*>(p_data->avk_config.codec_info));
config_req.sample_rate =
A2DP_GetTrackSampleRate(p_data->avk_config.codec_info);
diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc
index 4778c9403c..34f027a676 100644
--- a/system/btif/src/btif_dm.cc
+++ b/system/btif/src/btif_dm.cc
@@ -854,20 +854,7 @@ static void btif_dm_cb_create_bond(const RawAddress bd_addr,
static_cast<tBT_DEVICE_TYPE>(device_type));
}
- if (!com::android::bluetooth::flags::connect_hid_after_service_discovery() &&
- is_hid && (device_type & BT_DEVICE_TYPE_BLE) == 0) {
- tAclLinkSpec link_spec;
- link_spec.addrt.bda = bd_addr;
- link_spec.addrt.type = addr_type;
- link_spec.transport = transport;
- const bt_status_t status =
- GetInterfaceToProfiles()->profileSpecific_HACK->btif_hh_connect(
- link_spec);
- if (status != BT_STATUS_SUCCESS)
- bond_state_changed(status, bd_addr, BT_BOND_STATE_NONE);
- } else {
- BTA_DmBond(bd_addr, addr_type, transport, device_type);
- }
+ BTA_DmBond(bd_addr, addr_type, transport, device_type);
/* Track originator of bond creation */
pairing_cb.is_local_initiated = true;
}
@@ -1658,27 +1645,8 @@ static bool btif_should_ignore_uuid(const Uuid& uuid) {
}
static bool btif_is_gatt_service_discovery_post_pairing(const RawAddress bd_addr) {
- if (!com::android::bluetooth::flags::
- reset_pairing_only_for_related_service_discovery()) {
- if (bd_addr == pairing_cb.bd_addr || bd_addr == pairing_cb.static_bdaddr) {
- if (pairing_cb.gatt_over_le !=
- btif_dm_pairing_cb_t::ServiceDiscoveryState::SCHEDULED) {
- log::error(
- "gatt_over_le should be SCHEDULED, did someone clear the control "
- "block for {} ?",
- bd_addr);
- }
-
- return true;
- }
-
- return false;
- }
-
- return ((bd_addr == pairing_cb.bd_addr ||
- bd_addr == pairing_cb.static_bdaddr) &&
- (pairing_cb.gatt_over_le ==
- btif_dm_pairing_cb_t::ServiceDiscoveryState::SCHEDULED));
+ return (bd_addr == pairing_cb.bd_addr || bd_addr == pairing_cb.static_bdaddr) &&
+ (pairing_cb.gatt_over_le == btif_dm_pairing_cb_t::ServiceDiscoveryState::SCHEDULED);
}
static void btif_merge_existing_uuids(RawAddress& addr, std::set<Uuid>* uuids) {
@@ -1716,11 +1684,7 @@ static void btif_on_service_discovery_results(
if (pairing_cb.sdp_attempts) {
log::warn("SDP failed after bonding re-attempting for {}", bd_addr);
pairing_cb.sdp_attempts++;
- if (com::android::bluetooth::flags::force_bredr_for_sdp_retry()) {
- btif_dm_get_remote_services(bd_addr, BT_TRANSPORT_BR_EDR);
- } else {
- btif_dm_get_remote_services(bd_addr, BT_TRANSPORT_AUTO);
- }
+ btif_dm_get_remote_services(bd_addr, BT_TRANSPORT_BR_EDR);
} else {
log::warn("SDP triggered by someone failed when bonding");
}
@@ -3493,10 +3457,6 @@ static void btif_dm_ble_key_notif_evt(tBTA_DM_SP_KEY_NOTIF* p_ssp_key_notif) {
static bool btif_dm_ble_is_temp_pairing(RawAddress& bd_addr, bool ctkd) {
if (btm_get_bond_type_dev(bd_addr) == BOND_TYPE_TEMPORARY) {
- if (!com::android::bluetooth::flags::ignore_bond_type_for_le()) {
- return true;
- }
-
return ctkd;
}
diff --git a/system/gd/rust/linux/stack/src/bluetooth_media.rs b/system/gd/rust/linux/stack/src/bluetooth_media.rs
index 6275fc5aec..a3f9eb19a2 100644
--- a/system/gd/rust/linux/stack/src/bluetooth_media.rs
+++ b/system/gd/rust/linux/stack/src/bluetooth_media.rs
@@ -1254,6 +1254,12 @@ impl BluetoothMedia {
BtavConnectionState::Disconnected => {
info!("[{}]: a2dp disconnected.", DisplayAddress(&addr));
+ if self.a2dp_audio_connection_listener.is_some() {
+ let listener = self.a2dp_audio_connection_listener.take().unwrap();
+ let data: Vec<u8> = vec![0];
+ self.write_data_to_listener(listener, data);
+ }
+
self.a2dp_states.remove(&addr);
self.a2dp_caps.remove(&addr);
self.a2dp_audio_state.remove(&addr);
@@ -1484,6 +1490,13 @@ impl BluetoothMedia {
}
BthfConnectionState::Disconnected => {
info!("[{}]: hfp disconnected.", DisplayAddress(&addr));
+
+ if self.hfp_audio_connection_listener.is_some() {
+ let listener = self.hfp_audio_connection_listener.take().unwrap();
+ let data: Vec<u8> = vec![0];
+ self.write_data_to_listener(listener, data);
+ }
+
self.uhid_destroy(&addr);
self.hfp_states.remove(&addr);
self.hfp_cap.remove(&addr);
@@ -3047,14 +3060,8 @@ impl BluetoothMedia {
return;
}
- self.call_list.push(CallInfo {
- index: 1,
- dir_incoming: false,
- state: CallState::Active,
- number: "".into(),
- });
- self.phone_state.num_active = 1;
- self.phone_state_change("".into());
+ self.dialing_call_impl("".into(), None);
+ self.answer_call_impl();
}
pub fn get_group_devices(&self, group_id: i32) -> HashSet<RawAddress> {
diff --git a/system/gd/rust/topshim/btav_sink/btav_sink_shim.cc b/system/gd/rust/topshim/btav_sink/btav_sink_shim.cc
index b97015f5fa..5c1103d12c 100644
--- a/system/gd/rust/topshim/btav_sink/btav_sink_shim.cc
+++ b/system/gd/rust/topshim/btav_sink/btav_sink_shim.cc
@@ -18,8 +18,8 @@
#include <memory>
-#include "include/hardware/bluetooth.h"
#include "btif/include/btif_av.h"
+#include "include/hardware/bluetooth.h"
#include "rust/cxx.h"
#include "src/profiles/a2dp.rs.h"
#include "types/raw_address.h"
diff --git a/system/log/src/vlog_android.cc b/system/log/src/vlog_android.cc
index a0c5b1bff4..e6bb2006a5 100644
--- a/system/log/src/vlog_android.cc
+++ b/system/log/src/vlog_android.cc
@@ -29,8 +29,7 @@ static constexpr size_t kBufferSize = 1024;
void vlog(Level level, char const* tag, source_location location,
fmt::string_view fmt, fmt::format_args vargs) {
// Check if log is enabled.
- if (!__android_log_is_loggable(level, tag, ANDROID_LOG_INFO) &&
- !__android_log_is_loggable(level, "bluetooth", ANDROID_LOG_INFO)) {
+ if (!__android_log_is_loggable(level, "bluetooth", ANDROID_LOG_INFO)) {
return;
}
diff --git a/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc b/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc
index cf30d98cd9..32de722326 100644
--- a/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc
+++ b/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc
@@ -1,77 +1,239 @@
-#include <cstddef>
-#include <cstdint>
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
-#include "avrcp_packet.h"
#include "device.h"
+#include "fuzzer/FuzzedDataProvider.h"
#include "internal_include/stack_config.h"
#include "packet_test_helper.h"
-#include "stack/include/a2dp_api.h"
-#include "types/raw_address.h"
+#include "pass_through_packet.h"
bool btif_av_src_sink_coexist_enabled(void) { return true; }
namespace bluetooth {
namespace avrcp {
+
+static uint32_t kMinSize = 0;
+static uint32_t kMaxSize = 10;
+static uint32_t kMaxLen = 100;
+static uint8_t kMinScope = 0;
+static uint8_t kMaxScope = 3;
+static uint8_t kMediaOpId = 0x44;
+static uint8_t kMask = 0xFF;
+static uint8_t k8BitShift = 8;
+
+const Opcode kValidOpCodes[] = {Opcode::VENDOR, Opcode::UNIT_INFO,
+ Opcode::SUBUNIT_INFO, Opcode::PASS_THROUGH};
+
+const CType kValidCTypes[] = {
+ CType::CONTROL, CType::STATUS, CType::NOTIFY,
+ CType::NOT_IMPLEMENTED, CType::ACCEPTED, CType::REJECTED,
+ CType::STABLE, CType::CHANGED, CType::INTERIM};
+
+const BrowsePdu kPduVal[] = {BrowsePdu::SET_BROWSED_PLAYER,
+ BrowsePdu::GET_FOLDER_ITEMS,
+ BrowsePdu::CHANGE_PATH,
+ BrowsePdu::GET_ITEM_ATTRIBUTES,
+ BrowsePdu::GET_TOTAL_NUMBER_OF_ITEMS,
+ BrowsePdu::GENERAL_REJECT};
+
+const CommandPdu kCommandPduVal[] = {
+ CommandPdu::GET_CAPABILITIES,
+ CommandPdu::LIST_PLAYER_APPLICATION_SETTING_ATTRIBUTES,
+ CommandPdu::LIST_PLAYER_APPLICATION_SETTING_VALUES,
+ CommandPdu::GET_CURRENT_PLAYER_APPLICATION_SETTING_VALUE,
+ CommandPdu::SET_PLAYER_APPLICATION_SETTING_VALUE,
+ CommandPdu::GET_ELEMENT_ATTRIBUTES,
+ CommandPdu::GET_PLAY_STATUS,
+ CommandPdu::REGISTER_NOTIFICATION,
+ CommandPdu::SET_ABSOLUTE_VOLUME,
+ CommandPdu::SET_ADDRESSED_PLAYER,
+ CommandPdu::PLAY_ITEM};
+
class FakeMediaInterface : public MediaInterface {
public:
- virtual void SendKeyEvent(uint8_t key, KeyState state) {}
+ FakeMediaInterface(FuzzedDataProvider* fdp) : mFdp(fdp) {}
+ void SendKeyEvent(uint8_t /* key */, KeyState /* state */) { return; }
using SongInfoCallback = base::Callback<void(SongInfo)>;
- virtual void GetSongInfo(SongInfoCallback info_cb) {}
+ void GetSongInfo(SongInfoCallback info_cb) {
+ SongInfo sInfo;
+ sInfo.media_id = mFdp->ConsumeRandomLengthString(kMaxLen);
+ sInfo.attributes.insert(AttributeEntry(
+ Attribute(mFdp->ConsumeIntegralInRange<uint8_t>(
+ uint8_t(Attribute::TITLE), uint8_t(Attribute::DEFAULT_COVER_ART))),
+ mFdp->ConsumeRandomLengthString(kMaxLen)));
+ info_cb.Run(sInfo);
+ return;
+ }
using PlayStatusCallback = base::Callback<void(PlayStatus)>;
- virtual void GetPlayStatus(PlayStatusCallback status_cb) {}
+ void GetPlayStatus(PlayStatusCallback status_cb) {
+ PlayStatus pst;
+ status_cb.Run(pst);
+ return;
+ }
using NowPlayingCallback =
base::Callback<void(std::string, std::vector<SongInfo>)>;
- virtual void GetNowPlayingList(NowPlayingCallback now_playing_cb) {}
+ void GetNowPlayingList(NowPlayingCallback now_playing_cb) {
+ std::string currentSongId = mFdp->ConsumeRandomLengthString(kMaxLen);
+ size_t size = mFdp->ConsumeIntegralInRange<uint8_t>(kMinSize, kMaxSize);
+ std::vector<SongInfo> songInfoVec;
+ for (size_t iter = 0; iter < size; ++iter) {
+ SongInfo tempSongInfo;
+ tempSongInfo.media_id = mFdp->ConsumeRandomLengthString(kMaxLen);
+ tempSongInfo.attributes.insert(
+ AttributeEntry(Attribute(mFdp->ConsumeIntegralInRange<uint8_t>(
+ uint8_t(Attribute::TITLE),
+ uint8_t(Attribute::DEFAULT_COVER_ART))),
+ mFdp->ConsumeRandomLengthString(kMaxLen)));
+ songInfoVec.push_back(tempSongInfo);
+ }
+ now_playing_cb.Run(currentSongId, songInfoVec);
+ return;
+ }
using MediaListCallback =
base::Callback<void(uint16_t curr_player, std::vector<MediaPlayerInfo>)>;
- virtual void GetMediaPlayerList(MediaListCallback list_cb) {}
+ void GetMediaPlayerList(MediaListCallback list_cb) {
+ uint16_t currentPlayer = mFdp->ConsumeIntegral<uint16_t>();
+ size_t size = mFdp->ConsumeIntegralInRange<uint8_t>(kMinSize, kMaxSize);
+ std::vector<MediaPlayerInfo> playerList;
+ for (size_t iter = 0; iter < size; ++iter) {
+ MediaPlayerInfo tempInfo;
+ tempInfo.id = mFdp->ConsumeIntegral<uint16_t>();
+ tempInfo.name = mFdp->ConsumeRandomLengthString(kMaxLen);
+ tempInfo.browsing_supported = mFdp->ConsumeBool();
+ playerList.push_back(tempInfo);
+ }
+ list_cb.Run(currentPlayer, playerList);
+ return;
+ }
using FolderItemsCallback = base::Callback<void(std::vector<ListItem>)>;
- virtual void GetFolderItems(uint16_t player_id, std::string media_id,
- FolderItemsCallback folder_cb) {}
+ void GetFolderItems(uint16_t /* player_id */, std::string /* media_id */,
+ FolderItemsCallback folder_cb) {
+ size_t size = mFdp->ConsumeIntegralInRange<uint8_t>(kMinSize, kMaxSize);
+ std::vector<ListItem> list;
+ for (size_t iter = 0; iter < size; ++iter) {
+ ListItem tempList;
+ tempList.type = mFdp->ConsumeBool() ? ListItem::FOLDER : ListItem::SONG;
+ tempList.folder.media_id = mFdp->ConsumeRandomLengthString(kMaxLen);
+ tempList.folder.name = mFdp->ConsumeRandomLengthString(kMaxLen);
+ tempList.folder.is_playable = mFdp->ConsumeBool();
+ tempList.song.media_id = mFdp->ConsumeRandomLengthString(kMaxLen);
+ tempList.song.attributes.insert(
+ AttributeEntry(Attribute(mFdp->ConsumeIntegralInRange<uint8_t>(
+ uint8_t(Attribute::TITLE),
+ uint8_t(Attribute::DEFAULT_COVER_ART))),
+ mFdp->ConsumeRandomLengthString(kMaxLen)));
+ list.push_back(tempList);
+ }
+ folder_cb.Run(list);
+ }
using SetBrowsedPlayerCallback = base::Callback<void(
bool success, std::string root_id, uint32_t num_items)>;
- virtual void SetBrowsedPlayer(uint16_t player_id,
- SetBrowsedPlayerCallback browse_cb) {}
- virtual void PlayItem(uint16_t player_id, bool now_playing,
- std::string media_id) {}
- virtual void SetActiveDevice(const RawAddress& address) {}
- virtual void RegisterUpdateCallback(MediaCallbacks* callback) {}
- virtual void UnregisterUpdateCallback(MediaCallbacks* callback) {}
+ void SetBrowsedPlayer(uint16_t player_id,
+ SetBrowsedPlayerCallback browse_cb) {
+ std::string rootId = mFdp->ConsumeRandomLengthString(kMaxLen);
+ uint32_t numItems = mFdp->ConsumeIntegral<uint32_t>();
+ browse_cb.Run(player_id, rootId, numItems);
+ return;
+ }
+ void PlayItem(uint16_t /* player_id */, bool /* now_playing */,
+ std::string /* media_id */) {
+ return;
+ }
+ void SetActiveDevice(const RawAddress& /* address */) { return; }
+ void RegisterUpdateCallback(MediaCallbacks* /* callback */) { return; }
+ void UnregisterUpdateCallback(MediaCallbacks* /* callback */) { return; }
+
+ private:
+ FuzzedDataProvider* mFdp;
};
class FakeVolumeInterface : public VolumeInterface {
public:
- virtual void DeviceConnected(const RawAddress& bdaddr) {}
- virtual void DeviceConnected(const RawAddress& bdaddr, VolumeChangedCb cb) {}
- virtual void DeviceDisconnected(const RawAddress& bdaddr) {}
- virtual void SetVolume(int8_t volume) {}
+ FakeVolumeInterface(FuzzedDataProvider* fdp) : mFdp(fdp) {}
+ void DeviceConnected(const RawAddress& /* bdaddr */) { return; }
+ void DeviceConnected(const RawAddress& /* bdaddr */, VolumeChangedCb cb) {
+ uint8_t volume = mFdp->ConsumeIntegral<uint8_t>();
+ cb.Run(volume);
+ return;
+ }
+ void DeviceDisconnected(const RawAddress& /* bdaddr */) { return; }
+ void SetVolume(int8_t /* volume */) { return; }
+
+ private:
+ FuzzedDataProvider* mFdp;
};
class FakePlayerSettingsInterface : public PlayerSettingsInterface {
public:
- virtual void ListPlayerSettings(ListPlayerSettingsCallback cb) {}
- virtual void ListPlayerSettingValues(PlayerAttribute setting,
- ListPlayerSettingValuesCallback cb) {}
- virtual void GetCurrentPlayerSettingValue(
- std::vector<PlayerAttribute> attributes,
- GetCurrentPlayerSettingValueCallback cb) {}
- virtual void SetPlayerSettings(std::vector<PlayerAttribute> attributes,
- std::vector<uint8_t> values,
- SetPlayerSettingValueCallback cb) {}
+ FakePlayerSettingsInterface(FuzzedDataProvider* fdp) : mFdp(fdp) {}
+ void ListPlayerSettings(ListPlayerSettingsCallback cb) {
+ uint8_t label = mFdp->ConsumeIntegral<uint8_t>();
+ size_t size = mFdp->ConsumeIntegralInRange<uint8_t>(kMinSize, kMaxSize);
+ std::vector<PlayerAttribute> attributes;
+ for (size_t iter = 0; iter < size; ++iter) {
+ PlayerAttribute playerAttr =
+ (PlayerAttribute)mFdp->ConsumeIntegralInRange<uint8_t>(
+ uint8_t(PlayerAttribute::EQUALIZER),
+ uint8_t(PlayerAttribute::SCAN));
+ attributes.push_back(playerAttr);
+ }
+ cb.Run(attributes);
+ return;
+ }
+ void ListPlayerSettingValues(PlayerAttribute setting,
+ ListPlayerSettingValuesCallback cb) {
+ size_t size = mFdp->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+ std::vector<uint8_t> values = mFdp->ConsumeBytes<uint8_t>(size);
+ cb.Run(setting, values);
+ return;
+ }
+ void GetCurrentPlayerSettingValue(std::vector<PlayerAttribute> attributes,
+ GetCurrentPlayerSettingValueCallback cb) {
+ std::vector<uint8_t> values(attributes.size());
+ for (size_t iter = 0; iter < attributes.size(); ++iter) {
+ values.push_back(mFdp->ConsumeIntegral<uint8_t>());
+ }
+ cb.Run(attributes, values);
+ return;
+ }
+ void SetPlayerSettings(std::vector<PlayerAttribute> /* attributes */,
+ std::vector<uint8_t> /* values */,
+ SetPlayerSettingValueCallback cb) {
+ bool success = mFdp->ConsumeBool();
+ cb.Run(success);
+ return;
+ }
+
+ private:
+ FuzzedDataProvider* mFdp;
};
class FakeA2dpInterface : public A2dpInterface {
public:
- virtual RawAddress active_peer() { return RawAddress(); }
- virtual bool is_peer_in_silence_mode(const RawAddress& peer_address) {
+ RawAddress active_peer() { return RawAddress::kAny; }
+ bool is_peer_in_silence_mode(const RawAddress& /* peer_address */) {
return false;
}
- virtual void connect_audio_sink_delayed(uint8_t handle,
- const RawAddress& peer_address) {
+ void connect_audio_sink_delayed(uint8_t /* handle */,
+ const RawAddress& /* peer_address */) {
return;
}
- virtual uint16_t find_audio_sink_service(const RawAddress& peer_address,
- tA2DP_FIND_CBACK p_cback) override {
+ uint16_t find_audio_sink_service(const RawAddress& /* peer_address */,
+ tA2DP_FIND_CBACK /* p_cback */) override {
return 0;
}
};
@@ -103,25 +265,124 @@ const stack_config_t interface = {get_pts_avrcp_test,
void Callback(uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {}
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
- FakeMediaInterface fmi;
- FakeVolumeInterface fvi;
+class AVRCPDeviceFuzzer {
+ public:
+ AVRCPDeviceFuzzer(const uint8_t* Data, size_t Size) : mFdp(Data, Size) {}
+ void Process();
+
+ private:
+ void CreateBrowsePacket(std::vector<uint8_t>& packet);
+ void CreateAvrcpPacket(std::vector<uint8_t>& packet);
+ FuzzedDataProvider mFdp;
+};
+
+void AVRCPDeviceFuzzer::CreateBrowsePacket(std::vector<uint8_t>& packet) {
+ // Used to consume a maximum of 50% of the data to create packet.
+ // This ensures that we don't completely exhaust data and use the rest 50% for
+ // fuzzing of APIs.
+ packet = mFdp.ConsumeBytes<uint8_t>(mFdp.ConsumeIntegralInRange<size_t>(
+ 0, mFdp.remaining_bytes() * 50 / 100));
+
+ if (packet.size() < Packet::kMinSize()) {
+ packet.resize(Packet::kMinSize());
+ }
+ packet[0] = (uint8_t)mFdp.PickValueInArray(kPduVal);
+ // Set packet[1] and packet[2] to corresponding value of little endian
+ uint16_t size = packet.size() - BrowsePacket::kMinSize();
+ packet[1] = (size >> k8BitShift) & kMask;
+ packet[2] = size & kMask;
+}
+
+void AVRCPDeviceFuzzer::CreateAvrcpPacket(std::vector<uint8_t>& packet) {
+ // Used to consume a maximum of 50% of the data to create packet.
+ // This ensures that we don't completely exhaust data and use the rest 50% for
+ // fuzzing of APIs.
+ packet = mFdp.ConsumeBytes<uint8_t>(mFdp.ConsumeIntegralInRange<size_t>(
+ 0, mFdp.remaining_bytes() * 50 / 100));
+ if (packet.size() < Packet::kMinSize()) {
+ packet.resize(Packet::kMinSize());
+ }
+ packet[0] = (uint8_t)mFdp.PickValueInArray(kValidCTypes);
+ packet[2] = (uint8_t)mFdp.PickValueInArray(kValidOpCodes);
+ if (packet[2] == uint8_t(Opcode::PASS_THROUGH)) {
+ packet.resize(PassThroughPacket::kMinSize());
+ packet[3] =
+ mFdp.ConsumeBool() ? kMediaOpId : mFdp.ConsumeIntegral<uint8_t>();
+ } else if (packet[2] == uint8_t(Opcode::VENDOR)) {
+ if (packet.size() <= VendorPacket::kMinSize()) {
+ packet.resize(VendorPacket::kMinSize() + 1);
+ }
+ packet[3] = mFdp.ConsumeIntegralInRange<uint8_t>(kMinScope, kMaxScope);
+ packet[5] = (uint8_t)mFdp.ConsumeBool(); // Direction
+ packet[6] = (uint8_t)mFdp.PickValueInArray(kCommandPduVal);
+ // Set packet[8] and packet[9] to corresponding value of little endian
+ uint16_t size = packet.size() - VendorPacket::kMinSize();
+ packet[8] = (size >> k8BitShift) & kMask;
+ packet[9] = size & kMask;
+ }
+}
+void AVRCPDeviceFuzzer::Process() {
+ FakeMediaInterface fmi(&mFdp);
+ FakeVolumeInterface fvi(&mFdp);
FakeA2dpInterface fai;
- FakePlayerSettingsInterface fpsi;
+ FakePlayerSettingsInterface fpsi(&mFdp);
- std::vector<uint8_t> Packet(Data, Data + Size);
Device device(
- RawAddress::kAny, true,
+ RawAddress::kAny /* bdaddr */,
+ mFdp.ConsumeBool() /* avrcp13_compatibility */,
base::BindRepeating(
- [](uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {}),
- 0xFFFF, 0xFFFF);
+ [](uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {
+ }) /* send_msg_cb */,
+ mFdp.ConsumeIntegral<uint16_t>() /* ctrl_mtu */,
+ mFdp.ConsumeIntegral<uint16_t>() /* browse_mtu */);
+
device.RegisterInterfaces(&fmi, &fai, &fvi, &fpsi);
- auto browse_request = TestPacketType<BrowsePacket>::Make(Packet);
- device.BrowseMessageReceived(1, browse_request);
+ while (mFdp.remaining_bytes()) {
+ auto invokeAVRCP = mFdp.PickValueInArray<const std::function<void()>>({
+ [&]() {
+ device.SetBrowseMtu(
+ mFdp.ConsumeIntegral<uint16_t>() /* browse_mtu */);
+ },
+ [&]() {
+ device.SetBipClientStatus(mFdp.ConsumeBool() /* connected */);
+ },
+ [&]() {
+ std::vector<uint8_t> browse_packet;
+ CreateBrowsePacket(browse_packet);
+ auto browse_request =
+ TestPacketType<BrowsePacket>::Make(browse_packet);
+ device.BrowseMessageReceived(
+ mFdp.ConsumeIntegral<uint8_t>() /* label */, browse_request);
+ },
+ [&]() {
+ /* Crafting PassThroughPacket Packets */
+ std::vector<uint8_t> avrcp_packet;
+ CreateAvrcpPacket(avrcp_packet);
+ auto avrcp_request =
+ TestPacketType<avrcp::Packet>::Make(avrcp_packet);
+ device.MessageReceived(mFdp.ConsumeIntegral<uint8_t>() /* label */,
+ avrcp_request);
+ },
+ [&]() {
+ device.SendMediaUpdate(mFdp.ConsumeBool() /* metadata */,
+ mFdp.ConsumeBool() /* play_status */,
+ mFdp.ConsumeBool() /* queue */);
+ },
+ [&]() {
+ device.SendFolderUpdate(mFdp.ConsumeBool() /* available_players */,
+ mFdp.ConsumeBool() /* addressed_player */,
+ mFdp.ConsumeBool() /* uids */);
+ },
+ });
+ invokeAVRCP();
+ }
+ device.DeviceDisconnected();
+}
- auto avrcp_request = TestPacketType<avrcp::Packet>::Make(Packet);
- device.MessageReceived(1, avrcp_request);
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ AVRCPDeviceFuzzer avrcp_device_fuzzer(Data, Size);
+ avrcp_device_fuzzer.Process();
return 0;
}
} // namespace avrcp
diff --git a/system/stack/btm/btm_sco_hfp_hal_linux.cc b/system/stack/btm/btm_sco_hfp_hal_linux.cc
index fdb534628e..24dfbd2ed5 100644
--- a/system/stack/btm/btm_sco_hfp_hal_linux.cc
+++ b/system/stack/btm/btm_sco_hfp_hal_linux.cc
@@ -136,7 +136,7 @@ constexpr uint16_t HCI_DEV_NONE = 0xffff;
int btsocket_open_mgmt(uint16_t hci) {
int fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_NONBLOCK, BTPROTO_HCI);
if (fd < 0) {
- log::debug("Failed to open BT socket.");
+ log::debug("Failed to open BT socket, hci: %u", hci);
return -errno;
}
@@ -364,7 +364,7 @@ bool enable_offload(bool enable) {
static bool get_single_codec(int codec, bt_codec** out) {
for (cached_codec_info& c : cached_codecs) {
- if (c.inner.codec == codec) {
+ if (c.inner.codec == static_cast<uint64_t>(codec)) {
*out = &c.inner;
return true;
}
@@ -443,7 +443,7 @@ void set_codec_datapath(tBTA_AG_UUID_CODEC codec_uuid) {
size_t get_packet_size(int codec) {
for (const cached_codec_info& c : cached_codecs) {
- if (c.inner.codec == codec) {
+ if (c.inner.codec == static_cast<uint64_t>(codec)) {
return c.pkt_size;
}
}
diff --git a/system/stack/smp/smp_act.cc b/system/stack/smp/smp_act.cc
index f9c1580039..97fc68c165 100644
--- a/system/stack/smp/smp_act.cc
+++ b/system/stack/smp/smp_act.cc
@@ -535,12 +535,7 @@ void smp_proc_pair_fail(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
p_cb->rcvd_cmd_len);
p_cb->status = SMP_INVALID_PARAMETERS;
} else {
- if (com::android::bluetooth::flags::
- fix_pairing_failure_reason_from_remote()) {
- p_cb->status = static_cast<tSMP_STATUS>(p_data->p_data[0]);
- } else {
- p_cb->status = p_data->status;
- }
+ p_cb->status = static_cast<tSMP_STATUS>(p_data->p_data[0]);
}
/* Cancel pending auth complete timer if set */