2010-02-01 140 views
4

有人能解釋如何snd_pcm_writei如何使用ALSA的snd_pcm_writei()?

snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, 
           snd_pcm_uframes_t size) 

的作品?

我已經用它像這樣:

for (int i = 0; i < 1; i++) { 
    f = snd_pcm_writei(handle, buffer, frames); 

    ... 
} 

完整的源代碼在http://pastebin.com/m2f28b578

這是否意味着,我不應該在buffersnd_pcm_writei()的 數所有的幀,但只

SAMPLE_RATE *延遲= frames

因此,如果我例如有: SAMPLE_RATE = 44100 延遲= 0.5 [秒] all_frames = 100000

幀,我應該給snd_pcm_writei()的數目將是

SAMPLE_RATE *延遲=幀 44100×0.5 = 22050

and for循環的迭代次數應該是:

(int)100000/22050 = 4;與幀= 22050

和一個額外的,但只有

100000 MOD 22050 = 11800個

幀?

它是如何工作的?

路易絲

http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html#gf13067c0ebde29118ca05af76e5b17a9

回答

5

應幀(樣本)的數量,您希望從緩存寫入。系統的聲音驅動程序將開始立即將這些樣本傳送到聲卡,並且它們將以恆定速率播放。

延遲引入了幾個地方。在等待傳輸到卡上時,驅動程序緩衝的數據會有延遲。至少有一個數據緩衝區在任何時候都被傳輸到卡上,並且在應用程序端有緩衝區,這是您似乎關心的問題。

爲了減少應用程序端的延遲,您需要編寫最適合您的緩衝區。如果您的應用程序執行DSP任務,那通常是一個窗口值得的數據。

在循環中編寫小緩衝區沒有任何優勢 - 只需繼續並一次寫入所有內容 - 但需要了解的一點很重要:爲了最大限度地減少延遲,應用程序應該以比驅動程序更快的速度寫入驅動程序將數據寫入聲卡,否則最終會堆積更多數據並積累越來越多的延遲。

對於能夠以聲音驅動程序的鎖步生成數據相對容易的設計,請查看基於向聲音播放引擎註冊回調函數的插孔(http://jackaudio.org/)。事實上,如果你真的關心延遲,你可能會更好地使用jack,而不是自己試着去做。

+0

我只需要打出〜17000架,在應用端這樣的延遲,會好起來的。最奇怪的是,如果我給snd_pcm_writei()所有幀,並刪除for循環,則不播放任何內容。如果我保留for循環和例如將其設置爲5次迭代,它將在〜17000幀中循環兩次。如果我在第11行查看libsndfile的示例http://pastebin.com/m559397b3,他會遍歷緩衝區。當我這樣做時,什麼都不玩。另外我覺得奇怪的是,snd_pcm_writei()總是返回我給它的相同數量的幀。它永遠不會返回一個更低的數字,這是我所期望的。 ? – Louise 2010-02-02 23:42:04

+2

17000個採樣少於1秒的播放時間。通過反覆將聲音緩衝區寫入聲卡驅動程序,您基本上一次又一次地播放該聲卡,但是從您的描述中可以看出,系統中的某些內容會阻止播放聲音的開始。 首先,通過緩衝區是正確的事情;你不需要多次寫一個樣本。 其次,要查看您的聲卡驅動程序或聲卡是否無法播放聲音的開頭,請嘗試在開始處填充緩衝區大約一秒鐘的0個採樣點,然後查看該問題是否有所幫助。 – 2010-02-03 15:36:24

+0

非常感謝你清除所有這一切。現在當你提到它時,我在播放ALSA時遇到了一些音頻問題。 MPlayer的。前2秒左右沒有什麼玩,然後它播放。我會嘗試升級到Fedora 12,然後再試一次。再次感謝=) – Louise 2010-02-03 23:14:56

3

我做了一些測試,以確定爲什麼snd_pcm_writei()似乎並沒有給我用幾個例子我在ALSA教程發現什麼,我得出的結論是,簡單的例子,在做一個snd_pcm_close()聲音設備可以播放完整之前工作流發送給它。

我將速率設置爲11025,使用128字節的隨機緩衝區,並且對於循環的snd_pcm_writei()爲11025/128每秒的聲音。兩秒需要86 * 2電話snd_pcm_write()才能獲得兩秒的聲音。

爲了讓設備有足夠的時間將數據轉換爲音頻,我在snd_pcm_writei()循環之後使用了一個for循環來延遲snd_pcm_close()函數的執行。

經過測試,我不得不得出結論,示例代碼在調用snd_pcm_close函數之前沒有提供足夠的樣本來克服設備延遲,這意味着close函數比snd_pcm_write()函數具有更少的延遲。

3

我認爲「過早」設備關閉的原因是您需要在snd_pcm_close(handle);之前致電snd_pcm_drain(handle);以確保在關閉設備之前播放所有數據。