天天看點

ALSA驅動中-EBADFD錯誤原因解析及對策

在alsa驅動中有如下狀态:

#define SNDRV_PCM_STATE_OPEN  ((__force snd_pcm_state_t) 0) /* stream is open */

#define SNDRV_PCM_STATE_SETUP  ((__force snd_pcm_state_t) 1) /* stream has a setup */

#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2) /* stream is ready to start */

#define SNDRV_PCM_STATE_RUNNING  ((__force snd_pcm_state_t) 3) /* stream is running */

#define SNDRV_PCM_STATE_XRUN  ((__force snd_pcm_state_t) 4) /* stream reached an xrun */

#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5) /* stream is draining */

#define SNDRV_PCM_STATE_PAUSED  ((__force snd_pcm_state_t) 6) /* stream is paused */

#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7) /* hardware is suspended */

#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8) /* hardware is disconnected */

#define SNDRV_PCM_STATE_LAST  SNDRV_PCM_STATE_DISCONNECTED

     在ALSA最底層寫函數snd_pcm_lib_write1中,首先檢測目前PCM的狀态,是 SNDRV_PCM_STATE_PREPARED、SNDRV_PCM_STATE_RUNNING、 SNDRV_PCM_STATE_PAUSED這三種狀态下,驅動就開始transfer資料,如果為SNDRV_PCM_STATE_XRUN傳回-EPIPE錯誤,如果為SNDRV_PCM_STATE_SUSPENDED,就傳回 -ESTRPIPE;其他狀态均傳回-EBADFD錯誤。

    在打開一個PCM流時,PCM的狀态為SNDRV_PCM_STATE_OPEN ,給這個流配置參數,如channel數、采樣率、采樣精度後,PCM的狀态配置為SNDRV_PCM_STATE_SETUP,在寫資料之前,需要提示驅動去各繼各位,準備工作,這時候去prepare一下,就像是考試前的動員大會一樣,讓你熱血沸騰、充滿信心,prepare後PCM流的狀态為SNDRV_PCM_STATE_PREPARED,開始寫資料的過程中,PCM的狀态會設定為 SNDRV_PCM_STATE_RUNNING,播放完資料後,通常需要去drain一下來sync,在調snd_pcm_drain過程中,PCM的狀态為PCM的狀态,drain完以後PCM的狀态為會設定為SNDRV_PCM_STATE_SETUP,是以在再次寫資料的時候,驅動就會傳回-EBADFD的錯誤,那麼如何有效避免呢?

     辦法當然是有的,alsa-lib中提供了非常完善的接口。筆者也曾碰到過-EBADFD的錯誤,很煩人啊!出了錯後,alsa驅動就需要恢複錯誤狀态,或者幹脆重新打開一次播放流程,但是這樣做的後果就是有可能帶來“茲茲”噪音或者如“都-都”這樣的怪音,這種現象出來對産品來說肯定是不利的,是以在上層再次調用alsa寫函數的時候,首先去擷取一些目前PCM的狀态是什麼,用snd_pcm_state函數,如果目前PCM為 SNDRV_PCM_STATE_SETUP,隻需要snd_pcm_prepare一下,就可以進行正常的資料寫操作。

    在系統進入省電模式時,驅動會執行suspend,PCM狀态變為SNDRV_PCM_STATE_SUSPENDED,在喚醒系統後,筆者在adroid系統中發現,PCM的狀态仍然為SNDRV_PCM_STATE_SUSPENDED狀态,在這種狀态下,直接進行寫操作,無疑會帶來-EBADFD的錯誤。如果在寫資料的之前,檢測到的pcm狀态為SNDRV_PCM_STATE_SUSPENDED,就可以先snd_pcm_resume,再snd_pcm_prepare一下,alsa就可以回到正常工作狀态,可以正常的寫資料。

    -EBADFD錯誤的産生,就是因為alsa的驅動狀态沒有控制好,得嚴格按照alsa要求的狀态轉換去工作,否則會碰壁。

繼續閱讀