【android bluetooth 协议分析 02】【bluetooth hal 层详解 6】【bt_vendor_opcode_t 介绍】

bt_vendor_opcode_t 介绍

在 AOSP 的 Bluetooth Vendor 接口中,bt_vendor_opcode_t 定义了一组供上层调用的操作指令。这些操作在蓝牙初始化、使用和关闭过程中由协议栈(如 Bluedroid)驱动调用,按照一定的顺序执行。

这些枚举项代表 Vendor Interface API 的操作码,协议栈通过调用 vendor_call() 接口并传入这些 opcodes 来控制蓝牙芯片的底层行为。其设计目的在于:

  • 平台差异适配(如不同 SoC 的上电、串口打开方式)
  • 硬件加速支持(如 A2DP offload)
  • 功耗优化(如 LPM 控制)
  • 音频子系统协同(如 SCO、音频状态)

1. 详解介绍

  • hidl_hci/1.0/default/bt_vendor_lib.h
c 复制代码
/** Vendor specific operations OPCODE */
typedef enum {
  /*  [operation]
   *      Power on or off the BT Controller.
   *  [input param]
   *      A pointer to int type with content of bt_vendor_power_state_t.
   *      Typecasting conversion: (int *) param.
   *  [return]
   *      0 - default, don't care.
   *  [callback]
   *      None.
   */
  BT_VND_OP_POWER_CTRL,

  /*  [operation]
   *      Perform any vendor specific initialization or configuration
   *      on the BT Controller. This is called before stack initialization.
   *  [input param]
   *      None.
   *  [return]
   *      0 - default, don't care.
   *  [callback]
   *      Must call fwcfg_cb to notify the stack of the completion of vendor
   *      specific initialization once it has been done.
   */
  BT_VND_OP_FW_CFG,

  /*  [operation]
   *      Perform any vendor specific SCO/PCM configuration on the BT
   * Controller.
   *      This is called after stack initialization.
   *  [input param]
   *      None.
   *  [return]
   *      0 - default, don't care.
   *  [callback]
   *      Must call scocfg_cb to notify the stack of the completion of vendor
   *      specific SCO configuration once it has been done.
   */
  BT_VND_OP_SCO_CFG,

  /*  [operation]
   *      Open UART port on where the BT Controller is attached.
   *      This is called before stack initialization.
   *  [input param]
   *      A pointer to int array type for open file descriptors.
   *      The mapping of HCI channel to fd slot in the int array is given in
   *      bt_vendor_hci_channels_t.
   *      And, it requires the vendor lib to fill up the content before
   * returning
   *      the call.
   *      Typecasting conversion: (int (*)[]) param.
   *  [return]
   *      Numbers of opened file descriptors.
   *      Valid number:
   *          1 - CMD/EVT/ACL-In/ACL-Out via the same fd (e.g. UART)
   *          2 - CMD/EVT on one fd, and ACL-In/ACL-Out on the other fd
   *          4 - CMD, EVT, ACL-In, ACL-Out are on their individual fd
   *  [callback]
   *      None.
   */
  BT_VND_OP_USERIAL_OPEN,

  /*  [operation]
   *      Close the previously opened UART port.
   *  [input param]
   *      None.
   *  [return]
   *      0 - default, don't care.
   *  [callback]
   *      None.
   */
  BT_VND_OP_USERIAL_CLOSE,

  /*  [operation]
   *      Get the LPM idle timeout in milliseconds.
   *      The stack uses this information to launch a timer delay before it
   *      attempts to de-assert LPM WAKE signal once downstream HCI packet
   *      has been delivered.
   *  [input param]
   *      A pointer to uint32_t type which is passed in by the stack. And, it
   *      requires the vendor lib to fill up the content before returning
   *      the call.
   *      Typecasting conversion: (uint32_t *) param.
   *  [return]
   *      0 - default, don't care.
   *  [callback]
   *      None.
   */
  BT_VND_OP_GET_LPM_IDLE_TIMEOUT,

  /*  [operation]
   *      Enable or disable LPM mode on BT Controller.
   *  [input param]
   *      A pointer to uint8_t type with content of bt_vendor_lpm_mode_t.
   *      Typecasting conversion: (uint8_t *) param.
   *  [return]
   *      0 - default, don't care.
   *  [callback]
   *      Must call lpm_cb to notify the stack of the completion of LPM
   *      disable/enable process once it has been done.
   */
  BT_VND_OP_LPM_SET_MODE,

  /*  [operation]
   *      Assert or Deassert LPM WAKE on BT Controller.
   *  [input param]
   *      A pointer to uint8_t type with content of bt_vendor_lpm_wake_state_t.
   *      Typecasting conversion: (uint8_t *) param.
   *  [return]
   *      0 - default, don't care.
   *  [callback]
   *      None.
   */
  BT_VND_OP_LPM_WAKE_SET_STATE,

  /*  [operation]
   *      Perform any vendor specific commands related to audio state changes.
   *  [input param]
   *      a pointer to bt_vendor_op_audio_state_t indicating what audio state is
   *      set.
   *  [return]
   *      0 - default, don't care.
   *  [callback]
   *      None.
   */
  BT_VND_OP_SET_AUDIO_STATE,

  /*  [operation]
   *      The epilog call to the vendor module so that it can perform any
   *      vendor-specific processes (e.g. send a HCI_RESET to BT Controller)
   *      before the caller calls for cleanup().
   *  [input param]
   *      None.
   *  [return]
   *      0 - default, don't care.
   *  [callback]
   *      Must call epilog_cb to notify the stack of the completion of vendor
   *      specific epilog process once it has been done.
   */
  BT_VND_OP_EPILOG,

  /*  [operation]
   *      Call to the vendor module so that it can perform all vendor-specific
   *      operations to start offloading a2dp media encode & tx.
   *  [input param]
   *      pointer to bt_vendor_op_a2dp_offload_start_t containing elements
   *      required for VND FW to setup a2dp offload.
   *  [return]
   *      0  - default, dont care.
   *  [callback]
   *      Must call a2dp_offload_start_cb to notify the stack of the
   *      completion of vendor specific setup process once it has been done.
   */
  BT_VND_OP_A2DP_OFFLOAD_START,

  /*  [operation]
   *      Call to the vendor module so that it can perform all vendor-specific
   *      operations to suspend offloading a2dp media encode & tx.
   *  [input param]
   *      pointer to bt_vendor_op_a2dp_offload_t containing elements
   *      required for VND FW to setup a2dp offload.
   *  [return]
   *      0  - default, dont care.
   *  [callback]
   *      Must call a2dp_offload_cb to notify the stack of the
   *      completion of vendor specific setup process once it has been done.
   */
  BT_VND_OP_A2DP_OFFLOAD_STOP,

} bt_vendor_opcode_t;
枚举项 作用说明 触发时机 典型应用场合
BT_VND_OP_POWER_CTRL 控制蓝牙芯片上电/断电 蓝牙开启或关闭前后 控制 BT SoC 电源,如初始化前上电,退出前下电
BT_VND_OP_FW_CFG 执行厂商特有的固件初始化配置 蓝牙协议栈初始化前 加载 firmware patch、设置特有寄存器等,完成后调用 fwcfg_cb 通知上层
BT_VND_OP_SCO_CFG 执行厂商特定的 SCO/PCM 音频配置 协议栈初始化之后(有 SCO 功能时) 设置 HCI SCO 路径,配置 PCM 接口参数,完成后需调用 scocfg_cb
BT_VND_OP_USERIAL_OPEN 打开串口或类似物理连接接口,用于 HCI 通信 初始化前 为主控和 BT 控制器之间建立 HCI 通道(如 UART),返回 fd 列表供上层使用
BT_VND_OP_USERIAL_CLOSE 关闭串口或物理连接接口 清理蓝牙前 关闭 UART、SPI、USB 接口文件描述符
BT_VND_OP_GET_LPM_IDLE_TIMEOUT 获取低功耗空闲超时(单位 ms) 启用 LPM 功能后,发送数据后启动 idle 计时器 控制下行数据发送后 LPM WAKE deassert 的延迟时间,避免频繁切换
BT_VND_OP_LPM_SET_MODE 设置是否启用低功耗模式(LPM) 蓝牙初始化后,根据策略动态设置 进入低功耗模式(例如未连接时)、退出低功耗(如开始通信时),需调用 lpm_cb
BT_VND_OP_LPM_WAKE_SET_STATE 设置 WAKE 状态:assert 或 deassert LPM 状态切换时,通常由协议栈驱动 控制 LPM 的 WAKE GPIO,保持通信或释放资源
BT_VND_OP_SET_AUDIO_STATE 通知音频状态变化以执行特定命令 音频连接或断开时 比如 HFP 通话开始/结束,通知底层做相关设置
BT_VND_OP_EPILOG 蓝牙关闭前的收尾工作 cleanup() 调用前 发出 HCI_RESET 等命令,释放资源,完成后调用 epilog_cb
BT_VND_OP_A2DP_OFFLOAD_START 启动 A2DP 硬件 offload(编码和传输) 开始播放 A2DP 音乐时 将音频流交给底层硬件加速处理,完成后调用 a2dp_offload_start_cb
BT_VND_OP_A2DP_OFFLOAD_STOP 停止 A2DP offload 暂停或停止音乐播放时 通知底层停止 offload 模块,完成后调用 a2dp_offload_cb

2. 如何触发调用

例如:

c 复制代码
  ALOGI("Turn On BT power");
  powerstate = BT_VND_PWR_ON;
  ret = lib_interface_->op(BT_VND_OP_POWER_CTRL, &powerstate);
c 复制代码
/*
 * Bluetooth Host/Controller VENDOR Interface
 */
typedef struct {
  /** Set to sizeof(bt_vndor_interface_t) */
  size_t size;

  /*
   * Functions need to be implemented in Vendor libray (libbt-vendor.so).
   */

  /**
   * Caller will open the interface and pass in the callback routines
   * to the implemenation of this interface.
   */
  int (*init)(const bt_vendor_callbacks_t* p_cb, unsigned char* local_bdaddr);

  /**  Vendor specific operations */
  int (*op)(bt_vendor_opcode_t opcode, void* param);

  /** Closes the interface */
  void (*cleanup)(void);
} bt_vendor_interface_t;

2. 案例赏析

1. 一般蓝牙操作流程

下面是一个典型的蓝牙开启、使用、关闭的完整流程,配合 Vendor 操作指令说明。


1. 蓝牙初始化阶段(Bluetooth Turn ON)

顺序 操作 opcode 描述
1 打开串口 BT_VND_OP_USERIAL_OPEN 打开与 BT 芯片通信的物理接口(如 UART)
2 芯片上电 BT_VND_OP_POWER_CTRL 通知 vendor 上电;若芯片已供电则可能为 no-op
3 固件配置 BT_VND_OP_FW_CFG 执行固件加载或寄存器配置,完成后需调用 fwcfg_cb()
4 低功耗模式设置 BT_VND_OP_LPM_SET_MODE 启用或禁用 LPM(低功耗)模式,完成后调用 lpm_cb()
5 获取 LPM 超时 BT_VND_OP_GET_LPM_IDLE_TIMEOUT 获取 LPM 模式下的空闲超时时间

⚠️ 有 SCO 功能设备还会执行:

  • BT_VND_OP_SCO_CFG:设置 PCM 参数,完成后调用 scocfg_cb()

2. 音频使用阶段(如通话、播放音乐)

情况 操作 opcode 描述
开始通话(HFP) BT_VND_OP_SET_AUDIO_STATE 通知底层开始 SCO 语音传输
播放音乐(A2DP) BT_VND_OP_A2DP_OFFLOAD_START 启动音频硬件 offload
暂停音乐 BT_VND_OP_A2DP_OFFLOAD_STOP 停止 A2DP 硬件 offload
通信中 BT_VND_OP_LPM_WAKE_SET_STATE 发送数据前 deassert WAKE;空闲后再 assert

3. 蓝牙关闭阶段(Bluetooth Turn OFF)

顺序 操作 opcode 描述
1 执行 epilog 清理流程 BT_VND_OP_EPILOG 可能发送 HCI_RESET 或其他定制命令,完成后需调用 epilog_cb()
2 关闭串口 BT_VND_OP_USERIAL_CLOSE 关闭 UART、SPI 或 USB 接口
3 芯片断电 BT_VND_OP_POWER_CTRL 通知 Vendor 关闭 BT 电源(如果支持)

c 复制代码
Bluetooth ON 流程:
 ┌───────────────────────────────┐
 │ USERIAL_OPEN                  │
 │ POWER_CTRL (ON)               │
 │ FW_CFG → fwcfg_cb             │
 │ SCO_CFG → scocfg_cb (可选)    │
 │ LPM_SET_MODE → lpm_cb         │
 │ GET_LPM_IDLE_TIMEOUT          │
 └───────────────────────────────┘

使用过程:
 ┌───────────────────────────────┐
 │ SET_AUDIO_STATE               │
 │ A2DP_OFFLOAD_START / STOP     │
 │ LPM_WAKE_SET_STATE            │
 └───────────────────────────────┘

Bluetooth OFF 流程:
 ┌───────────────────────────────┐
 │ EPILOG → epilog_cb            │
 │ USERIAL_CLOSE                 │
 │ POWER_CTRL (OFF)              │
 └───────────────────────────────┘

3. 补充说明

  • 所有 *_cb() 结尾的操作都需要在异步完成后由 vendor 层手动调用回调通知协议栈。
  • vendor lib 是一个中间层,负责将这些操作转换为实际硬件控制动作(如 ioctl、GPIO 控制、UART 操作等)。
  • 上层 bt_vendor_interface_t->op() 接口在 vendor.c 中实现,内部 switch-case 匹配这些 opcode。
c 复制代码
typedef struct {
  /** set to sizeof(bt_vendor_callbacks_t) */
  size_t size;

  /*
   * Callback and callout functions have implemented in HCI libray
   * (libbt-hci.so).
   */

  /* notifies caller result of firmware configuration request */
  cfg_result_cb fwcfg_cb;

  /* notifies caller result of sco configuration request */
  cfg_result_cb scocfg_cb;

  /* notifies caller result of lpm enable/disable */
  cfg_result_cb lpm_cb;

  /* notifies the result of codec setting */
  cfg_result_cb audio_state_cb;

  /* buffer allocation request */
  malloc_cb alloc;

  /* buffer deallocation request */
  mdealloc_cb dealloc;

  /* hci command packet transmit request */
  cmd_xmit_cb xmit_cb;

  /* notifies caller completion of epilog process */
  cfg_result_cb epilog_cb;

  /* notifies status of a2dp offload cmd's */
  cfg_a2dp_cb a2dp_offload_cb;
} bt_vendor_callbacks_t;
相关推荐
maki0771 天前
虚幻版Pico大空间VR入门教程 05 —— 原点坐标和项目优化技巧整理
android·游戏引擎·vr·虚幻·pico·htc vive·大空间
千里马学框架1 天前
音频焦点学习之AudioFocusRequest.Builder类剖析
android·面试·智能手机·车载系统·音视频·安卓framework开发·audio
fundroid1 天前
掌握 Compose 性能优化三步法
android·android jetpack
TeleostNaCl1 天前
如何在 IDEA 中使用 Proguard 自动混淆 Gradle 编译的Java 项目
android·java·经验分享·kotlin·gradle·intellij-idea
旷野说1 天前
Android Studio Narwhal 3 特性
android·ide·android studio
maki0771 天前
VR大空间资料 01 —— 常用VR框架对比
android·ue5·游戏引擎·vr·虚幻·pico
xhBruce2 天前
InputReader与InputDispatcher关系 - android-15.0.0_r23
android·ims
领创工作室2 天前
安卓设备分区作用详解-测试机红米K40
android·java·linux
hello_ludy2 天前
Android 中的 mk 和 bp 文件编译说明
android·编译
maki0772 天前
VR大空间资料 03 —— VRGK使用体验和源码分析
android·vr·虚幻·源码分析·oculus·htc vive·vrgk