(原)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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM