(原)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 = ;//1;
stAioAttr.u32FrmNum = ;/*缓存帧个数*/
stAioAttr.u32PtNumPerFrm = SAMPLE_AUDIO_PTNUMPERFRM;/*每帧的采样点个数*/
stAioAttr.u32ChnCnt = ;/*音频通道数*/
stAioAttr.u32ClkSel = ;
有人说我对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 = -;
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 -;
} 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 < )
{
printf("can't open tlv320,%s\n", TLV320_FILE);
return -;
} audio_ctrl.chip_num = ;
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 -;
} /*set sample of DAC and ADC */
if (ioctl(s_fdTlv,SET_DAC_SAMPLE,&audio_ctrl))
{
printf("ioctl err1\n");
close(s_fdTlv);
return -;
} if (ioctl(s_fdTlv,SET_ADC_SAMPLE,&audio_ctrl))
{
printf("ioctl err2\n");
close(s_fdTlv);
return -;
} /*set volume control of left and right DAC */
audio_ctrl.if_mute_route = ;
audio_ctrl.input_level = ;
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 = ;/*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 = ;
ioctl(s_fdTlv,SET_DATA_LENGTH,&audio_ctrl); /*DACL1 TO LEFT_LOP/RIGHT_LOP VOLUME CONTROL 82 92*/
audio_ctrl.if_mute_route = ;/* 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 = ;
audio_ctrl.if_powerup = ;
audio_ctrl.input_level = ;
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 =;
audio_ctrl.input_level = ;
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 = ;
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 ;
}
HI_S32 ADEC_AUDIO_AdecAo(AIO_ATTR_S *pstAioAttr)
{
HI_S32 s32Ret;
AUDIO_DEV AoDev = SAMPLE_AUDIO_AO_DEV;
AO_CHN AoChn = ;
ADEC_CHN AdChn = ;
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+);
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+, 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+); 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+, AdChn))
{
printf("unbind failed2.");
} return HI_SUCCESS;
}
(原)hisi3531立体声pcm实现播放方式的更多相关文章
- DirectSound播放PCM(可播放实时采集的音频数据)
前言 该篇整理的原始来源为http://blog.csdn.net/leixiaohua1020/article/details/40540147.非常感谢该博主的无私奉献,写了不少关于不同多媒体库的 ...
- Android 音乐(音效)播放方式总结
一.音效的分类 音效按照作用的不同,可以将音效分为即时音效和背景音乐.两种音效在Android中的实现技术是不同的. 主要的实现方式为:SoundPool.MediaPlayer. 区别在于,Medi ...
- (转)Unity3d游戏开场CG动画播放方式
1.在一个plane上播放 1 2 3 4 5 6 7 8 9 10 11 12 using UnityEngine; using System.Collections; public class M ...
- Cocos2dx 小技巧(十二) 一种可行的系列动画播放方式
今早发生了一件事让我感觉特气愤!去年的这个时候,我和小伙伴们一起在操场上拍毕业照,之后有个当地报纸的记者来我们学校取材,看到我们后打算给我们拍几张创意张扬点的毕业照.之后呢,照片出来了,拍的效果大伙都 ...
- 简单实用的PCM音频播放器--沉寂几年之后回归的第一份笔记
---恢复内容开始--- PCM音频网络流播放,至于用处,就不多解释了. 一个简单的类,基于NAudio,一个简单的拼装类,实例化时三个参数,依次是采样率,系统播放设备Index,播放声道,调用Pla ...
- 【原】AVAudio录制,播放 (解决真机播放音量太小)
原文链接:http://www.cnblogs.com/A--G/p/4624526.html 最近学习AVFoundation里的audio操作,最基本的录制和播放,参考了一个Code4pp的 一个 ...
- SACD-ISO音频镜像播放方式
SACD-ISO 音频文件不需要解压也不需要挂载光盘,可以直拖入播放器播放. 播放器下载 foobar2000https://www.foobar2000.org/download 解码插件下载 Su ...
- linux下mono播放PCM音频
测试环境: Ubuntu 14 MonoDevelop CodeBlocks 1.建立一个共享库(shared library) 这里用到了linux下的音频播放库,alsa-lib. al ...
- 【转】Android播放音频MediaPlayer的几种方式介绍
接下来笔者介绍一下Android中播放音频的几种方式,android.media包下面包含了Android开发中媒体类,当然笔者不会依次去介绍,下面介绍几个音频播放中常用的类: 1.使用MediaPl ...
随机推荐
- 深度 | 机器学习敲门砖:任何人都能看懂的TensorFlow介绍【转】
转自:http://oicwx.com/detail/1161517 选自 kdnuggets 作者:Soon Hin Khor 机器之心编译 参与:Rick.吴攀.李亚洲 本文是日本东京 Tenso ...
- 【ARM】2410裸机系列-按键查询式控制led
开发环境 硬件平台:FS2410 主机:Ubuntu 12.04 LTS LED灯原理图 按键原理图 按键的接线资源 KSCAN0 -> GPE11 KSCAN1 -> GPG6 ...
- Unique constraint on single String column with GreenDao
转:http://stackoverflow.com/questions/22070281/greendao-support-for-unique-constraint-on-multiple-col ...
- Python 连接数据库 mysql
python 连接 数据库 import pymysql db = pymysql.connect(host='127.0.0.1',port=3306,user='root',password='r ...
- 【Linux】crontab 每隔1小时 2小时的执行job写法
crontab -l crontab -e 每五分钟执行 */5 * * * * 每小时执行 0 * * * * 每2小时执行 0 */2 * * * 每天执行 0 0 ...
- IPC相关的命令
进程间通信概述 进程间通信有如下的目的: 1.数据传输,一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M之间: 2.共享数据,多个进程想要操作共享数据,一个进程对数据的修改,其他进 ...
- easyui扩展
datagrid行内编辑时为datetimebox $.extend($.fn.datagrid.defaults.editors, { datetimebox: {// datetimebox就是你 ...
- nginx中配置proxy_pass
在nginx中配置proxy_pass时,当在后面的url加上了/,相当于是绝对根路径,则nginx不会把location中匹配的路径部分代理走;如果没有/,则会把匹配的路径部分也给代理走. 下面四种 ...
- iOSTableview 禁止下拉,允许上拉
1 回弹机制:bounces alwaysBounceHorizontal alwaysBounceVerticalbounces:描述的当scrollview的显示超过内容区域的边缘以及返回时,是否 ...
- docker探索-swarm搭建docker集群(七)
前言 Swarm 在 Docker 1.12 版本之前属于一个独立的项目,在 Docker 1.12 版本发布之后,该项目合并到了 Docker 中,成为 Docker 的一个子命令,docker s ...