1.T31芯片音频支持的功能
音频功能包含音频输入,音频输出,回音消除,音频编码和音频解码 5 个模块。
其中音频输入和音频输出存在设备和通道的概念。其中一个 MIC 认为是一个 Device,而一个 MIC 可以有多路 Channel 输入。同样的一个 SPK 认为是一个放音 Device, 而一个 SPK 也可以有多路 Channel 输出。当前版本的音频 API 一个 Device 只支持一个 Channel。 (T31只一路输入和一路输出)
回音消除位于音频输入接口中,具体说明在功能描述中体现。
2.主流的音频格式和T31支持的音频格式
2.1.主流的音频格式:(音视频常用到的音频格式)
PCM:大部分芯片出来的原始音频数据流。
G711A&G711U:
G711是国际电信联盟ITU-T定制出来的一套语音压缩标准,它代表了对数PCM(logarithmic pulse-code modulation)抽样标准,主要用于电话。它主要用脉冲编码调制对音频采样,采样率为8k每秒。它利用一个 64Kbps 未压缩通道传输语音讯号。 起压缩率为1:2, 即把16位数据压缩成8位。G.711是主流的波形声音编解码器。
G.711 标准下主要有两种压缩算法。一种是u-law algorithm (又称often u-law, ulaw, mu-law),主要运用于北美和日本;另一种是A-law algorithm,主要运用于欧洲和世界其他地区。其中,后者是特别设计用来方便计算机处理的
G711的内容是将14bit(uLaw)或者13bit(aLaw)采样的PCM数据编码成8bit的数据流,播放的时候在将此8bit的数据还原成14bit或者13bit进行播放,不同于MPEG这种对于整体或者一段数据进行考虑再进行编解码的做法,G711是波形编解码算法,就是一个sample对应一个编码,所以压缩比固定为:
8/14 = 57% (uLaw)
8/13 = 62% (aLaw) 简单理解,G.711就是语音模拟信号的一种非线性量化, bitrate 是64kbps
AAC:
AAC,全称Advanced Audio Coding,中文名:高级音频编码,是一种专为声音数据设计的文件压缩格式。与MP3不同,它采用了全新的算法进行编码,更加高效,具有更高的“性价比”。利用AAC格式,可使人感觉声音质量没有明显降低的前提下,更加小巧。苹果ipod、诺基亚手机支持AAC格式的音频文件。
2.2.T31目前支持的音频格式
音频编码当前音频 API 中支持 PT_G711A、PT_G711U 和 PT_G726 格式音频编码,
如需要增加新的编码方式,需要注册编码器。
音频解码当前音频 API 中支持 PT_G711A、PT_G711U 和 PT_G726 格式音频解码,
如需要增加新的解码方式,需要注册解码器。
3.代码框架流程图
以下我们画出系统的流程图:音频采集的过程图
MIC指带的东西就是咪头,用来把外界的声音采集进来,采集模拟信号进来,通过T31芯片转成数字信号,再以一定格式的内容保存成文件下来。
4.代码实战
君正T31SDK里面提供了sample,关于如何从T31芯片获取音频裸数据,并保存到flash中的代码。
里面有几个函数需要重点讲解一下:
4.1:创建线程
_ai_basic_record_test_thread:我们所有的操作都是在这个线程里面运行的,你们可以理解为一个任务。
4.2:设置音频输入设备属性
IMP_AI_SetPubAttr:
代码语言:javascript复制 int devID = 1; //devID:0:数字MIC,1:代表模拟MIC
IMPAudioIOAttr attr;
attr.samplerate = AUDIO_SAMPLE_RATE_16000; //音频采样率为16000
attr.bitwidth = AUDIO_BIT_WIDTH_16; //音频采样精度16位
attr.soundmode = AUDIO_SOUND_MODE_MONO; //采取单声道模式
attr.frmNum = 40; //缓存帧的数目
attr.numPerFrm = 640; //每帧的采样点个数
attr.chnCnt = 1; //支持的通道个数
ret = IMP_AI_SetPubAttr(devID, &attr);
4.3:获取音频原始桢数据
代码语言:javascript复制 /* Step 6: get audio record frame. */
/*在使用IMP_AI_GetFrame之前使用该接口,当该接口调用成功之后表示音频
数据已经准备完毕,可以使用IMP_AI_GetFrame获取音频数据*/
ret = IMP_AI_PollingFrame(devID, chnID, 1000);
if (ret != 0 ) {
IMP_LOG_ERR(TAG, "Audio Polling Frame Data errorn");
}
/*
* @param[in] audioDevId 音频设备号.
* @param[in] aiChn 音频输入通道号.
* @param[out] frm 音频帧结构体指针.
* @param[in] block 阻塞/非阻塞标识.
*/
IMPAudioFrame frm;
ret = IMP_AI_GetFrame(devID, chnID, &frm, BLOCK);
if(ret != 0) {
IMP_LOG_ERR(TAG, "Audio Get Frame Data errorn");
return NULL;
}
/* Step 8: release the audio record frame. */
ret = IMP_AI_ReleaseFrame(devID, chnID, &frm);
if(ret != 0) {
IMP_LOG_ERR(TAG, "Audio release frame data errorn");
return NULL;
}
4.4:君正原始SDK的DEMO程序
代码语言:javascript复制/*
* Ingenic IMP AI implement.
*
* Copyright (C) 2017 Ingenic Semiconductor Co.,Ltd
*
*/
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/time.h>
#include <imp/imp_audio.h>
#include <imp/imp_log.h>
#define TAG "Sample-AI"
#define AI_BASIC_TEST_RECORD_FILE "ai_lbb.pcm"
#define AI_BASIC_TEST_RECORD_NUM 600
static void *_ai_basic_record_test_thread(void *argv)
{
int ret = -1;
int record_num = 0;
FILE *record_file = fopen(AI_BASIC_TEST_RECORD_FILE, "wb");
if(record_file == NULL) {
IMP_LOG_ERR(TAG, "fopen %s failedn", AI_BASIC_TEST_RECORD_FILE);
return NULL;
}
/* Step 1: set public attribute of AI device. */
int devID = 1;
IMPAudioIOAttr attr;
attr.samplerate = AUDIO_SAMPLE_RATE_16000;
attr.bitwidth = AUDIO_BIT_WIDTH_16;
attr.soundmode = AUDIO_SOUND_MODE_MONO;
attr.frmNum = 40;
attr.numPerFrm = 640;
attr.chnCnt = 1;
ret = IMP_AI_SetPubAttr(devID, &attr);
if(ret != 0) {
IMP_LOG_ERR(TAG, "set ai %d attr err: %dn", devID, ret);
return NULL;
}
memset(&attr, 0x0, sizeof(attr));
ret = IMP_AI_GetPubAttr(devID, &attr);
if(ret != 0) {
IMP_LOG_ERR(TAG, "get ai %d attr err: %dn", devID, ret);
return NULL;
}
IMP_LOG_INFO(TAG, "Audio In GetPubAttr samplerate : %dn", attr.samplerate);
IMP_LOG_INFO(TAG, "Audio In GetPubAttr bitwidth : %dn", attr.bitwidth);
IMP_LOG_INFO(TAG, "Audio In GetPubAttr soundmode : %dn", attr.soundmode);
IMP_LOG_INFO(TAG, "Audio In GetPubAttr frmNum : %dn", attr.frmNum);
IMP_LOG_INFO(TAG, "Audio In GetPubAttr numPerFrm : %dn", attr.numPerFrm);
IMP_LOG_INFO(TAG, "Audio In GetPubAttr chnCnt : %dn", attr.chnCnt);
/* Step 2: enable AI device. */
ret = IMP_AI_Enable(devID);
if(ret != 0) {
IMP_LOG_ERR(TAG, "enable ai %d errn", devID);
return NULL;
}
/* Step 3: set audio channel attribute of AI device. */
int chnID = 0;
IMPAudioIChnParam chnParam;
chnParam.usrFrmDepth = 40;
ret = IMP_AI_SetChnParam(devID, chnID, &chnParam);
if(ret != 0) {
IMP_LOG_ERR(TAG, "set ai %d channel %d attr err: %dn", devID, chnID, ret);
return NULL;
}
memset(&chnParam, 0x0, sizeof(chnParam));
ret = IMP_AI_GetChnParam(devID, chnID, &chnParam);
if(ret != 0) {
IMP_LOG_ERR(TAG, "get ai %d channel %d attr err: %dn", devID, chnID, ret);
return NULL;
}
IMP_LOG_INFO(TAG, "Audio In GetChnParam usrFrmDepth : %dn", chnParam.usrFrmDepth);
/* Step 4: enable AI channel. */
ret = IMP_AI_EnableChn(devID, chnID);
if(ret != 0) {
IMP_LOG_ERR(TAG, "Audio Record enable channel failedn");
return NULL;
}
/* Step 5: Set audio channel volume. */
int chnVol = 60;
ret = IMP_AI_SetVol(devID, chnID, chnVol);
if(ret != 0) {
IMP_LOG_ERR(TAG, "Audio Record set volume failedn");
return NULL;
}
ret = IMP_AI_GetVol(devID, chnID, &chnVol);
if(ret != 0) {
IMP_LOG_ERR(TAG, "Audio Record get volume failedn");
return NULL;
}
IMP_LOG_INFO(TAG, "Audio In GetVol vol : %dn", chnVol);
int aigain = 28;
ret = IMP_AI_SetGain(devID, chnID, aigain);
if(ret != 0) {
IMP_LOG_ERR(TAG, "Audio Record Set Gain failedn");
return NULL;
}
ret = IMP_AI_GetGain(devID, chnID, &aigain);
if(ret != 0) {
IMP_LOG_ERR(TAG, "Audio Record Get Gain failedn");
return NULL;
}
IMP_LOG_INFO(TAG, "Audio In GetGain gain : %dn", aigain);
while(1) {
/* Step 6: get audio record frame. */
ret = IMP_AI_PollingFrame(devID, chnID, 1000);
if (ret != 0 ) {
IMP_LOG_ERR(TAG, "Audio Polling Frame Data errorn");
}
IMPAudioFrame frm;
ret = IMP_AI_GetFrame(devID, chnID, &frm, BLOCK);
if(ret != 0) {
IMP_LOG_ERR(TAG, "Audio Get Frame Data errorn");
return NULL;
}
printf("seq = %d,timeStamp = %lldn",frm.seq,frm.timeStamp);
/* Step 7: Save the recording data to a file. */
fwrite(frm.virAddr, 1, frm.len, record_file);
/* Step 8: release the audio record frame. */
ret = IMP_AI_ReleaseFrame(devID, chnID, &frm);
if(ret != 0) {
IMP_LOG_ERR(TAG, "Audio release frame data errorn");
return NULL;
}
if( record_num >= AI_BASIC_TEST_RECORD_NUM)
break;
}
sleep(3);
/* Step 9: disable the audio channel. */
ret = IMP_AI_DisableChn(devID, chnID);
if(ret != 0) {
IMP_LOG_ERR(TAG, "Audio channel disable errorn");
return NULL;
}
/* Step 10: disable the audio devices. */
ret = IMP_AI_Disable(devID);
if(ret != 0) {
IMP_LOG_ERR(TAG, "Audio device disable errorn");
return NULL;
}
fclose(record_file);
pthread_exit(0);
}
int main(void)
{
int ret = -1;
pthread_t record_thread_id;
printf("[INFO] Test 1: Start audio record test.n");
printf("[INFO] : Can create the %s file.n", AI_BASIC_TEST_RECORD_FILE);
printf("[INFO] : Please input any key to continue.n");
getchar();
/* Step 1: Start audio recording thread. */
ret = pthread_create(&record_thread_id, NULL, _ai_basic_record_test_thread, NULL);
if(ret != 0) {
IMP_LOG_ERR(TAG, "[ERROR] %s: pthread_create Audio Record failedn", __func__);
return -1;
}
pthread_join(record_thread_id, NULL);
return 0;
}