ANC与噪声处理
本文档介绍杰理(Jieli)蓝牙 SDK 中 ANC(主动降噪)与噪声处理能力的完整实现:噪声处理模式(标准/降噪/通透)的获取与设置、模式切换顺序、按键绑定、自适应 ANC 算法,以及智能免摘、场景降噪、风噪监测等人声相关功能,涵盖 RCSPController 高层接口与 JL_BluetoothManager 底层命令两种调用方式。
Purpose and Scope
本页面向 device-functions.anc-noise 目录主题,覆盖 SDK 中与 ANC 及噪声处理相关的全部能力:
- ANC 模式管理:
VoiceMode数据模型、获取全部模式列表、获取/设置当前模式、设置模式切换顺序、按键切换绑定; - 自适应 ANC 算法:能力检测、参数获取/设置、检测流程启动与结果回调;
- 智能语音功能族:智能免摘(SmartNoPick)、场景降噪(SceneDenoising)、风噪监测(WindNoiseDetection)、人声增强(VocalBooster);
- 两种调用范式:高层
RCSPController封装接口与底层JL_BluetoothManager命令构造(CommandBuilder+AttrAndFunCode)。
以下主题属于兄弟页面,不在本页展开:EQ 均衡器调节(参见 EqAdvancedSetFragment)、设备通用属性读写(ADVInfoResponse 的通用机制可参考设备信息相关页面)。ANC 相关 UI 布局见 view_anc_func.xml。
Overview
ANC(Active Noise Cancellation,主动降噪)是蓝牙耳机/音箱设备的核心卖点功能。在杰理 SDK 中,ANC 并非一个孤立的开关,而是一组围绕"噪声处理模式"(VoiceMode)展开的协议能力:
- 设备支持若干种噪声处理模式,典型三种:标准模式(关闭降噪)、降噪模式(屏蔽环境噪声)、通透模式(透传环境声);
- 每种模式可携带左右声道的增益范围与当前增益值(
leftMax/leftCurVal/rightMax/rightCurVal),用于 UI 展示降噪强度; - App 需要知道设备支持哪些模式、当前处于哪个模式,并允许用户切换;还可以自定义"模式切换顺序"——即耳机上按键/触控循环切换时的轮转列表;
- 更高端的设备还支持自适应 ANC:通过算法自动检测佩戴状态并调整降噪参数,App 侧需要提供"开始检测"流程与结果回调;
- 同一协议家族中还包含智能免摘、场景降噪、风噪监测、人声增强等 VoiceFunc 子类功能,它们共享同一套"读取-缓存-回调"模式。
SDK 提供两条 API 路径:RCSPController(单例、带事件回调与设备缓存,推荐使用)与 JL_BluetoothManager(底层命令构造,适合对协议层做精细控制)。两者最终都走同一条 RCSP 蓝牙通道与设备交互。
Architecture
flowchart TD
subgraph sg_App["应用层 (btsmart App)"]
UI["ANC 设置界面<br/>view_anc_func.xml / EqAdvancedSetFragment"]
ANCDemo["ANCDemo(测试/示例代码)"]
end
subgraph sg_Sdk["SDK 高层封装层"]
RCSP["RCSPController (单例)"]
DeviceInfo["DeviceInfo(设备信息缓存)"]
Callback["BTRcspEventCallback / OnRcspActionCallback<br/>OnAdaptiveANCListener"]
end
subgraph sg_Protocol["协议构造层"]
CmdBuilder["CommandBuilder"]
AttrFun["AttrAndFunCode 功能码/属性掩码"]
CHex["CHexConver 字节工具"]
end
subgraph sg_Data["数据模型层"]
VoiceMode["VoiceMode"]
AdaptiveData["AdaptiveData"]
SmartNoPick["SmartNoPick"]
SceneDenoising["SceneDenoising"]
WindNoiseDetection["WindNoiseDetection"]
VocalBooster["VocalBooster"]
end
subgraph sg_Device["设备端"]
DEV["蓝牙耳机/音箱(RCSP 协议)"]
end
UI --> ANCDemo
ANCDemo -->|"getAllVoiceModes / setCurrentVoiceMode / startAdaptiveANC 等"| RCSP
RCSP --> DeviceInfo
RCSP --> Callback
RCSP -->|"底层命令"| CmdBuilder
CmdBuilder --> AttrFun
CmdBuilder --> CHex
RCSP -->|"蓝牙通道 (RCSP)"| DEV
DEV -->|"协议回复"| RCSP
RCSP -->|"解析为数据模型"| VoiceMode
VoiceMode --> DeviceInfo
Callback -->|"onVoiceModeList / onVoiceFunctionChange"| ANCDemo
VoiceMode --> ANCDemo
架构说明:ANCDemo(或 App 内各 Fragment)作为调用方,统一经由单例 RCSPController 发起请求。控制器内部使用 CommandBuilder/AttrAndFunCode 构造协议命令、CHexConver 完成字节序转换,通过蓝牙 RCSP 通道下发到设备;设备回复后,控制器把原始字节解析为 VoiceMode 或各 VoiceFunc 子类对象,写入 DeviceInfo 缓存,并通过 BTRcspEventCallback 等回调接口异步通知 UI。这种"发起接口 + 事件回调 + 设备缓存"三段式设计,让 UI 层无需关心协议细节,同时保证数据一致性(同一设备多次读取可命中缓存)。
核心数据模型:VoiceMode
噪声处理模式是整套 ANC 功能的基础数据结构。官方文档给出了完整定义:
public class VoiceMode implements Parcelable {
private int mode = -1; //ANC模式
private int leftMax; //左声道最大值
private int leftCurVal; //左声道当前值
private int rightMax; //右声道最大值
private int rightCurVal; //右声道当前值
//标准模式
public final static int VOICE_MODE_CLOSE = 0;
//降噪模式
public final static int VOICE_MODE_DENOISE = 1;
//通透模式
public final static int VOICE_MODE_TRANSPARENT = 2;
}
Source: anc_ctrl.rst.txt
设计要点:
mode字段与三个常量对应,默认-1表示"未知/无效"状态,App 侧在回调数据时应先判空再使用;- 左右声道各带
Max与CurVal,用于降噪强度条/滑块的展示与设置——这也是 ANC 与普通开关类功能的最大区别:它携带连续可调参数; - 常量命名中
CLOSE(关闭=标准)、DENOISE(降噪)、TRANSPARENT(通透)明确了三种模式的语义,切换顺序列表正是基于这些 mode 值构造的。
ANC 模式操作
获取所有噪声处理模式
App 启动或进入 ANC 设置页时,应先拉取设备支持的全部模式列表。ANCDemo 演示了标准流程:注册事件回调 → 发起请求 → 在 onVoiceModeList 中接收数据。
public void getAllVoiceModes() {
//获取RCSPController对象
RCSPController controller = RCSPController.getInstance();
//注册蓝牙RCSP事件监听器
controller.addBTRcspEventCallback(new BTRcspEventCallback() {
@Override
public void onVoiceModeList(BluetoothDevice device, List<VoiceMode> voiceModes) {
//此处将会回调噪声处理信息列表
}
});
//执行获取所有噪声处理信息功能并等待结果回调
controller.getAllVoiceModes(controller.getUsingDevice(), new OnRcspActionCallback<Boolean>() {
@Override
public void onSuccess(BluetoothDevice device, Boolean message) {
//成功回调
//数据将在BTRcspEventCallback#onVoiceModeList回调
}
@Override
public void onError(BluetoothDevice device, BaseError error) {
//失败回调
//error - 错误信息
}
});
}
Source: ANCDemo.java
底层等价命令(JL_BluetoothManager 方式)使用公共属性函数 + 掩码:
- function:
AttrAndFunCode.SYS_INFO_FUNCTION_PUBLIC(公共属性) - mask:
0x01 << AttrAndFunCode.SYS_INFO_ATTR_ALL_NOISE_MODE(所有噪声处理信息) - 命令构造:
CommandBase getAllVoiceModesCmd = CommandBuilder.buildGetAllVoiceModes();
Source: anc_ctrl.rst.txt
获取当前噪声处理模式
public void getCurrentVoiceMode() {
//获取RCSPController对象
RCSPController controller = RCSPController.getInstance();
//注册蓝牙RCSP事件监听器
controller.addBTRcspEventCallback(new BTRcspEventCallback() {
@Override
public void onCurrentVoiceMode(BluetoothDevice device, VoiceMode voiceMode) {
//此处将会回调当前噪声处理模式信息
}
});
//执行获取当前噪声处理模式信息功能并等待结果回调
controller.getCurrentVoiceMode(controller.getUsingDevice(), new OnRcspActionCallback<Boolean>() {
@Override
public void onSuccess(BluetoothDevice device, Boolean message) {
//成功回调
//数据将在BTRcspEventCallback#onCurrentVoiceMode回调
}
@Override
public void onError(BluetoothDevice device, BaseError error) {
//失败回调
//error - 错误信息
}
});
}
Source: ANCDemo.java
底层等价命令使用 SYS_INFO_ATTR_CURRENT_NOISE_MODE 掩码:CommandBuilder.buildGetCurrentVoiceMode()。
设置当前噪声处理模式
public void setCurrentVoiceMode(VoiceMode voiceMode) {
//获取RCSPController对象
RCSPController controller = RCSPController.getInstance();
//voiceMode - 噪声处理模式
//执行设置当前噪声处理模式功能并等待结果回调
controller.setCurrentVoiceMode(controller.getUsingDevice(), voiceMode, new OnRcspActionCallback<Boolean>() {
@Override
public void onSuccess(BluetoothDevice device, Boolean message) {
//成功回调
}
@Override
public void onError(BluetoothDevice device, BaseError error) {
//失败回调
//error - 错误信息
}
});
}
Source: ANCDemo.java
设置模式时传入的 VoiceMode 应来自之前 getAllVoiceModes/getCurrentVoiceMode 回调(或按需构造),其中 mode 字段决定目标模式;若包含左右声道增益值,则同时完成强度设置。
设置模式切换顺序(循环列表)
耳机实体按键/触控通常只做"下一档"循环切换,因此 App 需要把可参与循环的模式列表写入设备。切换列表以位掩码编码:每个模式占 1 bit,至少 2 个模式:
public void changeVoiceModeList(int[] modes) {
//获取RCSPController对象
RCSPController controller = RCSPController.getInstance();
//噪声模式切换不能小于2个
if (modes == null || modes.length < 2) return;
//设置模式切换顺序
int value = 0x00;
for (int mode : modes) {
byte bit = (byte) (mode & 0xff);
value = value | (0x01 << bit);
}
//执行设置模式切换顺序功能并等待结果回调
controller.modifyDeviceSettingsInfo(controller.getUsingDevice(), AttrAndFunCode.ADV_TYPE_ANC_MODE_LIST, CHexConver.intToBigBytes(value), new OnRcspActionCallback<Integer>() {
@Override
public void onSuccess(BluetoothDevice device, Integer message) {
//成功回调
//成功之后,可以获取结果
controller.getDeviceSettingsInfo(device, 0x01 << AttrAndFunCode.ADV_TYPE_ANC_MODE_LIST, new OnRcspActionCallback<ADVInfoResponse>() {
@Override
public void onSuccess(BluetoothDevice device, ADVInfoResponse message) {
// message.getModes();//噪声模式切换顺序
}
@Override
public void onError(BluetoothDevice device, BaseError error) {
//失败回调
//error - 错误信息
}
});
}
@Override
public void onError(BluetoothDevice device, BaseError error) {
//失败回调
//error - 错误信息
}
});
}
Source: ANCDemo.java
关键细节:
value | (0x01 << bit)把模式号映射为 bit 位:如[0, 1, 2]→0b111,[0, 2]→0b101;CHexConver.intToBigBytes(value)负责大端字节序转换——协议层对整数的字节序有严格要求,不能直接发送 int;- 写入成功后通过
getDeviceSettingsInfo回读校验,ADVInfoResponse.getModes()可还原模式切换顺序; - 底层命令方式等价使用
ADV_TYPE_ANC_MODE_LIST作为功能码(见 anc_ctrl.rst.txt)。
按键绑定:一键切换 ANC 模式
设备按键功能列表中可把某个按键绑定为"切换 ANC 模式",功能 ID 固定为 255:
public void setKeyFunction() {
//获取RCSPController对象
RCSPController controller = RCSPController.getInstance();
List<ADVInfoResponse.KeySettings> list = new ArrayList<>(); //获取设备设置信息得到
list.get(0).setFunction(AttrAndFunCode.KEY_FUNC_ID_SWITCH_ANC_MODE); //anc
//设置按键功能切换ANC设置功能并等待结果回调
controller.configKeySettings(controller.getUsingDevice(), list, new OnRcspActionCallback<Integer>() {
@Override
public void onSuccess(BluetoothDevice device, Integer message) {
//成功回调
}
@Override
public void onError(BluetoothDevice device, BaseError error) {
//失败回调
//error - 错误信息
}
});
}
Source: ANCDemo.java
官方文档特别强调:切换噪声处理模式的按键功能 ID 固定是 255(KEY_FUNC_ID_SWITCH_ANC_MODE),该常量定义在 AttrAndFunCode 中,底层方式则以 ADV_TYPE_KEY_SETTINGS 为功能码、逐项调用 KeySettings.toData() 序列化后下发(见 anc_ctrl.rst.txt)。
自适应 ANC 算法
自适应 ANC 是 ANC 的高级形态:设备内置算法在用户佩戴耳机后自动检测耳道密封度、漏音等情况,动态校准降噪参数。App 侧需完成四件事:能力检测、读取参数、设置参数、启动检测流程。
能力检测
public boolean isSupportAdaptiveANC() {
//获取RCSPController对象
RCSPController controller = RCSPController.getInstance();
//获取当前操作设备
BluetoothDevice usingDevice = controller.getUsingDevice();
if (null == usingDevice) return false;
//判断设备是否支持自适应ANC算法
return controller.isSupportAdaptiveANC(usingDevice);
}
Source: ANCDemo.java
所有高级功能(自适应 ANC、智能免摘、场景降噪、风噪监测等)都遵循"先查支持、再操作"的防御性设计——SDK 内 isSupportXxx 系列方法基于设备固件能力掩码判断,避免向不支持功能的设备发送无效命令。
读取自适应 ANC 数据
public void getAdaptiveANCData() {
if (!isSupportAdaptiveANC()) return;
//获取RCSPController对象
final RCSPController controller = RCSPController.getInstance();
//获取当前操作设备
BluetoothDevice usingDevice = controller.getUsingDevice();
if (null == usingDevice) return;
DeviceInfo deviceInfo = controller.getDeviceInfo(usingDevice);
if (null == deviceInfo) return; //设备未初始化
boolean isForceRead = true; //是否强制读取
//获取缓存的自适应ANC状态信息
AdaptiveData adaptiveData = deviceInfo.getAdaptiveData();
if (!isForceRead && null != adaptiveData) return; //已有缓存信息
final BTRcspEventCallback eventCallback = new BTRcspEventCallback() {
@Override
public void onVoiceFunctionChange(BluetoothDevice device, VoiceFunc voiceFunc) {
if (null == device || null == voiceFunc) return;
if (voiceFunc instanceof AdaptiveData) {
//回调自适应ANC数据
controller.removeBTRcspEventCallback(this);
}
}
};
//注册RCSP事件监听器
controller.addBTRcspEventCallback(eventCallback);
//执行获取自适应ANC数据的接口
controller.getAdaptiveANCData(usingDevice, new OnRcspActionCallback<Boolean>() {
@Override
public void onSuccess(BluetoothDevice device, Boolean message) {
//回调操作成功
//结果将在 BTRcspEventCallback#onVoiceFunctionChange 回调
}
@Override
public void onError(BluetoothDevice device, BaseError error) {
//回调操作失败
controller.removeBTRcspEventCallback(eventCallback);
}
});
}
Source: ANCDemo.java
这段代码是整个 VoiceFunc 家族的"标准模板",被智能免摘、场景降噪等所有功能复用,包含四个关键设计:
- 缓存优先:
deviceInfo.getAdaptiveData()读取本地缓存,isForceRead为 false 且缓存存在时直接返回,减少蓝牙通信; - 实例类型匹配:所有语音功能共用
onVoiceFunctionChange回调,通过instanceof AdaptiveData区分数据归属; - 事件自清理:收到目标数据后立即
removeBTRcspEventCallback(this),避免监听器泄漏; - 失败对称清理:
onError中也移除监听器,保证任何路径都不会残留回调。
AdaptiveData 的数据结构(继承自 VoiceFunc):
public class AdaptiveData extends VoiceFunc {
/**
* 不检测状态
*/
public static final int STATE_NO_CHECK = 0;
/**
* 开始检测
*/
public static final int STATE_START_CHECK = 1;
private boolean isOn; //开关
private int state; //状态
private int code; //结果码
}
Source: anc_ctrl.rst.txt
STATE_NO_CHECK=0 表示设备未处于检测状态,STATE_START_CHECK=1 表示检测进行中;code 为检测结果码,由 OnAdaptiveANCListener.onFinish(int code) 带出。
设置参数与启动检测
public void setAdaptiveANCData() {
if (!isSupportAdaptiveANC()) return;
...
//获取缓存的自适应ANC状态信息
AdaptiveData adaptiveData = deviceInfo.getAdaptiveData();
if (null == adaptiveData) { //可以通过 RCSPController#getAdaptiveANCData 接口获取
adaptiveData = new AdaptiveData();
}
//置反开关状态
adaptiveData.setOn(!adaptiveData.isOn());
//执行设置自适应ANC参数的接口
controller.setAdaptiveANCData(usingDevice, adaptiveData, new OnRcspActionCallback<Boolean>() {
@Override
public void onSuccess(BluetoothDevice device, Boolean message) {
//回调操作结果
}
...
});
}
Source: ANCDemo.java
public void startAdaptiveANCCheck() {
if (!isSupportAdaptiveANC()) return;
...
//执行开始自适应ANC算法检测流程的接口
controller.startAdaptiveANC(usingDevice, new OnAdaptiveANCListener() {
@Override
public void onStart() {
//回调检测流程开始
}
@Override
public void onFinish(int code) {
//回调检测流程结束
//code --- 结果码
}
});
}
Source: ANCDemo.java
自适应 ANC 检测流程
flowchart TD
Start([用户点击"开始检测"]) --> Check{"isSupportAdaptiveANC?"}
Check -->|"否"| Exit["直接返回,不发起命令"]
Check -->|"是"| StartCmd["controller.startAdaptiveANC<br/>(OnAdaptiveANCListener)"]
StartCmd --> OnStart["onStart()<br/>UI 提示佩戴耳机/保持安静"]
OnStart --> Detect["设备端算法检测<br/>(佩戴状态/漏音/密封度)"]
Detect --> OnFinish["onFinish(code)<br/>code = 结果码"]
OnFinish --> Decide{"code 判定"}
Decide -->|"成功"| Apply["写入 AdaptiveData<br/>缓存到 DeviceInfo"]
Decide -->|"失败/取消"| Reset["重置为 STATE_NO_CHECK"]
Apply --> Done([结束])
Reset --> Done
自适应检测是异步长流程:startAdaptiveANC 只负责触发,设备端算法运行需要数秒;期间 UI 应通过 onStart 进入"检测中"状态(对应 AdaptiveData.STATE_START_CHECK),最终由 onFinish(code) 决定结果。App 不应阻塞主线程等待。
智能语音功能族
ANC 之外,同一协议家族还包含四个人声/噪声相关功能。它们共享 VoiceFunc 基类与完全一致的"查支持 → 读缓存/强制读 → 事件回调 → 修改参数 → 写回"模式,这里以场景降噪为例展示,其余功能结构相同。
场景降噪(SceneDenoising)
public void setSceneDenoising() {
if(!isSupportSceneDenoising()) return;
...
//获取缓存的场景降噪信息
SceneDenoising sceneDenoising = deviceInfo.getSceneDenoising();
if (null == sceneDenoising) { //可以通过 RCSPController#getSceneDenoising 接口获取
sceneDenoising = new SceneDenoising();
}
//设置智能模式
sceneDenoising.setMode(SceneDenoising.MODE_SMART);
...
//执行设置场景降噪参数的接口
controller.setSceneDenoising(usingDevice, sceneDenoising, new OnRcspActionCallback<Boolean>() {
@Override
public void onSuccess(BluetoothDevice device, Boolean message) {
//回调操作成功
//结果将在 BTRcspEventCallback#onVoiceFunctionChange 回调
}
...
});
}
Source: ANCDemo.java
场景降噪支持多种模式(如智能模式 MODE_SMART),通过 setMode 选择算法策略;其读取流程(getSceneDenoising + instanceof SceneDenoising 回调)与自适应 ANC 完全相同(见 ANCDemo.java)。
智能免摘(SmartNoPick)
智能免摘用于通话场景:检测到用户开口说话时自动取消静音/降噪,停止说话后恢复。对应方法:
controller.isSupportSmartNoPick(device)— 能力检测(ANCDemo.java L276-L283)controller.getSmartNoPick(device, callback)— 读取,回调中instanceof SmartNoPick判断(L286-L324)controller.setSmartNoPickParam(device, smartNoPick, callback)— 设置,setOn(!isOn())切换开关(L327-L370)
风噪监测(WindNoiseDetection)
风噪监测用于骑行/户外场景,自动识别风声并调整麦克风拾音策略。对应方法:
controller.isSupportWindNoiseDetection(device)— 能力检测(ANCDemo.java L469-L476)controller.getWindNoiseDetection(device, callback)— 读取(L478 起)
人声增强(VocalBooster)
ANCDemo 顶部导入声明中包含了 com.jieli.bluetooth.bean.device.voice.VocalBooster(见 ANCDemo.java L11),说明 SDK 中同样提供人声增强功能,属于 VoiceFunc 子类。其具体方法签名在本次调研范围内未完整读取,调用模式与其他 VoiceFunc 一致;如需精确签名,请查阅 SDK 源码中 RCSPController 的 isSupportVocalBooster/getVocalBooster/setVocalBooster 系列接口。
Core Flow:一次完整的 ANC 模式查询
下图以"查询所有噪声处理模式"为例,展示 RCSPController 高层封装的完整时序:
sequenceDiagram
participant App as App / ANCDemo
participant RCSP as RCSPController
participant Cache as DeviceInfo
participant BT as 蓝牙 RCSP 通道
participant Dev as 耳机设备
App->>RCSP: addBTRcspEventCallback(callback)
App->>RCSP: getAllVoiceModes(device, actionCallback)
RCSP->>BT: 构造并下发 SYS_INFO 查询命令<br/>(SYS_INFO_ATTR_ALL_NOISE_MODE 掩码)
BT->>Dev: 协议请求
Dev-->>BT: 协议回复(模式列表原始字节)
BT-->>RCSP: 解析回复
RCSP->>Cache: 写入 DeviceInfo(模式缓存)
RCSP->>RCSP: 触发 onSuccess(device, true)
RCSP->>App: BTRcspEventCallback.onVoiceModeList(device, modes)
App->>App: 渲染 ANC 设置 UI(模式选项列表)
时序说明:
- 注册监听器必须先于发起请求——
onVoiceModeList是异步回调,若未提前注册会丢失数据; OnRcspActionCallback.onSuccess只表示"命令送达且协议层成功",真正的业务数据在BTRcspEventCallback的专用回调中;- 结果写入
DeviceInfo缓存,后续getAllVoiceModes可配合isForceRead=false直接读缓存; - 设置类操作(
setCurrentVoiceMode)的时序相同,只是方向相反,且成功后通常触发onVoiceModeList/onCurrentVoiceMode推送设备最新状态。
API Reference
以下为 ANCDemo 与官方文档中出现的 RCSPController 公开接口汇总(参数与回调均已按源码验证)。
模式管理
| 方法 | 说明 | 结果回调 |
|---|---|---|
getAllVoiceModes(device, OnRcspActionCallback<Boolean>) | 获取全部噪声处理模式 | BTRcspEventCallback.onVoiceModeList(device, List<VoiceMode>) |
getCurrentVoiceMode(device, OnRcspActionCallback<Boolean>) | 获取当前模式 | onCurrentVoiceMode(device, VoiceMode) |
setCurrentVoiceMode(device, VoiceMode, OnRcspActionCallback<Boolean>) | 设置当前模式 | onSuccess/onError |
modifyDeviceSettingsInfo(device, ADV_TYPE_ANC_MODE_LIST, byte[], OnRcspActionCallback<Integer>) | 设置模式切换顺序(位掩码) | onSuccess/onError |
getDeviceSettingsInfo(device, mask, OnRcspActionCallback<ADVInfoResponse>) | 回读设备设置(含模式顺序) | ADVInfoResponse.getModes() |
configKeySettings(device, List<KeySettings>, OnRcspActionCallback<Integer>) | 配置按键功能(ANC 切换 ID=255) | onSuccess/onError |
自适应 ANC
| 方法 | 说明 |
|---|---|
isSupportAdaptiveANC(device): boolean | 是否支持自适应 ANC |
getAdaptiveANCData(device, OnRcspActionCallback<Boolean>) | 读取数据,结果经 onVoiceFunctionChange 回调 AdaptiveData |
setAdaptiveANCData(device, AdaptiveData, OnRcspActionCallback<Boolean>) | 设置参数(开关 isOn 等) |
startAdaptiveANC(device, OnAdaptiveANCListener) | 启动检测流程 |
OnAdaptiveANCListener:
onStart():检测流程开始,UI 应提示用户(佩戴耳机、保持安静);onFinish(int code):检测结束,code为结果码(成功/失败/取消由固件定义)。
智能语音功能族
| 方法 | 说明 |
|---|---|
isSupportSmartNoPick(device): boolean | 智能免摘能力检测 |
getSmartNoPick(device, callback) / setSmartNoPickParam(device, SmartNoPick, callback) | 读取/设置智能免摘(setOn 切换开关) |
isSupportSceneDenoising(device): boolean | 场景降噪能力检测 |
getSceneDenoising(device, callback) / setSceneDenoising(device, SceneDenoising, callback) | 读取/设置场景降噪(setMode(SceneDenoising.MODE_SMART) 等) |
isSupportWindNoiseDetection(device): boolean | 风噪监测能力检测 |
getWindNoiseDetection(device, callback) | 读取风噪监测数据 |
所有读取类接口的业务数据回调统一走 BTRcspEventCallback.onVoiceFunctionChange(device, VoiceFunc),通过 instanceof 分派到对应模型类;OnRcspActionCallback.onSuccess 仅代表命令执行成功。
常量与功能码(AttrAndFunCode)
| 常量 | 值 | 用途 |
|---|---|---|
SYS_INFO_FUNCTION_PUBLIC | — | 公共属性函数,用于查询噪声模式 |
SYS_INFO_ATTR_ALL_NOISE_MODE | — | 掩码:所有噪声处理信息 |
SYS_INFO_ATTR_CURRENT_NOISE_MODE | — | 掩码:当前噪声处理模式 |
ADV_TYPE_ANC_MODE_LIST | — | 设备设置功能码:ANC 模式切换顺序 |
ADV_TYPE_KEY_SETTINGS | — | 设备设置功能码:按键设置 |
KEY_FUNC_ID_SWITCH_ANC_MODE | 255 | 按键功能 ID:切换 ANC 模式(固定值) |
VoiceMode / AdaptiveData 字段
| 模型 | 字段 | 说明 |
|---|---|---|
VoiceMode | mode | 模式:VOICE_MODE_CLOSE=0 / VOICE_MODE_DENOISE=1 / VOICE_MODE_TRANSPARENT=2 |
VoiceMode | leftMax/leftCurVal/rightMax/rightCurVal | 左右声道增益最大值/当前值 |
AdaptiveData | isOn | 自适应 ANC 开关 |
AdaptiveData | state | STATE_NO_CHECK=0(未检测)/ STATE_START_CHECK=1(检测中) |
AdaptiveData | code | 检测结果码 |
失败模式、边界情况与并发
设备未连接 / 未初始化
所有示例代码都以"判空短路"开头:controller.getUsingDevice() 返回 null 直接 return、controller.getDeviceInfo(usingDevice) 返回 null 视为"设备未初始化"直接退出(如 ANCDemo.java L174-L175)。这是因为 RCSP 命令必须绑定具体蓝牙设备,未连接时任何请求都必然失败,提前短路可避免无谓的蓝牙通信。
命令失败与监听器泄漏
OnRcspActionCallback.onError(device, BaseError error) 携带 BaseError 错误对象。读取类接口在 onError 中必须执行 removeBTRcspEventCallback(eventCallback)(如 L217),否则该匿名回调会一直留在控制器中:既可能被后续无关的 onVoiceFunctionChange 误触发,也构成内存泄漏。成功路径与失败路径都要清理是这套 API 的铁律。
缓存与强制读取
DeviceInfo 缓存了每种 VoiceFunc 的最新值。isForceRead=false 且缓存命中时跳过蓝牙查询;isForceRead=true 时即使有缓存也强制下发命令。设计意图是:日常刷新用缓存省流量、降延迟;用户主动进入设置页或怀疑状态过期时强制读取以保证一致。注意缓存命中仅发生在"查询"阶段,设备主动推送(如耳机端按键切换模式)仍会实时回调 onVoiceModeList/onVoiceFunctionChange 更新缓存。
模式切换顺序的约束
- 最少 2 个模式:
modes.length < 2直接 return——循环切换至少需要两档,否则无意义(L112); - 位掩码容量:
value是 32 位 int,每个模式占 1 bit,因此最多表达 32 个模式位;实际设备模式数远小于此,但实现上模式号必须< 32; - 回读校验:写入后通过
getDeviceSettingsInfo回读,getModes()校验固件是否接受——固件可能拒绝非法组合(如设备不支持的某一模式),App 应以回读结果为准刷新 UI。
回调时序与并发
onSuccess与业务回调(onVoiceModeList/onVoiceFunctionChange)是两个独立回调,且业务回调可能在onSuccess之前触发(设备推送场景);UI 逻辑不应假设二者先后顺序;- 多个功能(自适应 ANC、智能免摘、场景降噪)共用
onVoiceFunctionChange,必须用instanceof精确匹配后处理,且收到目标实例后立刻removeBTRcspEventCallback,避免多个并发请求互相干扰; - 同一设备上并发发起多个读取时,每个请求注册独立的匿名回调实例,互不覆盖。
性能与运维注意事项
- 减少蓝牙往返:优先使用
DeviceInfo缓存(isForceRead=false),仅在进入设置页或收到可疑状态时强制读取; - 一次性监听器模式:每个请求都注册"用完即弃"的事件回调(成功/失败均移除),既防泄漏也避免回调风暴;
- 命令体积:模式切换顺序以位掩码编码(
CHexConver.intToBigBytes)而非逐个模式发送,一次命令完成全部配置,显著降低低功耗蓝牙链路上的传输量; - UI 线程安全:所有回调均在 SDK 内部线程派发,更新 UI 需自行切回主线程(demo 中省略,生产代码应使用 Handler/runOnUiThread)。
扩展点
- 新增 VoiceFunc 子类:语音功能族以
VoiceFunc为基类,新增功能(如新的降噪策略)只需继承并实现序列化,复用onVoiceFunctionChange分派机制; - BTRcspEventCallback 继承:App 可继承该类只覆写关心的回调(如仅
onVoiceModeList),其余保持空实现,降低耦合; - OnAdaptiveANCListener 适配:检测流程的
onStart/onFinish可包装为业务层状态机(如"检测中/成功/失败"),对接不同 UI 表现; - 底层命令通路:
CommandBuilder+AttrAndFunCode提供协议级入口,适合对 RCSP 命令做深度定制(自定义掩码组合、批量属性读写)。
测试覆盖
仓库中的 ANCDemo(btsmart/src/test/java/com/jieli/btsmart/demo/ 目录)本质上是针对该功能族的集成测试/示例集合,覆盖:
- 全部模式查询与设置的正向流程(
getAllVoiceModes/getCurrentVoiceMode/setCurrentVoiceMode); - 模式切换顺序位掩码构造与回读校验(
changeVoiceModeList); - 按键绑定(
setKeyFunction); - 自适应 ANC 四接口(能力检测、读取、设置、启动检测)及
OnAdaptiveANCListener回调; - 智能免摘、场景降噪、风噪监测的"查支持→读→改→写"闭环。
这些示例同时充当 API 用法契约:任何接口签名变更都会在 demo 编译期暴露,是 SDK 版本升级时的回归基线。
Related Links
- ANCDemo.java(ANC 功能完整示例)
- anc_ctrl.rst.txt(官方 ANC 设置功能文档,中文)
- anc_ctrl.html(官方 ANC 设置功能文档,渲染版)
- ANC_setting_flow.png(ANC 设置流程图)
- adaptive_anc_flow.png(自适应 ANC 流程图)
- view_anc_func.xml(ANC 功能 UI 布局)
相关主题:EQ 均衡器调节参见 EqAdvancedSetFragment 对应页面;设备通用属性读写机制参见设备信息相关页面。