1. 程式人生 > >linux_sound_alsa_ALSA體系SOC子系統中資料流分析

linux_sound_alsa_ALSA體系SOC子系統中資料流分析

前言:

    linux中,無論是oss還是alsa體系,錄音和放音的資料流必須分析清楚。先分析alsa驅動層,然後關聯到alsa庫層和應用層。

連結分析:

    core/pcm_native.c檔案中.mmap = snd_pcm_mmap呼叫snd_pcm_mmap_data(substream, file, area);進一步呼叫substream->ops->mmap(substream, area);根據soc/pxa/pxa3xx-pcm.c檔案中.mmap = pxa3xx_pcm_mmap,可知dma_mmap_writecombine(, ,runtime->dma_addr,);函式被呼叫。上一章分析過soc/pxa/pxa3xx-pcm.c檔案中pxa3xx_pcm_hw_params()函式會建立連結串列,根據dma_buff_phys = runtime->dma_addr;和dma_desc->dsadr = dma_buff_phys;可知runtime->dma_addr為dma記憶體端地址,且此地址由alsa庫層傳遞進來。又根據dma_desc->dtadr = prtd->params->dev_addr和soc/pxa/pxa3xx-ac97.c檔案中.dev_addr = __PREG(PCDR),可知dma外設端地址為ac97控制器中fifo讀寫暫存器PCDR。至此,第一條鏈路建立完畢:FIFO通過DMA和記憶體互動。待續1

    ac97介面或者i2s或者pcm介面可以將cpu和codec(wm9714/alc5620/alc5621)連線起來,配置好格式:pcm介面必須配置取樣率、取樣位數、通道數和傳送格式;i2s介面必須配置取樣率、取樣位數、通道數和對齊方式;ac97介面比較靈活,可以認為cpu這端不用配置,只需要在codec端配置就行了。當然,電源、時鐘、IO任何數字晶片都得配置。最後不能混淆資料介面和控制介面的慨念,i2s和pcm只能傳輸音訊資料,訪問codec的暫存器必須通過i2c等控制介面,ac97介面分時傳輸控制和資料。codec中的adc、dac通過ac97等介面同cpu的fifo互動資料。第二條鏈路建立完畢。待續2

    alsa_lib原始碼中pcm.c檔案中snd_pcm_readi(,buffer,size)呼叫pcm_local.h檔案中_snd_pcm_readi(,buffer,size);進一步呼叫pcm->fast_ops->readi(pcm->fast_op_arg, buffer, size);根據pcm_hw.h檔案中.readi = snd_pcm_hw_readi可知,ioctl(fd, SNDRV_PCM_IOCTL_READI_FRAMES, &xferi);被呼叫。核心中,根據/soc/pcm_native.c檔案中.unlocked_ioctl = snd_pcm_capture_ioctl,可知snd_pcm_capture_ioctl1被呼叫,根據SNDRV_PCM_IOCTL_READI_FRAMES引數可知snd_pcm_lib_read(substream, xferi.buf, xferi.frames);被呼叫,最終snd_pcm_lib_read1(,,,,snd_pcm_lib_read_transfer)被呼叫。根據transfer被呼叫可知snd_pcm_lib_read_transfer被呼叫,然後呼叫copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)),可知,將dma端記憶體的資料拷貝到alsa_lib提供的一個指標所指的記憶體,alsa庫函式snd_pcm_readi、snd_pcm_writei實現了記憶體到記憶體的互動,或者近似地認為是記憶體到音訊檔案的互動。至此最後一條鏈路建立完畢。待續3

執行分析:

    錄音:mic接到codec,經過adc變成數字訊號,經過待續2中ac97等介面儲存到cpu的fifo中,經過待續1中的dma傳輸儲存到記憶體,經過待續3中alsa_lib中snd_pcm_readi介面傳給錄音軟體,經過編碼,進而形成音訊檔案。

    放音:播放軟體將音訊檔案解碼,並通過待續3中snd_pcm_writei介面逐漸傳遞到和dma相關的記憶體,經過待續2中dma傳遞給cpu的fifo,再經過ac97等介面傳遞給dac,最後傳給連線在codec上的speaker。

心得:

    1.ac97資料傳輸頗覆雜,分時複用,cpu端fifo和codec端adc/dac關係要對應好。比如,cpu端的pcm left fifo佔用slot3,那麼adc只有配置成slot3才能把資料傳遞給它,如果配置成slot6,那就傳給cpu的mic in fifo了。錄音單聲道通常選擇slot6,錄音雙聲道通常兩個adc分別選擇slot3和slot4。

    2.wav音訊檔案大小計算:要測試錄音是否丟禎,就必然要計算檔案大小,通常的方法是:根據錄音時間,用公式:錄音時間(單位s)x取樣率x(取樣位數/8)x通道數。比如,錄音時間5秒,取樣率8kHz,位數16位,通道數1,那麼5x8000x(16/8)x1=80k,實際的wav檔案大小稍大於80k就對了。還有一種計算檔案大小的方法:通常音訊系統要用dma,也會用到dma中斷,可以在dma中斷中列印計數,次數xdma中斷週期位元組就行了。

    3.資料交換的大小問題:待續1中DMA傳輸必須和FIFO的特性匹配:若FIFO位寬是16位,深度是16,並且半滿時向DMA發出請求(握手),則連結串列式DMA必須配置成傳輸位寬16位,1次突發16位元組,才能保證不丟失位數和資料個數。待續2中cpu端FIFO位數要和codec端adc/dac取樣位數匹配,i2s/pcm介面可以配置成一樣的值,比如16位,ac97介面複雜一點,cpu端不用配置,那麼取樣位數是多少呢?若cpu端fifo一個聲道位寬16位,codec端adc/dac位寬18位,ac97通道20位,則傳輸到fifo端就被擷取到有效的16位,整體取樣位數16位,adc/dac的效能沒有充分發揮而已。待續3中snd_pcm_readi、snd_pcm_writei函式第三個引數表示讀寫資料的大小,單位是禎,不是位元組。雙聲道16位格式一禎大小為4位元組。


後記:

    下篇寫除錯音訊中碰到的問題和解決方法。