(原)hisi3531立体声pcm实现播放方式

版权声明:本文为博主原创文章,未经博主允许不得转载(http://www.cnblogs.com/lihaiping/p/5251854.html)

最近在使用hisi3531做一个项目,需要实现本地文件播放的功能,在做音频播放功能的时候,调试了很久才算基本调通。

因为hisi3531的硬解码音频功能不支持对mp3和aac等常见类型的解码,所以这里需要实现音频播放,当然就需要借助强大的ffpmeg来实现软件解码音频,我当初的实现方案是:ffmpeg-->dec--->pcm--->adec(LPCM)---ao;这套思路是实现的。目前经过调试,成功了,方案也同样是这套,只不过这中间的曲折,花了不少时间,目前我打算记录这中间的调试过程,给需要帮组的人。

通过ffmpeg实现解码,解码后的pcm文件我在中间进行了一个转换,转换为s16的格式,因为考虑到其他的格式可能3531不支持,所以这里我在做的时候,都统一使用s16的音频采样格式。

拿到s16的格式PCM以后,我的做法是设置3531的ao属性和adec属性,然后创建,打开,绑定adec和ao,接着按照sample的代码,将pcm发送给adec实现解码播放.结果播放出来的效果为:声音被拉长,声道的左右声道音量大小不一样这种情况。

开始我以为是解码有问题,将解码后的pcm写成文件,我拷贝到pc上进行试播放,pc上播放完全是正常的,这就奇怪了,到底哪里出问题了呢?

于是我拿hisi官方的sample来做测试,播放刚刚那个pcm文件,结果效果还是跟刚刚一样。

这时候,我就开始问度娘,找论坛看之前有人遇到跟我一样的情况不,在论坛里面找到了:http://www.ebaina.com/bbs/forum.php?mod=viewthread&tid=7100&highlight=pcm

播放声音被拉长,难道是采样率的问题?我回过头再去看看,结果我设置模式没有错啊?

/* init stAio. all of cases will use it */
stAioAttr.enSamplerate = AUDIO_SAMPLE_RATE_44100;//AUDIO_SAMPLE_RATE_8000;
stAioAttr.enBitwidth = AUDIO_BIT_WIDTH_16;
stAioAttr.enWorkmode = AIO_MODE_I2S_SLAVE;/*从模式*/
/*音频声道模式*/
stAioAttr.enSoundmode = AUDIO_SOUND_MODE_STEREO;;
stAioAttr.u32EXFlag = 0;//1;
stAioAttr.u32FrmNum = 30;/*缓存帧个数*/
stAioAttr.u32PtNumPerFrm = SAMPLE_AUDIO_PTNUMPERFRM;/*每帧的采样点个数*/
stAioAttr.u32ChnCnt = 2;/*音频通道数*/
stAioAttr.u32ClkSel = 1;

有人说我对aic31这个codec配置有问题,采样率不对,于是我结合驱动,把SAMPLE_Tlv320_CfgAudio函数又确认了一次,把aic31芯片看了下,发现采样率设置没问题。

那到底哪出了问题?

在没有办法找出原因的情况下,我将ffmpeg解码后的PCM数据设置为单声道,然后我再进行播放,这时候声音播放效果正常了。什么原因?从这一点也确实证明了,我设置采样率是没有问题的。

然后接着查原因,既然我从ai----->ao可以实现立体声,那么应该这个也是可以的,于是我再换回立体声,查看系统调试打印信息进行对比:

在ai----->ao模式下stero的调试信息如下:

然后我试一下播放stero的file,adec---->ao:

通过对比发现ao通道这时候有一个通道是没有数据的。

难怪会不正常。

==========================

这时候我就跟网上一个朋友沟通,然后我截这两个图给他,他问我,你用stereo模式?用mono啊,都是单声道,2个。

我奇怪,我说难道这个不支持stereo?我看官方文档没写啊?

他说2个单声道不就是双声道了。

我然后又说:难道你要我两个mono来实现,分别写?

他说:对

我说:好吧,那我来试试。

================

通过设置mono的方式,我打开了ao设备4的两个通道(0,1),然后将两个通道bind到adec的同一个通道上(0),然后开始写数据.

结果奇迹般的实现了,声音也没出现一大一小,节拍不对的情况。OK,就这么搞定了,哎,想想都是泪啊,hisi这坑。

下面贴上我的调试代码:

HI_S32 ADEC_Tlv320_CfgAudio(AIO_MODE_E enWorkmode,AUDIO_SAMPLE_RATE_E enSample)
{
    HI_S32 s32Samplerate;
    HI_S32 vol = 0x100;
    Audio_Ctrl audio_ctrl;
    int s_fdTlv = -1;
    HI_BOOL bPCMmode = HI_FALSE;
    HI_BOOL bMaster = HI_TRUE;      /* 这里的主模式是对于Tlv320aic31来说的 */
    HI_BOOL bPCMStd = HI_FALSE;

    /* aic31外接着一个12.288M的晶振,对于44.1k系列的采样率与48k系列的采样率,
        需要给aic31配置不同的P、R、J、D值,所以这里设置一标志来记录 */
    HI_BOOL b44100HzSeries = HI_FALSE;         

    if (AUDIO_SAMPLE_RATE_8000 == enSample)
    {
        s32Samplerate = AC31_SET_8K_SAMPLERATE;
    }
    else if (AUDIO_SAMPLE_RATE_12000 == enSample)
    {
        s32Samplerate = AC31_SET_12K_SAMPLERATE;
    }
    else if (AUDIO_SAMPLE_RATE_11025 == enSample)
    {
        b44100HzSeries = HI_TRUE;
        s32Samplerate = AC31_SET_11_025K_SAMPLERATE;
    }
    else if (AUDIO_SAMPLE_RATE_16000 == enSample)
    {
        s32Samplerate = AC31_SET_16K_SAMPLERATE;
    }
    else if (AUDIO_SAMPLE_RATE_22050 == enSample)
    {
        b44100HzSeries = HI_TRUE;
        s32Samplerate = AC31_SET_22_05K_SAMPLERATE;
    }
    else if (AUDIO_SAMPLE_RATE_24000 == enSample)
    {
        s32Samplerate = AC31_SET_24K_SAMPLERATE;
    }
    else if (AUDIO_SAMPLE_RATE_32000 == enSample)
    {
        s32Samplerate = AC31_SET_32K_SAMPLERATE;
    }
    else if (AUDIO_SAMPLE_RATE_44100 == enSample)
    {
        b44100HzSeries = HI_TRUE;
        s32Samplerate = AC31_SET_44_1K_SAMPLERATE;
    }
    else if (AUDIO_SAMPLE_RATE_48000 == enSample)
    {
        s32Samplerate = AC31_SET_48K_SAMPLERATE;
    }
    else
    {
        printf("SAMPLE_Tlv320_CfgAudio(), not support enSample:%d\n",enSample);
        return -1;
    }

    if(AIO_MODE_I2S_MASTER == enWorkmode)
    {
        bPCMmode = HI_FALSE;
        bMaster = HI_FALSE;
    }
    else if(AIO_MODE_I2S_SLAVE == enWorkmode)
    {
        bPCMmode = HI_FALSE;
        bMaster = HI_TRUE;
    }
    else if((AIO_MODE_PCM_MASTER_NSTD == enWorkmode)||(AIO_MODE_PCM_MASTER_STD == enWorkmode))
    {
        bPCMmode = HI_TRUE;
        bMaster = HI_FALSE;
    }
    else if((AIO_MODE_PCM_SLAVE_NSTD == enWorkmode)||(AIO_MODE_PCM_SLAVE_STD == enWorkmode))
    {
        bPCMmode = HI_TRUE;
        bMaster = HI_TRUE;
    }
    else
    {
        printf("SAMPLE_Tlv320_CfgAudio(), not support workmode:%d\n\n",enWorkmode);
    }

    s_fdTlv = open(TLV320_FILE,O_RDWR);
    if (s_fdTlv < 0)
    {
        printf("can‘t open tlv320,%s\n", TLV320_FILE);
        return -1;
    }     

    audio_ctrl.chip_num = 0;
    if (ioctl(s_fdTlv,SOFT_RESET,&audio_ctrl))
    {
        printf("[Func]:%s [Line]:%d [Info]:%s\n", __FUNCTION__, __LINE__, "tlv320aic31 reset failed");
    }

    /* 设置主从模式 1为主模式*/
    audio_ctrl.ctrl_mode = bMaster;
    audio_ctrl.if_44100hz_series = b44100HzSeries;
    audio_ctrl.sample = s32Samplerate;
    ioctl(s_fdTlv,SET_CTRL_MODE,&audio_ctrl); 

    /* set transfer mode 0:I2S 1:PCM */
    audio_ctrl.trans_mode = bPCMmode;
    if (ioctl(s_fdTlv,SET_TRANSFER_MODE,&audio_ctrl))
    {
        printf("set tlv320aic31 trans_mode err\n");
        close(s_fdTlv);
        return -1;
    }

    /*set sample of DAC and ADC */
    if (ioctl(s_fdTlv,SET_DAC_SAMPLE,&audio_ctrl))
    {
        printf("ioctl err1\n");
        close(s_fdTlv);
        return -1;
    }

    if (ioctl(s_fdTlv,SET_ADC_SAMPLE,&audio_ctrl))
    {
        printf("ioctl err2\n");
        close(s_fdTlv);
        return -1;
    }     

    /*set volume control of left and right DAC */
    audio_ctrl.if_mute_route = 0;
    audio_ctrl.input_level = 0;
    ioctl(s_fdTlv,LEFT_DAC_VOL_CTRL,&audio_ctrl);
    ioctl(s_fdTlv,RIGHT_DAC_VOL_CTRL,&audio_ctrl);

    /*Right/Left DAC Datapath Control */
    /*
    * 0:Left/Right DAC datapath plays off
    * 1:Left/Right DAC datapath plays left/right channel input data
    * 2:Left/Right DAC datapath plays right/left channel input data
    * 3:Left/Right DAC datapath plays mono mix of left/right channel input data
    */
    audio_ctrl.if_powerup = 1;/*Left/Right DAC datapath plays left/right channel input data*/
    //audio_ctrl.if_powerup = 3;/*lhp:test*/
    ioctl(s_fdTlv,LEFT_DAC_POWER_SETUP,&audio_ctrl);
    //audio_ctrl.if_powerup = 2;/*lhp:test*/
    ioctl(s_fdTlv,RIGHT_DAC_POWER_SETUP,&audio_ctrl);

    /* 设置PCM标准模式和非标准模式 */
    if ((AIO_MODE_PCM_MASTER_STD == enWorkmode)||(AIO_MODE_PCM_SLAVE_STD == enWorkmode))
    {
        bPCMStd = HI_TRUE;
        audio_ctrl.data_offset = bPCMStd;
        ioctl(s_fdTlv,SET_SERIAL_DATA_OFFSET,&audio_ctrl);
    }
    else if ((AIO_MODE_PCM_MASTER_NSTD == enWorkmode)||(AIO_MODE_PCM_SLAVE_NSTD == enWorkmode))
    {
        bPCMStd = HI_FALSE;
        audio_ctrl.data_offset = bPCMStd;
        ioctl(s_fdTlv,SET_SERIAL_DATA_OFFSET,&audio_ctrl);
    }
    else
    {;}

    /* 数据位宽 (0:16bit 1:20bit 2:24bit 3:32bit) */
    audio_ctrl.data_length = 0;
    ioctl(s_fdTlv,SET_DATA_LENGTH,&audio_ctrl);

    /*DACL1 TO LEFT_LOP/RIGHT_LOP VOLUME CONTROL 82 92*/
    audio_ctrl.if_mute_route = 1;/* route*/
    audio_ctrl.input_level = vol; /*level control*/
    ioctl(s_fdTlv,DACL1_2_LEFT_LOP_VOL_CTRL,&audio_ctrl);
    ioctl(s_fdTlv,DACR1_2_RIGHT_LOP_VOL_CTRL,&audio_ctrl);

    /* LEFT_LOP/RIGHT_LOP OUTPUT LEVEL CONTROL 86 93*/
    audio_ctrl.if_mute_route = 1;
    audio_ctrl.if_powerup = 1;
    audio_ctrl.input_level = 0;
    ioctl(s_fdTlv,LEFT_LOP_OUTPUT_LEVEL_CTRL,&audio_ctrl);
    ioctl(s_fdTlv,RIGHT_LOP_OUTPUT_LEVEL_CTRL,&audio_ctrl);

    /*配置AD*/
    /* LEFT/RIGHT ADC PGA GAIN CONTROL 15 16*/
    audio_ctrl.if_mute_route =0;
    audio_ctrl.input_level = 0;
    ioctl(s_fdTlv,LEFT_ADC_PGA_CTRL,&audio_ctrl);
    ioctl(s_fdTlv,RIGHT_ADC_PGA_CTRL,&audio_ctrl); 

    /*INT2L TO LEFT/RIGTH ADCCONTROL 17 18*/
    audio_ctrl.input_level = 0;
    ioctl(s_fdTlv,IN2LR_2_LEFT_ADC_CTRL,&audio_ctrl);
    ioctl(s_fdTlv,IN2LR_2_RIGTH_ADC_CTRL,&audio_ctrl); 

    /*IN1L_2_LEFT/RIGTH_ADC_CTRL 19 22*/
    /*audio_ctrl.input_level = 0xf;
    audio_ctrl.if_powerup = 1;
    printf("audio_ctrl.input_level=0x%x,audio_ctrl.if_powerup=0x%x\n",audio_ctrl.input_level,audio_ctrl.if_powerup);
    if (ioctl(s_fdTlv,IN1L_2_LEFT_ADC_CTRL,&audio_ctrl)==0)
        perror("ioctl err\n");
    getchar();
    printf("audio_ctrl.input_level=0x%x,audio_ctrl.if_powerup=0x%x\n",audio_ctrl.input_level,audio_ctrl.if_powerup);
    ioctl(s_fdTlv,IN1R_2_RIGHT_ADC_CTRL,&audio_ctrl);
    getchar();
    printf("set 19 22\n");*/

    close(s_fdTlv);
    printf("Set aic31 ok: bMaster = %d, enWorkmode = %d, enSamplerate = %d\n",
            bMaster, enWorkmode, enSample);
    return 0;
}
HI_S32 ADEC_AUDIO_AdecAo(AIO_ATTR_S *pstAioAttr)
{
    HI_S32      s32Ret;
    AUDIO_DEV   AoDev = SAMPLE_AUDIO_AO_DEV;
    AO_CHN      AoChn = 0;
    ADEC_CHN    AdChn = 0;
    FILE        *pfd = NULL;

    if (NULL == pstAioAttr)
    {
        printf("[Func]:%s [Line]:%d [Info]:%s\n", __FUNCTION__, __LINE__, "NULL pointer");
        return HI_FAILURE;
    }
#if 0
    s32Ret = SAMPLE_COMM_AUDIO_CfgAcodec(pstAioAttr, gs_bMicIn);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_DBG(s32Ret);
        return HI_FAILURE;
    }
#else
/*使用新的测试函数:for test by lhp*/
    s32Ret=ADEC_Tlv320_CfgAudio(pstAioAttr->enWorkmode, pstAioAttr->enSamplerate);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_DBG(s32Ret);
        return HI_FAILURE;
    }
#endif

   #if 0
   //调整一下顺序
   s32Ret = SAMPLE_COMM_AUDIO_StartAdec(AdChn, gs_enPayloadType);
   if (s32Ret != HI_SUCCESS)
   {
       SAMPLE_DBG(s32Ret);
       return HI_FAILURE;
   }
   #endif

    s32Ret = SAMPLE_COMM_AUDIO_StartAo(AoDev, AoChn, pstAioAttr, gs_pstAoReSmpAttr);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
        return HI_FAILURE;
    }
    /*通过mono的方式实现stero*/
    s32Ret = HI_MPI_AO_EnableChn(AoDev, AoChn+1);
    if(HI_SUCCESS != s32Ret)
    {
        printf("%s: HI_MPI_AO_EnableChn(%d) failed with %#x!\n", __FUNCTION__,               AoChn, s32Ret);
        return HI_FAILURE;
    }
#if 1
    //调整一下顺序
    s32Ret = SAMPLE_COMM_AUDIO_StartAdec(AdChn, gs_enPayloadType);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
        return HI_FAILURE;
    }
#endif
    s32Ret = SAMPLE_COMM_AUDIO_AoBindAdec(AoDev, AoChn, AdChn);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
        return HI_FAILURE;
    }
    //立体声绑定测试
    s32Ret = SAMPLE_COMM_AUDIO_AoBindAdec(AoDev, AoChn+1, AdChn);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
        return HI_FAILURE;
    }

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

    printf("bind adec:%d to ao(%d,%d,%d) ok \n", AdChn, AoDev, AoChn,AoChn+1);

    printf("\nplease press twice ENTER to exit this sample\n");
    getchar();
    getchar();

    SAMPLE_COMM_AUDIO_DestoryTrdFileAdec(AdChn);
    SAMPLE_COMM_AUDIO_StopAo(AoDev, AoChn, gs_bAioReSample);
    SAMPLE_COMM_AUDIO_StopAdec(AdChn);

    if(SAMPLE_COMM_AUDIO_AoUnbindAdec(AoDev, AoChn, AdChn))
    {
        printf("unbind failed1.");
    }

    if(SAMPLE_COMM_AUDIO_AoUnbindAdec(AoDev, AoChn+1, AdChn))
    {
        printf("unbind failed2.");
    }

    return HI_SUCCESS;
}
时间: 2024-10-03 06:28:01

(原)hisi3531立体声pcm实现播放方式的相关文章

Cocos2dx 小技巧(十二) 一种可行的系列动画播放方式

定义: 将一个类(Adaptee)的接口转换成客户(Client)希望的另外一个接口(Target). 目标接口(Target):客户所期待的接口.目标可以是具体的或抽象的类,也可以是接口. 需要适配的类(Adaptee):需要适配的类或适配者类. 适配器(Adapter):使得一个东西适合另一个东西的东西.百度中定义为:接口转换器.通过包装一个需要适配的对象,把源接口转换成目标接口. 为什么要适配:需要的东西已做好,但是不能用,短时间又不能改造,想办法适配它. 作用: 使得原本由于接口不兼容而

DirectSound播放PCM(可播放实时采集的音频数据)

前言 该篇整理的原始来源为http://blog.csdn.net/leixiaohua1020/article/details/40540147.非常感谢该博主的无私奉献,写了不少关于不同多媒体库的博文.让我这个小白学习到不少.现在将其整理是为了收录,以备自己查看. 一.DirectSound简介 DirectSound是微软所开发DirectX的组件之一,可以在Windows 操作系统上录音,并且记录波形音效(waveform sound).目前DirectSound 是一个成熟的API ,

Unity3d游戏开场CG动画播放方式

1.在一个plane上播放 1 2 3 4 5 6 7 8 9 10 11 12 using UnityEngine; using System.Collections; public class MobileMovieTexture : MonoBehaviour { public MovieTexture movTexture;   void Start() { GetComponent<Renderer>().material.mainTexture = movTexture; movT

SACD-ISO音频镜像播放方式

SACD-ISO 音频文件不需要解压也不需要挂载光盘,可以直拖入播放器播放. 播放器下载 foobar2000https://www.foobar2000.org/download 解码插件下载 Super Audio CD Decoderhttps://sourceforge.net/projects/sacddecoder/files/foo_input_sacd/ 安装步骤 原文地址:https://www.cnblogs.com/jinzesudawei/p/11980511.html

Android 音频播放——AudioTrack直接播PCM、MediaPlayer播媒体文件可以是audio

http://blog.csdn.net/java_android_c/article/details/52678265 Android平台播放音频的方式一般有3种.1.利用系统内置的应用程序播放音频    2.利用AudioTrack播放原始音频   3.使用MediaPlayer播放.此3种音频播放方式,以第三种MediaPlayer播放这种方式使用的最多,必须掌握! 一.使用系统内置的程序. Google想的"周到",一般都给我们提供了一些内置程序,然而这些内置程序的UI效果,那

【转】Android播放音频MediaPlayer的几种方式介绍

接下来笔者介绍一下Android中播放音频的几种方式,android.media包下面包含了Android开发中媒体类,当然笔者不会依次去介绍,下面介绍几个音频播放中常用的类: 1.使用MediaPlayer播放音频 MediaPlayer的功能很强大,下面附上一张该类封装音频的生命周期图: MediaPlayer支持AAC.AMR.FLAC.MP3.MIDI.OGG.PCM等格式,MediaPlayer可以通过设置元数据和播放源来音频. 1.1播放Raw文件夹下面音频的元数据 //直接创建,不

c#实现播放器的集中方式

http://www.cnblogs.com/iskyoole/archive/2012/03/25/2417181.html(原文链接地址) 一.使用vs自带的windows media play控件 优点:上手容易,使用简单: 缺点:界面固定,支持格式有限. 二.使用微软的DirectX播放 优点:可以自定义界面,支持的播放格式增多: 缺点:播放视频的时候必须另外安装解码器. 三.使用libvlc播放 优点:可以自己封装libvlc.dll(开源程序有牛人已经封装,可以直接拿来用),支持的格

Android音频处理——通过AudioRecord去保存PCM文件进行录制,播放,停止,删除功能

Android音频处理--通过AudioRecord去保存PCM文件进行录制,播放,停止,删除功能 音频这方面很博大精深,我这里肯定讲不了什么高级的东西,最多也只是一些基础类知识,首先,我们要介绍一下Android他提供的录音类,实际上他有两个,一个是MediaRecorder,还有一个就是我们今天要用到的AudioRecord,那他们有什么区别呢? 一.区别 MediaRecorder和AudioRecord都可以录制音频,区别是MediaRecorder录制的音频文件是经过压缩后的,需要设置

PCM数据格式

1. 音频简介 经常见到这样的描述: 44100HZ 16bit stereo 或者 22050HZ 8bit mono 等等. 44100HZ 16bit stereo: 每秒钟有 44100 次采样, 采样数据用 16 位(2字节)记录, 双声道(立体声); 22050HZ 8bit  mono: 每秒钟有 22050 次采样, 采样数据用 8 位(1字节)记录, 单声道; 当然也可以有 16bit 的单声道或 8bit 的立体声, 等等. 采样率是指:声音信号在“模→数”转换过程中单位时间