[英]ALSA - Non blocking (interleaved) read
我繼承了一些在Linux嵌入式平台上運行的ALSA代碼。 現有的實現確實使用snd_pcm_readi()
和snd_pcm_writei()
來阻止讀寫。
我的任務是使它在ARM處理器上運行,但是我發現阻塞的交錯讀取將CPU提升到99%,因此我正在探索非阻塞的讀寫。
我可以打開設備:
snd_pcm_handle *handle;
const char* hwname = "plughw:0"; // example name
snd_pcm_open(&handle, hwname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
然后,我可以根據要求提供其他ALSA物品。
在這一點上值得一提的是:
像這樣讀取流:
int32* buffer; // buffer set up to hold #period_size samples
int actual = snd_pcm_readi(handle, buffer, period_size);
在阻塞模式下,此調用大約需要15 [ms]才能完成。 顯然, actual
變量將返回1024。
問題是; 在非阻塞模式下,此功能還需要15毫秒才能完成, actual
返回值始終為1024。
我希望該函數將立即返回, actual
為<= 1024,並且很有可能讀取“ EAGAIN”(-11)。
在兩次讀取嘗試之間,我計划使線程進入特定時間的睡眠狀態,從而將CPU時間分配給其他進程。
我是否誤解了ALSA API? 還是我的代碼缺少重要的一步?
如果函數返回值1024,則在調用時至少有1024個幀可用。 (驅動程序實際啟動設備可能需要15毫秒的時間。)
無論如何,阻塞或非阻塞模式對CPU使用率沒有任何影響。 要減少CPU使用率,請將default
設備替換為plughw
或hw
,但隨后會丟失設備共享或采樣率/格式轉換等功能。
我通過如下包裝snd_pcm_readi()
解決了我的問題:
/*
** Read interleaved stream in non-blocking mode
*/
template <typename SampleType>
snd_pcm_sframes_t snd_pcm_readi_nb(snd_pcm_t* pcm, SampleType* buffer, snd_pcm_uframes_t size, unsigned samplerate)
{
const snd_pcm_sframes_t avail = ::snd_pcm_avail(pcm);
if (avail < 0) {
return avail;
}
if (avail < size) {
snd_pcm_uframes_t remain = size - avail;
unsigned long msec = (remain * 1000) / samplerate;
static const unsigned long SLEEP_THRESHOLD_MS = 1;
if (msec > SLEEP_THRESHOLD_MS) {
msec -= SLEEP_THRESHOLD_MS;
// exercise for the reader: sleep for msec
}
}
return ::snd_pcm_readi(pcm, buffer, size);
}
這對我來說很好。 我的音頻過程現在“僅”占用19%的CPU時間。 而且,是否使用SND_PCM_NONBLOCK
或0
打開PCM接口並不重要。
將執行callgrind分析,以查看是否可以在代碼的其他位置保存更多的CPU周期。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.