关于A2DP硬件卸载功能,描述可以看https://source.android.com/docs/core/connect/bluetooth/hci_requirements#a2dp-hardware-offload-support。
如我在Android Bluetooth A2DP_阅后即奋的博客-CSDN博客中的3.2.7节所述,Audio Stream通过Audio处理器直接发给了BT控制器。
1. 功能开关
1.1 UI开关
继续以Android手机为例,该功能的开关,可以开发者选项中看到开关。
默认地,停用蓝牙A2DP硬件卸载功能是关闭的,双重否定即肯定,那么这里的意思就是默认支持A2DP Hardware Offload功能,也就是前面所述Audio Stream通过Audio处理器直接发给了BT控制器。
1.2 Code Check
判断是否使能A2DP Hardware Offload功能。
// packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterProperties.java
// a2dp offload是否禁用
private static final String A2DP_OFFLOAD_DISABLED_PROPERTY =
"persist.bluetooth.a2dp_offload.disabled";
// a2dp offload是否支持
private static final String A2DP_OFFLOAD_SUPPORTED_PROPERTY =
"ro.bluetooth.a2dp_offload.supported";
// 请斟酌使能和支持的区别
public void init(RemoteDevices remoteDevices) {
// ......
mA2dpOffloadEnabled =
SystemProperties.getBoolean(A2DP_OFFLOAD_SUPPORTED_PROPERTY, false)
&& !SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false);
// ......
}
/**
* @return A2DP offload support
*/
boolean isA2dpOffloadEnabled() {
return mA2dpOffloadEnabled;
}
2. 日志分析。
资源下载:https://download.csdn.net/download/hihan_5/87108298
下面的日志,表示Audio Source设备不支持Bluetooth Broadcast Audio profile。
11-21 16:15:17.255 1002 13479 13515 D A2dpService: setActiveDevice: BA active false
11-21 16:15:17.255 1002 13479 13515 D A2dpService: Switch A2DP devices to CC:98:8B:57:23:39 from null
11-21 16:15:17.255 1002 13479 13515 W A2dpService: setActiveDevice coming out of mutex lock
11-21 16:15:17.256 1002 13479 13515 I BluetoothA2dpServiceJni: setActiveDeviceNative: sBluetoothA2dpInterface: 0x7d043e3d30
// packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
// vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
private boolean setActiveDeviceInternal(BluetoothDevice device) {
// .......
try {
mA2dpNativeInterfaceLock.readLock().lock();
if (mA2dpNativeInterface != null && !mA2dpNativeInterface.setActiveDevice(device)) {
Log.e(TAG, "setActiveDevice(" + device + "): Cannot set as active in native layer");
return false;
}
} finally {
mA2dpNativeInterfaceLock.readLock().unlock();
}
// ......
}
mA2dpNativeInterface.setActiveDevice(device)调用Native函数。
// packages/apps/Bluetooth/jni/com_android_bluetooth_a2dp.cpp
// vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/jni/com_android_bluetooth_a2dp.cpp
static jboolean setActiveDeviceNative(JNIEnv* env, jobject object,
jbyteArray address) {
ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
if (!sBluetoothA2dpInterface) {
ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__);
return JNI_FALSE;
}
jbyte* addr = env->GetByteArrayElements(address, nullptr);
RawAddress bd_addr = RawAddress::kEmpty;
if (addr) {
bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
}
bt_status_t status = sBluetoothA2dpInterface->set_active_device(bd_addr);
if (status != BT_STATUS_SUCCESS) {
ALOGE("%s: Failed A2DP set_active_device, status: %d", __func__, status);
}
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static void initNative(JNIEnv* env, jobject object,
jint maxConnectedAudioDevices,
jobjectArray codecConfigArray,
jobjectArray codecConfigOffload) {
// ......
const bt_interface_t* btInf = getBluetoothInterface();
if (btInf == nullptr) {
ALOGE("%s: Bluetooth module is not loaded", __func__);
return;
}
// ......
sBluetoothA2dpInterface =
(btav_source_interface_t *)btInf->get_profile_interface(
BT_PROFILE_ADVANCED_AUDIO_ID);
// ......
bt_status_t status = sBluetoothA2dpInterface->init(
&sBluetoothA2dpCallbacks, maxConnectedAudioDevices, codec_priorities,
codec_offloading);
// ......
}
这里面重点是找到sBluetoothA2dpInterface指向谁?JNI函数初始化时会执行initNative,这里进行了sBluetoothA2dpInterface的赋值,然后执行了init函数。
先看btInf的指向。
// packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
// vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
const bt_interface_t* getBluetoothInterface() { return sBluetoothInterface; }
static void classInitNative(JNIEnv* env, jclass clazz) {
//......
if (hal_util_load_bt_library((bt_interface_t const**)&sBluetoothInterface)) {
ALOGE("No Bluetooth Library found");
}
}
int hal_util_load_bt_library(const bt_interface_t** interface) {
// #define BLUETOOTH_INTERFACE_STRING "bluetoothInterface"
const char* sym = BLUETOOTH_INTERFACE_STRING;
bt_interface_t* itf = nullptr;
// The library name is not set by default, so the preset library name is used.
char path[PROPERTY_VALUE_MAX] = "";
// 高通机型,这里加载了libbluetooth_qti.so
// 非高通机型,例如MTK,加载libbluetooth.so
property_get(PROPERTY_BT_LIBRARY_NAME, path, DEFAULT_BT_LIBRARY_NAME);
void* handle = dlopen(path, RTLD_NOW);
if (!handle) {
const char* err_str = dlerror();
LOG(ERROR) << __func__ << ": failed to load Bluetooth library, error="
<< (err_str ? err_str : "error unknown");
goto error;
}
// Get the address of the bt_interface_t.
itf = (bt_interface_t*)dlsym(handle, sym);
if (!itf) {
LOG(ERROR) << __func__ << ": failed to load symbol from Bluetooth library "
<< sym;
goto error;
}
// Success.
LOG(INFO) << __func__ << " loaded HAL: btinterface=" << itf
<< ", handle=" << handle;
*interface = itf;
return 0;
error:
*interface = NULL;
if (handle) dlclose(handle);
return -EINVAL;
}
拿到全局变量bluetoothInterface的地址,即btInf指向该地址。
// system/bt/btif/src/bluetooth.cc
// vendor/qcom/opensource/commonsys/system/bt/btif/src/bluetooth.cc
EXPORT_SYMBOL bt_interface_t bluetoothInterface = {
sizeof(bluetoothInterface),
init,
enable,
disable,
cleanup,
get_adapter_properties,
get_adapter_property,
set_adapter_property,
get_remote_device_properties,
get_remote_device_property,
set_remote_device_property,
get_remote_service_record,
get_remote_services,
start_discovery,
cancel_discovery,
create_bond,
create_bond_out_of_band,
remove_bond,
cancel_bond,
get_connection_state,
pin_reply,
ssp_reply,
get_profile_interface,
dut_mode_configure,
dut_mode_send,
le_test_mode,
set_os_callouts,
read_energy_info,
dump,
dumpMetrics,
config_clear,
interop_database_clear,
interop_database_add,
interop_database_name_add,
get_avrcp_service,
obfuscate_address,
get_metric_id,
set_dynamic_audio_buffer_size,
generate_local_oob_data,
};
到这明朗了,sBluetoothA2dpInterface指向get_profile_interface返回的地址。
// system/bt/btif/src/bluetooth.cc
// vendor/qcom/opensource/commonsys/system/bt/btif/src/bluetooth.cc
static const void* get_profile_interface(const char* profile_id) {
// ......
if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID))
return btif_av_get_src_interface();
// ......
}
最终,sBluetoothA2dpInterface指向全局变量bt_av_src_interface。
// system/bt/btif/src/btif_av.cc
// vendor/qcom/opensource/commonsys/system/bt/btif/src/btif_av.cc
const btav_source_interface_t* btif_av_get_src_interface(void) {
BTIF_TRACE_EVENT("%s", __func__);
return &bt_av_src_interface;
}
static const btav_source_interface_t bt_av_src_interface = {
sizeof(btav_source_interface_t),
init_src,
src_connect_sink,
src_disconnect_sink,
set_silence_device,
set_active_device,
#ifdef MULTI_A2DP_ENABLE
enable_multi_a2dp,
disable_multi_a2dp,
set_multi_a2dp_device,
get_multi_a2dp_device,
#endif
codec_config_src,
cleanup_src,
#ifdef BT_AV_SHO_FEATURE
allow_connection,
select_audio_device,
#endif
};
sBluetoothA2dpInterface赋值后,就进行了init初始化动作。
bt_status_t status = sBluetoothA2dpInterface->init(
&sBluetoothA2dpCallbacks, maxConnectedAudioDevices, codec_priorities,
codec_offloading);
// vendor/qcom/opensource/commonsys/system/bt/btif/src/btif_av.cc
/*******************************************************************************
*
* Function init_src
*
* Description Initializes the AV interface for source mode
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t init_src(
btav_source_callbacks_t* callbacks,
const std::vector<btav_a2dp_codec_config_t> &codec_priorities,
const std::vector<btav_a2dp_codec_config_t> &offload_enabled_codecs,
int max_a2dp_connections, int a2dp_multicast_state) {
bt_status_t status = BT_STATUS_FAIL;
BTIF_TRACE_EVENT("%s() with max conn = %d", __func__, max_a2dp_connections);
char value[PROPERTY_VALUE_MAX] = {'\0'};
#if (OFF_TARGET_TEST_ENABLED == FALSE)
// 这部分的代码,就要去看到vendor/qcom/opensource/commonsys/system/bt/device/src/controller.cc
// start_up函数进行了变量的赋值
bt_split_a2dp_enabled = controller_get_interface()->supports_spilt_a2dp();
#else
bt_split_a2dp_enabled = false;
#endif
btif_av_update_multicast_state(0);
BTIF_TRACE_DEBUG("split_a2dp_status = %d",bt_split_a2dp_enabled);
osi_property_get("persist.vendor.btstack.twsplus.defaultchannelmode",
value, "mono");
BTIF_TRACE_DEBUG("tws default channel mode = %s",value);
tws_defaultmono_supported = (strcmp(value, "mono") == 0);
BTIF_TRACE_DEBUG("default mono channel mode = %d",tws_defaultmono_supported);
offload_enabled_codecs_config_ = offload_enabled_codecs;
codec_priorities_ = codec_priorities;
#if (TWS_STATE_ENABLED == TRUE)
//osi_property_get("persist.vendor.btstack.twsplus.state", value, "false");
tws_state_supported =
controller_get_interface()->supports_twsp_remote_state();
#endif
if (bt_av_sink_callbacks != NULL)
// already did btif_av_init()
status = BT_STATUS_SUCCESS;
else {
if (a2dp_multicast_state)
is_multicast_supported = true;
btif_max_av_clients = max_a2dp_connections;
BTIF_TRACE_EVENT("%s() with max conn changed to = %d", __func__,
btif_max_av_clients);
if (btif_av_is_split_a2dp_enabled()) {
btif_a2dp_src_vsc.multi_vsc_support = false;
}
for (int i = 0; i < btif_max_av_clients; i++)
btif_av_cb[i].codec_priorities = codec_priorities;
if (codec_config_update_enabled != false) {
BTIF_TRACE_IMP("%s: Codec cfg update enabled changed to false", __func__);
codec_config_update_enabled = false;
}
// btif_av初始化动作
status = btif_av_init(BTA_A2DP_SOURCE_SERVICE_ID);
if (status == BT_STATUS_SUCCESS) bt_av_src_callbacks = callbacks;
}
return status;
}
如下为蓝牙控制器start_up函数(代码有点长,就不放了,感兴趣的读者自行查阅)打印的日志。
11-21 16:15:15.120 1002 13479 13545 I bt_controller: start_up:: soc_name:hastings, soc_type = 4
11-21 16:15:15.120 1002 13479 13545 I bt_controller: start_up:: spilt_a2dp_supported = 0
11-21 16:15:15.120 1002 13479 13545 I bt_controller: start_up:: a2dp_offload_Cap = sbc-aptx-aptxtws-aptxhd-aac-ldac-aptxadaptiver2
11-21 16:15:15.120 1002 13479 13545 I bt_controller: start_up:: wipower_supported = 0
11-21 16:15:15.120 1002 13479 13545 I bt_controller: start_up:: aac_frame_ctl_enabled = 1
11-21 16:15:15.120 1002 13479 13545 I bt_controller: start_up:: a2dp_multicast_supported = 0
11-21 16:15:15.120 1002 13479 13545 I bt_controller: start_up:: twsp_state_supported = 0
11-21 16:15:15.120 1002 13479 13545 I bt_controller: decode_max_power_values: MAX POW property is not set
11-21 16:15:15.120 1002 13479 13545 I bt_controller: start_up:: max_power_prop_enabled = 0
11-21 16:15:15.128 1002 13479 13545 I bt_controller: start_up Send command to enable soc logging
11-21 16:15:15.128 1002 13479 13545 I bt_controller: send_soc_log_command for soc_type: 4
11-21 16:15:15.160 1002 13479 13545 D bt_controller: start_up read local simple pairing options
11-21 16:15:15.161 1002 13479 13545 D bt_controller: start_up simple pairing options is 0x1
11-21 16:15:15.163 1002 13479 13545 D bt_controller: start_up HCI write RF compensation tx value : 0, rx value : 0
如下为init_src日志。
11-21 16:15:15.329 1002 13479 13479 I bt_btif : btif_av_get_src_interface
11-21 16:15:15.330 1002 13479 13479 I bt_btif : init_src() with max conn = 5
11-21 16:15:15.330 1002 13479 13479 D bt_btif : btif_av_update_multicast_state: max_multi_a2dp:0,multicast_disabled:1
11-21 16:15:15.330 1002 13479 13479 E bt_btif : btif_sm_get_state : Invalid handle
11-21 16:15:15.330 1002 13479 13479 D bt_btif : btif_av_get_num_connected_devices: AV Connection count: 0
11-21 16:15:15.330 1002 13479 13479 D bt_btif : split_a2dp_status = 0
11-21 16:15:15.330 1002 13479 13479 D bt_btif : tws default channel mode = mono
11-21 16:15:15.330 1002 13479 13479 D bt_btif : default mono channel mode = 1
11-21 16:15:15.330 1002 13479 13479 I bt_btif : init_src() with max conn changed to = 5
再其后,btif_av_init -> bta_av_co_init -> A2DP_SetOffloadStatus,这里面会进行各个codec offload的设置,后续会用到。
再回到最初的bt_status_t status = sBluetoothA2dpInterface->set_active_device(bd_addr)。set_active_device中,会去判断btif_av_is_split_a2dp_enabled的值
// vendor/qcom/opensource/commonsys/system/bt/btif/src/btif_av.cc
/*******************************************************************************
*
* Function set_active_device
*
* Description Tears down the AV signalling channel with the remote headset
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t set_active_device(const RawAddress& bd_addr) {
CHECK_BTAV_INIT();
int active_index = btif_av_get_latest_device_idx_to_start();
int set_active_device_index = btif_av_idx_by_bdaddr(&(RawAddress&)bd_addr);
int tws_pair_index = btif_max_av_clients;
BTIF_TRACE_EVENT("%s: active_index: %d, set_active_device_index: %d",
__func__, active_index, set_active_device_index);
// ......
// 在bta_av_core中设置配对设备
if (!bta_av_co_set_active_peer(bd_addr)) {
BTIF_TRACE_WARNING("%s: unable to set active peer in BtaAvCo",__func__);
}
#ifndef SUPPORT_LHDC_CODEC
if (btif_a2dp_source_is_hal_v2_supported()) {
#else
if (btif_av_is_split_a2dp_enabled() || btif_av_get_multicast_state() == true) {
#endif
std::unique_lock<std::mutex> guard(session_wait_mutex_);
session_wait = false;
/* Initiate handoff for the device with address in the argument*/
btif_transfer_context(btif_av_handle_event, BTIF_AV_TRIGGER_HANDOFF_REQ_EVT,
(char *)&bd_addr, sizeof(RawAddress), NULL);
BTIF_TRACE_EVENT("%s: wating for signal",__func__);
session_wait_cv.wait_for(guard, std::chrono::milliseconds(1000),
[]{return session_wait;});
BTIF_TRACE_EVENT("%s: done with signal",__func__);
if (!bd_addr.IsEmpty())
btif_transfer_context(btif_av_handle_event, BTIF_AV_CHECK_PENDING_PLAY_EVT,
(char *)&bd_addr, sizeof(RawAddress), NULL);
return BT_STATUS_SUCCESS;
} else {
/* Initiate handoff for the device with address in the argument*/
return btif_transfer_context(btif_av_handle_event,
BTIF_AV_TRIGGER_HANDOFF_REQ_EVT,(char *)&bd_addr, sizeof(RawAddress), NULL);
}
}
/* SPLITA2DP*/
/*******************************************************************************
*
* Function btif_av_is_split_a2dp_enabled
*
* Description Check if split a2dp is enabled.
*
* Returns TRUE if split a2dp is enabled, FALSE otherwise
*
******************************************************************************/
bool btif_av_is_split_a2dp_enabled() {
//BTIF_TRACE_DEBUG("btif_a2dp_source_is_hal_v2_supported %d ",
// btif_a2dp_source_is_hal_v2_supported());
if (is_multicast_supported) {
//BTIF_TRACE_ERROR("%s,Mulitcast enabled, default non-split mode",__func__);
return false;
}
if (!btif_a2dp_source_is_hal_v2_supported()) {
BTIF_TRACE_DEBUG("btif_av_is_split_a2dp_enabled: %d", bt_split_a2dp_enabled);
return bt_split_a2dp_enabled;
} else if(isBATEnabled()) {
BTIF_TRACE_DEBUG("%s: going for split as BA is active", __func__);
return true;
#ifdef ADV_AUDIO_FEATURE
} else if (btif_bap_broadcast_is_active()) {
return true;
#endif
}else {
if (!bta_av_co_is_active_peer()) {
BTIF_TRACE_ERROR("%s: No active peer codec config found, "
"by default splitmode", __func__);
return true;
}
A2dpCodecConfig* a2dpCodecConfig = bta_av_get_a2dp_current_codec();
if (a2dpCodecConfig == nullptr) {
BTIF_TRACE_ERROR("%s: active peer set but still no current codec "
"available, by default splitmode ", __func__);
return true;
}
if(A2DP_IsCodecEnabledInOffload(a2dpCodecConfig->codecIndex())) {
BTIF_TRACE_DEBUG("%s: going for split ", __func__);
return true;
} else if(A2DP_IsCodecEnabledInSoftware(a2dpCodecConfig->codecIndex())) {
BTIF_TRACE_DEBUG("%s: going for non split ", __func__);
return false;
} else {
BTIF_TRACE_ERROR("%s: current codec is not enabled either of modes"
" going ahead with split", __func__);
return true;
}
}
}
对应日志如下:
11-21 16:15:17.256 1002 13479 13515 E bt_btif : btif_av_get_latest_device_idx_to_start:No valid active device found
11-21 16:15:17.256 1002 13479 13515 I bt_btif : set_active_device: active_index: 5, set_active_device_index: 0
11-21 16:15:17.256 1002 13479 13515 I bt_btif : set_active_device: set_active_device_index flags: 0
11-21 16:15:17.256 1002 13479 13515 I bt_btif : btif_ba_get_state BA not iniitlized
11-21 16:15:17.256 1002 13479 13515 D bt_btif : [BapBroadcast]:btif_bap_broadcast_is_active
11-21 16:15:17.256 1002 13479 13515 E bt_btif : bta_av_co_get_active_peer: active peer index: 0
11-21 16:15:17.256 1002 13479 13515 E bt_btif : bta_av_co_get_active_peer: active peer index: 0
11-21 16:15:17.256 1002 13479 13515 D bt_btif : btif_av_is_split_a2dp_enabled: going for split
从上面日志看,A2DP_IsCodecEnabledInOffload函数返回了true。
bool A2DP_IsCodecEnabledInOffload(btav_a2dp_codec_index_t codec_index) {
bool codec_status = false;
if (offload_capability) {
switch (codec_index) {
case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
codec_status = sbc_offload;
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
codec_status = aac_offload;
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
codec_status = aptx_offload;
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
codec_status = aptxhd_offload;
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_ADAPTIVE:
codec_status = aptx_adaptive_offload;
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
if (!ldac_offload)
LOG_INFO(LOG_TAG,"LDAC not enabled in offload currently");
codec_status = ldac_offload;
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_TWS:
codec_status = aptxtws_offload;
break;
#ifdef SUPPORT_LHDC_CODEC
case BTAV_A2DP_CODEC_INDEX_SOURCE_LHDCV3:
case BTAV_A2DP_CODEC_INDEX_SOURCE_LHDCV2:
case BTAV_A2DP_CODEC_INDEX_SOURCE_LHDCV1:
if (!lhdc_offload)
LOG_INFO(LOG_TAG,"LHDC not enabled in offload currently");
codec_status = lhdc_offload;
break;
#endif
case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
case BTAV_A2DP_QVA_CODEC_INDEX_SOURCE_MAX:
case BTAV_A2DP_CODEC_INDEX_SINK_MAX:
default:
break;
}
}
return codec_status;
}
codec_index的值,是在bta_av_co_init -> A2dpCodecs::init -> A2dpCodecConfig::createCodec中完成了设置。这下面的codec其实就是设备支持的codec。
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec SBC
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec AAC
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec aptX
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec aptX-HD
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec LDAC
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec aptX-adaptive
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec aptX-TWS
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec UNKNOWN CODEC INDEX
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec UNKNOWN CODEC INDEX
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec UNKNOWN CODEC INDEX
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec UNKNOWN CODEC INDEX
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec UNKNOWN CODEC INDEX
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec LHDC_V2
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec LHDC_V3
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec LHDC_V1
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec SBC SINK
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec UNKNOWN CODEC INDEX
11-21 16:15:15.333 1002 13479 13479 D a2dp_codec: createCodec: codec UNKNOWN CODEC INDEX
btif_av_is_split_a2dp_enabled的返回值为true,则表示支持a2dp offload。
11-21 16:15:17.257 1002 13479 13510 E bt_btif_a2dp_source: btif_a2dp_source_restart_session: old_peer_address=00:00:00:00:00:00 new_peer_address=cc:98:8b:57:23:39 is_streaming=0 state=2
11-21 16:15:17.257 1002 13479 13510 E bt_btif_a2dp_source: btif_a2dp_source_start_session: peer_address=cc:98:8b:57:23:39 state=2
11-21 16:15:17.257 1002 13479 13510 W bt_stack: [WARNING:a2dp_encoding.cc(2609)] init
11-21 16:15:17.257 1002 13479 13510 W bt_stack: [WARNING:a2dp_encoding.cc(2584)] get_hal_version
11-21 16:15:17.259 1002 13479 13510 W bt_stack: [WARNING:a2dp_encoding.cc(2591)] get_hal_version:hal version 2.1
11-21 16:15:17.259 1002 13479 13510 I bt_stack: [INFO:a2dp_encoding.cc(1698)] a2dp_get_selected_hal_codec_config_2_1: profile_type: 1
11-21 16:15:17.260 1002 13479 13510 I bt_stack: [INFO:a2dp_encoding.cc(2463)] a2dp_get_selected_hal_codec_config_2_1: codec_type\xFF
11-21 16:15:17.261 1002 13479 13510 I bt_stack: [INFO:a2dp_encoding.cc(2475)] a2dp_get_selected_hal_codec_config_2_1LDAC bitrate0
11-21 16:15:17.261 1002 13479 13510 I bt_stack: [INFO:a2dp_encoding.cc(2526)] a2dp_get_selected_hal_codec_config_2_1: CodecConfiguration={.codecType = LDAC, .encodedAudioBitrate = 0, .peerMtu = 882, .isScmstEnabled = 0, .isScramblingEnabled = 0, .config = {.sbcConfig = {.sampleRate = RATE_96000, .channelMode = JOINT_STEREO, .blockLength = 0x7f, .numSubbands = SUBBAND_8, .allocMethod = 0, .bitsPerSample = BITS_UNKNOWN, .minBitpool = 0, .maxBitpool = 0}, .aacConfig = {.objectType = 0x8, .sampleRate = 0x47f01, .channelMode = UNKNOWN, .variableBitRateEnabled = DISABLED, .bitsPerSample = BITS_UNKNOWN, .frameControlEnabled = 0}, .ldacConfig = {.sampleRate = RATE_96000, .channelMode = STEREO, .qualityIndex = QUALITY_ABR, .bitsPerSample = BITS_32}, .aptxConfig = {.sampleRate = RATE_96000, .channelMode = MONO, .bitsPerSample = 0x7f}, .aptxAdaptiveConfig = {.sampleRate = RATE_96000, .channelMode = 0x47f01, .bitsPerSample = BITS_UNKNOWN, .aptxMode = UNKNOWN, .sinkBuffering = {.minSinkBuff_LL = 0, .maxSinkBuff_LL = 0, .minSinkBuff_HQ = 0, .maxSinkBuff_HQ = 0, .minSinkBuff_TWS = 0, .maxSinkBuff_TWS = 0}, .ttp = {.TTP_LL_low = 0, .TTP_LL_high = 0, .TTP_HQ_low = 0, .TTP_HQ_high = 0, .TTP_TWS_low = 0, .TTP_TWS_high = 0}, .inputMode = STEREO, .inputFadeDuration = 0, .aptxAdaptiveConfigStream = [25]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, .aptxTwsConfig = {.sampleRate = RATE_96000, .channelMode = MONO, .syncMode = 127}, .baCeltConfig = {.sampleRate = RATE_96000, .channelMode = MONO, .frameSize = 4, .complexity = 0, .predictionMode = 0, .vbrFlag = 0}, .lc3Config = {.txConfig = {.sampleRate = RATE_96000, .channelMode = STEREO, .octetsPerFrame = 4, .frameDuration = 0, .bitrate = 0, .bitsPerSample = BITS_UNKNOWN, .numBlocks = 0}, .rxConfig = {.sampleRate = RATE_UNKNOWN, .channelMode = UNKNOWN, .octetsPerFrame = 0, .frameDuration = 0, .bitrate = 0, .bitsPerSample = BITS_UNKNOWN, .numBlocks = 0}, .rxConfigSet = 0, .rxLatency = 0, .decoderOuputChannels = 0, .mode = 0, .codecSpecific = [16]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, .defaultQlevel = 0, .NumStreamIDGroup = 0, .streamMap = [48]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, .lhdcConfig = {.sampleRate = RATE_96000, .channelMode = STEREO, .qualityIndex = 0x7f, .bitsPerSample = BITS_32, .lhdcMode = UNKNOWN, .lhdcVersion = UNKNOWN, .lhdcMaxTargetBitrate = MaxTargerBitrate_900k, .lhdcChannelSplitMode = 0, .arEnable = DISABLE, .metaEnable = DISABLE, .llacEnable = DISABLE, .mbrEnable = DISABLE, .larcEnable = DISABLE}}}
11-21 16:15:17.261 1002 13479 13510 W bt_stack: [WARNING:a2dp_encoding.cc(2629)] init:Session type OFFLOAD
11-21 16:15:17.262 1002 13479 13510 W bt_stack: [WARNING:a2dp_encoding.cc(2654)] initInit A2dpTransport_2_1
从MSC中可以看到如下的audio stream setup流程。文章来源:https://www.toymoban.com/news/detail-447087.html
文章来源地址https://www.toymoban.com/news/detail-447087.html
11-21 16:15:17.266 1002 13479 13510 W bt_stack: [WARNING:a2dp_encoding.cc(2928)] start_session
11-21 16:15:17.270 1002 13479 13510 I bt_stack: [INFO:client_interface.cc(526)] startSession_cb(SUCCESS)
11-21 16:15:37.790 1002 13479 13510 I bt_stack: [INFO:a2dp_encoding.cc(3021)] ack_stream_started: result=PENDING
11-21 16:15:38.496 1002 13479 13510 I bt_stack: [INFO:a2dp_encoding.cc(3021)] ack_stream_started: result=SUCCESS_FINISHED
11-21 16:15:44.742 1002 13479 13510 I bt_stack: [INFO:a2dp_encoding.cc(3052)] ack_stream_suspended: result=PENDING
11-21 16:15:44.792 1002 13479 13510 I bt_stack: [INFO:a2dp_encoding.cc(3052)] ack_stream_suspended: result=SUCCESS_FINISHED
11-21 16:15:50.365 1002 13479 13510 I bt_stack: [INFO:a2dp_encoding.cc(3021)] ack_stream_started: result=PENDING
11-21 16:15:50.474 1002 13479 13510 I bt_stack: [INFO:a2dp_encoding.cc(3021)] ack_stream_started: result=SUCCESS_FINISHED
到了这里,关于A2DP Hardware Offload的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!