繁体   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