簡體   English   中英

ALSA-非阻塞(交錯)讀取

[英]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物品。
在這一點上值得一提的是:

  • 我們將采樣率設置為48,000 [Hz]
  • 樣本類型是帶符號的32位整數
  • 設備始終將我們請求的周期大小覆蓋為1024幀

像這樣讀取流:

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設備替換為plughwhw ,但隨后會丟失設備共享或采樣率/格式轉換等功能。

我通過如下包裝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_NONBLOCK0打開PCM接口並不重要。

將執行callgrind分析,以查看是否可以在代碼的其他位置保存更多的CPU周期。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM