Hi3519A播放ACC理解

硬件相关内容

ACC编解码器

海思平台内置了ACC编解码器。

音频接口

音频输入输出接口简称AIO(Audio Input/Output)接口,用于和Audio Codec对接,完成声音的录制和播放。AIO接口分为两种类型:只支持输入或只支持输出,当为输入类型时,又称为 AIP,当为输出类型时,又称为 AOP。

软件中负责抽象音频接口输入功能的单元,称之为 AI 设备;负责抽象音频接口输出功能的单元,称之为 AO 设备。

对每个输入输出接口,软件根据该接口支持的功能,分别与 AI 设备和 AO 设备建立映射关系。例如:AIP0 只支持音频输入,则 AIP0 映射为 AiDev0;AOP0 只支持音频输出,则 AOP0 映射为 AoDev0。

播放原理

芯片利用 DMA 将内存中的数据传输到 AO 设备。AO设备通过 I2S 时序或 PCM 时序向 Audio Codec 发送数据。Audio Codec 完成数字信号到模拟信号的转换过程,并输出模拟信号。示意图如下所示。

音频接口时序

支持标准 IIS 接口时序模式和 PCM 接口时序模式,并提供灵活的配置以支持与多种 Audio Codec 对接。详细的时序支持情况请参考对应芯片的用户指南。

AI、AO通道

Hi3519A播放ACC理解_第1张图片

API相关

音频相关的API都在HiMPP中。

音频 API 接口依赖 HI_MPI_SYS_Init 和 HI_MPI_SYS_Exit 的顺序调用,不支持异步调用 HI_MPI_SYS_Init 和 HI_MPI_SYS_Exit。

基本流程

1、创建独立线程。

2、先调用 HI_MPI_SYS_Init()。

3、调用音频相关的接口初始化,如 HI_MPI_ADEC_AacInit()。

4、打开fopen()音频文件。

5、读取文件。

6、发送frame到AO接口

....

n、出初始化时,需要先调用音频相关接口去初始化,如 HI_MPI_ADEC_AacDeInit(),再调用 HI_MPI_SYS_Exit()。

重点函数

和ACC解码相关的 API 函数名称基本为 HI_MPI_ADEC_xxxx(),包括如下几个。

HI_MPI_ADEC_CreateChn

创建音频解码通道。

HI_MPI_ADEC_DestoryChn

销毁音频解码通道。

HI_MPI_ADEC_SendStream

发送音频解码流到音频解码通道。

  • 创建解码通道时可以指定解码方式为 pack 方式或 stream 方式。
    • - pack 方式用于确定码流包为一帧的情况下,比如从 AENC 直接获取的码流,从文件读取确切知道一帧边界(语音编码码流长度固定,很容易确定边界)的码流,效率较高。
    • - stream 方式用于不确定码流包为一帧的情况下,效率较低,且可能会有延迟。
  • 支持阻塞或非阻塞方式发送码流。
  • 当阻塞方式发送码流时,如果用于缓存解码后的音频帧的 Buffer 满,则此接口调用会被阻塞,直至解码后的音频帧数据被取走,或 ADEC 通道被销毁。

【参数】

AdChn 通道号。
取值范围:[0, ADEC_MAX_CHN_NUM)。
输入
pstStream 音频码流。 输入
bBlock 阻塞标识。
HI_TRUE:阻塞。
HI_FALSE:非阻塞。

HI_MPI_ADEC_ClearChnBuf

清除 ADEC 通道中当前的音频数据缓存。

HI_MPI_ADEC_RegisterDecoder

注册解码器。

HI_MPI_ADEC_UnRegisterDecoder

注销解码器。

HI_MPI_ADEC_GetFrame

获取音频解码帧数据。

HI_MPI_ADEC_ReleaseFrame

释放音频解码帧数据。

HI_MPI_ADEC_SendEndOfStream

向解码器发送码流结束标志符,并清除码流Buffer。

数据结构

AIO_ATTR_S

定义音频输入输出设备属性结构体。

typedef struct hiAIO_ATTR_S {
    AUDIO_SAMPLE_RATE_E enSamplerate; /*sample rate*/
    AUDIO_BIT_WIDTH_E enBitwidth; /*bitwidth*/
    AIO_MODE_E enWorkmode; /*master or slave mode*/
    AUDIO_SOUND_MODE_E enSoundmode; /*momo or steror*/
    HI_U32 u32EXFlag; /*expand 8bit to 16bit */
    HI_U32 u32FrmNum; /*frame num in buffer*/
    HI_U32 u32PtNumPerFrm; /*number of samples*/
    HI_U32 u32ChnCnt;
    HI_U32 u32ClkSel;
    AIO_I2STYPE_E enI2sType;
}AIO_ATTR_S;
enSamplerate 音频采样率(从模式下,此参数不起作用)。
静态属性。
enBitwidth 音频采样精度(从模式下,此参数必须和音频 AD/DA 的采样精
度匹配)。
静态属性。
enWorkmode 音频输入输出工作模式。
静态属性。
enSoundmode 音频声道模式。
静态属性。
u32EXFlag 取值范围:{0, 1, 2}。
 0:不扩展。
 1:扩展成 16 位,8bit 到 16bit 扩展标志(只对 AI 采样精度为
8bit 时有效)。
 2:24 位裁剪成 16 位,在外置 Codec 的场景下可能用到。
静态属性,保留参数,一般设置成 1 即可。
u32FrmNum 缓存帧数目。
取值范围:[2, MAX_AUDIO_FRAME_NUM]。
静态属性。
u32PtNumPerFrm 每帧的采样点个数。
取值范围:G711、G726、ADPCM_DVI4 编码时取值为 80、
160、240、320、480;ADPCM_IMA 编码时取值为 81、161、
241、321、481。
AI 取值范围为:[80, 2048],AO 取值范围为:[80, 4096]。
静态属性。
u32ChnCnt 支持的通道数目。
取值:1、2、4、8、16。
(输入最多支持 AIO_MAX_CHN_NUM 个通道,输出最多支持 2
个通道)。
u32ClkSel 配置 AI 设备 0 是否复用 AO 设备 0 的帧同步时钟及位流时钟。
取值:0、1。
0:不复用;
1:复用。
enI2sType 配置设备 I2S 类型 (仅
Hi3559AV100/Hi3519AV100/Hi3516CV500/Hi3516EV200 支持该
参数)。
AI 取值:AIO_I2STYPE_INNERCODEC,
AIO_I2STYPE_EXTERN
AO 取值:AIO_I2STYPE_INNERCODEC,
AIO_I2STYPE_EXTERN,AIO_I2STYPE_INNERHDMI。
静态属性。

ADEC_CHN_ATTR_S

定义解码通道属性结构体。

typedef struct hiADEC_CH_ATTR_S {
    PAYLOAD_TYPE_E enType;
    HI_U32 u32BufSize;
    ADEC_MODE_E enMode;
    HI_VOID ATTRIBUTE *pValue;
} ADEC_CHN_ATTR_S;
enType 音频解码协议类型。
静态属性。
u32BufSize 音频解码缓存大小。
取值范围:[2, MAX_AUDIO_FRAME_NUM],以帧为单位。
静态属性。
enMode 解码方式。
静态属性。
pValue 具体协议属性指针。

简单样例

来自海思 SDK 的 Sample 。

/******************************************************************************
* function : get stream from file, and send it  to Adec
******************************************************************************/
void *SAMPLE_COMM_AUDIO_AdecProc(SAMPLE_ADEC_S *pstAdec)
{
    HI_S32 s32Ret;
    AUDIO_STREAM_S stAudioStream;
    HI_U32 u32Len = 2048;
    HI_U32 u32ReadLen;
    HI_S32 s32AdecChn;
    HI_U8 *pu8AudioStream = NULL;
    SAMPLE_ADEC_S *pstAdecCtl = (SAMPLE_ADEC_S *)pstAdec;
    AO_CHN_STATE_S pstStatus;
    FILE *pfd = pstAdecCtl->pfd;
    s32AdecChn = pstAdecCtl->AdChn;
 
    pu8AudioStream = (HI_U8*)malloc(sizeof(HI_U8)*MAX_AUDIO_STREAM_LEN);
 
    if (NULL == pu8AudioStream)
    {
        printf("%s: malloc failed!\n", __FUNCTION__);
        return NULL;
    }
 
    while (HI_TRUE == pstAdecCtl->bStart)
    {
        /* read from file */
        stAudioStream.pStream = pu8AudioStream;
        u32ReadLen = fread(stAudioStream.pStream, 1, u32Len, pfd);
        if (u32ReadLen <= 0)
        {
            /*
            s32Ret = HI_MPI_ADEC_SendEndOfStream(s32AdecChn, HI_FALSE);
            if (HI_SUCCESS != s32Ret)
            {
                printf("%s: HI_MPI_ADEC_SendEndOfStream failed!\n", __FUNCTION__);
            }
            fseek(pfd, 0, SEEK_SET);
            */
            printf("u32ReadLen <= 0 break! s32Ret:%d \n",s32Ret);
            break;
        }
 
        /* here only demo adec streaming sending mode, but pack sending mode is commended */
        stAudioStream.u32Len = u32ReadLen;
        s32Ret = HI_MPI_ADEC_SendStream(s32AdecChn, &stAudioStream, HI_TRUE);
        if(HI_SUCCESS != s32Ret)
        {
            printf("%s: HI_MPI_ADEC_SendStream(%d) failed with %#x!\n",\
                   __FUNCTION__, s32AdecChn, s32Ret);
            //break;
        }
        usleep(1000*10);
    }
 
    while (HI_TRUE == pstAdecCtl->bStart)
    {
        s32Ret = HI_MPI_AO_QueryChnStat(0, 0,&pstStatus);
        //printf("pstStatus.u32ChnBusyNum: %d\n",pstStatus.u32ChnBusyNum);
        if(pstStatus.u32ChnBusyNum < 1)
        {
            s32Ret = HI_MPI_ADEC_SendEndOfStream(s32AdecChn, HI_FALSE);
            if (HI_SUCCESS != s32Ret)
            {
                printf("%s: HI_MPI_ADEC_SendEndOfStream failed!\n", __FUNCTION__);
            }
            break;
        }
        sleep(1);
    }
 
 
    free(pu8AudioStream);
    pu8AudioStream = NULL;
    fclose(pfd);
    pstAdecCtl->bStart = HI_FALSE;
    return NULL;
}

/******************************************************************************
* function : Create the thread to get stream from file and send to adec
******************************************************************************/
HI_S32 SAMPLE_COMM_AUDIO_CreatTrdFileAdec(ADEC_CHN AdChn, FILE *pAdcFd) {
    SAMPLE_ADEC_S *pstAdec = NULL;
 
    if (NULL == pAdcFd)
    {
        return HI_FAILURE;
    }
 
    pstAdec = &gs_stSampleAdec[AdChn];
    pstAdec->AdChn = AdChn;
    pstAdec->pfd = pAdcFd;
    pstAdec->bStart = HI_TRUE;
    //pthread_create(&pstAdec->stAdPid, 0, SAMPLE_COMM_AUDIO_AdecProc, pstAdec);
    SAMPLE_COMM_AUDIO_AdecProc(pstAdec);
 
    return HI_SUCCESS;
}

HI_S32 main(int argc, char *argv[]) {
    char ch;
    HI_S32 s32Ret= HI_SUCCESS;
    AIO_ATTR_S stAioAttr;
 
    /* init stAio. all of cases will use it */
    memset(&stAioAttr, 0, sizeof(AIO_ATTR_S));
    stAioAttr.enBitwidth = AUDIO_BIT_WIDTH_16;
    stAioAttr.enWorkmode = AIO_WORK_MODE;
    stAioAttr.enSoundmode = AUDIO_SOUND_MODE_MONO;
    stAioAttr.u32EXFlag = 0;
    stAioAttr.u32FrmNum = 30;
    stAioAttr.u32ChnCnt = 1;
#ifdef HI_ACODEC_TYPE_TLV320AIC31
    stAioAttr.u32ClkSel = 1;
#else
    stAioAttr.u32ClkSel = 0;
#endif
 
    stAioAttr.enSamplerate = AUDIO_SAMPLE_RATE_8000;
    stAioAttr.u32PtNumPerFrm = (AAC_TYPE_AACLC == gs_enAacType) ? 1024 : 2048;
 
    //signal(SIGINT, SAMPLE_AUDIO_HandleSig);
    //signal(SIGTERM, SAMPLE_AUDIO_HandleSig);
 
    s32Ret = SAMPLE_COMM_SYS_Init();
    if (HI_SUCCESS != s32Ret) {
        printf("%s: system init failed with %d!\n", __FUNCTION__, s32Ret);
        return HI_FAILURE;
    }
 
    /* register aac encoder and decoder */
    HI_MPI_ADEC_AacInit();
 
    s32Ret = SAMPLE_AUDIO_AdecAo(argv[1],&stAioAttr);/* read audio stream from file,decode and send AO*/
 
    if (s32Ret != HI_SUCCESS) {
 
    }
 
    SAMPLE_COMM_SYS_Exit();
 
    return HI_SUCCESS;
}

 

你可能感兴趣的:(Hi3519A)