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

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

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

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

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

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

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

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

Line-in、SPDIF与声卡功能

本文档介绍杰理(Jieli)Android 蓝牙 SDK 中 Line-in(AUX 外接音源)、SPDIF(数字音频输入) 与 声卡(Sound Card) 三大音频外设功能的实现机制、控制流程与 API 用法。这些功能均通过 RCSPController 与设备建立 RCSP(Remote Control Serial Protocol)通信,并由 BTRcspEventCallback 事件回调驱动 UI 更新,是设备端音频输入通道在 App 侧的完整控制入口。

Purpose and Scope

本页面覆盖以下能力的完整实现链路:

  • Line-in / AUX 模式:检测设备是否支持 AUX、当前是否处于 AUX 模式、获取外接设备播放状态、播放/暂停控制;
  • SPDIF 数字音频输入:查询 SPDIF 信息、播放/暂停、切换音源(HDMI / 光纤 / 同轴),由 SPDIFControlViewModel 封装为 LiveData 数据流;
  • 声卡功能:声卡状态查询、声卡 EQ 获取与设置、声卡功能参数下发,以及 JLChipFlag.JL_CHIP_FLAG_695X_SOUND_CARD 芯片类型判定。

不涉及的内容(请参考兄弟页面):蓝牙设备连接与 RCSP 协议底层封装(见"设备连接"相关页面)、EQ 通用效果调节(见"EQ 均衡器"页面)、以及 USB 声卡等未在本仓库实现的能力。

Overview

在杰理蓝牙音频方案中,设备端芯片可以同时具备多种音频输入通道:蓝牙 A2DP、Line-in(3.5mm 外接模拟音源,也称 AUX)、SPDIF(Sony/Philips Digital Interface,承载 HDMI/光纤/同轴数字音频信号)以及 USB 声卡模式。App 端通过 RCSPController(单例)向设备下发 RCSP 指令,设备解析指令后切换音频路由或返回状态,再通过 BTRcspEventCallback 回调把结果推送给 App。

三个功能在实现上遵循同一套**「指令-回调」模式**:

  1. App 调用 RCSPController 的 getXxx / setXxx 方法发送指令;
  2. 指令执行结果通过 OnRcspActionCallback<Boolean> 返回(仅表示指令是否送达/执行成功);
  3. 真正的数据内容通过 BTRcspEventCallback 的 onXxxChange 系列回调异步到达;
  4. UI 层(ViewModel / Activity)把回调数据封装为 LiveData 或直接刷新界面。

SPDIFControlViewModel 是仓库内唯一完整的 ViewModel 层实现,展示了这套模式在生产代码中的标准写法;LineinDemo 与 SoundCardDemo 是官方提供的测试用例(demo),可作为接入参考。

Architecture

flowchart TD
    subgraph sg_App["App 层 (btsmart)"]
        SPDIFVM["SPDIFControlViewModel"]
        UI["Activity / Fragment"]
        LDM["LineinDemo (test)"]
        SCD["SoundCardDemo (test)"]
        UH["UIHelper.isSoundCardType()"]
    end

    subgraph sg_SDK["SDK 层 (com.jieli.bluetooth)"]
        RCSP["RCSPController (单例)"]
        CB["BTRcspEventCallback"]
        ACB["OnRcspActionCallback"]
        DI["DeviceInfo"]
        SPI["SPDIFPlayStatusInfo / SPDIFAudioSourceInfo"]
        SC["SoundCard 状态/EQ 数据"]
    end

    subgraph sg_Dev["设备端"]
        DEV["蓝牙音频设备 (695X 等)"]
    end

    SPDIFVM -->|"注册/注销事件"| CB
    SPDIFVM -->|"getSPDIFInfo / setSPDIFPlayStatusInfo / setSPDIFSPDIFAudioSourceInfo"| RCSP
    LDM -->|"isAuxEnable / getAuxStatusInfo / auxPlayOrPause"| RCSP
    SCD -->|"getSoundCardStatusInfo / getSoundCardEqInfo / setSoundCardEqInfo / setSoundCardFunction"| RCSP
    UH -->|"JLChipFlag.JL_CHIP_FLAG_695X_SOUND_CARD 判定"| RCSP
    RCSP -->|"RCSP 指令下发 (BLE/经典蓝牙)"| DEV
    DEV -->|"状态上报"| RCSP
    RCSP -->|"解析到 DeviceInfo 缓存"| DI
    DI --> SPI
    DI --> SC
    RCSP -->|"事件分发"| CB
    CB -->|"onSPDIFPlayStatusChange / onSPDIFAudioSourceInfoChange"| SPDIFVM
    CB -->|"onAuxStatusChange / onSoundCardStatusChange / onSoundCardEqChange"| LDM
    CB -->|"onSoundCardStatusChange / onSoundCardEqChange"| SCD
    SPDIFVM -->|"MutableLiveData 推送"| UI
    ACB -->|"onSuccess / onError"| LDM
    ACB -->|"onSuccess / onError"| SCD

架构解读: 上层 App 组件(ViewModel、Demo 用例、工具类)只依赖 RCSPController 单例与 BTRcspEventCallback 抽象,不直接接触蓝牙协议细节。RCSPController 负责指令序列化、发送、响应解析,并把设备状态缓存进 DeviceInfo;DeviceInfo 持有 SPDIFPlayStatusInfo、SPDIFAudioSourceInfo 等状态对象,供 ViewModel 初始化时同步读取。这种「单例控制器 + 事件回调 + 状态缓存」的设计把协议复杂度隔离在 SDK 内部,使 App 层代码保持简洁且可测试。

Main Content

1. Line-in(AUX)外接音源功能

Line-in 功能在仓库中体现为 AUX(Auxiliary)模式,设备通过 3.5mm 接口接收外部模拟音频,App 侧负责查询支持能力、查询播放状态并控制播放/暂停。参考实现位于 LineinDemo.java。

1.1 能力与模式判定

public boolean isSupportAuxMode() {
    //获取RCSPController对象
    RCSPController controller = RCSPController.getInstance();
    //获取当前操作设备
    BluetoothDevice usingDevice = controller.getUsingDevice();
    if (null == usingDevice) return false;
    DeviceInfo deviceInfo = controller.getDeviceInfo(usingDevice);
    if (null == deviceInfo) return false; //设备未初始化
    return deviceInfo.isAuxEnable();
}

public boolean isDeviceInAuxMode() {
    //获取RCSPController对象
    RCSPController controller = RCSPController.getInstance();
    //获取当前操作设备
    BluetoothDevice usingDevice = controller.getUsingDevice();
    if (null == usingDevice) return false;
    DeviceInfo deviceInfo = controller.getDeviceInfo(usingDevice);
    if (null == deviceInfo) return false; //设备未初始化
    return deviceInfo.getCurFunction() == AttrAndFunCode.SYS_INFO_FUNCTION_AUX;
}

Source: LineinDemo.java

设计意图:isAuxEnable() 读取的是设备能力位(设备固件是否编译了 AUX 功能),而 getCurFunction() 与 AttrAndFunCode.SYS_INFO_FUNCTION_AUX 比较得到的是设备当前运行的功能模式。两者含义不同——前者是"硬件/固件支持",后者是"当前是否处于该模式",UI 层通常先用前者决定是否展示入口,再用后者决定入口的选中状态。

1.2 播放状态查询与控制

void getAuxStatusInfo() {
    //获取RCSPController对象
    RCSPController controller = RCSPController.getInstance();
    //添加蓝牙RCSP事件监听器
    controller.addBTRcspEventCallback(new BTRcspEventCallback() {
        @Override
        public void onAuxStatusChange(BluetoothDevice device, boolean isPlay) {
            //此处回调外接设备播放状态
        }
    });
    //执行获取外接设备播放状态功能并等待结果回调
    controller.getAuxStatusInfo(controller.getUsingDevice(), new OnRcspActionCallback<Boolean>() {
        @Override
        public void onSuccess(BluetoothDevice device, Boolean message) {
            //成功回调
            //结果将会在BTRcspEventCallback#onAuxStatusChange回调
        }

        @Override
        public void onError(BluetoothDevice device, BaseError error) {
            //失败回调
            //error - 错误信息
        }
    });
}

void auxPlayOrPause() {
    //获取RCSPController对象
    RCSPController controller = RCSPController.getInstance();
    //执行外接设备播放或暂停功能并等待结果回调
    controller.auxPlayOrPause(controller.getUsingDevice(), new OnRcspActionCallback<Boolean>() {
        @Override
        public void onSuccess(BluetoothDevice device, Boolean message) {
            //成功回调
        }

        @Override
        public void onError(BluetoothDevice device, BaseError error) {
            //失败回调
            //error - 错误信息
        }
    });
}

Source: LineinDemo.java

设计意图:getAuxStatusInfo 的 OnRcspActionCallback<Boolean> 只确认"指令执行成功与否",真正的播放状态 isPlay 通过 onAuxStatusChange 事件回调返回。这种查询指令与状态事件分离的设计允许设备在播放状态自发变化(如拔出 AUX 线)时也能主动通知 App,而不仅是应答查询。

2. SPDIF 数字音频输入功能

SPDIF 功能是仓库中实现最完整的一块,由 SPDIFControlViewModel.java 承担。它继承自 BtBasicVM,通过 AndroidX MutableLiveData 向界面暴露两类状态:SPDIFPlayStatusInfo(播放状态)与 SPDIFAudioSourceInfo(音频源类型)。

2.1 ViewModel 初始化与状态同步

public SPDIFControlViewModel() {
    mRCSPController.addBTRcspEventCallback(callback);
    DeviceInfo deviceInfo = mRCSPController.getDeviceInfo();
    SPDIFPlayStatusInfo spdifPlayStatusInfo = deviceInfo.getSPDIFPlayStatusInfo();
    if (spdifPlayStatusInfo != null) {
        mSPDIFPlayStatusInfo = spdifPlayStatusInfo;
        spdifPlayStatusInfoLiveData.postValue(spdifPlayStatusInfo);
    }
    SPDIFAudioSourceInfo spdifAudioSourceInfo = deviceInfo.getSPDIFAudioSourceInfo();
    if (spdifAudioSourceInfo != null) {
        mSPDIFAudioSourceInfo = spdifAudioSourceInfo;
        spdifAudioSourceInfoLiveData.postValue(spdifAudioSourceInfo);
    }
}

@Override
protected void release() {
    mRCSPController.removeBTRcspEventCallback(callback);
    super.release();
}

Source: SPDIFControlViewModel.java

设计意图:构造时先注册事件回调、再从 DeviceInfo 缓存中同步读取最新状态并立即 postValue,保证 ViewModel 重建(如旋转屏幕)后界面能立刻显示设备当前真实状态,无需等待网络往返;release() 中对称地移除回调,避免内存泄漏。

2.2 播放控制与音源切换

/**
 * 播放暂停
 */
public void playOrPause() {
    SPDIFPlayStatusInfo spdifPlayStatusInfo = new SPDIFPlayStatusInfo();
    spdifPlayStatusInfo.setPlayStatus(mSPDIFPlayStatusInfo.getPlayStatus() == SPDIFPlayStatusInfo.PLAY_STATUS_PAUSE ? SPDIFPlayStatusInfo.PLAY_STATUS_PLAY : SPDIFPlayStatusInfo.PLAY_STATUS_PAUSE);
    mRCSPController.setSPDIFPlayStatusInfo(getConnectedDevice(), spdifPlayStatusInfo, null);
}
public void getSPDIFInfo() {
    mRCSPController.getSPDIFInfo(mRCSPController.getUsingDevice(), null);
}
public void setAudioSourceHDMI() {
    SPDIFAudioSourceInfo spdifAudioSourceInfo = new SPDIFAudioSourceInfo();
    spdifAudioSourceInfo.setAudioSource(SPDIFAudioSourceInfo.AUDIO_SOURCE_HDMI);
    mRCSPController.setSPDIFSPDIFAudioSourceInfo(getConnectedDevice(), spdifAudioSourceInfo, null);
}

public void setAudioSourceOptical() {
    SPDIFAudioSourceInfo spdifAudioSourceInfo = new SPDIFAudioSourceInfo();
    spdifAudioSourceInfo.setAudioSource(SPDIFAudioSourceInfo.AUDIO_SOURCE_OPTICAL);
    mRCSPController.setSPDIFSPDIFAudioSourceInfo(getConnectedDevice(), spdifAudioSourceInfo, null);
}

public void setAudioSourceCoaxial() {
    SPDIFAudioSourceInfo spdifAudioSourceInfo = new SPDIFAudioSourceInfo();
    spdifAudioSourceInfo.setAudioSource(SPDIFAudioSourceInfo.AUDIO_SOURCE_COAXIAL);
    mRCSPController.setSPDIFSPDIFAudioSourceInfo(getConnectedDevice(), spdifAudioSourceInfo, null);
}

Source: SPDIFControlViewModel.java

设计意图:playOrPause() 基于本地缓存的 mSPDIFPlayStatusInfo 计算目标状态(取反),再通过 setSPDIFPlayStatusInfo 下发——这种"读缓存-取反-写设备"的模式避免了先查询再下发的额外往返。音源切换(HDMI/光纤/同轴)通过复用同一个 setSPDIFSPDIFAudioSourceInfo 方法、仅改变 SPDIFAudioSourceInfo.AUDIO_SOURCE_* 常量实现,体现了参数化指令的设计:同一指令通道承载不同取值。

2.3 事件回调与设备切换

private final BTRcspEventCallback callback = new BTRcspEventCallback() {
    @Override
    public void onSPDIFPlayStatusChange(BluetoothDevice device, SPDIFPlayStatusInfo spdifPlayStatusInfo) {
        mSPDIFPlayStatusInfo = spdifPlayStatusInfo;
        spdifPlayStatusInfoLiveData.postValue(spdifPlayStatusInfo);
    }

    @Override
    public void onSPDIFAudioSourceInfoChange(BluetoothDevice device, SPDIFAudioSourceInfo spdifAudioSourceInfo) {
        mSPDIFAudioSourceInfo = spdifAudioSourceInfo;
        spdifAudioSourceInfoLiveData.postValue(spdifAudioSourceInfo);
    }
    @Override
    public void onSwitchConnectedDevice(BluetoothDevice device) {
        super.onSwitchConnectedDevice(device);
        getSPDIFInfo();
    }
};

Source: SPDIFControlViewModel.java

设计意图:两个状态回调都先更新本地缓存、再 postValue 到 LiveData,保证 UI 与缓存始终一致。关键点在于重写 onSwitchConnectedDevice:当用户切换连接的设备时,主动调用 getSPDIFInfo() 重新拉取新设备的 SPDIF 状态——这是因为不同设备的状态不共享,必须在新设备上重新初始化,否则界面会显示上一台设备的过期数据。

3. 声卡(Sound Card)功能

声卡功能将蓝牙设备模拟为外部 USB/数字声卡,App 侧负责查询声卡状态、读取/设置 EQ、下发声卡功能参数。参考实现位于 SoundCardDemo.java。

3.1 声卡状态查询

@Test
void getSoundCardStatusInfo() {
    //获取RCSPController对象
    RCSPController controller = RCSPController.getInstance();
    //注册蓝牙RCSP事件监听器
    controller.addBTRcspEventCallback(new BTRcspEventCallback() {
        @Override
        public void onSoundCardStatusChange(BluetoothDevice device, long mask, byte[] values) {
            //此处将会回调声卡状态
        }
    });
    //执行获取声卡状态信息功能并等待结果回调
    controller.getSoundCardStatusInfo(controller.getUsingDevice(), new OnRcspActionCallback<Boolean>() {
        @Override
        public void onSuccess(BluetoothDevice device, Boolean message) {
            //成功回调
            //结果将会在BTRcspEventCallback#onSoundCardStatusChange回调
        }

        @Override
        public void onError(BluetoothDevice device, BaseError error) {
            //失败回调
            //error - 错误信息
        }
    });
}

Source: SoundCardDemo.java

设计意图:声卡状态回调携带 long mask(功能位掩码,标识哪些功能参数发生变化)与 byte[] values(原始状态数据)。掩码机制让设备可以一次上报多项状态变更,App 通过 mask 判断需要刷新哪些 UI 项,避免对未变化项做无谓重绘。

3.2 声卡 EQ 与功能设置

@Test
void getSoundCardEqInfo() {
    //获取RCSPController对象
    RCSPController controller = RCSPController.getInstance();
    //注册蓝牙RCSP事件监听器
    controller.addBTRcspEventCallback(new BTRcspEventCallback() {
        @Override
        public void onSoundCardEqChange(BluetoothDevice device, EqInfo eqInfo) {
            //此处将会回调声卡效果信息
        }
    });
    //执行获取声卡效果信息功能并等待结果回调
    controller.getSoundCardEqInfo(controller.getUsingDevice(), new OnRcspActionCallback<Boolean>() {
        @Override
        public void onSuccess(BluetoothDevice device, Boolean message) {
            //成功回调
            //结果将会在BTRcspEventCallback#onSoundCardEqChange回调
        }

        @Override
        public void onError(BluetoothDevice device, BaseError error) {
            //失败回调
            //error - 错误信息
        }
    });
}

@Test
void setSoundCardEqInf(byte[] value) {
    //获取RCSPController对象
    RCSPController controller = RCSPController.getInstance();
    //执行设置声卡效果功能并等待结果回调
    controller.setSoundCardEqInfo(controller.getUsingDevice(), value, new OnRcspActionCallback<Boolean>() {
        @Override
        public void onSuccess(BluetoothDevice device, Boolean message) {
            //成功回调
        }

        @Override
        public void onError(BluetoothDevice device, BaseError error) {
            //失败回调
            //error - 错误信息
        }
    });
}

@Test
void setSoundCardFunction(byte index, int value) {
    //获取RCSPController对象
    RCSPController controller = RCSPController.getInstance();
    //设置声卡功能并等待结果回调
    controller.setSoundCardFunction(controller.getUsingDevice(), index, value, new OnRcspActionCallback<Boolean>() {
        @Override
        public void onSuccess(BluetoothDevice device, Boolean message) {
            //成功回调
        }

        @Override
        public void onError(BluetoothDevice device, BaseError error) {
            //失败回调
            //error - 错误信息
        }
    });
}

Source: SoundCardDemo.java

设计意图:声卡 EQ 的获取返回结构化对象 EqInfo(与通用 EQ 功能复用同一数据类型),而设置则接受原始 byte[] 参数——这是因为 EQ 曲线数据格式由固件定义,SDK 层透传避免重复解析。setSoundCardFunction(byte index, int value) 则是"功能索引 + 值"的通用设置通道,可用于各类开关与数值型声卡参数,保持协议的可扩展性。

3.3 声卡芯片类型判定

public static boolean isSoundCardType(int sdkType) {
    return JLChipFlag.JL_CHIP_FLAG_695X_SOUND_CARD == sdkType;
}

Source: UIHelper.java

设计意图:UIHelper.isSoundCardType 通过 SDK 上报的芯片标志 JLChipFlag.JL_CHIP_FLAG_695X_SOUND_CARD 判断当前设备是否为 695X 系列声卡芯片。这类"类型判断"通常用于决定界面是否显示声卡相关入口——非声卡芯片的设备不应展示声卡设置项,从而避免用户对不支持功能的误操作。

Core Flow

SPDIF 控制完整时序

sequenceDiagram
    participant UI as Activity (UI)
    participant VM as SPDIFControlViewModel
    participant RCSP as RCSPController
    participant CB as BTRcspEventCallback
    participant DEV as 蓝牙设备

    Note over VM: 构造:注册回调 + 读取 DeviceInfo 缓存
    VM->>RCSP: addBTRcspEventCallback(callback)
    RCSP-->>VM: 缓存状态 postValue → LiveData
    UI->>VM: observe(spdifPlayStatusInfoLiveData)
    UI->>VM: 用户点击播放/暂停 → playOrPause()
    VM->>VM: 读取本地缓存,计算目标 PlayStatus(取反)
    VM->>RCSP: setSPDIFPlayStatusInfo(device, info, null)
    RCSP->>DEV: RCSP 指令下发 (播放/暂停)
    DEV-->>RCSP: 状态上报
    RCSP-->>CB: onSPDIFPlayStatusChange(device, info)
    CB-->>VM: 更新 mSPDIFPlayStatusInfo + postValue
    VM-->>UI: LiveData 通知,界面刷新
    Note over VM: 设备切换时
    CB->>VM: onSwitchConnectedDevice(device)
    VM->>RCSP: getSPDIFInfo() 重新拉取新设备状态

Line-in / 声卡查询时序

sequenceDiagram
    participant APP as App (Demo/UI)
    participant RCSP as RCSPController
    participant CB as BTRcspEventCallback
    participant DEV as 蓝牙设备

    APP->>RCSP: getAuxStatusInfo(device, callback)
    RCSP->>DEV: 查询指令
    DEV-->>RCSP: 状态数据
    RCSP-->>CB: onAuxStatusChange(device, isPlay)
    CB-->>APP: 刷新播放状态
    APP->>RCSP: auxPlayOrPause(device, callback)
    RCSP->>DEV: 播放/暂停指令
    DEV-->>RCSP: 执行结果
    RCSP-->>APP: OnRcspActionCallback.onSuccess/onError

    APP->>RCSP: getSoundCardStatusInfo(device, callback)
    RCSP->>DEV: 声卡状态查询
    DEV-->>RCSP: mask + values
    RCSP-->>CB: onSoundCardStatusChange(device, mask, values)
    CB-->>APP: 按 mask 刷新声卡 UI

流程要点: 所有功能遵循「发送指令 → OnRcspActionCallback 确认执行 → BTRcspEventCallback 推送数据」三段式流程。OnRcspActionCallback 的 Boolean 结果只代表指令是否执行成功,业务数据一律走事件回调;SDK 内部会把设备状态缓存进 DeviceInfo,因此 ViewModel 构造时可以直接同步初始化,无需每次进入页面都发起查询。

API Reference

以下 API 均由 RCSPController 单例提供(com.jieli.bluetooth.impl.rcsp.RCSPController),OnRcspActionCallback<Boolean> 的 onSuccess/onError 表示指令执行结果,BaseError 携带错误信息。

getAuxStatusInfo(BluetoothDevice device, OnRcspActionCallback<Boolean> callback)

查询外接设备(AUX)播放状态。

  • 参数:device 目标设备;callback 指令结果回调(可为 null)
  • 返回:指令执行结果 Boolean;真实播放状态通过 BTRcspEventCallback#onAuxStatusChange(BluetoothDevice, boolean isPlay) 回调
  • 典型场景:进入 AUX 页面时刷新播放/暂停按钮状态

auxPlayOrPause(BluetoothDevice device, OnRcspActionCallback<Boolean> callback)

控制外接设备播放/暂停。

  • 参数:device 目标设备;callback 指令结果回调
  • 返回:指令执行结果;播放状态变化由 onAuxStatusChange 事件回调确认

getSPDIFInfo(BluetoothDevice device, OnRcspActionCallback<Boolean> callback)

拉取 SPDIF 完整信息(播放状态 + 音频源类型)。

  • 参数:device 目标设备;callback 指令结果回调(可为 null)
  • 返回:数据经 onSPDIFPlayStatusChange / onSPDIFAudioSourceInfoChange 事件回调送达
  • 典型场景:onSwitchConnectedDevice 后重新同步新设备状态

setSPDIFPlayStatusInfo(BluetoothDevice device, SPDIFPlayStatusInfo info, OnRcspActionCallback<Boolean> callback)

设置 SPDIF 播放状态(播放/暂停)。

  • 参数:device 目标设备;info 携带 PLAY_STATUS_PLAY 或 PLAY_STATUS_PAUSE 的 SPDIFPlayStatusInfo
  • 返回:指令执行结果;设备确认后经 onSPDIFPlayStatusChange 回调

setSPDIFSPDIFAudioSourceInfo(BluetoothDevice device, SPDIFAudioSourceInfo info, OnRcspActionCallback<Boolean> callback)

设置 SPDIF 音频源类型。

  • 参数:device;info 的 audioSource 取值为 AUDIO_SOURCE_HDMI / AUDIO_SOURCE_OPTICAL / AUDIO_SOURCE_COAXIAL 之一
  • 返回:指令执行结果;设备确认后经 onSPDIFAudioSourceInfoChange 回调

getSoundCardStatusInfo(BluetoothDevice device, OnRcspActionCallback<Boolean> callback)

查询声卡状态。

  • 参数:device;callback 指令结果回调
  • 返回:状态数据经 onSoundCardStatusChange(BluetoothDevice, long mask, byte[] values) 回调;mask 为变更位掩码,values 为原始状态字节

getSoundCardEqInfo(BluetoothDevice device, OnRcspActionCallback<Boolean> callback)

获取声卡 EQ 效果信息。

  • 参数:device;callback 指令结果回调
  • 返回:EqInfo 经 onSoundCardEqChange(BluetoothDevice, EqInfo) 回调

setSoundCardEqInfo(BluetoothDevice device, byte[] value, OnRcspActionCallback<Boolean> callback)

设置声卡 EQ 效果。

  • 参数:device;value 固件定义的 EQ 原始字节数据;callback 指令结果回调
  • 返回:指令执行结果

setSoundCardFunction(BluetoothDevice device, byte index, int value, OnRcspActionCallback<Boolean> callback)

设置声卡功能参数(通用功能索引通道)。

  • 参数:device;index 功能索引(由固件协议定义);value 功能值;callback 指令结果回调
  • 返回:指令执行结果

事件回调(BTRcspEventCallback 需重写的方法)

回调方法触发时机携带数据
onAuxStatusChange(device, isPlay)AUX 播放状态变化boolean isPlay
onSPDIFPlayStatusChange(device, info)SPDIF 播放状态变化SPDIFPlayStatusInfo
onSPDIFAudioSourceInfoChange(device, info)SPDIF 音频源变化SPDIFAudioSourceInfo
onSoundCardStatusChange(device, mask, values)声卡状态上报long mask + byte[] values
onSoundCardEqChange(device, eqInfo)声卡 EQ 变化EqInfo
onSwitchConnectedDevice(device)切换连接设备BluetoothDevice

状态常量

常量所属类含义
PLAY_STATUS_PLAY / PLAY_STATUS_PAUSESPDIFPlayStatusInfoSPDIF 播放/暂停状态
AUDIO_SOURCE_HDMISPDIFAudioSourceInfoHDMI 数字音源
AUDIO_SOURCE_OPTICALSPDIFAudioSourceInfo光纤数字音源
AUDIO_SOURCE_COAXIALSPDIFAudioSourceInfo同轴数字音源
SYS_INFO_FUNCTION_AUXAttrAndFunCode设备当前处于 AUX 功能模式
JL_CHIP_FLAG_695X_SOUND_CARDJLChipFlag695X 声卡芯片类型标志

Configuration Options

本功能组不涉及独立的配置文件,其"配置"主要体现在设备能力位与芯片标志上:

配置/标志类型来源说明
DeviceInfo.isAuxEnable()boolean设备能力位设备固件是否支持 AUX 模式,false 时不应展示 AUX 入口
DeviceInfo.getCurFunction()int设备当前模式与 SYS_INFO_FUNCTION_AUX 比较判断是否处于 AUX 模式
DeviceInfo.getSPDIFPlayStatusInfo()SPDIFPlayStatusInfoDeviceInfo 缓存SPDIF 播放状态缓存,ViewModel 构造时同步读取
DeviceInfo.getSPDIFAudioSourceInfo()SPDIFAudioSourceInfoDeviceInfo 缓存SPDIF 音频源缓存
JLChipFlag.JL_CHIP_FLAG_695X_SOUND_CARDintSDK 芯片标志用于 UIHelper.isSoundCardType() 判断声卡芯片

Professional Notes

失败模式与边界情况

  • 设备未连接/未初始化:LineinDemo 中对 getUsingDevice() 与 getDeviceInfo() 均做了 null 检查并返回 false。实际 UI 接入时应同样处理,避免 NPE;若设备未初始化就调用 getSPDIFInfo,指令将无法送达,OnRcspActionCallback.onError 会携带 BaseError 返回。
  • 回调未注册导致数据丢失:事件回调必须在指令发送之前注册(如 LineinDemo.getAuxStatusInfo 先 addBTRcspEventCallback 再 getAuxStatusInfo)。若先发指令后注册,设备响应到达时无人监听,查询结果会静默丢失。
  • 设备切换状态串台:SPDIF 状态缓存属于单台设备,SPDIFControlViewModel 通过重写 onSwitchConnectedDevice 主动调用 getSPDIFInfo() 重新同步,防止显示上一台设备的过期状态。
  • playOrPause 的取反竞态:playOrPause() 依赖本地缓存 mSPDIFPlayStatusInfo 取反。若连续快速点击,缓存尚未被 onSPDIFPlayStatusChange 更新,可能产生两次相同的目标状态。UI 层应在收到回调前禁用按钮或做防抖处理。

并发与线程

  • RCSPController 为全局单例,所有指令串行经蓝牙通道发送,SDK 内部处理指令排队;App 层无需额外加锁。
  • ViewModel 使用 postValue()(而非 setValue())更新 LiveData,因为回调可能来自蓝牙 SDK 的工作线程,postValue 是线程安全的。
  • release() 中必须 removeBTRcspEventCallback,否则 ViewModel 销毁后回调仍会触发,导致内存泄漏或对已销毁 UI 的更新。

扩展点

  • 新增 SPDIF 音频源:在 SPDIFAudioSourceInfo 中定义新常量并仿照 setAudioSourceHDMI/Optical/Coaxial 添加方法即可,无需改动协议通道。
  • 新增声卡功能参数:通过通用通道 setSoundCardFunction(byte index, int value) 扩展,只需在固件协议中定义新的 index 含义。
  • 界面层可通过继承 BtBasicVM 并复用 mRCSPController 的既有模式,为其他外设功能(如 FM、USB)建立同样的 ViewModel 封装。

测试覆盖

  • LineinDemo(isSupportAuxMode、isDeviceInAuxMode、getAuxStatusInfo、auxPlayOrPause)覆盖 AUX 能力判定、状态查询与控制路径。
  • SoundCardDemo(getSoundCardStatusInfo、getSoundCardEqInfo、setSoundCardEqInf、setSoundCardFunction)覆盖声卡状态、EQ 读写与功能设置路径。
  • Demo 以 @Test 标注,可在 JUnit 环境中作为集成测试用例运行,是接入第三方 App 的最佳参考范例。

Related Links

  • SPDIFControlViewModel.java(SPDIF 控制 ViewModel 实现)
  • LineinDemo.java(Line-in/AUX 测试用例)
  • SoundCardDemo.java(声卡功能测试用例)
  • UIHelper.java(声卡芯片类型判定工具)
  • 相关兄弟页面:设备连接与 RCSP 协议(另见)、EQ 均衡器功能(另见)
Prev
录音与语音控制
Next
音频编解码库