Hi3518重生记(二)音频播放

(一)参考源码

首先需要注明,我们参考的源码是海思SDK的audio的demo,并不是某一个github的项目。本次采用的demo来自于SDK:

https://dl.openipc.org/SDK/HiSilicon/Hi3518Ev20X_16Cv200/

的Hi3518E_SDK_V1.0.4.0,其中mpp文件夹下就是各类源码demo。

我们找到sample下的audio,这个就是官方audio例程。

里面打包有4个demo,其中 SAMPLE_AUDIO_AdecAo 这个demo比较合适,因为摄像头一般就是读文件然后播音,不需要读取网络音频流,比较方便。

(二)启动流程

海思SDK启动流程:

1-对任何应用都需要启动SYS和VB部分功能:

HI_MPI_VB_Init()

 HI_MPI_SYS_Init()

2-对视频

获取/dev下的驱动文件的文件号:open()

启动摄像头部分功能:AE、AF、ISP,比如HI_MPI_ISP_MemInit,这些函数都在mpi_ae文件里,难道是after effect的意思?文档似乎没有说明。

设置VI属性:HI_MPI_VI_SetDevAttr、HI_MPI_VI_SetWDRAttr、HI_MPI_VI_EnableDev

设置VI通道:HI_MPI_VI_SetChnAttr、HI_MPI_VI_EnableChn

设置VPSS功能:HI_MPI_VPSS_CreateGrp、HI_MPI_VPSS_StartGrp

VPSS(Video Process Sub-System)支持对一幅输入图像进行统一预处理,如去噪、去 隔行等,然后再对各通道分别进行缩放、锐化等处理,最后输出多种不同分辨率的图 像。

设置VENC功能:HI_MPI_VENC_CreateChn

VENC 模块,即视频编码模块。

3-对音频

设置编码:(这段代码没看懂)

创建ADEC通道:HI_MPI_ADEC_CreateChn

启动AO功能:

       设置AO属性:HI_MPI_AO_SetPubAttr

      使能AO:HI_MPI_AO_Enable

      使能AO 通道:HI_MPI_AO_EnableChn

      还有些额外配置就不说了

AO通道与系统绑定:HI_MPI_SYS_Bind

打开音频文件:open

创建一个子线程不停地发送:HI_MPI_ADEC_SendStream

(三)源码结构

sample下的源码都有一个特点,都会对hi sdk的函数进行进一步的封装。

比如音频里面的 “AO通道与系统绑定:HI_MPI_SYS_Bind”

 

其将之封装进了一个叫 SAMPLE_COMM_AUDIO_AoBindAdec 的函数里面,这些函数定义在sample_comm_audio.c里面

(四)移植

1-我们要把 sample_comm_audio.c 这个源码添加进工程

2-sample_comm_audio.c的函数声明都在 sample_comm.h,这个头文件也要加进去

3-(选)系统初始化函数在sample_comm_sys.c 里面,但由于hi_minihttp这个开源工程已经实现了这部分功能,在start_sdk里面,就不需要额外移植

4-我们移植官方audio例程,其mian.c文件叫做sample_audio.c,里面同样有不少关键函数,也要拷贝过来:

static PAYLOAD_TYPE_E gs_enPayloadType = PT_LPCM;
static HI_BOOL gs_bAioReSample = HI_FALSE;
static AUDIO_SAMPLE_RATE_E enInSampleRate = AUDIO_SAMPLE_RATE_BUTT;
static AUDIO_SAMPLE_RATE_E enOutSampleRate = AUDIO_SAMPLE_RATE_BUTT;

HI_S32 SAMPLE_AUDIO_AdecAo(HI_VOID);
void SAMPLE_AUDIO_HandleSig(HI_S32 signo);
HI_VOID SAMPLE_COMM_SYS_Exit(void);
HI_S32 SAMPLE_COMM_SYS_Init(VB_CONF_S *pstVbConf);
static FILE *SAMPLE_AUDIO_OpenAdecFile(ADEC_CHN AdChn, PAYLOAD_TYPE_E enType);

//SAMPLE_PRT
#define SAMPLE_PRT(fmt...)                           \
    do                                               \
    {                                                \
        printf("[%s]-%d: ", __FUNCTION__, __LINE__); \
        printf(fmt);                                 \
    } while (0)
//SAMPLE_DBG
#define SAMPLE_DBG(s32Ret)                                                     \
    do                                                                         \
    {                                                                          \
        printf("s32Ret=%#x,fuc:%s,line:%d\n", s32Ret, __FUNCTION__, __LINE__); \
    } while (0)

我把声明罗列在这里,定义顺着拷过去就行。

5-由于官方例程的 SAMPLE_AUDIO_AdecAo 这个测试函数是初始化销毁一体的,需要拆分为start和stop:

start:

HI_S32 s32Ret;
AUDIO_DEV AoDev = SAMPLE_AUDIO_AO_DEV;
AO_CHN AoChn = 0;
ADEC_CHN AdChn = 0;
HI_S32 s32AoChnCnt;
FILE *pfd = NULL;
AIO_ATTR_S stAioAttr;

HI_S32 TINNU_AUDIO_AdecAo_Start(HI_VOID)
{
    stAioAttr.enSamplerate = AUDIO_SAMPLE_RATE_16000;
    stAioAttr.enBitwidth = AUDIO_BIT_WIDTH_16;
    stAioAttr.enWorkmode = AIO_MODE_I2S_MASTER;
    stAioAttr.enSoundmode = AUDIO_SOUND_MODE_MONO;
    stAioAttr.u32EXFlag = 0;
    stAioAttr.u32FrmNum = 30;
    stAioAttr.u32PtNumPerFrm = SAMPLE_AUDIO_PTNUMPERFRM;
    stAioAttr.u32ChnCnt = 1;
    stAioAttr.u32ClkSel = 0;

    gs_bAioReSample = HI_FALSE;
    enInSampleRate = AUDIO_SAMPLE_RATE_BUTT;
    enOutSampleRate = AUDIO_SAMPLE_RATE_BUTT;

    s32Ret = SAMPLE_COMM_AUDIO_CfgAcodec(&stAioAttr);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_DBG(s32Ret);
        goto ADECAO_ERR3;
    }

    s32Ret = SAMPLE_COMM_AUDIO_StartAdec(AdChn, gs_enPayloadType);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
        goto ADECAO_ERR3;
    }

    s32AoChnCnt = stAioAttr.u32ChnCnt;
    s32Ret = SAMPLE_COMM_AUDIO_StartAo(AoDev, s32AoChnCnt, &stAioAttr, enInSampleRate, gs_bAioReSample, NULL, 0);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
        goto ADECAO_ERR2;
    }

    s32Ret = SAMPLE_COMM_AUDIO_AoBindAdec(AoDev, AoChn, AdChn);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
        goto ADECAO_ERR1;
    }

    pfd = SAMPLE_AUDIO_OpenAdecFile(AdChn, gs_enPayloadType);
    if (!pfd)
    {
        SAMPLE_DBG(HI_FAILURE);
        goto ADECAO_ERR0;
    }
    s32Ret = SAMPLE_COMM_AUDIO_CreatTrdFileAdec(AdChn, pfd);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
        goto ADECAO_ERR0;
    }

    return s32Ret;

    s32Ret = SAMPLE_COMM_AUDIO_DestoryTrdFileAdec(AdChn);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
        return HI_FAILURE;
    }

ADECAO_ERR0:
    s32Ret = SAMPLE_COMM_AUDIO_AoUnbindAdec(AoDev, AoChn, AdChn);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
    }

ADECAO_ERR1:
    s32Ret |= SAMPLE_COMM_AUDIO_StopAo(AoDev, s32AoChnCnt, gs_bAioReSample, HI_FALSE);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
    }
ADECAO_ERR2:
    s32Ret |= SAMPLE_COMM_AUDIO_StopAdec(AdChn);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
    }
ADECAO_ERR3:
    return s32Ret;
}

stop:


HI_S32 TINNU_AUDIO_AdecAo_Stop(HI_VOID)
{
    s32Ret = SAMPLE_COMM_AUDIO_DestoryTrdFileAdec(AdChn);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
        return HI_FAILURE;
    }


    s32Ret = SAMPLE_COMM_AUDIO_AoUnbindAdec(AoDev, AoChn, AdChn);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
    }


    s32Ret |= SAMPLE_COMM_AUDIO_StopAo(AoDev, s32AoChnCnt, gs_bAioReSample, HI_FALSE);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
    }

    s32Ret |= SAMPLE_COMM_AUDIO_StopAdec(AdChn);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
    }

}

5-在主循环附近调用,就能移植播放音乐:

    TINNU_AUDIO_AdecAo_Start();
    while (keepRunning)
    {
        nanosleep(&ts, NULL);
        EventLoop(s32MainFd);
    }
    TINNU_AUDIO_AdecAo_Stop();

6-音频文件

音频文件的定义在 SAMPLE_AUDIO_OpenAdecFile 函数内:

snprintf(aszFileName, FILE_NAME_LEN, "audio_chn%d.%s", AdChn, SAMPLE_AUDIO_Pt2Str(enType));

AdChn为0,文件类型为pcm(demo里面默认是adpcm,我把

static PAYLOAD_TYPE_E gs_enPayloadType = PT_ADPCMA;

改为

 

static PAYLOAD_TYPE_E gs_enPayloadType = PT_ADPCMA;

)因此文件名为audio_chn0.pcm

这里有个标准的pcm文件供测试:http://ai.baidu.com/forum/topic/show/498327

不过这个pcm文件是16000采样率的,demo里面的stAioAttr.enSamplerate要改一下

stAioAttr.enSamplerate = AUDIO_SAMPLE_RATE_16000;

(五)使能8002A功放输出

经群里的 @一图 群友测试,需要额外使能8002a 功放的,首先把gpio7.3复用为通用gpio,再设置为输出,再输出高电平。只是输出高电平给贴片三极管基极,拉低集电极,给8002a第一脚shut一个低电平,从而开启功放推动喇叭。

himm 0x200F00EC 0x01
himm 0x201B0400 0x08
himm 0x201B03FC 0x08

finish!

上一篇:日志打印之C语言宏打印日志


下一篇:php中比较复杂但又常用的字符串函数