A2DP Hardware Offload

关于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流程。

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

文章来源地址https://uudwc.com/A/Avga

原文地址:https://blog.csdn.net/hihan_5/article/details/127908151

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

h
上一篇 2023年06月17日 06:38
布隆(Bloom Filter)过滤器——全面讲解,建议收藏
下一篇 2023年06月17日 06:38