版权声明:本文为博主原创文章,未经博主允许不得转载(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实现播放方式的更多相关文章

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

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

  2. Android 音乐(音效)播放方式总结

    一.音效的分类 音效按照作用的不同,可以将音效分为即时音效和背景音乐.两种音效在Android中的实现技术是不同的. 主要的实现方式为:SoundPool.MediaPlayer. 区别在于,Medi ...

  3. (转)Unity3d游戏开场CG动画播放方式

    1.在一个plane上播放 1 2 3 4 5 6 7 8 9 10 11 12 using UnityEngine; using System.Collections; public class M ...

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

    今早发生了一件事让我感觉特气愤!去年的这个时候,我和小伙伴们一起在操场上拍毕业照,之后有个当地报纸的记者来我们学校取材,看到我们后打算给我们拍几张创意张扬点的毕业照.之后呢,照片出来了,拍的效果大伙都 ...

  5. 简单实用的PCM音频播放器--沉寂几年之后回归的第一份笔记

    ---恢复内容开始--- PCM音频网络流播放,至于用处,就不多解释了. 一个简单的类,基于NAudio,一个简单的拼装类,实例化时三个参数,依次是采样率,系统播放设备Index,播放声道,调用Pla ...

  6. 【原】AVAudio录制,播放 (解决真机播放音量太小)

    原文链接:http://www.cnblogs.com/A--G/p/4624526.html 最近学习AVFoundation里的audio操作,最基本的录制和播放,参考了一个Code4pp的 一个 ...

  7. SACD-ISO音频镜像播放方式

    SACD-ISO 音频文件不需要解压也不需要挂载光盘,可以直拖入播放器播放. 播放器下载 foobar2000https://www.foobar2000.org/download 解码插件下载 Su ...

  8. linux下mono播放PCM音频

         测试环境: Ubuntu 14 MonoDevelop CodeBlocks 1.建立一个共享库(shared library) 这里用到了linux下的音频播放库,alsa-lib. al ...

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

    接下来笔者介绍一下Android中播放音频的几种方式,android.media包下面包含了Android开发中媒体类,当然笔者不会依次去介绍,下面介绍几个音频播放中常用的类: 1.使用MediaPl ...

随机推荐

  1. [Windows Azure] How to Monitor Cloud Services

    How to Monitor Cloud Services To use this feature and other new Windows Azure capabilities, sign up ...

  2. 【Miktex】使用教程以及数学符号整理总结

    LaTeX是当今世界上最流行和使用最为广泛的 TeX格式.它构筑在 Plain TeX的基础之上,并加进了很多的功能以使得使用者可以更为方便的利用 TeX的强大功能.使用 LaTeX基本上不需要使用者 ...

  3. VMware网络使用NAT模式

    公司的网络中,要在本地安装一个Linux虚拟机,但是只分配给宿主机一个IP,那么怎么实现Linux虚拟机的网络访问呢? 使用NAT模式:这是VMware用于虚拟NAT网络下的虚拟交换机. 1.设置网络 ...

  4. 初学SSH 配置+错误总结

    初学java web 一上手就接触ssh,前段时间,断断续续配置好了ssh,今天从Hibernate入手开始学习.先总结今天遇到的问题. 配置链接的是sqlserver的数据库,首先是下载了一个jdb ...

  5. 基于jQuery和CSS3超酷Material Design风格滑动菜单导航特效

    分享一款效果非常炫酷的谷歌 Material Design 风格jQuery和CSS3滑动选项卡特效.该选项卡特效集合了扁平风格设计和按钮点击波特效.是一款设计的非常不错的Material Desig ...

  6. bootstrap插件(对话框)bootbox参数和自定义弹出框宽度设置

    参考:https://hisune.com/post/view/17/bootstrap-plugin-bootbox-and-custom-width-dialog 官网:http://bootbo ...

  7. EM算法学习资料备忘

    将学习EM算法过程中看到的好的资料汇总在这里,供以后查询.也供大家參考. 1. 这是我学习EM算法最先看的优秀的入门文章,讲的比較通俗易懂,并且举了样例来说明当中的原理.不错! http://blog ...

  8. 快速理解RequireJs(转)

    RequireJs已经流行很久了,我们在项目中也打算使用它.它提供了以下功能: 声明不同js文件之间的依赖 可以按需.并行.延时载入js库 可以让我们的代码以模块化的方式组织 初看起来并不复杂. 在h ...

  9. 将已有jar添加至本地maven仓库

    官网链接:http://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html 比如有 commons-dbutils-1.6.jar ...

  10. 【MarkdownPad】不能输入表格Table

    使用MarkdownPad时,需要制作一个表格.搜到参照这篇文章,发现还是无法显示表格,测试效果是如下这样的: Markdown文本: 显示效果: 谷歌一下,原来是MarkdownPad默认的处理器不 ...