我继承了一些在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吗?还是我的代码缺少重要的步骤?
答案 0 :(得分:0)
如果函数返回的值为1024,则在调用时至少有1024个帧可用。 (驱动程序实际启动设备可能需要15毫秒的时间。)
无论如何,阻塞或非阻塞模式对CPU使用率没有任何影响。要减少CPU使用率,请用default
或plughw
替换hw
设备,但随后会丢失设备共享或采样率/格式转换等功能。
答案 1 :(得分:0)
我通过如下包装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周期。