目录
- 一、概述
- 二、main 函数解析
- 三、main_inner 函数解析
- 四、sample_audio_ai_ao 函数解析
- 4.1 Audio Codec相关配置
- 4.2 sample_audio_ai_ao 函数简析
- 4.3 sample_audio_ai_ao 的 sample_audio_ai_ao_init_param 函数
- 4.4 sample_audio_ai_ao 的 sample_comm_audio_start_ai 函数
- 五
一、概述
上篇文章 【海思SS528】MPP媒体处理软件V5.0 | 音频模块 – 学习笔记 学习了海思MPP媒体处理平台的一小部分音频知识,这篇文章继续学习与音频相关的例程,这样可以更好理解《MPP 媒体处理软件 V5.0 开发参考.pdf》中的音频模块知识。
本篇文章涉及到的SDK文件及路径说明:
- 《MPP 媒体处理软件 V5.0 开发参考.pdf》:在SDK的路径为
SS528ReleaseDoc\software\board\MPP
- 《22AP30 H.265编解码处理器用户指南.pdf》:在SDK的路径为
SS528ReleaseDoc\hardware\chip
- sample_audio.c :在SDK的路径为
SS528V100_SDK_V2.0.0.3/mpp/sample/audio/sample_audio.c
二、main 函数解析
先看 main 函数,主要做了以下工作:
- 判断程序输入参数,错误的话,就打印程序功能及用法;
- 初始化系统和VB:sample_comm_sys_init
- 初始化 AAC 编码和解码:hi_mpi_aenc_aac_init、hi_mpi_adec_aac_init
- 根据输入参数,调用对应例子:main_inner
- 退出程序时的反初始化:hi_mpi_aenc_aac_deinit、hi_mpi_adec_aac_deinit、sample_comm_sys_exit
从main函数来看,主要的内容在
main_inner
函数。下面是main函数的代码:
/* function : main */#ifdef __LITEOS__hi_s32 app_main(int argc, char *argv[])#elsehi_s32 main(int argc, char *argv[])#endif{hi_s32 ret;hi_vb_cfg vb_conf;hi_u32 index;if (argc != 2) {/* 2:argv num */sample_audio_usage();return HI_FAILURE;}if (!strncmp(argv[1], "-h", 2)) { /* 2:arg num */sample_audio_usage();return HI_FAILURE;}if ((strlen(argv[1]) != 1) ||(argv[1][0] < '0' || argv[1][0] > '6')) { /* 6:arg num */sample_audio_usage();return HI_FAILURE;}index = atoi(argv[1]);sample_sys_signal(&sample_audio_handle_sig);#if defined(OT_VQE_USE_STATIC_MODULE_REGISTER)ret = sample_audio_register_vqe_module();if (ret != HI_SUCCESS) {return HI_FAILURE;}#endifret = memset_s(&vb_conf, sizeof(hi_vb_cfg), 0, sizeof(hi_vb_cfg));if (ret != EOK) {printf("%s: vb_config init failed with %d!\n", __FUNCTION__, ret);return HI_FAILURE;}ret = sample_comm_sys_init(&vb_conf);if (ret != HI_SUCCESS) {printf("%s: system init failed with %d!\n", __FUNCTION__, ret);return HI_FAILURE;}hi_mpi_aenc_aac_init();hi_mpi_adec_aac_init();main_inner(index);hi_mpi_aenc_aac_deinit();hi_mpi_adec_aac_deinit();sample_comm_sys_exit();return ret;}
三、main_inner 函数解析
main_inner函数主要是根据程序输入的第二个参数来决定调用哪个例子,分别以下几种:
- sample_audio_ai_ao:从 AI 设备采集音频,然后从 AO 设备播放,最简单的一个例子;
- sample_audio_ai_aenc:从 AI 设备采集音频,然后进行编码写文件,最后再解码且从 AO 设备播放;
- sample_audio_adec_ao:从文件读取音频数据,解码,从 AO 设备播放;
- sample_audio_ai_vqe_process_ao:
- sample_audio_ai_hdmi_ao:
- sample_audio_ai_to_ao_sys_chn:
- sample_audio_ai_to_ext_resample:
这后面几个例子,还没使用,后面补充。2023-06-30 21:25:34
main_inner的代码如下,这也是没什么内容的一个函数。
static hi_void main_inner(hi_u32 index){switch (index) {case 0: { /* 0:ai->ao */sample_audio_ai_ao();break;}case 1: { /* 1:ai->aenc->adec->ao */sample_audio_ai_aenc();break;}case 2: { /* 2:file->adec->ao */sample_audio_adec_ao();break;}case 3: { /* 3:ai->ao vqe */sample_audio_ai_vqe_process_ao();break;}case 4: { /* 4:ai->ao hdmi */sample_audio_ai_hdmi_ao();break;}case 5: { /* 5:ai->ao synchn */sample_audio_ai_to_ao_sys_chn();break;}case 6: { /* 6:resample test */sample_audio_ai_to_ext_resample();break;}default: {break;}}}
四、sample_audio_ai_ao 函数解析
这是 sample_audio.c 的第一个例子,可以带我们 熟悉AI设备和AO设备的启用流程。
这个例子已经涉及到很多AI和AO的API函数了,需要对开发文档《MPP 媒体处理软件 V5.0 开发参考.pdf》中音频相关的API函数有一定了解,可以再阅读过程碰到不认识的API再去开发文档查询。
4.1 Audio Codec相关配置
正式阅读代码前,先看一下有关Audio Codec的相关配置,因为在初始化参数时会使用到,如果AIO参数没有配置好的话,可能出现各种问题。
我使用的板子没有使用内置的Audio Codec,而是使用 ES7243S 去做采集音频的模数转换,采样率、采集精度、声道是驱动工程师写驱动时写死的,而 sample_audio.c 的例子中提供了sample_comm_audio_cfg_acodec
对Audio codec进行设置的,不设置的话,程序一跑就退出了。根据我的情况,我用不上这个函数,所以要注释掉,并且配置AIO参数时,也配置好对应的采样率、采集精度、声道和AI设备号。我的采样率、采集精度、声道和AI设备号如下:
- 采样率:48kHz
- 采样精度:16bit
- 声道:双声道
- AI设备号:1
- AO设备号:0
AI、AO设备号的确定需要看自己板子电路图的Audio codec芯片接在
I2S0_SD_RX
,还是I2S1_SD_RX
,
接在I2S0_SD_RX
则对应AI设备号为 0;
接在I2S1_SD_RX
则对应AI设备号为 1;
下图是我的板子原理图,对应AI设备号为 1;
下图是接在AO的原理图,接在
I2S0_SD_TX
,对应的AO设备号为 0;
4.2 sample_audio_ai_ao 函数简析
这小节简单介绍 sample_audio_ai_ao 函数的基本内容:
- 初始化AIO参数:
sample_audio_ai_ao_init_param
,这个函数里的参数要配置对,下小节会介绍这函数。- 初始化vqe参数:
sample_audio_set_ai_vqe_param
,这个函数只是几个赋值,按照默认即可;- 启用AI设备:
sample_comm_audio_start_ai
,这个函数有启用AI的流程,需要学习;- 启用AO设备:
sample_comm_audio_start_ao
,这个函数有启用AO的流程,也需要学习;- 配置Audio codec:
sample_comm_audio_cfg_acodec
,这个不同板子不一样,我这里不需要,所以注释掉;- 绑定AI到AO:
sample_audio_ai_ao_inner
,使AI的音频帧发送到AO设备播放。- 其他:其他的是退出程序的一些工作,如:停止AO设备、停止AI设备等。
sample_audio_ai_ao 函数代码:
/* function : ai -> ao(with fade in/out and volume adjust) */hi_s32 sample_audio_ai_ao(hi_void){hi_s32 ret;hi_u32 ai_chn_cnt;hi_u32 ao_chn_cnt;hi_audio_dev ai_dev;hi_audio_dev ao_dev;const hi_ai_chn ai_chn = 0;const hi_ao_chn ao_chn = 0;hi_aio_attr aio_attr = {0};sample_comm_ai_vqe_param ai_vqe_param = {0};sample_audio_ai_ao_init_param(&aio_attr, &ai_dev, &ao_dev);/* enable AI channel */ai_chn_cnt = aio_attr.chn_cnt;sample_audio_set_ai_vqe_param(&ai_vqe_param, g_out_sample_rate, g_aio_resample, HI_NULL, 0);ret = sample_comm_audio_start_ai(ai_dev, ai_chn_cnt, &aio_attr, &ai_vqe_param, -1);if (ret != HI_SUCCESS) {sample_dbg(ret);goto ai_ao_err3;}/* enable AO channel */ao_chn_cnt = aio_attr.chn_cnt;ret = sample_comm_audio_start_ao(ao_dev, ao_chn_cnt, &aio_attr, g_in_sample_rate, g_aio_resample);if (ret != HI_SUCCESS) {sample_dbg(ret);goto ai_ao_err2;}/* config internal audio codec */ret = sample_comm_audio_cfg_acodec(&aio_attr);if (ret != HI_SUCCESS) {sample_dbg(ret);goto ai_ao_err1;}sample_audio_ai_ao_inner(ai_dev, ai_chn, ao_dev, ao_chn);ai_ao_err1:ret = sample_comm_audio_stop_ao(ao_dev, ao_chn_cnt, g_aio_resample);if (ret != HI_SUCCESS) {sample_dbg(ret);}ai_ao_err2:ret = sample_comm_audio_stop_ai(ai_dev, ai_chn_cnt, g_aio_resample, HI_FALSE);if (ret != HI_SUCCESS) {sample_dbg(ret);}ai_ao_err3:return ret;}
4.3 sample_audio_ai_ao 的 sample_audio_ai_ao_init_param 函数
sample_audio_ai_ao_init_param
函数主要是初始化AIO单元的参数,参数结构体的具体解析可以查看开发手册的hi_aio_attr
结构体。这里只介绍几个与Audio codec相关的参数,我的参数在上面 4.1 节有介绍。采样率sample_rate
、采样精度bit_width
、声道chn_cnt
,这三个参数根据自己 Audio Codec 配置即可,我的对应参数是 48KHZ、16bit、双声道 ;然后clk_share
参数,我选择0。
下面是我修改过AIO参数的代码,你可以参考自己Audio codec的情况,参考修改:
/** * @brief 初始化AIO模块参数 2023-06-30 09:55:01 ** @param aio_attr :输出变量,模块参数 * @param ai_dev :输出变量,传出AI设备号 * @param ao_dev :输出变量,传出AO设备号 * @return hi_void*/static hi_void sample_audio_ai_ao_init_param(hi_aio_attr *aio_attr, hi_audio_dev *ai_dev, hi_audio_dev *ao_dev){/** * 注意: * 1、采样率sample_rate、采样精度bit_width、声道chn_cnt,这三个参数根据自己 Audio Codec 配置即可,我的对应参数是 48KHZ、16bit、双声道* 2、AI设备号:需要看硬件原理图,如果采集音频接口最终接到 I2S0_BCLK ,则是第0个AI设备,设备号0;如果接到 I2S1_BCLK 则设备号 1。 **/ aio_attr->sample_rate = HI_AUDIO_SAMPLE_RATE_48000;//HI_AUDIO_SAMPLE_RATE_16000;aio_attr->bit_width = HI_AUDIO_BIT_WIDTH_16;aio_attr->work_mode = HI_AIO_MODE_I2S_SLAVE;//HI_AIO_MODE_I2S_MASTER;aio_attr->snd_mode= HI_AUDIO_SOUND_MODE_STEREO;aio_attr->expand_flag = 0;aio_attr->frame_num = 30; /* 30:frame num */aio_attr->point_num_per_frame = AACLC_SAMPLES_PER_FRAME;aio_attr->chn_cnt = 2; /* 2:chn cnt */*ai_dev = 1;//SAMPLE_AUDIO_EXTERN_AI_DEV;*ao_dev = SAMPLE_AUDIO_EXTERN_AO_DEV;aio_attr->clk_share= 0;//1;aio_attr->i2s_type = HI_AIO_I2STYPE_EXTERN;g_aio_resample = HI_FALSE;/* config ao resample attr if needed */if (g_aio_resample == HI_TRUE) {/* ai 48k -> 32k */g_out_sample_rate = HI_AUDIO_SAMPLE_RATE_32000;/* ao 32k -> 48k */g_in_sample_rate= HI_AUDIO_SAMPLE_RATE_32000;} else {g_in_sample_rate= HI_AUDIO_SAMPLE_RATE_BUTT;g_out_sample_rate = HI_AUDIO_SAMPLE_RATE_BUTT;}/* resample and anr should be user get mode */g_user_get_mode = (g_aio_resample == HI_TRUE) " />: HI_FALSE;}
4.4 sample_audio_ai_ao 的 sample_comm_audio_start_ai 函数
sample_comm_audio_start_ai
函数介绍了AI设备启用流程,可以学习后,应用到自己代码。基本流程如下:
- 1、设置 AI 设备属性:
hi_mpi_ai_set_pub_attr
,参数解释参考开发手册- 2、使能 AI 设备
- 3、启用 AI 通道
- 4、根据标志,判断是否启用 AI 重采样
- 5、使能AI的声音质量增强功能
五
如果文章有帮助的话,点赞、收藏⭐,支持一波,谢谢