【Bluedroid】bta_av_sink_media_callback(BTA_AV_SINK_MEDIA_CFG_EVT)流程源码分析

发布于:2025-07-29 ⋅ 阅读:(27) ⋅ 点赞:(0)

本文深入分析Android蓝牙协议栈中A2DP Sink设备接收音频配置事件(BTA_AV_SINK_MEDIA_CFG_EVT)后的完整处理流程。从事件触发、参数解析、解码器更新到最终音频配置生效,详细剖析多线程协作机制和编解码器处理逻辑。重点揭示了采样率声道数关键参数的提取过程,以及SBC/AAC/私有编解码器的差异化处理方式。

一、概述

1.1 核心场景:A2DP 音频配置事件触发

当蓝牙音频发送设备(如手机)与接收设备(如耳机)建立 A2DP 连接或切换编解码器时,协议栈触发BTA_AV_SINK_MEDIA_CFG_EVT事件,驱动接收设备完成音频参数配置与解码器初始化。

1.2 关键模块与流程

整个流程可分为事件处理、参数提取、解码器管理三大阶段,涉及多模块协作:

阶段一:事件处理与参数暂存(bta_av_sink_media_callback
  • 事件触发:协议栈通过BTA_AV_SINK_MEDIA_CFG_EVT事件传递编解码器信息(p_codec_info)。

  • 参数暂存:从p_codec_info中提取采样率(A2DP_GetTrackSampleRate)、声道数(A2DP_GetTrackChannelCount)等关键参数,封装为btif_av_sink_config_req_t

  • 消息传递:将配置请求事件(BTIF_AV_SINK_CONFIG_REQ_EVT)提交至主线程,触发上层处理。

阶段二:解码器信息更新(btif_a2dp_sink_update_decoder
  • 消息封装:将p_codec_info(长度固定为AVDT_CODEC_SIZE=20字节)包装为tBTIF_MEDIA_SINK_DECODER_UPDATE结构体,附加协议栈通用消息头(BT_HDR_RIGID)。

  • 线程调度:通过工作线程(btif_a2dp_sink_cb.worker_thread)确保解码器操作在专用线程执行,避免主线程阻塞。

阶段三:解码器初始化与配置(btif_a2dp_sink_decoder_update_event
  • 线程安全:通过互斥锁(g_mutex)保护全局状态(如采样率、位深)的修改。

  • 参数校验:调用A2DP_GetTrackSampleRateA2DP_GetTrackBitsPerSample等函数提取并校验参数,确保合法性(如采样率是否在支持范围内)。

  • 解码器接口获取:根据编解码器类型(A2DP_MEDIA_CT_SBC/AAC/ 厂商私有),通过A2DP_GetDecoderInterface路由至对应解码器接口(如A2DP_GetDecoderInterfaceSbc)。

  • 解码器初始化:调用接口的decoder_init函数初始化解码器,并通过decoder_configure应用编解码器参数。

1.3 编解码器类型分发机制

所有参数提取(如采样率、声道数)和解码器接口获取函数均采用类型分发模式:

  • 标准编解码器(如 SBC、AAC):通过switch-case直接调用对应解析函数(如A2DP_GetTrackSampleRateSbc)。

  • 厂商私有编解码器(如 aptX、LDAC):通过A2DP_MEDIA_CT_NON_A2DP类型,路由至厂商自定义函数(如A2DP_VendorGetTrackSampleRate)。

  • 条件编译支持:通过#if !defined(EXCLUDE_NONSTANDARD_CODECS)宏,灵活控制是否支持非标准编解码器(如 AAC),适配不同设备资源需求。

二、源码解析

bta_av_sink_media_callback(BTA_AV_SINK_MEDIA_CFG_EVT)

packages/modules/Bluetooth/system/btif/src/btif_av.cc
// TODO: All processing should be done on the JNI thread
static void bta_av_sink_media_callback(const RawAddress& peer_address,
                                       tBTA_AV_EVT event,
                                       tBTA_AV_MEDIA* p_data) {
  log::verbose("event={}", event);

  switch (event) {
    ...
    case BTA_AV_SINK_MEDIA_CFG_EVT: {
      // 1. 暂存本次音频配置的关键参数(采样率、声道数、对端设备地址等)
      btif_av_sink_config_req_t config_req;

      log::verbose("address={}",
                   ADDRESS_TO_LOGGABLE_CSTR(p_data->avk_config.bd_addr));

      // 2. 更新解码器的编解码器信息
      // Update the codec info of the A2DP Sink decoder
      btif_a2dp_sink_update_decoder((uint8_t*)(p_data->avk_config.codec_info));

      // 3. 提取音频采样率
      config_req.sample_rate =
          A2DP_GetTrackSampleRate(p_data->avk_config.codec_info);
      if (config_req.sample_rate == -1) {
        log::error("Cannot get the track frequency");
        break;
      }
      
      // 4. 提取音频声道数
      config_req.channel_count =
          A2DP_GetTrackChannelCount(p_data->avk_config.codec_info);
      if (config_req.channel_count == -1) {
        log::error("Cannot get the channel count");
        break;
      }
      
      // 5. 封装并传递配置事件
      config_req.peer_address = p_data->avk_config.bd_addr;
      BtifAvEvent btif_av_event(BTIF_AV_SINK_CONFIG_REQ_EVT, &config_req,
                                sizeof(config_req));
      do_in_main_thread(
          FROM_HERE, base::BindOnce(&btif_av_handle_event,
                                    AVDT_TSEP_SRC,  // peer_sep
                                    config_req.peer_address, kBtaHandleUnknown,
                                    btif_av_event));
      break;
    }
    default:
      break;
  }
}

当蓝牙设备(如手机)与音频接收设备(如蓝牙耳机)建立 A2DP 连接时,协议栈会触发 BTA_AV_SINK_MEDIA_CFG_EVT 事件,通知底层需要完成音频参数(采样率、声道数等)的配置。主要作用是:

  1. 从协议栈传递的参数中提取音频关键信息(采样率、声道数);

  2. 将信息封装为事件,传递给主线程的上层处理函数(btif_av_handle_event),完成最终的音频配置。

btif_a2dp_sink_update_decoder

packages/modules/Bluetooth/system/btif/src/btif_a2dp_sink.cc
void btif_a2dp_sink_update_decoder(const uint8_t* p_codec_info) {
  log::info("");
  tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf =
      reinterpret_cast<tBTIF_MEDIA_SINK_DECODER_UPDATE*>(
          osi_malloc(sizeof(tBTIF_MEDIA_SINK_DECODER_UPDATE)));

  log::verbose("p_codec_info[{:x}:{:x}:{:x}:{:x}:{:x}:{:x}]", p_codec_info[1],
               p_codec_info[2], p_codec_info[3], p_codec_info[4],
               p_codec_info[5], p_codec_info[6]);

  memcpy(p_buf->codec_info, p_codec_info, AVDT_CODEC_SIZE);
  p_buf->hdr.event = BTIF_MEDIA_SINK_DECODER_UPDATE;

  btif_a2dp_sink_cb.worker_thread.DoInThread(
      FROM_HERE,
      base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR_RIGID*)p_buf));
}

// 蓝牙协议栈通用消息头(包含事件类型、长度等元数据)
typedef struct {
  uint16_t event;
  uint16_t len;
  uint16_t offset;
  uint16_t layer_specific;
  // Note: Removal of flexible array member with no specified size.
  // This struct may be embedded in any position within other structs
  // and will not trigger various flexible member compilation issues.
} BT_HDR_RIGID;

/* Maximum size in bytes of the codec capabilities information element. */
#define AVDT_CODEC_SIZE 20

// 存储编解码器具体参数的数组
typedef struct {
  BT_HDR_RIGID hdr;
  uint8_t codec_info[AVDT_CODEC_SIZE];
} tBTIF_MEDIA_SINK_DECODER_UPDATE;

当蓝牙音频接收设备(如耳机)需要更新解码器配置(例如切换音频编码格式,如从 SBC 切换到 AAC)时,协议栈会通过 p_codec_info 传递新的编解码器参数。此函数的作用是:

  1. 将编解码器参数包装为自定义消息结构体;

  2. 将消息提交到专用工作线程,确保后续处理(如解码器初始化、参数生效)在正确的线程上下文执行。

btif_a2dp_sink_command_ready(BTIF_MEDIA_SINK_DECODER_UPDATE)
packages/modules/Bluetooth/system/btif/src/btif_a2dp_sink.cc
static void btif_a2dp_sink_command_ready(BT_HDR_RIGID* p_msg) {
  log::verbose("event {} {}", p_msg->event, dump_media_event(p_msg->event));

  switch (p_msg->event) {
    case BTIF_MEDIA_SINK_DECODER_UPDATE:
      btif_a2dp_sink_decoder_update_event(
          (tBTIF_MEDIA_SINK_DECODER_UPDATE*)p_msg);
      break;
    ...
    default:
      log::error("unknown event {}", p_msg->event);
      break;
  }

  log::verbose("{} DONE", dump_media_event(p_msg->event));
  osi_free(p_msg);
}
btif_a2dp_sink_decoder_update_event
packages/modules/Bluetooth/system/btif/src/btif_a2dp_sink.cc
static void btif_a2dp_sink_decoder_update_event(
    tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf) {
  log::info("");
  // 1. 线程安全:互斥锁保护共享状态
  LockGuard lock(g_mutex);
  log::verbose("p_codec_info[{:x}:{:x}:{:x}:{:x}:{:x}:{:x}]",
               p_buf->codec_info[1], p_buf->codec_info[2], p_buf->codec_info[3],
               p_buf->codec_info[4], p_buf->codec_info[5],
               p_buf->codec_info[6]);

  
  // 2. 音频参数提取与校验
  int sample_rate = A2DP_GetTrackSampleRate(p_buf->codec_info);
  if (sample_rate == -1) {
    log::error("cannot get the track frequency");
    return;
  }
  int bits_per_sample = A2DP_GetTrackBitsPerSample(p_buf->codec_info);
  if (bits_per_sample == -1) {
    log::error("cannot get the bits per sample");
    return;
  }
  int channel_count = A2DP_GetTrackChannelCount(p_buf->codec_info);
  if (channel_count == -1) {
    log::error("cannot get the channel count");
    return;
  }
  int channel_type = A2DP_GetSinkTrackChannelType(p_buf->codec_info);
  if (channel_type == -1) {
    log::error("cannot get the Sink channel type");
    return;
  }
  
  // 3. 更新全局状态
  btif_a2dp_sink_cb.sample_rate = sample_rate;
  btif_a2dp_sink_cb.bits_per_sample = bits_per_sample;
  btif_a2dp_sink_cb.channel_count = channel_count;

  // 4. 重置接收状态与保存编解码器信息
  btif_a2dp_sink_cb.rx_flush = false;  // 重置接收刷新标志
  log::verbose("reset to Sink role");
  bta_av_co_save_codec(p_buf->codec_info); // 保存编解码器信息

  // 5. 获取并初始化解码器接口
  btif_a2dp_sink_cb.decoder_interface =
      A2DP_GetDecoderInterface(p_buf->codec_info);
  if (btif_a2dp_sink_cb.decoder_interface == nullptr) {
    log::error("cannot stream audio: no source decoder interface");
    return;
  }
  if (!btif_a2dp_sink_cb.decoder_interface->decoder_init(
          btif_a2dp_sink_on_decode_complete)) {
    log::error("failed to initialize decoder");
    return;
  }

  // 6. 解码器参数配置
  if (btif_a2dp_sink_cb.decoder_interface->decoder_configure != nullptr) {
    btif_a2dp_sink_cb.decoder_interface->decoder_configure(p_buf->codec_info);
  }

从消息中提取音频参数(采样率、位深等),初始化对应的解码器(如 SBC、AAC 解码器),并应用配置,确保解码器能正确解析后续音频数据。

A2DP_GetTrackSampleRate

packages/modules/Bluetooth/system/stack/a2dp/a2dp_codec_config.cc
/* AV Media Codec Types (Audio Codec ID) */
#define A2DP_MEDIA_CT_SBC 0x00 /* SBC media codec type */
#define A2DP_MEDIA_CT_AAC 0x02 /* AAC media codec type */
/* Non-A2DP media codec type (vendor-specific codec) */
#define A2DP_MEDIA_CT_NON_A2DP 0xFF

int A2DP_GetTrackSampleRate(const uint8_t* p_codec_info) {
  // 1. 获取编解码器类型
  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);

  log::verbose("codec_type = 0x{:x}", codec_type);

  // 2. 根据编解码器类型分发采样率提取逻辑
  switch (codec_type) {
    case A2DP_MEDIA_CT_SBC:
      return A2DP_GetTrackSampleRateSbc(p_codec_info);
#if !defined(EXCLUDE_NONSTANDARD_CODECS)
    case A2DP_MEDIA_CT_AAC:
      return A2DP_GetTrackSampleRateAac(p_codec_info);
    case A2DP_MEDIA_CT_NON_A2DP:
      return A2DP_VendorGetTrackSampleRate(p_codec_info); // 厂商自定义编解码器
#endif
    default:
      break;
  }

  log::error("unsupported codec type 0x{:x}", codec_type);
  return -1;
}

typedef uint8_t tA2DP_CODEC_TYPE; /* A2DP Codec type: A2DP_MEDIA_CT_* */

tA2DP_CODEC_TYPE A2DP_GetCodecType(const uint8_t* p_codec_info) {
  return (tA2DP_CODEC_TYPE)(p_codec_info[AVDT_CODEC_TYPE_INDEX]);
}

蓝牙 A2DP 协议规定,音频数据在传输前需通过编解码器(如 SBC、AAC)进行压缩编码,而编解码器的参数(如采样率)需通过 codec_info 字段(长度固定为 AVDT_CODEC_SIZE 的字节数组)传递。 函数的核心作用是:

  • 输入:蓝牙协议栈传递的编解码器信息(p_codec_info);

  • 处理:识别编解码器类型(如 SBC、AAC),调用对应类型的采样率提取函数;

  • 输出:音频采样率(如 44100Hz、48000Hz),或 -1(提取失败)。

A2DP_GetTrackSampleRateSbc
packages/modules/Bluetooth/system/stack/a2dp/a2dp_sbc.cc
int A2DP_GetTrackSampleRateSbc(const uint8_t* p_codec_info) {
  tA2DP_SBC_CIE sbc_cie;

  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
  if (a2dp_status != A2DP_SUCCESS) {
    log::error("cannot decode codec information: {}", a2dp_status);
    return -1;
  }

  switch (sbc_cie.samp_freq) {
    case A2DP_SBC_IE_SAMP_FREQ_16:
      return 16000;
    case A2DP_SBC_IE_SAMP_FREQ_32:
      return 32000;
    case A2DP_SBC_IE_SAMP_FREQ_44:
      return 44100;
    case A2DP_SBC_IE_SAMP_FREQ_48:
      return 48000;
    default:
      break;
  }

  return -1;
}

SBC 是蓝牙 A2DP 协议强制要求支持的音频编码格式,广泛用于蓝牙耳机等设备。 函数的核心作用是:

  • 输入:SBC 编解码器信息(p_codec_info,符合蓝牙协议的字节数组);

  • 处理:解析该字节数组,提取其中的采样率字段;

  • 输出:实际采样率(如 16000Hz),或 -1(解析失败)。

A2DP_ParseInfoSbc


// Parses the SBC Media Codec Capabilities byte sequence beginning from the
// LOSC octet. The result is stored in |p_ie|. The byte sequence to parse is
// |p_codec_info|. If |is_capability| is true, the byte sequence contains
// codec capability.
// Returns A2DP_SUCCESS on success, otherwise the corresponding A2DP error
// status code.
static tA2DP_STATUS A2DP_ParseInfoSbc(tA2DP_SBC_CIE* p_ie,
                                      const uint8_t* p_codec_info,
                                      bool is_capability) {
  uint8_t losc;
  uint8_t media_type;
  tA2DP_CODEC_TYPE codec_type;

  // 1. 参数校验(输入合法性检查)
  if (p_ie == NULL || p_codec_info == NULL) return A2DP_INVALID_PARAMS;

  // 2. 校验 LOSC(Length of Service Capabilities)字段
  // Check the codec capability length
  losc = *p_codec_info++;
  if (losc != A2DP_SBC_INFO_LEN) return A2DP_WRONG_CODEC;

  // 3. 校验媒体类型与编解码器类型
  media_type = (*p_codec_info++) >> 4;
  codec_type = *p_codec_info++;
  /* Check the Media Type and Media Codec Type */
  if (media_type != AVDT_MEDIA_TYPE_AUDIO || codec_type != A2DP_MEDIA_CT_SBC) {
    return A2DP_WRONG_CODEC;
  }

  // 4. 解析 SBC 编解码器核心参数
  // 第4字节:采样频率(samp_freq)和声道模式(ch_mode)
  p_ie->samp_freq = *p_codec_info & A2DP_SBC_IE_SAMP_FREQ_MSK;  // 低4位:采样率标志
  p_ie->ch_mode = *p_codec_info & A2DP_SBC_IE_CH_MD_MSK;       // 高4位:声道模式标志
  p_codec_info++;

  // 第5字节:块长度(block_len)、子带数(num_subbands)、分配方法(alloc_method)
  p_ie->block_len = *p_codec_info & A2DP_SBC_IE_BLOCKS_MSK;      // 低4位:块长度标志
  p_ie->num_subbands = *p_codec_info & A2DP_SBC_IE_SUBBAND_MSK;   // 中2位:子带数标志
  p_ie->alloc_method = *p_codec_info & A2DP_SBC_IE_ALLOC_MD_MSK;  // 高2位:分配方法标志
  p_codec_info++;

  // 第6-7字节:最小/最大位池(bitpool)
  p_ie->min_bitpool = *p_codec_info++;  // 最小位池(决定编码复杂度下限)
  p_ie->max_bitpool = *p_codec_info++;  // 最大位池(决定编码复杂度上限)

  // 5. 校验位池参数(bitpool)
  if (p_ie->min_bitpool < A2DP_SBC_IE_MIN_BITPOOL ||
      p_ie->min_bitpool > A2DP_SBC_IE_MAX_BITPOOL) {
    return A2DP_BAD_MIN_BITPOOL; // 最小位池越界
  }

  if (p_ie->max_bitpool < A2DP_SBC_IE_MIN_BITPOOL ||
      p_ie->max_bitpool > A2DP_SBC_IE_MAX_BITPOOL ||
      p_ie->max_bitpool < p_ie->min_bitpool) {
    return A2DP_BAD_MAX_BITPOOL; // 最大位池越界或小于最小位池
  }

  // 6. 校验参数的位设置(能力信息 vs 配置信息)
  if (is_capability) {
    // NOTE: The checks here are very liberal. We should be using more
    // pedantic checks specific to the SRC or SNK as specified in the spec.
    if (A2DP_BitsSet(p_ie->samp_freq) == A2DP_SET_ZERO_BIT)
      return A2DP_BAD_SAMP_FREQ;
    if (A2DP_BitsSet(p_ie->ch_mode) == A2DP_SET_ZERO_BIT)
      return A2DP_BAD_CH_MODE;
    if (A2DP_BitsSet(p_ie->block_len) == A2DP_SET_ZERO_BIT)
      return A2DP_BAD_BLOCK_LEN;
    if (A2DP_BitsSet(p_ie->num_subbands) == A2DP_SET_ZERO_BIT)
      return A2DP_BAD_SUBBANDS;
    if (A2DP_BitsSet(p_ie->alloc_method) == A2DP_SET_ZERO_BIT)
      return A2DP_BAD_ALLOC_METHOD;

    return A2DP_SUCCESS;
  }

  if (A2DP_BitsSet(p_ie->samp_freq) != A2DP_SET_ONE_BIT)
    return A2DP_BAD_SAMP_FREQ;
  if (A2DP_BitsSet(p_ie->ch_mode) != A2DP_SET_ONE_BIT) return A2DP_BAD_CH_MODE;
  if (A2DP_BitsSet(p_ie->block_len) != A2DP_SET_ONE_BIT)
    return A2DP_BAD_BLOCK_LEN;
  if (A2DP_BitsSet(p_ie->num_subbands) != A2DP_SET_ONE_BIT)
    return A2DP_BAD_SUBBANDS;
  if (A2DP_BitsSet(p_ie->alloc_method) != A2DP_SET_ONE_BIT)
    return A2DP_BAD_ALLOC_METHOD;

  return A2DP_SUCCESS;
}


/* the return values from A2DP_BitsSet() */
#define A2DP_SET_ONE_BIT 1   /* one and only one bit is set */
#define A2DP_SET_ZERO_BIT 0  /* all bits clear */
#define A2DP_SET_MULTL_BIT 2 /* multiple bits are set */

/******************************************************************************
 * Function         A2DP_BitsSet
 *
 * Description      Check the given num for the number of bits set
 * Returns          A2DP_SET_ONE_BIT, if one and only one bit is set
 *                  A2DP_SET_ZERO_BIT, if all bits clear
 *                  A2DP_SET_MULTL_BIT, if multiple bits are set
 *****************************************************************************/
uint8_t A2DP_BitsSet(uint64_t num) {
  if (num == 0) return A2DP_SET_ZERO_BIT; // 无位设置
  if ((num & (num - 1)) == 0) return A2DP_SET_ONE_BIT; // 仅一个位设置(如 0b1000)
  return A2DP_SET_MULTL_BIT; // 多个位设置(如 0b1010)}

解析 SBC 编解码器信息(Codec Information Element, CIE),将 SBC 编解码器的字节数组(协议栈传递的 p_codec_info)转换为结构化的配置参数(如采样率、声道模式等),并校验其合规性。

A2DP_GetTrackSampleRateAac
packages/modules/Bluetooth/system/stack/a2dp/a2dp_aac.cc
int A2DP_GetTrackSampleRateAac(const uint8_t* p_codec_info) {
  // 1. 解析 AAC 编解码器信息到结构体
  // 存储 AAC 编解码器的配置信息元素(Codec Information Element, CIE),包含采样率、声道数、编码格式等关键参数
  tA2DP_AAC_CIE aac_cie;

  // Check whether the codec info contains valid data
  tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
  if (a2dp_status != A2DP_SUCCESS) {
    log::error("cannot decode codec information: {}", a2dp_status);
    return -1;
  }

  switch (aac_cie.sampleRate) {
    case A2DP_AAC_SAMPLING_FREQ_8000:
      return 8000;
    case A2DP_AAC_SAMPLING_FREQ_11025:
      return 11025;
    case A2DP_AAC_SAMPLING_FREQ_12000:
      return 12000;
    case A2DP_AAC_SAMPLING_FREQ_16000:
      return 16000;
    case A2DP_AAC_SAMPLING_FREQ_22050:
      return 22050;
    case A2DP_AAC_SAMPLING_FREQ_24000:
      return 24000;
    case A2DP_AAC_SAMPLING_FREQ_32000:
      return 32000;
    case A2DP_AAC_SAMPLING_FREQ_44100:
      return 44100;
    case A2DP_AAC_SAMPLING_FREQ_48000:
      return 48000;
    case A2DP_AAC_SAMPLING_FREQ_64000:
      return 64000;
    case A2DP_AAC_SAMPLING_FREQ_88200:
      return 88200;
    case A2DP_AAC_SAMPLING_FREQ_96000:
      return 96000;
  }

  return -1;
}

AAC(Advanced Audio Coding,高级音频编码)编解码器信息中提取采样率(如 8000Hz、44100Hz 等)。AAC 是蓝牙 A2DP 协议的可选音频编码格式(非强制支持),常用于需要高质量音频的场景(如音乐播放)。

A2DP_ParseInfoAac

packages/modules/Bluetooth/system/stack/a2dp/a2dp_aac.cc
// Parses the AAC Media Codec Capabilities byte sequence beginning from the
// LOSC octet. The result is stored in |p_ie|. The byte sequence to parse is
// |p_codec_info|. If |is_capability| is true, the byte sequence is
// codec capabilities, otherwise is codec configuration.
// Returns A2DP_SUCCESS on success, otherwise the corresponding A2DP error
// status code.
static tA2DP_STATUS A2DP_ParseInfoAac(tA2DP_AAC_CIE* p_ie,
                                      const uint8_t* p_codec_info,
                                      bool is_capability) {
  uint8_t losc;
  uint8_t media_type;
  tA2DP_CODEC_TYPE codec_type;

  if (p_ie == NULL || p_codec_info == NULL) return A2DP_INVALID_PARAMS;

  // Check the codec capability length
  losc = *p_codec_info++;
  if (losc != A2DP_AAC_CODEC_LEN) return A2DP_WRONG_CODEC;

  // 校验媒体类型与编解码器类型
  media_type = (*p_codec_info++) >> 4;
  codec_type = *p_codec_info++;
  /* Check the Media Type and Media Codec Type */
  if (media_type != AVDT_MEDIA_TYPE_AUDIO || codec_type != A2DP_MEDIA_CT_AAC) {
    return A2DP_WRONG_CODEC;
  }

  // 对象类型(编码格式,如 AAC-LC、HE-AAC 等)
  p_ie->objectType = *p_codec_info++;
  // 采样率(由两个字节的部分位组合而成)
  p_ie->sampleRate = (*p_codec_info & A2DP_AAC_SAMPLING_FREQ_MASK0) |
                     (*(p_codec_info + 1) << 8 & A2DP_AAC_SAMPLING_FREQ_MASK1);
  p_codec_info++;
  // 声道模式(如单声道、立体声)
  p_ie->channelMode = *p_codec_info & A2DP_AAC_CHANNEL_MODE_MASK;
  p_codec_info++;

  // 可变比特率支持(是否支持动态调整比特率)
  p_ie->variableBitRateSupport =
      *p_codec_info & A2DP_AAC_VARIABLE_BIT_RATE_MASK;

  // 比特率(由三个字节组合而成,单位:bps)
  p_ie->bitRate = ((*p_codec_info) << 16 & A2DP_AAC_BIT_RATE_MASK0) |
                  (*(p_codec_info + 1) << 8 & A2DP_AAC_BIT_RATE_MASK1) |
                  (*(p_codec_info + 2) & A2DP_AAC_BIT_RATE_MASK2);
  p_codec_info += 3;

  // 校验参数的位设置(能力信息 vs 配置信息)
  if (is_capability) {
    // 能力信息(支持的参数集合):允许设置多个位(如支持多种采样率)
    // NOTE: The checks here are very liberal. We should be using more
    // pedantic checks specific to the SRC or SNK as specified in the spec.
    if (A2DP_BitsSet(p_ie->objectType) == A2DP_SET_ZERO_BIT)
      return A2DP_BAD_OBJ_TYPE;
    if (A2DP_BitsSet(p_ie->sampleRate) == A2DP_SET_ZERO_BIT)
      return A2DP_BAD_SAMP_FREQ;
    if (A2DP_BitsSet(p_ie->channelMode) == A2DP_SET_ZERO_BIT)
      return A2DP_BAD_CH_MODE;

    return A2DP_SUCCESS;
  }

  //  配置信息(当前使用的参数):必须仅设置一个位(如当前使用 44100Hz 采样率)
  if (A2DP_BitsSet(p_ie->objectType) != A2DP_SET_ONE_BIT)
    return A2DP_BAD_OBJ_TYPE;
  if (A2DP_BitsSet(p_ie->sampleRate) != A2DP_SET_ONE_BIT)
    return A2DP_BAD_SAMP_FREQ;
  if (A2DP_BitsSet(p_ie->channelMode) != A2DP_SET_ONE_BIT)
    return A2DP_BAD_CH_MODE;

  return A2DP_SUCCESS;
}

将 AAC 编解码器的字节数组(协议栈传递的 p_codec_info)转换为结构化的配置参数(如采样率、声道模式等),并校验其是否符合蓝牙协议规范。

A2DP_VendorGetTrackSampleRate
packages/modules/Bluetooth/system/stack/a2dp/a2dp_vendor.cc
int A2DP_VendorGetTrackSampleRate(const uint8_t* p_codec_info) {
  // 1. 提取厂商 ID 和编解码器 ID
  uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
  uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);

  // 2. 根据厂商和编解码器 ID 分发采样率提取逻辑
  // Check for aptX (高通的低延迟编解码器)
  if (vendor_id == A2DP_APTX_VENDOR_ID &&
      codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
    return A2DP_VendorGetTrackSampleRateAptx(p_codec_info);
  }

  // Check for aptX-HD (高通的高清编解码器)
  if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
      codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
    return A2DP_VendorGetTrackSampleRateAptxHd(p_codec_info);
  }

  // Check for LDAC (索尼的高解析度编解码器)
  if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
    return A2DP_VendorGetTrackSampleRateLdac(p_codec_info);
  }

  // Check for Opus (开源的低延迟编解码器)
  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
    return A2DP_VendorGetTrackSampleRateOpus(p_codec_info);
  }

  // Add checks based on <vendor_id, codec_id>

  return -1;
}

根据厂商 ID(vendor_id)和编解码器 ID(codec_id),将厂商私有编解码器信息(如 aptX、LDAC 等)路由至对应的采样率提取逻辑。

A2DP_GetTrackBitsPerSample

packages/modules/Bluetooth/system/stack/a2dp/a2dp_codec_config.cc
int A2DP_GetTrackBitsPerSample(const uint8_t* p_codec_info) {
  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);

  log::verbose("codec_type = 0x{:x}", codec_type);

  switch (codec_type) {
    case A2DP_MEDIA_CT_SBC:
      return A2DP_GetTrackBitsPerSampleSbc(p_codec_info);
#if !defined(EXCLUDE_NONSTANDARD_CODECS)
    case A2DP_MEDIA_CT_AAC:
      return A2DP_GetTrackBitsPerSampleAac(p_codec_info);
    case A2DP_MEDIA_CT_NON_A2DP:
      return A2DP_VendorGetTrackBitsPerSample(p_codec_info);
#endif
    default:
      break;
  }

  log::error("unsupported codec type 0x{:x}", codec_type);
  return -1;
}

根据不同的编解码器类型(如 SBC、AAC 或厂商自定义编解码器),从编解码器信息中解析出音频的每样本位数(如 16 位、24 位)。蓝牙 A2DP 协议中,音频数据的每样本位数(如 16 位、24 位)是决定音频质量的关键参数(位数越高,动态范围越大,细节越丰富)。

A2DP_GetTrackChannelCount

packages/modules/Bluetooth/system/stack/a2dp/a2dp_codec_config.cc
int A2DP_GetTrackChannelCount(const uint8_t* p_codec_info) {
  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);

  log::verbose("codec_type = 0x{:x}", codec_type);

  switch (codec_type) {
    case A2DP_MEDIA_CT_SBC:
      return A2DP_GetTrackChannelCountSbc(p_codec_info);
#if !defined(EXCLUDE_NONSTANDARD_CODECS)
    case A2DP_MEDIA_CT_AAC:
      return A2DP_GetTrackChannelCountAac(p_codec_info);
    case A2DP_MEDIA_CT_NON_A2DP:
      return A2DP_VendorGetTrackChannelCount(p_codec_info);
#endif
    default:
      break;
  }

  log::error("unsupported codec type 0x{:x}", codec_type);
  return -1;
}

根据不同的编解码器类型(如 SBC、AAC 或厂商自定义编解码器),从编解码器信息中解析出音频的声道数(如单声道、立体声、多声道)。蓝牙 A2DP 协议中,音频的声道数(如单声道、立体声)是决定音频空间感的关键参数。

A2DP_GetSinkTrackChannelType

packages/modules/Bluetooth/system/stack/a2dp/a2dp_codec_config.cc
int A2DP_GetSinkTrackChannelType(const uint8_t* p_codec_info) {
  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);

  log::verbose("codec_type = 0x{:x}", codec_type);

  switch (codec_type) {
    case A2DP_MEDIA_CT_SBC:
      return A2DP_GetSinkTrackChannelTypeSbc(p_codec_info);
#if !defined(EXCLUDE_NONSTANDARD_CODECS)
    case A2DP_MEDIA_CT_AAC:
      return A2DP_GetSinkTrackChannelTypeAac(p_codec_info);
    case A2DP_MEDIA_CT_NON_A2DP:
      return A2DP_VendorGetSinkTrackChannelType(p_codec_info);
#endif
    default:
      break;
  }

  log::error("unsupported codec type 0x{:x}", codec_type);
  return -1;
}

根据不同的编解码器类型(如 SBC、AAC 或厂商自定义编解码器),从编解码器信息中解析出接收端支持的声道类型(如立体声、单声道、多声道等)。蓝牙 A2DP 协议中,音频的声道类型(如立体声、单声道)直接影响音频的空间感和设备的解码能力。

A2DP_GetDecoderInterface

packages/modules/Bluetooth/system/stack/a2dp/a2dp_codec_config.cc
const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterface(
    const uint8_t* p_codec_info) {
  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);

  log::verbose("codec_type = 0x{:x}", codec_type);

  switch (codec_type) {
    case A2DP_MEDIA_CT_SBC:
      return A2DP_GetDecoderInterfaceSbc(p_codec_info);
#if !defined(EXCLUDE_NONSTANDARD_CODECS)
    case A2DP_MEDIA_CT_AAC:
      return A2DP_GetDecoderInterfaceAac(p_codec_info);
    case A2DP_MEDIA_CT_NON_A2DP:
      return A2DP_VendorGetDecoderInterface(p_codec_info);
#endif
    default:
      break;
  }

  log::error("unsupported codec type 0x{:x}", codec_type);
  return NULL;
}

根据编解码器类型(如 SBC、AAC 或厂商自定义编解码器),返回对应的解码器接口(包含解码函数指针、参数配置等),是音频解码流程的 “接口路由枢纽”。蓝牙 A2DP 协议支持多种音频编解码器(如 SBC、AAC、厂商私有编解码器),不同编解码器的解码逻辑(如数据解析、格式转换)差异较大。

函数的核心作用是:

  • 输入:蓝牙协议栈传递的编解码器信息(p_codec_info,字节数组);

  • 处理:识别编解码器类型,调用对应类型的解码器接口获取函数;

  • 输出:解码器接口指针(tA2DP_DECODER_INTERFACE*),包含解码所需的函数指针(如初始化、解码、释放)和参数(如采样率、声道数),或 NULL(不支持该编解码器)。

btif_av_handle_event

 

三、总结

蓝牙 A2DP 音频接收设备的参数配置与解码器管理是实现高质量音频传输的核心环节。其设计亮点在于:

  • 协议兼容性:严格遵循蓝牙规范,支持 SBC(强制)、AAC(可选)等标准编解码器。

  • 可扩展性:通过厂商私有接口(A2DP_MEDIA_CT_NON_A2DP)支持 aptX、LDAC 等私有编解码器,满足差异化需求。

  • 线程安全性:通过工作线程和互斥锁机制,确保参数更新与解码器操作的线程安全。

  • 健壮性:多层参数校验(如A2DP_ParseInfoSbc中的 LOSC 字段检查、位设置校验)和错误处理(返回-1NULL),保障流程稳定性。

四、流程图

五、时序图

log关键字:

bta_av_sink_media_callback|btif_a2dp_sink_update_decoder|BTIF_MEDIA_SINK_DECODER_UPDATE|btif_a2dp_sink_decoder_update_event|A2DP_GetTrackSampleRate|A2DP_GetTrackBitsPerSample|A2DP_GetTrackChannelCount|A2DP_GetSinkTrackChannelType|A2DP_GetDecoderInterface|bt_btif_avrcp_audio_track|AAudioStreamBuilder_openStream|AudioStreamBuilder|AudioStreamTrack|AAudio  :



网站公告

今日签到

点亮在社区的每一天
去签到