版权声明:本文为博主原创文章,未经博主允许不得转载(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 0s32Ret = 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;}#endifs32Ret = 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;}
#endifs32Ret = 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;
}

转载于:https://www.cnblogs.com/lihaiping/p/5251854.html

(原)hisi3531立体声pcm实现播放方式相关推荐

  1. android 左右声道,Android立体声pcm的数据结构,左右声道拆分、左右声道反转

    立体声pcm数据结构 Android录音默认录制生成的是pcm文件,假设我们设置采样率为16K,录音类型为AudioFormat.CHANNEL_IN_STEREO(立体声录音),数据类型为Audio ...

  2. Android立体声pcm的数据结构,左右声道拆分、左右声道反转

    立体声pcm数据结构 Android录音默认录制生成的是pcm文件,假设我们设置采样率为16K,录音类型为AudioFormat.CHANNEL_IN_STEREO(立体声录音),数据类型为Audio ...

  3. html音乐唱片自动转,HTML5音乐播放器(四):播放列表与播放方式

    发现播放列表和播放方式切换两个功能是连在一起的,单独一个拿出来说不太合适,所以就都一块弄完了.废话不多说,进入主题,功能的逻辑我是这么设计的: 把整个歌曲文件的信息都写在 json 文件里,获取并生成 ...

  4. HTML5音乐播放器(四):播放列表与播放方式

    2019独角兽企业重金招聘Python工程师标准>>> 发现播放列表和播放方式切换两个功能是连在一起的,单独一个拿出来说不太合适,所以就都一块弄完了.废话不多说,进入主题,功能的逻辑 ...

  5. 流媒体的几种播放方式

    流媒体技术的出现,极大程度的解决了互联网传输多媒体数据的方式,不仅提高了网络直播.VOD点播等互联网传输.下载的速度,更改变了人们的生活和工作方式.在流媒体技术中,流媒体的份额是和播放方式是最终用户很 ...

  6. 微信小程序 音乐播放代码(播放方式,歌词滚动)

    自动滚动时,歌词太长造成了很长的偏移,如何解决: 每次滚动的时候,获取需要展示的那一行歌词的dom节点高度位置,直接滚动到当前节点的位置就可以了. 公式:需要滚动的位置 = dom节点位置 - 歌词区 ...

  7. ADI Blackfin DSP处理器-BF533的开发详解67:PCM的播放(含源码)

    硬件准备 ADSP-EDU-BF533:BF533开发板 AD-HP530ICE:ADI DSP仿真器 软件准备 Visual DSP++软件 硬件链接 代码实现功能 代码实现了打开代码工程目录下的& ...

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

    前言 该篇整理的原始来源为http://blog.csdn.net/leixiaohua1020/article/details/40540147.非常感谢该博主的无私奉献,写了不少关于不同多媒体库的 ...

  9. Android中Video的三种播放方式的实现

     在Android中,我们有三种方式来实现视频的播放. 1.使用其自带的播放器.指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型. 2.使用VideoView来 ...

最新文章

  1. Java格式化日期用斜杠_[java工具类01]__构建格式化输出日期和时间的工具类
  2. hibernate主键详细介绍
  3. 设置 myeclipse 编码格式
  4. centos7.6成功安装nerdtree插件
  5. Maven精选系列--发布jar包到Nexus私库
  6. 使用Java泛型的模板方法模式示例
  7. 模拟生命_吸烟致癌?
  8. python数字图像处理(10):图像简单滤波
  9. cve-2018-2893 WebLogic
  10. 【Android Studio 3.5.3】蓝牙串口及USB串口例程
  11. IC授权卡和复制卡的区别_DIY电脑——A卡和N卡有区别吗
  12. Android客户端面经总结
  13. 2017年精选文章集合
  14. 高考530计算机专业,高考530分以下,学生该先选择大学还是专业?高考名师给出分析...
  15. bitmap 设置图片尺寸,避免 内存溢出 OutOfMemoryError的优化方法
  16. SDRAM DQM的解释,总算明白了
  17. Android之ContentProvider
  18. 3星|《混乱》:案例比较有趣,推导过程和结论略牵强
  19. 基于51单片机的废气检测I2Cproteus仿真
  20. VR热播:VR 剧集以及及大量精彩VR视频

热门文章

  1. 支持他们的应用程序突袭Cloudberry狂潮
  2. 通过对json数据解析爬取虎牙直播数据并存入csv文件
  3. 【网络信息安全】身份认证
  4. html视频滑动抖音代码,抖音 - 分享代码,大鱼海棠,片段滚动效果代码!
  5. th themlefy 计算_航程计算的数学模型
  6. 网络协议 -- UDP协议(3)广播
  7. RISC-V_GD32VF103-对 Debug 设置
  8. 正和游戏:加密协议正在重塑公共产品 |链捕手
  9. 联想Y400电脑装WIN7无法重装系统解决方法
  10. 第七十五篇:学术论文写作技巧