AudioCalibrator_V2.3.7 的使用及音频文件处理方法

作者:周维华
前言:
在AudioCalibrator_V2.3.7的readme 目录就有《音频实时校准工具用户指南_V1.2.pdf》
这是RDA 官方的文档(后面简称:“RDA文档”)。即使仔细阅读,也是步步艰难。 几次想认真研究下这个工具到底怎么用,奈何悟性不够,以至疲于各种ERROR 提示;得益于金总和国良的指点,总算能让工具正常的跑起来, 此音频工具能调节的参数非常多,我这里就挑重点讲解下如何成功的读取和设置参数到模块,作为抛砖引玉,让大家能顺利的使用此工具(工具在下面的“音频工具包”中能下载)。

一.使用工具的目的

目前合宙的AT指令对音量控制的,只有这两个指令

通话音量控制:AT+CLVL
本地音频播放音量控制:AT+CRSL
实际和声音相关的参数非常多如校准,滤波,均衡,动态,回音等等,客户的产品有涉及到语音的大概率需要调节这些参数(也有不少默认的就满足客户要求,这跟产品的设计结构电路也有关系),所以这里就是要告诉大家怎么来使用这个工具,远离工具异常提示。

二.工具运行所需环境

有几个前提条件:

1.合宙CAT1模块的USB 驱动程序要先安装:

http://openluat-luatcommunity.oss-cn-hangzhou.aliyuncs.com/attachment/20200808183454135_sw_file_20200303181718_8910_module_usb_driver_signed%20_20200303_hezhou.7z
音频工具包:
http://openluat-luatcommunity.oss-cn-hangzhou.aliyuncs.com/attachment/20200814120426598_%E9%9F%B3%E9%A2%91%E5%8F%82%E6%95%B0%E4%B8%8B%E8%BD%BD.rar

2.设备USB 接到电脑,并且设备开机,WINDOWS 会识别到USB的虚拟串口。

undefined

不同机器串口COMxx 序号可能不同,只要看到”LUAT USB Device 1 AT” 的就可以。
3.RDA 音频工具包解压后,无需安装, 双击AudioCalibrator.exe 即可运行,进到主界面后有几个重要的配置点:
undefined
A. 配置串口,就选 LUAT USB Device 1 AT 的串口,也就是COM14即可:
undefined
B. 点击 绿色三角形,启动串口。
C. 选择平台 8910-UNI
D. 选择版本 ca020109
E. 点击”GetAll” 按钮,可以读出模块内的音频参数。
注意:上面的ABCDE 条件中,首次操作循序是:ACDBE,后面基本就是B或E用的多些。
如果B或E这一步过不去,就不需要往下看,先确保虚拟串口不要被其他串口工具或者
LUAT TOOL给占用了,排查,直到能连上。
****这里有个非常规的可能: 就是二次开发固件截获了USBDATA,导致USB的
虚拟串口并非真正的AT默认功能,这一点需要跟当事软件工程师确认好。

4.读出模块内的音频参数后,界面如下:

undefined

三.调节参数

参数这么多,到底要调节那些呢,我们可以先用实际产品做个归类,下面的Test Setting
会为我们分出大类:

undefined

1.比如数字对讲机:

放音部分选 APMode Sel 就选 “1 Music Play”,
录音部分选 “2 Music Record”

2.比如传统商话或者学生卡

喇叭部分 APMode Sel 就选 “0:Voice Call NB”窄带,
或者 “5:Voice Call WB”宽带
MIC部分 “0: HandSet” 或者 “1: HandFree”
***注意,MIC部分好说,硬件怎么设计就怎么选,喇叭或者听筒部分那就真的是坑!主要有两点:
A.此参数不在通话的时候是无法调节的,只有边通话边调试。
undefined
B.真正通话的时候,到底是宽带还是窄带,目前看也很随机,但是经过
反复琢磨也能找到方法: 那就是通话之后,先尝试窄带0:Voice Call NB:
undefined

如果点击“Send Cmd” 没有错误提示,并且“条目下参数列表”会清空,
就说明当前语音通道,是可以被调节的,于是重新选择要修改的条目,具体
修改相关值,然后再“Send Cmd”写入,模块可以即刻生效,然后点击“Write to Flash”按钮,存到FLASH 。

如果在窄带,写入数据弹出类似”ERROR 59”的错误,则说明当前通话在宽带
用同样的方式去尝试5:Voice Call WB, 二选一必定有一个是能调节的。
***这里要说明下: 上面说通话时窄带宽带很随机,并非真的随机,而是对方手机 的VOLTE高清通话是否打开了,如果开了就是宽带WB;如果没有开就是窄带NB,由于我们并不知道对方手机处于什么设置,所以打给不同的用户看起来有点随机。

3.ITF Sel 实际上就是语音通道,根据硬件设计来选就可以了

4.关于上图中“要修改的条目”,有几个条目是我们常用的:

atctst_aud_codec_get_ingain 可以理解成:MIC 增益调节
atctst_aud_codec_get_outgain可以理解成:喇叭/听筒增益
更多的条目,可以参考 RDA文档。

四.生成参数文件

参数调节好了之后,需要生成音频文件,因为这种参数工具只能针对几台机器做升级,

并不适合量产,所以我们在成功设置了参数之后, 可以点击”Export from FLASH” 来将模块内的音频参数导出到电脑上,默认文件格式是 cfp
undefined
但是这个文件,并不能被AT, LUAT CSDK 所接受,需要转换成BIN 文件:
undefined
点击工具条上的 BIN=CFP 互转的工具,可以将CFP 文件转换成BIN 文件。
undefined
文件大小固定就是10372字节。(就目前RDA的CAT1方案而言)

音频文件的更新原理:
1 首先要在模块的磁盘上创建一个目录:/usernvm 这个是固定名称。
2. /usernvm目录下先后创建两个固定文件
A.音频实体文件user_audio_calib.bin,就是音频文件的长度(4字节小端) 加上音频文件的内容 LEN[4] + DATA[10372]
B.音频标志文件 user_audio_calib_flag.bin 就是设置一个标志。
3.目录和文件都就绪后,重启模块后一个正确的音频实体文件会被模块“吸纳”,
并且/usernvm找不到它(指实体文件),然而user_audio_calib_flag.bin 标志文件仍然健在—–
就说明更新成功了,用户可以用RDA 音频工具读出来,生成另一个BIN 文件做比较。

五.AT固件更新音频文件

创建目录:AT+FSMKDIR. 创建 usernvm 目录
创建文件:AT+FSCREATE 分别创建音频实体文件和标志文件
写文件:AT+FSWRITE 分别写入音频实体文件和标志文件(标志文件固定写 “1” ,一个字符)
重启 :AT+RESET 重启模块
读文件:AT+FSREAD 分别读取音频实体文件和标志文件,根据上述更新原理判断是否更新成功, 下面是AT 指令的实际流程:

AT+FSLS=”" (此命令非必要,方便用户知道下模块内的目录层级)
nvm
modemnvm
usernvm
fota
C:
AMNV_CT11_000
AMNV_CT08_001
AMNV_CT12_000
AMNV_CT15_000
AMNV_CT48_000
AMNV_CT49_000
AMNV_CT13_000
AMNV_CT28_000
AMNV_CT01_000
AMNV_CT02_000
sms_dm_nv.bin
OK

AT+FSMKDIR=”\usernvm”
OK

AT+FSCREATE=”\usernvm\user_audio_calib.bin”
OK

AT+FSCREATE=”\usernvm\user_audio_calib_flag.bin”
OK

AT+FSWRITE=”\usernvm\user_audio_calib_flag.bin”,0,1,300
>
1
OK

AT+FSWRITE=”\usernvm\user_audio_calib.bin”,0,4,300
>
ABCD (实际数据就是 LEN[4] + DATA[10372])
OK

AT+FSLS=”\usernvm” (此命令非必要,只是方便用户查看是否真的写入了两个文件)
user_audio_calib.bin
user_audio_calib_flag.bin
OK

AT+RESET

//下面重启模块后如果格式正确,user_audio_calib.bin会被模块取走。 可以列举\usernvm” 的所有文件。
//如果标志文件在, 音频文件不在了,就说明更新成功

AT+FSLS=”\usernvm” (如果用了这个指令,后面分别 FSREAD 两个文件可以忽略)
user_audio_calib.bin
user_audio_calib_flag.bin
OK

AT+FSREAD=”\usernvm\user_audio_calib.bin”,0,100,0
ABCD
OK

AT+FSREAD=”\usernvm\user_audio_calib_flag.bin”,0,100,0
1
OK

六.LUAT 固件更新音频文件

(audio_calib.bin 就是10372 字节的音频文件)
module(…,package.seeall)

require”utils”
sys.taskInit(function()
    local USERNVM_DIR = “/usernvm”
    local USERNVM_AUDIOCALIB_FILE_PATH = USERNVM_DIR..”/user_audio_calib.bin”
    local USERNVM_AUDIOCALIB_SET_FILE_PATH = USERNVM_DIR..”/user_audio_calib_flag.bin”
    if rtos.make_dir(USERNVM_DIR) then
        if io.exists(USERNVM_AUDIOCALIB_SET_FILE_PATH) then
            if io.exists(USERNVM_AUDIOCALIB_FILE_PATH) then
                log.error(“audioParam USERNVM_AUDIOCALIB_FILE_PATH error”,USERNVM_AUDIOCALIB_FILE_PATH)
            else
                log.info(“audioParam success”)
            end
        else
            os.remove(USERNVM_AUDIOCALIB_FILE_PATH)
            local userAudioParam = io.readFile(“/lua/audio_calib.bin”)
            io.writeFile(USERNVM_AUDIOCALIB_FILE_PATH,pack.pack(“<i”,userAudioParam:len()))
            io.writeFile(USERNVM_AUDIOCALIB_FILE_PATH,userAudioParam,”ab”)
            io.writeFile(USERNVM_AUDIOCALIB_SET_FILE_PATH,”1”)
            
            log.info(“audioParam write, restart later…”)
            sys.restart(“audioParam”)
        end
    else
        log.error(“audioParam make_dir error”,USERNVM_DIR)
    end
end)

七.CSDK 固件更新音频文件

CSDK 的更新稍微麻烦一点,因为CSDK 不像LUAT 那样自由的安放文件。
CSDK 可以将10372 字节的音频文件做成数组:
const unsigned char clib_data[] ={
0x09,0x01,0x02,0xCA,0x40,0x1F,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x40,0x00,0x40………

然后在应用代码中增加如下:

#include “am_openat.h”
#include “am_openat_fs.h”
#include “am_openat_system.h”
#include “am_openat_drv.h”
#include “string.h”
#include “iot_debug.h”

BOOL dir_create(char * dir)
{
return iot_fs_make_dir(dir, E_FS_ATTR_DEFAULT)>=0?TRUE:FALSE;
}
BOOL file_exist(char* file)
{
INT32 fd;
fd = iot_fs_open_file(file, FS_O_RDONLY);

if (fd >= 0)
{
    iot_fs_close_file(fd);
    return TRUE;
}
return FALSE;

}
BOOL file_delete(char* file)
{
INT32 err;
err = iot_fs_delete_file(file);
if (err < 0)
return FALSE;
return TRUE;
}

BOOL file_write(char* file, unsigned char * write_buff, int length)
{
INT32 fd;
INT32 write_len;
fd = iot_fs_open_file(file, FS_O_WRONLY|FS_O_CREAT);
if (fd < 0)
return FALSE ;
write_len = iot_fs_write_file(fd, write_buff, length);
if (write_len < 0)
return FALSE;
iot_fs_close_file(fd);
return TRUE;
}

void check_user_calib(char * pcalib,int length)
{
char * USERNVM_PATH =”/usernvm”;
char * USERNVM_AUDIOCALIB_FILE_PATH =”/usernvm/user_audio_calib.bin”;
char * USERNVM_AUDIOCALIB_SET_FILE_PATH =”/usernvm/user_audio_calib_flag.bin”;
if(dir_create(USERNVM_PATH))
{
if(file_exist(USERNVM_AUDIOCALIB_SET_FILE_PATH))
{
if(file_exist(USERNVM_AUDIOCALIB_FILE_PATH))
{
iot_debug_print(“audioParam USERNVM_AUDIOCALIB_FILE_PATH error,=%s”, USERNVM_AUDIOCALIB_FILE_PATH);
} else
{
iot_debug_print(“audioParam success”);
}
} else
{
file_delete(USERNVM_AUDIOCALIB_FILE_PATH);
char * pbuf = malloc(length +4);
memset(pbuf,0, length +4);

           // '<' 小字节序,最低有效字节优先,更低的字节有效位占据着更低地址的内存空间。

           pbuf[0]= (unsigned char)((length & 0x000000FF)>>0);
           pbuf[1]= (unsigned char)((length & 0x0000FF00)>>8);
           pbuf[2]= (unsigned char)((length & 0x00FF0000)>>16);
           pbuf[3]= (unsigned char)((length & 0xFF000000)>>24);
           memcpy(&pbuf[4],pcalib,length);

           if(file_write(USERNVM_AUDIOCALIB_FILE_PATH, pbuf, length+4))
           {
                pbuf[0]=1;
                pbuf[1]=0;
                if(file_write(USERNVM_AUDIOCALIB_SET_FILE_PATH, pbuf, 1))
                {
                    iot_debug_print("audioParam write, restart later... write file len=%d", length);
                    iot_os_sleep(3000);
                    iot_os_restart();
                }
                else
                {
                    iot_debug_print("audioParam write error =%s", USERNVM_AUDIOCALIB_SET_FILE_PATH);
                }
           }
           else
           {
               iot_debug_print("audioParam write error =%s", USERNVM_AUDIOCALIB_FILE_PATH);
           }
      }
 } else
 {
     iot_debug_print("audioParam make_dir error  =%s",USERNVM_PATH);
 }

}

/*
开机后 调用一次:
check_user_calib(clib_data,sizeof(clib_data));

 COOL TOOL 上可以查看日志关键字  audioParam,观察写入是否成功。
 上面关于CSDK 代码的MD 显示的不友好,COPY 文本就可以了。

*/
若有新的理解,接着更新。。。

上次更新 2021-01-28