杰理 SDK 文档中心
首页
首页
  • 快速开始

    • 环境要求与权限配置
    • 集成SDK依赖
    • 运行示例应用
  • 核心架构与协议

    • RCSP协议与数据通道
    • 蓝牙连接与设备管理
    • TWS双耳功能
    • 基础功能接口与自定义命令
  • 设备功能控制

    • 设备音乐控制与ID3信息
    • 文件浏览与传输
    • FM收音与发射
    • 灯光控制
    • 闹钟与时间管理
    • 查找设备与防丢
    • ANC与噪声处理
    • 按键功能设置
    • 彩屏仓控制
    • AI翻译
  • 音效与音频处理

    • 均衡器音效调节
    • 录音与语音控制
    • Line-in、SPDIF与声卡功能
    • 音频编解码库
  • 扩展功能库

    • OTA固件升级
    • 数据加密与解密
    • 图片与动图格式转换
  • 示例应用 btsmart

    • 应用架构与界面导航
    • 设备功能适配与数据层
    • 设备配置JSON与资源文件
  • 参考与版本

    • 错误码参考
    • 版本历史与更新日志
    • 开发文档中心导航

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 家族的"标准模板",被智能免摘、场景降噪等所有功能复用,包含四个关键设计:

  1. 缓存优先:deviceInfo.getAdaptiveData() 读取本地缓存,isForceRead 为 false 且缓存存在时直接返回,减少蓝牙通信;
  2. 实例类型匹配:所有语音功能共用 onVoiceFunctionChange 回调,通过 instanceof AdaptiveData 区分数据归属;
  3. 事件自清理:收到目标数据后立即 removeBTRcspEventCallback(this),避免监听器泄漏;
  4. 失败对称清理: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(模式选项列表)

时序说明:

  1. 注册监听器必须先于发起请求——onVoiceModeList 是异步回调,若未提前注册会丢失数据;
  2. OnRcspActionCallback.onSuccess 只表示"命令送达且协议层成功",真正的业务数据在 BTRcspEventCallback 的专用回调中;
  3. 结果写入 DeviceInfo 缓存,后续 getAllVoiceModes 可配合 isForceRead=false 直接读缓存;
  4. 设置类操作(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_MODE255按键功能 ID:切换 ANC 模式(固定值)

VoiceMode / AdaptiveData 字段

模型字段说明
VoiceModemode模式:VOICE_MODE_CLOSE=0 / VOICE_MODE_DENOISE=1 / VOICE_MODE_TRANSPARENT=2
VoiceModeleftMax/leftCurVal/rightMax/rightCurVal左右声道增益最大值/当前值
AdaptiveDataisOn自适应 ANC 开关
AdaptiveDatastateSTATE_NO_CHECK=0(未检测)/ STATE_START_CHECK=1(检测中)
AdaptiveDatacode检测结果码

失败模式、边界情况与并发

设备未连接 / 未初始化

所有示例代码都以"判空短路"开头: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 对应页面;设备通用属性读写机制参见设备信息相关页面。

Prev
查找设备与防丢
Next
按键功能设置