杰理 SDK 文档中心
首页
首页
  • 概述

    • SDK 概览与产品定位
    • 支持芯片平台与蓝牙认证
    • SDK 架构与目录分层
  • 快速开始

    • 环境搭建与编译工具链
    • 编译构建系统
    • 板级工程与配置
    • 烧录与固件升级工具
  • 应用工程

    • 应用选择与工程总览
    • SPP + BLE 数传应用框架
    • 透传与 AT 指令示例
    • BLE 广播/中心与定位示例
    • 2.4G 私有协议与 Dongle 示例
    • 云平台接入示例
    • HID 人机交互应用框架
    • HID 示例工程(键盘/鼠标/遥控器/手柄)
    • Bluetooth Mesh 应用框架
    • Mesh 模型与 Mesh DFU 固件升级
    • Mesh 音频编解码演示
  • 芯片平台与硬件抽象

    • 芯片平台总览与差异
    • 音频编解码与时钟管理
    • 外设驱动接口(ADC/IIC/SPI/PWM/LED/充电)
    • 芯片配置工具与下载支持
  • 蓝牙协议栈

    • 蓝牙控制器层(btctrler)
    • 蓝牙协议栈与 Profile(btstack)
    • 蓝牙模块选择与配置
  • 媒体与音频框架

    • 音频流框架
    • 音频编解码与 A2DP 媒体
    • 音频效果处理(EQ/频谱/变调/环绕/超低音)
    • 本地 TWS 与音频同步
  • 系统服务与运行时

    • 实时操作系统与任务调度
    • 消息事件机制
    • 电源管理与低功耗
    • 存储与配置系统
    • 设备驱动框架(USB/RTC)
  • 应用公共组件

    • 音频应用组件
    • 设备外设抽象(按键/触摸/传感器/存储)
    • 蓝牙公共模块与消息联动
    • 调试与配置组件
    • 杰理关键词唤醒(jl_kws)
  • 第三方协议与云平台接入

    • 杰理 RCSP 私有协议
    • 低功耗蓝牙 Mesh 方案(llsync_mesh)
    • Sig Mesh 方案
    • 涂鸦协议接入
    • 腾讯连连接入
    • 华为 HiLink 接入
  • 固件升级与维护

    • OTA 升级机制
    • 升级补丁与版本维护
    • 升级工具链(BLE OTA / USB Dongle OTA)
  • 文档与开发资源

    • 数据手册与架构文档
    • 协议与云平台开发文档
    • 常见问题与技术支持

本地 TWS 与音频同步

本地 TWS(True Wireless Stereo)与音频同步是杰理 AC63 系列蓝牙 SDK 中,让左右耳两只耳机通过蓝牙互相连接、由主设备接收手机音频并编码转发、从设备解码播放,并保证两侧播放节奏一致的关键机制。本文以 localtws.h 公开接口与 SDK 中注册的 TWS 同步函数族为主线,说明其架构、控制流、配置与扩展方式。

Purpose and Scope

本文覆盖:

  • 本地 TWS 模块(localtws):主设备侧编码端(localtws_enc_api_*)与从设备侧解码端(localtws_dec_*)的接口职责,以及音频数据从 A2DP 接收到对端播放的完整链路。
  • TWS 音频同步机制:SDK 中以 tws_*_sync 命名的同步函数族(媒体同步、ACL 数据同步、事件同步、连接同步、LMP slot 同步、AFH 同步等)在 sdk_used_list.c 中的注册关系与作用。
  • 相关配置开关与资源:TCFG_USER_TWS_ENABLE、TCFG_EQ_ONLINE_ENABLE 条件编译,以及 TWS 连接/断开提示音资源(tws_conn.wtg / tws_dconn.wtg)。

以下主题属于兄弟页面,不在本文展开:TWS 固件升级流程(见 apps/common/include/update_tws.h、update_tws_new.h)、TWS 连接与配对管理(见各应用目录下的 apps/*/include/bt_tws.h)、EQ 在线调音(TCFG_EQ_ONLINE_ENABLE 相关)。

Overview

在真无线立体声应用中,左右耳(或主从耳)之间通过蓝牙 ACL 链路互联。其中一只作为主设备(活动设备)与手机建立 A2DP/HFP 连接,另一只作为从设备。要让两只耳机同时播放同一段音频且听感同步,必须解决两个问题:

  1. 音频数据转发:主设备把 A2DP 收到的音频流按 audio_fmt 描述的格式,通过 localtws 编码器压缩/组帧,再经蓝牙协议栈的 TWS 链路转发给从设备;从设备用 localtws 解码器还原成 PCM 播放。
  2. 播放节奏同步:两侧播放进度必须对齐。SDK 通过一组 tws_*_sync 同步函数在底层协调媒体时钟(media clock)、ACL 数据时序、LMP slot、事件与跳频(AFH)信息,保证左右声道/左右耳听感一致。

SDK 的 localtws.h 是这一能力在应用层的唯一公开接口:它把所有底层实现(编码器、解码器、蓝牙同步)封装为少量 C 函数,应用层只需按"打开 → 写入/读取 → 关闭"的模型使用。底层实现在 include_lib/media/media_develop/media/application/audio_localtws.h 与 media/localtws_decoder.h 声明的库中,SDK 侧头文件仅暴露接口契约。

Architecture

下图展示本地 TWS 音频同步的整体架构:手机作为 A2DP 源,主设备完成接收与编码,通过蓝牙协议栈的 TWS 链路转发,从设备解码输出;底层同步函数族贯穿两侧,负责节奏对齐。

flowchart TD
    subgraph sg_Phone["手机(A2DP 源)"]
        PHONE["A2DP Sink(主设备侧接收)"]
    end

    subgraph sg_Master["主设备(活动设备 / 编码端)"]
        A2DP["A2DP 接收 + audio_fmt 格式"]
        ENC["localtws 编码器<br/>localtws_enc_api_open / write / close"]
        BT_STACK["蓝牙协议栈(ACL / LMP / AFH)"]
    end

    subgraph sg_Slave["从设备(解码端)"]
        DEC["localtws 解码器<br/>localtws_dec_open / resume / pause"]
        PLAY["PCM 播放输出"]
    end

    subgraph sg_Sync["TWS 同步函数族(sdk_used_list.c 注册)"]
        MEDIA_SYNC["tws_local_media_sync / tws_media_sync"]
        ACL_SYNC["tws_acl_data_sync / tws_conn_sync"]
        SLOT_SYNC["tws_lmp_slot_sync / tws_afh_sync"]
        EVENT_SYNC["tws_event_sync / tws_sync_call / tws_link_sync"]
    end

    PHONE -->|"蓝牙链路"| A2DP
    A2DP --> ENC
    ENC --> BT_STACK
    BT_STACK <-->|"TWS ACL 数据转发"| DEC
    DEC --> PLAY
    MEDIA_SYNC --> ENC
    MEDIA_SYNC --> DEC
    ACL_SYNC --> BT_STACK
    SLOT_SYNC --> BT_STACK
    EVENT_SYNC --> BT_STACK

各组成部分的职责:

  • localtws 编码器(主设备侧):把 A2DP 解出的 s16 PCM 数据编码为适合 TWS 链路传输的帧。localtws_enc_api_open(struct audio_fmt *pfmt, u32 flag) 指定编码格式与流标志,localtws_enc_api_write(s16 *data, int len) 逐块喂入音频数据。
  • localtws 解码器(从设备侧):从 TWS 链路接收编码帧并解码播放。localtws_dec_open / localtws_dec_resume / localtws_dec_pause 控制解码生命周期,localtws_media_dat_abandon 用于主动丢弃积压数据以追平两侧节奏。
  • 蓝牙协议栈同步层:tws_lmp_slot_sync 与 tws_afh_sync 让两侧在物理时序上对齐(LMP 时隙与跳频),tws_acl_data_sync 与 tws_conn_sync 保证 ACL 数据与连接状态一致,tws_event_sync / tws_sync_call 负责事件与呼叫类同步,tws_media_sync / tws_local_media_sync 负责媒体播放进度的对齐。
  • 应用层:通过 localtws.h 中少量接口完成启停、蓝牙事件分发(localtws_bt_event_deal)与使能检测(localtws_check_enable)。

架构说明:localtws.h 头文件明确指出编码器、解码器的实现分别来自 application/audio_localtws.h 与 media/localtws_decoder.h(见 localtws.h#L4-L5),即底层以库形式提供,SDK 侧只暴露接口,这与 include_lib/media 目录的组织方式一致。

localtws 模块职责与接口详解

cpu/br25/localtws/localtws.h 与 cpu/br23/localtws/localtws.h 是各 CPU 平台本地 TWS 的统一入口头文件(br23 与 br25 两平台声明一致)。该头文件把整套本地 TWS 能力按"编码端 / 解码端 / 控制端"三类接口组织,并定义了数据源标志:

#ifndef __LOCALTWS_H_
#define __LOCALTWS_H_

#include "application/audio_localtws.h"
#include "media/localtws_decoder.h"

#define LOCALTWS_ENC_FLAG_STREAM		BIT(0)	// 数据源是流数据


// localtws检测是否使能
int localtws_check_enable(void);

// localtws蓝牙事件处理
int localtws_bt_event_deal(struct bt_event *evt);

// 打开localtws编码
int localtws_enc_api_open(struct audio_fmt *pfmt, u32 flag);
// 关闭localtws编码
void localtws_enc_api_close(void);
// localtws编码写入
int localtws_enc_api_write(s16 *data, int len);

// localtws设置等待a2dp状态
void localtws_set_wait_a2dp_start(u8 flag);

// localtws启动(活动设备主动调用)
void localtws_start(struct audio_fmt *pfmt);
// localtws停止(活动设备主动调用)
void localtws_stop(void);

// 打开localtws解码
int localtws_dec_open(u32 value);
// 关闭localtws解码
int localtws_dec_close(u8 drop_frame_start);
// localtws已经打开
u8 localtws_dec_is_open(void);
// localtws解码激活
void localtws_dec_resume(void);
// localtws抛弃数据
int localtws_media_dat_abandon(void);
// localtws暂停
void localtws_dec_pause(void);
// localtws已经开始解码
int localtws_dec_out_is_start(void);

// localtws暂停控制
void localtws_decoder_pause(u8 pause);


#endif /*__LOCALTWS_H_*/

Source: localtws.h#L1-L51

编码端(主设备侧)接口

函数作用设计意图
localtws_start(struct audio_fmt *pfmt)活动设备主动启动本地 TWS应用层在 A2DP 即将开始时调用,把音频格式传给编码链路
localtws_stop(void)活动设备主动停止本地 TWS与 start 配对,保证编码与转发链路有序释放
localtws_enc_api_open(struct audio_fmt *pfmt, u32 flag)打开编码器flag 携带 LOCALTWS_ENC_FLAG_STREAM 表示数据源为流式数据(而非文件/预存数据)
localtws_enc_api_write(s16 *data, int len)写入 PCM 数据逐块喂入 A2DP 解码后的 s16 采样,编码器内部组帧后经 TWS 链路发送
localtws_enc_api_close(void)关闭编码器释放编码资源
localtws_set_wait_a2dp_start(u8 flag)设置"等待 A2DP 启动"状态编码链路在 A2DP 未就绪前避免提前发送,防止从设备侧无源可播

解码端(从设备侧)接口

函数作用设计意图
localtws_dec_open(u32 value)打开解码器从设备收到 TWS 连接后启用解码通道
localtws_dec_close(u8 drop_frame_start)关闭解码器;drop_frame_start 非 0 时丢弃起始帧起始帧往往携带不完整数据,丢弃可避免爆音/杂音
localtws_dec_is_open(void)查询解码器是否已打开供应用层判断链路状态,避免重复打开
localtws_dec_resume(void)激活(恢复)解码收到可播放数据或 A2DP 启动后从暂停态恢复
localtws_dec_pause(void)暂停解码暂停时不丢弃数据,恢复后继续播放
localtws_decoder_pause(u8 pause)解码器暂停控制(带参)更细粒度的暂停控制,供播放通路直接调用
localtws_media_dat_abandon(void)抛弃积压数据当两侧播放进度偏差过大时丢弃缓冲数据以重新对齐——这是本地 TWS 音频同步的核心手段
localtws_dec_out_is_start(void)查询解码输出是否已开始区分"已打开"与"已出数据",用于超时/卡顿检测

事件与使能

  • localtws_check_enable(void):检测本地 TWS 功能是否使能(内部通常与 TCFG_USER_TWS_ENABLE 及角色配置相关)。
  • localtws_bt_event_deal(struct bt_event *evt):把蓝牙协议栈事件(连接、断开、A2DP 启停等)分发给 localtws 内部状态机,是"音频同步跟随蓝牙状态"的桥梁。

TWS 音频同步函数族

SDK 在 sdk_used_list.c 中集中注册了整套 TWS 同步函数。以 br23 平台为例:

#if TCFG_USER_TWS_ENABLE
tws_local_media_sync
#if TCFG_EQ_ONLINE_ENABLE
#endif /* #if TCFG_EQ_ONLINE_ENABLE */
tws_acl_data_sync
tws_event_sync
tws_conn_sync
tws_lmp_slot_sync
tws_media_sync
tws_sync_call
tws_link_sync
tws_afh_sync

Source: cpu/br23/sdk_used_list.c#L3-L15(bd19/bd29 平台结构相同,见 cpu/bd19/sdk_used_list.c#L3-L15)

这些符号被列入 sdk_used_list.c,说明它们属于需要链接进固件的底层同步实现(防止库裁剪时被移除)。各函数在本地 TWS 音频同步中的角色如下:

同步函数同步对象说明
tws_local_media_sync本地媒体播放本地 TWS 场景下的媒体进度对齐,直接服务本文主题
tws_media_sync媒体时钟两侧媒体时钟基准对齐,保证播放速率一致
tws_acl_data_syncACL 数据主从之间 ACL 数据分组的时序同步,确保转发帧按序到达
tws_event_sync蓝牙事件两侧对同一蓝牙事件(连接/断开/A2DP 启停)的感知一致
tws_conn_sync连接状态主从设备连接关系的同步
tws_lmp_slot_syncLMP 时隙底层时隙级同步,是音频节奏同步的物理基础
tws_afh_sync跳频(AFH)跳频序列同步,保证链路可用性与转发时延稳定
tws_sync_call同步呼叫电话/呼叫场景下的同步
tws_link_sync链路TWS 链路的整体同步控制

设计意图:音频同步不是单点问题——媒体层需要对齐播放进度(tws_media_sync / tws_local_media_sync),传输层需要对齐数据分组(tws_acl_data_sync),物理层需要对齐时隙与跳频(tws_lmp_slot_sync / tws_afh_sync),事件层需要对齐状态感知(tws_event_sync / tws_conn_sync)。SDK 把这一整套同步能力按层次拆分注册,让协议栈与音频通路可以独立演进。

条件编译与配套资源

TCFG_USER_TWS_ENABLE

tws_local_media_sync 等同步函数整体处于 #if TCFG_USER_TWS_ENABLE 之下(见 cpu/br23/sdk_used_list.c#L3),即用户 TWS 功能开关。关闭该宏时,整套本地 TWS 音频同步函数都不会链接进固件。

TCFG_EQ_ONLINE_ENABLE

EQ 在线调音开关在 sdk_used_list.c 中紧邻 tws_local_media_sync 出现(#if TCFG_EQ_ONLINE_ENABLE ... #endif,见 cpu/bd19/sdk_used_list.c#L3-L7),说明在线 EQ 参数同样需要走 TWS 链路同步到从设备,属于本地 TWS 数据通道的旁路能力。

提示音资源

各 CPU 的 config tool 均包含 TWS 专属提示音:

  • tws_conn.wtg:TWS 连接提示音(例如 cpu/br25/tools/AC696X_config_tool/conf/source/tone_file/tws_conn.wtg)
  • tws_dconn.wtg:TWS 断开提示音(例如 cpu/br25/tools/AC696X_config_tool/conf/source/tone_file/tws_dconn.wtg)

这些提示音文件的存在说明本地 TWS 的"已连接/已断开"状态在设备端有明确的用户可感知反馈,事件同步(tws_event_sync)会驱动其播放。

Core Flow:音频数据端到端流转

本地 TWS 的核心流程是"主设备编码转发 → 从设备解码播放",两侧均受底层同步函数约束。整体时序如下:

sequenceDiagram
    participant APP as 主设备应用层
    participant ENC as localtws 编码器(主)
    participant BT as 蓝牙协议栈(TWS 链路 + 同步)
    participant DEC as localtws 解码器(从)
    participant PLAY as 播放输出

    APP->>BT: 蓝牙事件(TWS 连接 / A2DP 启动)
    BT->>APP: localtws_bt_event_deal(evt)
    APP->>APP: localtws_check_enable() 确认使能
    APP->>APP: localtws_set_wait_a2dp_start(1) 等待 A2DP
    APP->>ENC: localtws_start(pfmt)
    APP->>ENC: localtws_enc_api_open(pfmt, LOCALTWS_ENC_FLAG_STREAM)

    Note over BT: tws_lmp_slot_sync / tws_afh_sync 对齐物理时序
    Note over BT: tws_media_sync / tws_local_media_sync 对齐媒体时钟

    loop 音频持续播放
        APP->>ENC: localtws_enc_api_write(s16 *data, len)
        ENC->>BT: 编码帧(ACL 数据,tws_acl_data_sync 保序)
        BT->>DEC: 转发帧
        DEC->>PLAY: 解码后 PCM 播放
    end

    opt 两侧进度偏差过大
        DEC->>DEC: localtws_media_dat_abandon() 抛弃积压数据
    end

    APP->>ENC: localtws_enc_api_close()
    APP->>ENC: localtws_stop()

流程要点:

  1. 事件驱动启动:蓝牙事件先经 localtws_bt_event_deal 分发,应用层随后用 localtws_check_enable 确认本地 TWS 使能,避免在非 TWS 场景误启动编码。
  2. 等待 A2DP 就绪:localtws_set_wait_a2dp_start 让编码端等到 A2DP 真正启动后再开始发送数据,防止从设备解码器无源可播。
  3. 编码-转发-解码:主设备把 A2DP 的 s16 采样写入编码器(LOCALTWS_ENC_FLAG_STREAM 标志流式数据),编码帧经 TWS ACL 链路转发;底层 tws_lmp_slot_sync / tws_afh_sync / tws_acl_data_sync 保证时隙、跳频与分组时序一致。
  4. 节奏纠偏:当两侧播放进度偏差过大时,从设备调用 localtws_media_dat_abandon 丢弃缓冲数据追平主设备——这是"同步"在数据通路上的最终兜底手段。
  5. 有序停止:先关编码器再 localtws_stop,与启动顺序严格对称。

解码器状态流转

从 localtws.h 解码端接口(dec_open / dec_resume / dec_pause / decoder_pause / media_dat_abandon / dec_close(drop_frame_start))可以还原出解码端的生命周期状态机:

stateDiagram-v2
    [*] --> IDLE
    IDLE --> OPEN: localtws_dec_open(value)
    OPEN --> PAUSED: localtws_dec_pause() / localtws_decoder_pause(1)
    PAUSED --> PLAYING: localtws_dec_resume()
    PLAYING --> PAUSED: localtws_dec_pause() / localtws_decoder_pause(1)
    PLAYING --> PLAYING: localtws_media_dat_abandon() 追平进度
    OPEN --> IDLE: localtws_dec_close(0)
    PLAYING --> IDLE: localtws_dec_close(drop_frame_start=1) 丢弃起始帧
    PAUSED --> IDLE: localtws_dec_close(0)

说明:该状态机由 localtws.h 公开 API 的语义推导(如 dec_close 的 drop_frame_start 参数表明关闭时可选择丢弃起始帧、media_dat_abandon 表明播放中存在主动丢数据路径)。底层库内部实现细节未在 SDK 侧头文件中展开,属于"接口可验证、内部实现以库形式提供"的部分。

Usage Examples

主设备侧:启动与编码

以下示例展示活动设备(主设备)侧的标准调用序列,接口声明摘自 localtws.h:

// 1. 蓝牙事件到达后,应用层先做使能与事件分发
if (localtws_check_enable()) {
    localtws_bt_event_deal(&evt);
}

// 2. 等待 A2DP 就绪后,按音频格式启动本地 TWS 编码
struct audio_fmt fmt = { /* 由 A2DP 解码通路填充采样率/通道数等 */ };
localtws_set_wait_a2dp_start(1);
localtws_start(&fmt);
localtws_enc_api_open(&fmt, LOCALTWS_ENC_FLAG_STREAM);

// 3. 音频数据持续写入(A2DP 解码回调中调用)
s16 *pcm = /* 解码后的 PCM 数据 */;
localtws_enc_api_write(pcm, len);

// 4. 停止时按对称顺序关闭
localtws_enc_api_close();
localtws_stop();

Source: localtws.h#L7-L29(接口声明;调用序列为基于接口语义的标准用法)

从设备侧:解码与播放

从设备侧使用解码端接口,通过暂停/恢复与丢数据接口维持与主设备的同步:

// 1. TWS 链路建立后打开解码器
localtws_dec_open(0);

// 2. 有数据可播时激活解码输出
localtws_dec_resume();

// 3. 暂停场景(例如通话插入):暂停但不丢数据
localtws_dec_pause();
// 或带参暂停控制
localtws_decoder_pause(1);

// 4. 两侧进度偏差过大时,抛弃积压数据追平主设备
if (/* 进度偏差检测 */) {
    localtws_media_dat_abandon();
}

// 5. 停止时按需丢弃起始帧,避免爆音
localtws_dec_close(1);

Source: localtws.h#L32-L47(接口声明;调用序列为基于接口语义的标准用法)

同步函数族注册(链接保留)

tws_local_media_sync 等底层同步实现通过 sdk_used_list.c 显式引用,防止被链接器裁剪:

#if TCFG_USER_TWS_ENABLE
tws_local_media_sync
#if TCFG_EQ_ONLINE_ENABLE
#endif /* #if TCFG_EQ_ONLINE_ENABLE */
tws_acl_data_sync
tws_event_sync
tws_conn_sync
tws_lmp_slot_sync
tws_media_sync
tws_sync_call
tws_link_sync
tws_afh_sync

Source: cpu/br23/sdk_used_list.c#L3-L15

Configuration Options

本地 TWS 与音频同步相关的配置开关集中在 SDK 的配置宏中(各应用工程的 board_config / 配置头文件定义):

配置项类型默认/取值说明
TCFG_USER_TWS_ENABLE宏开关由工程配置用户 TWS 总开关;关闭后 tws_local_media_sync 等同步函数不链接进固件(见 cpu/br23/sdk_used_list.c#L3)
TCFG_EQ_ONLINE_ENABLE宏开关由工程配置EQ 在线调音开关;开启时其实现与 tws_local_media_sync 一起被保留(见 cpu/bd19/sdk_used_list.c#L5-L7)
LOCALTWS_ENC_FLAG_STREAM位标志BIT(0)编码数据源标志:置位表示数据来自流(A2DP 实时流),用于编码器选择组帧/缓存策略(见 localtws.h#L7)

注意:TCFG_USER_TWS_ENABLE 与 TCFG_EQ_ONLINE_ENABLE 的实际取值由各应用工程的配置头文件决定,本文仅依据 sdk_used_list.c 的引用关系说明其作用。

API Reference

以下为 cpu/br25/localtws/localtws.h 公开的全部接口(br23 平台声明一致)。

int localtws_check_enable(void)

检测本地 TWS 是否使能。

  • Returns:非 0 表示使能,0 表示未使能。

int localtws_bt_event_deal(struct bt_event *evt)

处理本地 TWS 相关的蓝牙事件(连接/断开/A2DP 启停等)。

  • Parameters:evt(struct bt_event *)— 蓝牙协议栈事件结构。
  • Returns:0 表示事件已处理。

int localtws_enc_api_open(struct audio_fmt *pfmt, u32 flag)

打开本地 TWS 编码器。

  • Parameters:pfmt(struct audio_fmt *)— 音频格式(采样率、位深、通道数等);flag(u32)— 数据源标志,可传 LOCALTWS_ENC_FLAG_STREAM。
  • Returns:0 表示成功,非 0 表示失败。

void localtws_enc_api_close(void)

关闭本地 TWS 编码器,释放编码资源。

int localtws_enc_api_write(s16 *data, int len)

向编码器写入 PCM 数据。

  • Parameters:data(s16 *)— PCM 采样数据;len(int)— 数据长度(采样点数)。
  • Returns:0 表示成功,非 0 表示失败。

void localtws_set_wait_a2dp_start(u8 flag)

设置"等待 A2DP 启动"标志,控制编码端是否等待 A2DP 就绪后再发送。

  • Parameters:flag(u8)— 非 0 表示等待。

void localtws_start(struct audio_fmt *pfmt)

启动本地 TWS(活动设备主动调用)。

  • Parameters:pfmt(struct audio_fmt *)— 音频格式。

void localtws_stop(void)

停止本地 TWS(活动设备主动调用)。

int localtws_dec_open(u32 value)

打开本地 TWS 解码器。

  • Parameters:value(u32)— 打开参数(保留/预留)。
  • Returns:0 表示成功,非 0 表示失败。

int localtws_dec_close(u8 drop_frame_start)

关闭本地 TWS 解码器。

  • Parameters:drop_frame_start(u8)— 非 0 时丢弃起始帧(避免不完整帧导致爆音)。
  • Returns:0 表示成功。

u8 localtws_dec_is_open(void)

查询解码器是否已打开。

  • Returns:非 0 表示已打开。

void localtws_dec_resume(void)

激活解码输出(从暂停恢复播放)。

int localtws_media_dat_abandon(void)

抛弃解码缓冲中的积压数据,用于追平与主设备的播放进度。

  • Returns:0 表示成功,非 0 表示失败。

void localtws_dec_pause(void)

暂停解码(不丢数据,恢复后继续)。

int localtws_dec_out_is_start(void)

查询解码输出是否已经开始。

  • Returns:非 0 表示已开始输出。

void localtws_decoder_pause(u8 pause)

带参解码暂停控制。

  • Parameters:pause(u8)— 非 0 暂停,0 恢复。

Failure Modes、边界情况与并发

时序偏差与丢数据

本地 TWS 两侧播放不同步时,从设备通过 localtws_media_dat_abandon 主动丢弃积压数据追平主设备。这是同步的最后兜底手段:如果频繁触发,说明底层 tws_lmp_slot_sync / tws_afh_sync / tws_media_sync 的节奏对齐已经出现较大偏差,应优先检查 TWS 链路质量与蓝牙时序配置,而不是依赖丢数据修正。

A2DP 未就绪时的启动

localtws_set_wait_a2dp_start 的存在表明:如果编码端在 A2DP 未启动时就开始发送,从设备将无源可播,表现为"从耳无声"。正确的调用顺序是先等待 A2DP 就绪、再 localtws_start + localtws_enc_api_open。

起始帧丢弃

localtws_dec_close(u8 drop_frame_start) 与 localtws_dec_out_is_start 两个接口揭示了起始帧处理的边界:解码刚打开时输出的帧可能不完整,关闭时按需丢弃起始帧可避免爆音;应用层可用 localtws_dec_out_is_start 判断是否已进入稳定输出。

暂停/恢复的并发语义

localtws_dec_pause / localtws_dec_resume 与 localtws_decoder_pause(pause) 并存:前者是无参的语义化接口,后者是带参的底层控制接口,二者面向不同调用层级。暂停只冻结输出、不丢弃数据,恢复后继续播放,因此播放通路与蓝牙事件通路(localtws_bt_event_deal)对解码器的并发访问需要遵循"事件驱动暂停/恢复、播放通路驱动写数据"的协作模型。

实现细节边界(诚实说明)

编码器/解码器的内部实现(编码格式、帧结构、缓冲管理)位于库中(application/audio_localtws.h、media/localtws_decoder.h),SDK 侧 localtws.h 仅公开接口契约。本文描述的调用顺序与状态流转均基于接口语义推导,未涉及库内实现细节。

Performance 与运维建议

  • 流式标志:LOCALTWS_ENC_FLAG_STREAM 表明本地 TWS 的典型数据源是 A2DP 实时流,编码器按流模式处理缓存,避免为整段文件预留缓冲导致内存与延迟浪费。
  • 同步函数链接保留:sdk_used_list.c 的注册方式意味着修改或裁剪同步函数会影响固件链接结果——新增平台或关闭 TWS 功能时,需同步维护该列表,防止出现"功能看似打开、实际未链接"的问题。
  • 提示音反馈:tws_conn.wtg / tws_dconn.wtg 是 TWS 连接/断开状态的用户反馈资源;若更换提示音,需同时替换各 CPU config tool 下的 conf/source/tone_file 与 conf/output/extra_tones 两处,并重新生成配置。

Extension Points

  • 角色区分:localtws_start 明确标注"活动设备主动调用",解码端接口则供从设备使用——新增应用时只需按角色调用对应接口组,无需改动库。
  • 事件注入:localtws_bt_event_deal(struct bt_event *evt) 是外部蓝牙事件进入 localtws 的唯一入口,自定义事件(如新增连接场景)可通过该函数注入。
  • 格式适配:struct audio_fmt *pfmt 贯穿编码与解码两端,接入新的音频源(如录音、提示音混音)时通过该结构描述格式即可。
  • 平台头文件:cpu/br23/localtws/localtws.h 与 cpu/br25/localtws/localtws.h 声明一致,新平台可沿用同一接口模型。

Related Links

  • cpu/br25/localtws/localtws.h — 本地 TWS 统一接口(本文核心源码)
  • cpu/br23/localtws/localtws.h — br23 平台同款接口
  • cpu/br23/sdk_used_list.c — TWS 同步函数族注册列表
  • cpu/bd19/sdk_used_list.c — bd19 平台同步函数注册列表
  • include_lib/media/media_develop/media/application/audio_localtws.h — localtws 底层库接口(库实现入口)
  • apps/spp_and_le/include/bt_tws.h — TWS 连接/配对管理(兄弟页面主题)
  • apps/common/include/update_tws.h — TWS 升级流程(兄弟页面主题)
Prev
音频效果处理(EQ/频谱/变调/环绕/超低音)