KDocs 研发资料库
  • 音频技术应用文档入口汇总
  • 杰理WINDOWS环境安装及其他事项
  • LINUX安装和编译
  • Linux环境编译SDK教程(ubuntu18.04)
  • 音频类补丁汇总表
  • 认证资料获取汇总(最新资料后台会更新)
  • 《Hi-Res申请指南v1.0》
  • FreeRTOS 开源协议版本
  • uCOS 开源协议版本信息
  • 各个模块关键资料汇总
  • 软件调试方法
  • Makefile编译
  • 提bug的规范
  • 常规设备使用指导
  • 对外特别发布开发注意点信息汇总
  • AD697X软件问题整理
  • AC700N软件问题整理
  • AC701X耳机软件问题整理
  • 951&961软件问题整理
  • AC104X软件问题整理
  • AC128N问题整理文档
  • 可视化工具调试问题整理
  • 耳机资料汇总
  • AC704N、 AC705N相关应用
  • AC695N&AC696N&AC608N音箱问题整理
  • JL701N音箱问题整理
  • AC692X软件问题整理
  • AC706N音箱问题整理
  • JL701N音箱问题整理(可视化工具SDK)
  • JL703N音箱问题整理
  • JL709N(JL689N)音箱问题整理
  • JL7094系列-入门到进阶开发指导
  • AC210N音箱问题整理
  • 无线麦系列版本支持指南
  • AW32N无线麦问题整理
  • lAD697X&JL701X 无线麦软件共性问题整理
  • AC706N无线麦问题整理
  • AW36N无线麦问题整理
  • AC710X无线麦问题整理
  • 唤醒源获取及唤醒IO设置
  • 电源
  • LVD
  • 长按复位配置方法
  • 低功耗应用
  • TIMER
  • UART
  • SPI
  • 内部FLASH空间添加用户自定义区域
  • IIC
  • GPIO
  • MCPWM
  • SD&U盘
  • 时钟&晶振
  • GPCNT
  • IO口crossbar映射功能
  • 文件系统使用总结
  • 复用应用
  • LINEIN_AUX相关应用
  • IIS音频接口应用
  • SPDIF模式相关(HDMI_ARC、光纤、同轴)
  • PDM LINK
  • 外设相关应用
  • 蓝牙相关
  • 杰理蓝牙距离调试文档
  • TWS耳机配对方式使用及生产把控指南
  • GFP谷歌快连及其认证流程指引
  • 蓝牙发射器(bt_emitter)相关
  • BLE应用
  • 关于提升BLE传输速率说明
  • BLE测试数据
  • MUSIC 模式相关应用
  • MIDI音乐实现
  • PC相关应用
  • FM相关应用
  • AC695N_AC696N FM天线ESD静电防护措施说明V2.0_20250107
  • fm应用详细设计说明书
  • 杰理FM硬件指南-20230315
  • ADC模块
  • AUDIO相关应用
  • 新Tools的音效调试使用
  • 混响应用使用说明
  • 音效调式
  • 音箱耳机低音小音量增强实现方法
  • DAC输出功率调试
  • DAC性能测试指南
  • 针对各类底噪、电流声分析流程
  • 录音相关应用
  • OPUS编解码相关
  • RTC相关应用
  • 升级相关
  • UI相关应用
  • 通话调试流程指南
  • 通话相关应用
  • 省电容mic使用手册
  • 如何测试验证手表通话系统的语音失真 V1.0
  • AC695X_AC696X_AD697X 常见通话问题处理参考资料
  • 通话调试问题确定步骤
  • 内置触摸调试指南
  • 低功耗内置触摸介绍V2.2
  • 触摸相关文档
  • AC697X、AC698X内置触摸调试及整改方法V1.0
  • 产测相关应用
  • AC63X BLE DUT测试介绍
  • 兆华序列使用简易说明
  • JL_1T2蓝牙测试盒音频文件更换说明
  • ENC相关应用入口汇总
  • ANC相关应用入口汇总
  • JL DMS通话调试手册-V3.9.4
  • ANC-ENC结构设计要点-20240407
  • 半入耳式ANC耳机器件选型与结构设计指南V1.0
  • JL 耳道自适应调试指南
  • ANC相关问题处理
  • ANC调试文档
  • 评估蓝牙耳机通话上行降噪性能的方法 V1.0 (2)
  • FCC 或者 BQB 认证相关应用
  • BQB profile 测试中常遇到的问题点汇总
  • 蓝牙参数整理20210811
  • 杰理科技认证问题参考
  • 无线音频产品开发指南
  • 无线麦系列从入门到进阶开发指导
  • 量产烧录相关说明
  • 一拖八烧录器远程过程调用说明
  • 量产相关建议
  • EffectTool(eq)调试工具说明文档
  • AC897AD697系列的EQ调试方法-V3
  • 杰理调音指南-20220622
  • 音效模块总结
  • 简要调音步骤指引(可视化)
  • 耳机充电与通信调试指南
  • 充电仓硬件调试指南
  • 充电仓软件问题整理
  • AC951常用说明
  • AC951_AC961_开发板使用说明V1.0
  • 彩屏仓AC982 入门指导及FAQ
  • 蓝牙音频APP相关应用
  • 手机APP的简介和开发流程
  • 蓝牙音频系列-硬件设计指南
  • 静电测试及整改方法-20220706
  • TWS耳机底噪整改指南V1.2
  • 杰理蓝牙距离调试文档
  • 蓝牙RF硬件设计与调试V1.1-20250219
  • AC695N_AC696N FM天线ESD静电防护措施说明V2.0_20241228
  • 音效调试指南
  • 无线话筒K歌音箱标准开发流程
  • 杰理科技 700N TWS耳机产品标准-202303
  • 杰理科技 701N 广播产品标准-202303
  • JL-HAT ANC高效产测自适应
  • 无线话筒测试板使用介绍
  • 一拖八频偏校准使用说明
  • 领夹麦产测工具使用介绍
  • Dongle量产测试说明
  • Dongle+Tws或头戴式 SDK通过工具绑定配对功能说明文档
  • 双麦ENC产测宏配置验证方法 V1.0
  • JL耳机方案麦克风声学测试指令_V1.0
  • JL耳机方案麦克风声学测试指令_V2.0
  • JL_ENC自动测试命令_V0.0.1
  • JL蓝牙测试盒用例说明
  • LDAC自测环境搭建_ubuntu
  • 延迟小板使用手册
  • 杰理库文件的制作及添加实现过程
  • 关于 AC635N&AC636N系列免晶振兼容性补丁 说明
  • 关于 AC63系列VM兼容性修复补丁_20250224 说明
  • 关于 AC632N &AE632N_ 蓝牙& 低功耗兼容性修复补丁 说明
  • AD698N和AC638N电压优化补丁V3说明
  • 关于 AC635N&AC636N漏电和E&G版兼容联合补丁 说明
  • AD698N和AC638N电压优化补丁V2说明
  • 702相关应用
  • 2024-4-30 发布歌词显示SDK开发注意事项
  • BQB RF & FCC 认证测试固件问题汇总及源码
  • BQB profile 测试中常遇到的问题点汇总
  • 进dut测试模式方法及固件
  • 704-频偏修改bin文件合集
  • 701手表BQB PROFILE认证注意事项
  • 认证的干扰规避整改
  • 海外CRA认证报告生成说明
  • JL700N可视化工具问题处理文档
  • JL701X可视化工具问题处理文档
  • JL701N_earphone_release_v1.6.0_ANC 低功耗问题补丁
  • JL708X可视化工具问题处理文档
  • JL709N可视化工具问题处理文档
  • JLstudio可视化工具使用说明
  • 一拖二-串口_蓝牙_app在线EQ、通话参数及调试方式和内置触摸调试
  • 可视化JL701M_DONGLE_SDK添加MIC为发射源
  • 可视化JL701M_DONGLE_SDK添加按键切换usb audio与MIC发射源
  • JL701M_DONGLE_SDK_1.0.0_dongle输入linein输出dac
  • 701可视化_a2dp_to_le_demo说明
  • 耳机系列demo汇总
  • JL7018F&JL7006F_7003F AUX IIS
  • 一键连接应用
  • 普通SDK动态开关一拖二功能
  • 蓝牙分析仪(EllisysBluetoothAnalyzer)抓包例程
  • TWS配对常见应用
  • APP自定义按键的demo
  • AC700N 播歌双EQ DEMO示例及说明
  • AC698V164 MIC与蓝牙音乐共同输出DAC demo
  • 添加第三方算法以及多算法授权流程
  • 空间音频配置方法
  • 普通高低电平TWS耳机控制通讯
  • 入耳检测状态更新demo解析
  • 资源优化(非可视化的SDK)
  • 资源优化(可视化SDK)
  • 翻译耳机、语音识别应用demo
  • 耳机抗干扰问题排查和优化
  • AC698D2 抗干扰优化
  • AC696X软件问题整理
  • AC695X软件问题整理
  • AC695X软件问题整理_1722249702
  • AC608X软件问题整理
  • JL701N_2T1_DUPLEX 应用软件问题汇总
  • le_audio_1.0.0_patch05 以及之前的版本IRkey 功能异常修改
  • AC706N-le_audio-200SDK有线_无线麦录音demo
  • jl701n_le_audio_v200patch02 IO串口升级修改串口单次发送字节长度的修改办法
  • 703创建IIS 输入dac输出音频流demo
  • 703将媒体流音频同时上传PC_mic录音demo实现
  • 703四路IIS输入输出demo
  • 底噪调试
  • AW328A烧录说明
  • 文档合集
  • AC706N_wireless_mic_release_PATCH_20240712 补丁 说明
  • AC706N_wireless_mic_release_PATCH_20240726 补丁 说明
  • AC706N_wireless_mic_release_V1.0.0、1.0.1、1.0.2 补丁 说明
  • AC706N_wireless_mic_release_V1.1.2 中的2T1应用 RX端不绑定配对,TX端实现绑定配对的修改方法
  • 各系列省晶振实现方法
  • iis tx rx说明文档
  • spdif信号
  • 蓝牙电话本
  • 安卓手机同步时间补丁
  • CDC配置
  • PC模式下增加Teams唤起功能
  • 杰理HDMIARC开发实现过程
  • AC701N patch06之前的版本用第三方算法节点实现新版本的pcm delay节点功能
  • (K歌音箱)各SDK音效配置相关说明
  • 长文件录音
  • 点阵屏歌词字库相关(蓝牙歌词,普通歌词)
  • 字模提取工具说明
  • 音箱可视化彩屏-入门到进阶开发指导
  • 彩屏LVGL UI设计及工具使用
  • 使用内部UI框架进行UI调试的系列步骤
  • AD101C使用强制升级工具spi 烧录不了问题处理(测试版本)
  • AD161扩展灯板说明文档
  • 歌词显示器开发注意项
  • 使用硬件数字增益控制通话下行音量(可视化)
  • 杰理小牛产测资料
  • ENC配置说明
  • 通话调试流程指引
  • ANC相关功能demo
  • 无线麦硬件资料汇总
  • 无线麦相关应用
  • 无线麦复杂功能补丁包汇总
  • 无线话筒形态SDK程序&开发经验&问题点分享
  • 双模式结合应用问题汇总
  • 无线麦距离优化案例
  • 无线麦系列中的双工形态(duplex)演变开发对讲机方案开发资料
  • 音箱入门到进阶指导文档(编写中)
  • 蓝牙耳机品控和生产技巧
  • 982过_欠压标志获取异常
  • 如何获取最新涂鸦SDK及库文件
  • 无线话筒K歌音响-调音标准流程
  • 无线话筒产测流程

翻译耳机、语音识别应用demo

📎 原始文档:https://www.kdocs.cn/l/csk1MNwvvo3R 翻译耳机、语音识别应用demo
新文档已转移至:翻译耳机、语音识别,本链接不再更新维护

关于翻译耳机和语音识别

耳机只需要上传语音数据给APP,翻译和识别由APP实现
耳机可实现解码功能,播放app下发的音频(比如翻译好的语音)

翻译耳机常见形态/功能

普通录音

flowchart 普通录音只需要耳机将mic采到的音频数据发给手机APP,手机APP负责对音频数据进行存储、识别、翻译。

通话录音

flowchart 通话录音需要耳机将mic采到的音频数据和手机通话下行数据发给手机APP,手机APP负责对音频数据进行存储、识别、翻译。

音频翻译

flowchart 音频翻译应用于mic、音频和视频的声音翻译,耳机将音频数据传给app,app翻译后再发给耳机播放

通话翻译

通话翻译的两种应用:翻译通话下行音频,翻译通话上行音频
翻译通话下行音频,耳机将通话下行数据发给app,app将翻译好的音频发回给耳机播放,替代原始下行音频
flowchart 翻译通话上行音频,耳机将mic数据发给app,app将翻译好的音频发回给耳机,替代上行数据发给手机通话
flowchart

同声翻译

flowchart 两个不同语言的人对话,一人一个耳机,耳机采集佩戴人说话的声音,发给app翻译后在对方的耳机播出来

方案芯片选型

普通录音

支持的语音数据通信方式:BLE、SPP、ESCO
支持的芯片系列:
BLE、SPP:697N、700N、701N、708N、709N、689N、710N。
ESCO:走HFP,所有支持蓝牙通话的芯片都支持(实现原理同手机语音助手,需要APP获得手机权限)

通话录音

支持的语音数据通信方式:BLE、SPP
支持的芯片系列:
BLE、SPP:701N、708N、709N、689N。

音频翻译

支持的语音数据通信方式:BLE、SPP、ESCO
支持的芯片系列:
BLE、SPP:701N、708N、709N、689N。
ESCO:仅支持mic翻译,走HFP,所有支持蓝牙通话的芯片都支持(实现原理同手机语音助手,需要APP获得手机权限)

通话翻译

支持的语音数据通信方式:BLE、SPP
支持的芯片系列:
BLE、SPP:701N。

同声翻译

支持的语音数据通信方式:BLE、SPP、ESCO
支持的芯片系列:
BLE、SPP:701N、708N、709N、689N。
ESCO:走HFP,所有支持蓝牙通话的芯片都支持(实现原理同手机语音助手,需要APP获得手机权限),需要手机同时连接两个耳机的经典蓝牙,目前还没有APP用这种方案做同声翻译

开mic(不带编码),然后通过SPP或者BLE发出去

  1. SDK demo 【金山文档】 AC897N_AD697N_earphone_release_V2.4.0_mic_tx
    https://kdocs.cn/l/ctxL3VWuXMo5
    【金山文档】 AC700N_earphone_release_V1.3.7_mic_tx
    https://kdocs.cn/l/ckNSBHOeqx7w
  2. demo更新记录

2023年8月19日:

  1. 使用杰理之家的发数接口,自动切换SPP、BLE发数(但是杰理之家不支持SPP和BLE同时连接,需要同时连接的请改用数传,自行修改发数接口u32 send_data(u8 *data, int len))
  2. 优化BLE发数速率(详见:关于提升BLE传输速率说明.pdf,https://gitee.com/Jieli-Tech/fw-AC63_BT_SDK/issues/I59IL3)
  3. 移植到其他SDK 添加如下缓存和发数的代码,按照注释添加到代码中
#define SEND_PK_LEN  512
OS_SEM mic_sem;//通知发数任务用的信号量
cbuffer_t mic_cbuf_hd;
u8 *mic_buff = NULL;
u8 spp_send_busy = 0;//spp发数忙状态(没开APP功能才用)
u8 temp[SEND_PK_LEN];//SPP的发数缓存
u32 total_send = 0;//已发数据长度,用于计算发数速率
u32 start_point = 0;//用于计算发数速率
static volatile u8 task_release = 0;

/*
* adc采集到数据之后,通过此接口将数据缓存并通知任务发数
*/
void adc_output_2_mic_task(u8 *buff, u16 len)
{
    u32 wlen = cbuf_write(&mic_cbuf_hd, buff, len);
    if(wlen != len){
        putchar('m');
    }
    os_sem_post(&mic_sem);
}

#include "spp_user.h"
#include "btstack/avctp_user.h"
void spp_get_operation_table(struct spp_operation_t **interface_pt);

/*
* 发数接口,这里是通过SPP发,需要通过BLE发的话自行在这里调用BLE发数接口发数
* 只需要改里面的发数接口,不需要主动调用
*/
u32 send_data(u8 *data, int len)
{
#ifdef CONFIG_APP_BT_ENABLE
    struct spp_operation_t *interface_pt;
    spp_get_operation_table(&interface_pt);
    u32 ret = interface_pt ? interface_pt->send_data(NULL, data, len) : 0;
#else
    spp_send_busy = 1;
    u32 ret = user_send_cmd_prepare(USER_CTRL_SPP_SEND_DATA, len, data);
#endif
    if(ret){
        // printf("send_data err %d\n", ret);
    }
    return ret ? 0 : len;
}

/*
* 发数繁忙判断,这里只判断了SPP的状态,需要判断BLE状态的话自行在这里调用BLE接口判断
* 只需要改里面的判断接口,不需要主动调用
*/
u8 is_send_busy(void)
{
#ifdef CONFIG_APP_BT_ENABLE
    struct spp_operation_t *interface_pt;
    spp_get_operation_table(&interface_pt);
    return interface_pt ? interface_pt->busy_state() : 0;
#else
    return spp_send_busy;
#endif
}

/*
* 尝试发数接口
* 这个函数会判断有数据、且发数不繁忙才会发数,此接口不需要主动调用,由task执行
*/
void try_send(void)
{
    if(cbuf_get_data_len(&mic_cbuf_hd) && !is_send_busy()){
        putchar('S');
        int len = cbuf_get_data_len(&mic_cbuf_hd);
        if(len > SEND_PK_LEN){
            len = SEND_PK_LEN;
        }
        OS_ENTER_CRITICAL();
        cbuf_read(&mic_cbuf_hd, temp, len);
        OS_EXIT_CRITICAL();
        u32 wlen = send_data(temp, len);
        if(wlen != len){
            putchar('E');
            //跑到这里说明发数失败了
        }
        total_send += wlen;
        if(sys_timer_get_ms() - start_point >= 2000){
            printf("send speed %d Bps\n", 1000 * total_send / (sys_timer_get_ms() - start_point));
            start_point = sys_timer_get_ms();
            total_send = 0;
        }
    }
}

/*
* SPP发完回调接口,SPP发完数的时候调用一下
* 这个函数要在SPP发数完毕唤醒接口中调用,需要配合spp_user.h中的接口使用
* 可参考SDK demo中的用法
*/
void spp_wakeup_send_data(void)
{
    putchar('K');
    spp_send_busy = 0;
    if(task_release == 0){
        os_sem_post(&mic_sem);
    }
}

/*
* 清除SPP繁忙状态,停止发数的时候调用一下,spp断开的时候调用一下
*/
void clr_send_busy(void)
{
    spp_send_busy = 0;
}

/*
* 发数任务
*/
void mic_tx_task(void *p)
{
    printf("mic_data_task start\n");
    while(1){
        os_sem_pend(&mic_sem, 0);
        if(task_release){
            task_release = 2;
            continue;
        }
        try_send();
    }
}

#include "bt_tws.h"
void sys_auto_sniff_controle(u8 enable, u8 *addr);
/*
* 创建发数的任务,要在adc采集开始之前执行一下,例如:
    mic_data_task_create();
    audio_adc_mic_start(&mic_demo->mic_ch);
*/
void mic_data_task_create(void)
{
    mic_buff = malloc(ADC_DEMO_BUFS_SIZE*4);
    ASSERT(mic_buff);
    start_point = sys_timer_get_ms();
    printf("mic_buff %x\n", mic_buff);
    cbuf_init(&mic_cbuf_hd, mic_buff, ADC_DEMO_BUFS_SIZE*4);
    os_sem_create(&mic_sem, 0);
    sys_auto_sniff_controle(0, NULL);//关sniff
    user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);//退sniff
    tws_api_auto_role_switch_disable();//关自动主从切换
    clk_set("sys", 64000000);//提高系统时钟
    task_release = 0;
    int ret = os_task_create(mic_tx_task, NULL, 2, (SEND_PK_LEN * 2 / 128) * 128, 256, "mic_task");
    if(ret == 0){
        printf("mic_data_task_create succ\n");
        return;
    }

    printf("mic_data_task_create failed\n");
}

/*
* 删除发数的任务,要在停止adc采集之后执行一下,例如:
    audio_adc_del_output_handler(&adc_hdl, &mic_demo->adc_output);
    audio_adc_mic_close(&mic_demo->mic_ch);
    OS_ENTER_CRITICAL();
    free(mic_demo);
    mic_demo = NULL;
    OS_EXIT_CRITICAL();
    void mic_data_task_del(void);
    mic_data_task_del();
*/
void mic_data_task_del(void)
{
    printf("mic_data_task_del\n");
    task_release = 1;
    while (task_release == 1)
    {
        os_sem_post(&mic_sem);
        os_time_dly(10);
    }
    os_task_del("mic_task");
    os_sem_del(&mic_sem, 0);
    printf("mic_data_task_del ok\n");
    OS_ENTER_CRITICAL();
    free(mic_buff);
    mic_buff = NULL;
    OS_EXIT_CRITICAL();
    clr_send_busy();
    sys_auto_sniff_controle(1, NULL);//开sniff
    tws_api_auto_role_switch_enable();//开自动主从切换
}

开mic(带编码),然后通过SPP或者BLE发出去

  1. 697N SDK已支持MIC编码为OPUS或者SPEEX的流程
    音频编码选择二选一:
#define TCFG_ENC_OPUS_ENABLE 0
#define TCFG_ENC_SPEEX_ENABLE 0

配置发数接口

#define AUDIO_SEND_MIN_BUF_LEN   200
#define AUDIO_SPEECH_BUF_LEN     (3*1024 + 512)
#define AI_PL_DATA_SEND             gma_opus_voice_mic_send
AI_ENC_INFO_REGISTER(ai_enc_info, AUDIO_CODING_OPUS, STANDARD_OPUS);

打开宏:

#define BT_MIC_EN 1

获取编码数据:

static int rec_enc_output(void *priv, void *buf, int len)

启动编码:

int ai_mic_rec_start(void)

结束编码:

int ai_mic_rec_close(void)

参考流程:
XM_MMA_EN
2. 700N SDK已支持MIC编码为OPUS或者SPEEX的流程
音频编码选择二选一:

#define TCFG_ENC_OPUS_ENABLE 0
#define TCFG_ENC_SPEEX_ENABLE 0

配置发数接口:

int mic_rec_pram_init(u32 enc_type, u8 opus_type, u16(*speech_send)(u8 *buf, u16 len), u16 frame_num, u16 cbuf_size)
//mic_rec_pram_init(AUDIO_CODING_SPEEX, 0, app_protocol_send_voice_data, 5, 1024);

打开宏:

#define BT_MIC_EN 1

获取编码数据:

static int rec_enc_output(void *priv, void *buf, int len)

启动编码:

int ai_mic_rec_start(void)

结束编码:

int ai_mic_rec_close(void)

参考流程:
AI_APP_PROTOCOL下的APP_PROTOCOL_TME_CODE,APP_PROTOCOL_SPEECH_EN

翻译耳机(仅支持可视化SDK)

  • demo JL701N_翻译耳机_V3.0.0.zip-- JL701N_翻译耳机_V3.0.0_patch_01.10
    JL708N_翻译耳机_V3.0.0.zip
    注意:以下demo需要关闭随机核,改回固定核。修改如下
    imageJL701N_翻译耳机.zip-- 701N V1.0.0 patch_06_01
    JL701N_翻译耳机_2Amic.rar -- 701N V1.0.0 patch_06_01原立体声MIC+DAC改为MIC+MIC
    JL701N_翻译耳机_1Amic_1Dmic.rar -- 701N V1.0.0 patch_06_01原立体声MIC+DAC改为MIC+数字MIC
    【金山文档】 701N V1.0.0 patch_04 翻译耳机流程
    701N V1.0.0 patch_04 翻译耳机流程.zip
    AC701_100_1T2_patch04.03-debuaA-fix-siri.zip(修复siri状态异常问题)

更新记录:

2025年3月11日:
支持非通话下使用通话算法节点(打开CONST_REF_SRC,自行修改数据流节点)
2025年3月6日:
处理agc模块死机问题
2025年3月3日:
1、处理通话结束时死机问题
2、处理开机没播提示音的时候,开opus解码没声音的问题
2025年1月7日:
1、升级SDK到V3.0.0大版本
2024年11月20日:
1、buff改为malloc
2、支持录音和anc一起开
修改了以下文件:
image 2024年8月8日:
1、添加缺失文件处理编译错误
2024年8月6日:
1、升级到SDK版本701N V1.0.0 patch_06_01
2024年6月14日:
1、升级到SDK版本701N V1.0.0 patch_05.32
2、支持单声道和立体声编码切换,支持单声道解码
2024年5月27日:
1、提高BLE发数速率
2024年5月22日:
1、修复SPP发数据时opus帧被拆开导致帧不完整问题
2024年5月8日:
1、修复通话时开启opus解码会卡顿问题
2、修复通话时开启opus解码,解码声音会变调问题
2023年11月8日:
1、恢复公版SDK 的ble配置,不需要指令,ble连上直接发opus数据
2023年11月2日:

  1. 优化关解码会复位问题
  2. 优化启动解码的卡顿问题
  3. 修复定时器重复创建问题 2023年10月30日:
  4. 修复解码卡顿问题
  5. 修复解码没数据会导致音乐没声音问题 2023年10月16日:
  6. 实现音乐和通话喇叭声音上传

最新版本实现的功能:

PB1按键,单击打开mic进行opus编码并通过BLE发送,同时打开opus解码;双击将音乐或者通话远端声音进行opus编码并通过BLE发送,同时打开opus解码;三击将mic和dac(音乐或者通话远端)声音进行opus编码并通过BLE发送。
image

接口使用说明

typedef enum {
    MIC_TO_MONO_OPUS = (1 << 4) | MIC,//mic输出到单声道opus编码器(单声道)
    DAC_TO_MONO_OPUS = (1 << 4) | DAC,//dac输出到单声道opus编码器(单声道)
    MIC_TO_STERO_OPUS = (2 << 4) | MIC,//mic输出到立体声opus编码器(单声道)
    DAC_TO_STERO_OPUS = (2 << 4) | DAC,//dac输出到立体声opus编码器(单声道)
    MIC_DAC_TO_STERO_OPUS = (2 << 4) | MIC | DAC,//mic和dac输出到立体声opus编码器(立体声)
} stream_type;

/**
 * @brief 打开opus编码
 * 
 * @param ch_mode 见stream_type
 * @return int 0:成功;其他:失败
 */
int translation_ear_recoder_open_all(u8 ch_mode);

//关闭编码
void translation_ear_recoder_close_all(void);

//打开解码,ch_num暂时只支持填1,暂时只支持解码单声道opus编码器的编码数据
//source_uuid固定填NODE_UUID_SOURCE_DEV0
int dev_flow_player_open(u8 ch_num, u16 source_uuid);

//关闭解码
void dev_flow_player_close(void);

编码数据输出,可以在这个地方将数据发出去
image 自编自解:仅支持单声道opus编码器的编码数据(MIC_TO_MONO_OPUS、DAC_TO_MONO_OPUS)
需要调用dev_flow_player_open打开解码,然后把编码输出的数据填到解码缓存
image

实现方法

新建两个音频流程,分别处理单声道opus编码和立体声opus编码
image 单声道opus编码用的是公版SDK的opus编码器(silk-only 库,仅支持单声道,16k采样率 ,20ms帧编码,CBR编码,支持码率16/32/64kpbs,对应帧长40/80/160字节)
imageimage 立体声opus编码使用独立的立体声编码器(celt-only库,支持8000/16000/24000/48000采样率单双声道编码,支持封装格式: 0:百度无头. 1:size+rangeFinal. 源码可兼容版本. 2:ogg封装,pc软件可播放)
image 立体声编码参数修改(建议默认),需要不同的帧长可通过调整码率(br)实现
image 音乐场景和通话场景使用中间节点收集数据
imageimage

关于移植

按照上面的截图做好数据流,对比demo和公版701N V1.0.0 patch_06_01以下文件的修改
image

(作废)701N V1.0.0 patch_04实现的功能:

  1. 此demo开的mic是mic1、mic2、mic3,详见ADC节点配置(可自行修改,但需要注意下面第2点也要同步改) imageimage
  2. 三个mic的数据在effect dev0节点混合输出(开发者可以自行添加算法)(可自行修改) image
  3. PB1按键,单击打开mic进行opus编码并通过BLE发送,同时打开opus解码;三击将音乐或者通话远端声音进行opus编码并通过BLE发送,同时打开opus解码;双击结束编码和停止发送,同时结束解码。 image
  4. demo默认打开自编自解功能,把发送出去的opus数据传给解码播放,从喇叭输出。详见本地自编自解流程实现。
  • (作废)更新可视化SDK到最新版本以及最新补丁
  • (作废)mic数据上传以及语音下发实现方式
  1. 添加音频流程 imageimageimage
  2. 节点介绍
    1. AI_TX:将数据通过BLE或者SPP发出去的节点,对应代码文件:audio\framework\nodes\ai_tx_node.c
    2. Source_Dev0/Source_Dev1:可自定义实现的节点,用在音频流的起始,用于第三方来源的音频数据接入SDK音频流,本demo将来自ble的或者来自AI_TX的opus编码数据输入到Source_Dev0,然后经过解码器输出到dac播放出来。Source_Dev1则用于音乐和通话数据的编码,给到AI_TX发送出去。对应代码文件: audio\framework\plugs\source\source_dev0_file.c
      audio\framework\plugs\source\source_dev1_file.c
    3. EffectDev0/1/2/3/4:可自定义实现的节点,用在音频流的中间流程,可用于接入第三方算法,例如第三方双mic、三mic算法等。本demo的EffectDev0用来做mic数据混合(或者开发第三方算法),EffectDev1用于获取音乐和通话的pcm数据给Source_Dev1编码。对应代码文件: audio\framework\nodes\effect_dev0_node.c
      audio\framework\nodes\effect_dev1_node.c
      audio\framework\nodes\effect_dev2_node.c
      audio\framework\nodes\effect_dev3_node.c
      audio\framework\nodes\effect_dev4_node.c
  3. 发数实现方法 打开数传或者RCSP后,在AI_TX节点中调用数传或者rcsp的发数接口
    image 因不同方案使用的APP可能不一样,BLE那边的profile和uuid等不做详细描述,但开启数传功能和rcsp功能的方法就是在可视化工具中打开对应功能。提升发数速率的方法见发数速率提升方法
  4. APP语音以及解码播放实现方法
    1. 创建解码数据缓存
#include "circular_buf.h"

static cbuffer_t output_cbuf_h;
static u8 *output_buff = NULL;
#define OUTPUT_BUFF_SIZE    (2048)

static void output_buff_init(void)
{
    if(output_buff == NULL){
        output_buff = malloc(OUTPUT_BUFF_SIZE);
        ASSERT(output_buff);
        cbuf_init(&output_cbuf_h, output_buff, OUTPUT_BUFF_SIZE);
    }
}

static void output_buff_free(void)
{
    if(output_buff){
        OS_ENTER_CRITICAL();
        free(output_buff);
        output_buff = NULL;
        OS_EXIT_CRITICAL();
    }
}

//输出到解码
static u32 source_input_write(u8 *data, u16 len)
{
    if(output_buff == NULL){
        return 0;
    }
    return cbuf_write(&output_cbuf_h, data, len);
}

static u32 source_input_read(u8 *data, u16 len)
{
    if(output_buff == NULL){
        return 0;
    }
    if(len > cbuf_get_data_len(&output_cbuf_h)){
        len = (cbuf_get_data_len(&output_cbuf_h) / 40) * 40;//对齐到40字节,因为默认opus是40字节一帧
    }
    return cbuf_read(&output_cbuf_h, data, len);
}

u32 source_dev0_input_write(u8 *data, u16 len)
{
    return source_input_write(data, len);
}

image 2. BLE收数或者SPP收数后调用source_dev0_input_write写数据到缓存 3. Source_Dev0解码流程运行时,从缓存中拿数据解码

static u8 output[40];//数据大小根据实际数据格式调整。opus用40,pcm一般用512

image 5. 本地自编自解流程实现 在AI_TX调用source_dev0_input_write将编码数据写入解码缓存
image 6. 数据流程的启动和停止方式

//启动,先启动上传,再启动解码
/**
 * @brief 启动数据上传
 * 
 * @param pipeline_name 启动的场景,固定为"ai_voice"
 * @param source_uuid 上传的数据源,根据需要选择,上传mic选NODE_UUID_ADC,上传dac选NODE_UUID_SOURCE_DEV1
 * @param code_type 编码格式,见audio_base.h
 * @param ai_type 固定为0
 * @return int 
 */
int ai_voice_recoder_open(u8 *pipeline_name, u16 source_uuid, u32 code_type, u8 ai_type);
ai_voice_recoder_open("ai_voice", NODE_UUID_ADC, 0x00100000, 0);//mic数据上传启动
/**
 * @brief 自定义数据流播放器 启动
 * 
 * @param pipeline_name 启动的场景,固定为"ai_voice"
 * @param source_uuid 播放数据源,固定为NODE_UUID_SOURCE_DEV0
 * @return int 
 */
int dev_flow_player_open(u8 *pipeline_name, u16 source_uuid);
dev_flow_player_open("ai_voice", NODE_UUID_SOURCE_DEV0);//app语音数据下发解码启动
//停止,先停止解码,再停止上传
void dev_flow_player_close(u8 *pipeline_name);
dev_flow_player_close("ai_voice");//app语音数据下发解码关闭
void ai_voice_recoder_close(u8 *pipeline_name);
ai_voice_recoder_close("ai_voice");//mic数据上传关闭
  • (作废)本地dac数据上传以及语音下发实现方式
  1. 添加音频流程 image
  2. 节点介绍 同节点介绍
  3. dac数据变采样、缓存 dac音频编码上传,使用source dev1节点作为源节点,effect dev1将音乐的数据变采样后再给到source dev1节点,同样的effect dev1也是通过缓存的方式把数据给到source dev1
struct source_dev1_file_hdl *hdl_p;
static u16 input_sr = 44100;
static s16 output[256];

#include "circular_buf.h"

static cbuffer_t output_cbuf_h;
static u8 *output_buff = NULL;
#define OUTPUT_BUFF_SIZE    (2048)

static void output_buff_init(void)
{
    if(output_buff == NULL){
        output_buff = malloc(OUTPUT_BUFF_SIZE);
        ASSERT(output_buff);
        cbuf_init(&output_cbuf_h, output_buff, OUTPUT_BUFF_SIZE);
    }
}

static void output_buff_free(void)
{
    if(output_buff){
        OS_ENTER_CRITICAL();
        free(output_buff);
        output_buff = NULL;
        OS_EXIT_CRITICAL();
    }
}

static void source_dev1_packet_rx_notify(void *_hdl);
static u32 source_input_read(u8 *data, u16 len);
//输出到解码
static u32 source_input_write(u8 *data, u16 len)
{
    struct stream_frame *frame;
    struct source_dev1_file_hdl *hdl = hdl_p;
    if(output_buff == NULL || hdl == NULL){
        return 0;
    }
    u16 data_len = len;
    if(hdl->sw_src_api && hdl->sw_src_buf && len){//变采样流程
        if(hdl->src_in_sr != input_sr){
            hdl->src_in_sr = input_sr;
            hdl->sw_src_api->set_sr(hdl->sw_src_buf, input_sr);//更新采样率
        }
        len = hdl->sw_src_api->run(hdl->sw_src_buf, data, len >> 1, output);
        len <<= 1;
        data = output;
    }
    cbuf_write(&output_cbuf_h, data, len);//变采样后写缓存
    if(cbuf_get_data_len(&output_cbuf_h) >= 512){
        source_dev1_packet_rx_notify(hdl);//缓存够512字节再通知编码
    }
    return data_len;
}

static u32 source_input_read(u8 *data, u16 len)
{
    if(output_buff == NULL){
        return 0;
    }
    if(len > cbuf_get_data_len(&output_cbuf_h)){
        return 0;
    }
    return cbuf_read(&output_cbuf_h, data, len);
}

u32 source_dev1_input_write(u8 *data, u16 len)
{
    return source_input_write(data, len);
}

imageimageimageimage 4. 发数实现方法 同发数实现方法
5. 本地自编自解流程实现 同本地自编自解流程实现
6. 数据流程的启动和停止方式

//启动,先启动上传,再启动解码
/**
 * @brief 启动数据上传
 * 
 * @param pipeline_name 启动的场景,固定为"ai_voice"
 * @param source_uuid 上传的数据源,根据需要选择,上传mic选NODE_UUID_ADC,上传dac选NODE_UUID_SOURCE_DEV1
 * @param code_type 编码格式,见audio_base.h
 * @param ai_type 固定为0
 * @return int 
 */
int ai_voice_recoder_open(u8 *pipeline_name, u16 source_uuid, u32 code_type, u8 ai_type);
ai_voice_recoder_open("ai_voice", NODE_UUID_SOURCE_DEV1, 0x00100000, 0);//dac数据上传启动
/**
 * @brief 自定义数据流播放器 启动
 * 
 * @param pipeline_name 启动的场景,固定为"ai_voice"
 * @param source_uuid 播放数据源,固定为NODE_UUID_SOURCE_DEV0
 * @return int 
 */
int dev_flow_player_open(u8 *pipeline_name, u16 source_uuid);
dev_flow_player_open("ai_voice", NODE_UUID_SOURCE_DEV0);//app语音数据下发解码启动
//停止,先停止解码,再停止上传
void dev_flow_player_close(u8 *pipeline_name);
dev_flow_player_close("ai_voice");//app语音数据下发解码关闭
void ai_voice_recoder_close(u8 *pipeline_name);
ai_voice_recoder_close("ai_voice");//dac数据上传关闭

(作废)opus立体声编码demo

注意:以下demo需要关闭随机核,改回固定核。修改如下
imageJL701N_翻译耳机.zip--701N V1.0.0 patch_06_01
701N V1.0.0 patch_04_立体声opus编码.zip

更新记录:

2024年8月6日:
1、升级到SDK版本701N V1.0.0 patch_06_01
2024年6月14日:
1、升级到SDK版本701N V1.0.0 patch_05.32
2、支持单声道和立体声编码切换,支持单声道解码
2024年5月27日:
1、提高BLE发数速率
2024年5月22日:
1、修复SPP发数据时opus帧被拆开导致帧不完整问题
2024年5月13日:

  1. 添加缺少的文件
  2. 修复时钟不释放问题

701N V1.0.0 patch_06_01功能说明:

见701N V1.0.0 patch_06_01实现的功能:

701N V1.0.0 patch_04功能说明:

  1. 支持opus立体声编码(dac + mic)
  2. 支持opus单声道编码(dac或mic)
  3. 接口使用说明
void xxx_to_opus_close()
{
    ai_voice_recoder_close(0, "ai_voice");
    ai_voice_recoder_close(1, "ai_voice");
}

//opus单声道编码mic
void mic_to_opus()
{
    xxx_to_opus_close();
    void set_global_ch_mode(u8 mode);
    set_global_ch_mode(AUDIO_CH_L);
    if(bt_get_call_status() == 5){//非通话状态下才需要开adc
        ai_voice_recoder_open(0, "ai_voice", NODE_UUID_ADC, 0x00100000, 0);
    }
    ai_voice_recoder_open(1, "ai_voice", NODE_UUID_SOURCE_DEV1, 0x00100000, 0);
}

//opus单声道编码dac
void dac_to_opus()
{
    xxx_to_opus_close();
    void set_global_ch_mode(u8 mode);
    set_global_ch_mode(AUDIO_CH_R);
    if(bt_get_call_status() == 5){//非通话状态下才需要开adc
        ai_voice_recoder_open(0, "ai_voice", NODE_UUID_ADC, 0x00100000, 0);
    }
    ai_voice_recoder_open(1, "ai_voice", NODE_UUID_SOURCE_DEV1, 0x00100000, 0);
}

//opus立体声编码mic和dac
void mic_dac_to_opus()
{
    xxx_to_opus_close();
    void set_global_ch_mode(u8 mode);
    set_global_ch_mode(AUDIO_CH_LR);
    if(bt_get_call_status() == 5){//非通话状态下才需要开adc
        ai_voice_recoder_open(0, "ai_voice", NODE_UUID_ADC, 0x00100000, 0);
    }
    ai_voice_recoder_open(1, "ai_voice", NODE_UUID_SOURCE_DEV1, 0x00100000, 0);
}

修改编码输出格式
image

(作废)~~DAC数据通过SPP或者BLE转发给APP(仅701N支持)~~​

701可视化_a2dp_to_le_demo说明.otl

自定义的音频播放流程

以翻译耳机方案,播放APP下发的OPUS编码数据为例(代码见demo)

  1. 创建一个数据流 image
  2. 添加数据缓存流程,见APP语音以及解码播放实现方法
  3. 修改数据流启动代码 uuid对应数据流所在场景的id号
    image
  4. 修改源数据格式
    fmt->sample_rate = 16000;                //采样率
    fmt->coding_type = AUDIO_CODING_OPUS;    //数据类型,PCM用AUDIO_CODING_PCM,还要打开PCM解码器
    fmt->channel_mode = hdl->ch_num == 2 ? AUDIO_CH_LR : AUDIO_CH_MIX;        //通道模式,根据源数据的声道选择

image 解码PCM需要打开PCM解码器
image 5. 根据解码格式调整每帧数据长度 opus:demo单声道用40字节
pcm:根据采样率和声道定,单声道8K用160,16K用320,44100用512等,立体声则对应乘以2
imageimage 6. 启动解码和关闭解码

//打开解码,ch_num暂时只支持填1,暂时只支持解码单声道opus编码器的编码数据
//source_uuid固定填NODE_UUID_SOURCE_DEV0
int dev_flow_player_open(u8 ch_num, u16 source_uuid);

//关闭解码
void dev_flow_player_close(void);

opus编码写入SD卡demo

JL708N_翻译耳机_V3.0.0_feat_01_01.zip
注意:以下demo需要关闭随机核,改回固定核。修改如下
imageJL701N_翻译耳机_写SD卡_patch_06_01.zip -- gitlab
翻译耳机加写SD卡的流程(具体修改对比JL701N_翻译耳机.zip)
1、默认在线
2、支持EMMC
3、SDPG供电
4、支持PC模式查看文件

接口说明

  1. 修改SD卡IO image
  2. 读写卡的接口
void *sd_file_open(u8 *file_name);//打开或者创建并打开文件,file_name:文件名,建议用txt格式
void sd_file_close(void *file);//关闭文件
int sd_file_write(void *file, u8 *data, u16 len);//写入
int sd_file_read(void *file, u8 *data, u16 len);//读取
int sd_file_seek(void *file, u32 offset);//指定读取的偏移地址,offset:相对文件起始地址的偏移

demo
imageimage 3. 其他文件接口 见:\SDK\interface\utils\fs\fs.h

opus数据解码测试APP

【金山文档 | WPS云文档】 OPUS解码工具.rar
OPUS解码工具.rar
将编码文件(保证后缀是.opus),放到手机如下文件夹
imageimageimage

image 从手机中提取PCM数据
image

opus数据编码解码APP demo

Android:杰理音频解码库开发资料_V2.0.0_Android.zip
IOS:opus解码 v1.1.1_Beta2_2024_09_29.zip

发数速率提升方法

SPP:以512字节为单位发数效率最高。实测速率 120-227KB/s
BLE:关于提升BLE传输速率说明.pdf,改MTU:https://gitee.com/Jieli-Tech/fw-AC63_BT_SDK/issues/I59IL3

本文档包含以下子页面

Prev
资源优化(可视化SDK)
Next
耳机抗干扰问题排查和优化