首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何减少使用ALSA读取音频时的延迟?

如何减少使用ALSA读取音频时的延迟?
EN

Stack Overflow用户
提问于 2020-03-02 17:36:13
回答 1查看 661关注 0票数 0

当我试图在频域中获取一些信号时,我遇到了一个问题,即snd_pcm_readi()所花费的时间变化很大。这会导致代码的逻辑部分出现问题,该部分与时间有关。

大多数情况下,snd_pcm_readi()在大约0.00003到0.00006秒后返回。但是,对snd_pcm_readi()的每4-5次调用大约需要0.028秒。这是一个巨大的差异,并导致我的代码的逻辑部分失败。

如何获得每次调用snd_pcm_readi()的一致时间?

我尝试过对周期大小进行实验,但即使在多次重新阅读文档之后,我也不清楚它到底做了什么。我不使用中断驱动的设计,我只需调用snd_pcm_readi(),直到它返回数据。

我只能假设它阻塞的时间是可变的,因为snd_pcm_readi()从硬件缓冲区中提取数据,而硬件缓冲区恰好已经有数据可以随时传输到“应用程序缓冲区”(我正在维护该缓冲区)。但是,有时在内核空间或硬件方面还有额外的工作要做,因此函数调用在这些情况下需要更长的时间才能返回。

当我不使用中断驱动的设计时,“周期大小”起什么作用?我的问题可以通过对周期大小的操纵来解决,还是应该做其他的事情呢?

我想要实现的是,每次对snd_pcm_readi()的调用所花费的时间大致相同。我并没有要求一个实时兼容的API,但我不认为ALSA会尝试这样做,但是,我看到函数调用时间的差别是500倍的(这就是我所看到的!)那么这是一个真正的问题。

我们能做些什么,我应该做些什么?

我会给出一个最小的可重复的例子,但这在我的情况下并不容易。

EN

回答 1

Stack Overflow用户

发布于 2020-03-27 10:38:48

通常,在读和写音频时,周期大小指定ALSA在DMA硅中保留了多少数据。通常,周期大小指定延迟时间。因此,例如,当您正在填充一个通过DMA写入I2S硅的缓冲区时,一个DMA缓冲区已经被写入。

如果您的句点大小太小,那么CPU就没有时间在所提供的预定执行槽中写入音频。通常情况下,人们的目标是延迟至少500 us或1 ms。如果您正在进行大量的计算,那么您可能需要选择5 ms或10 ms的延迟。如果您使用的是功能不强的嵌入式系统,您可能会选择更多的延迟。

如果要推送系统的限制,则可以请求增加音频处理线程的优先级。通过增加线程的优先级,您可以要求调度程序在所有其他优先级较低的线程之前处理音频线程。

增加从gtkIOStream ALSA C++ OO类获取的优先级的一种方法是这样的(取自changeThreadPriority法):

代码语言:javascript
复制
/** Set the current thread's priority
\param priority <0 implies maximum priority, otherwise must be between sched_get_priority_max and sched_get_priority_min
\return 0 on success, error code otherwise
*/
static int changeThreadPriority(int priority){
  int ret;
  pthread_t thisThread = pthread_self(); // get the current thread
  struct sched_param origParams, params;
  int origPolicy, policy = SCHED_FIFO, newPolicy=0;

  if ((ret = pthread_getschedparam(thisThread, &origPolicy, &origParams))!=0)
    return ALSA::ALSADebug().evaluateError(ret, "when trying to pthread_getschedparam\n");
  printf("ALSA::Stream::changeThreadPriority : Current thread policy %d and priority %d\n", origPolicy, origParams.sched_priority);

  if (priority<0) //maximum priority
    params.sched_priority = sched_get_priority_max(policy);
  else
    params.sched_priority = priority;

  if (params.sched_priority>sched_get_priority_max(policy))
    return ALSA::ALSADebug().evaluateError(ALSA_SCHED_PRIORITY_ERROR, "requested priority is too high\n");
  if (params.sched_priority<sched_get_priority_min(policy))
    return ALSA::ALSADebug().evaluateError(ALSA_SCHED_PRIORITY_ERROR, "requested priority is too low\n");

  if ((ret = pthread_setschedparam(thisThread, policy, &params))!=0)
    return ALSA::ALSADebug().evaluateError(ret, "when trying to pthread_setschedparam - are you su or do you have permission to set this priority?\n");
  if ((ret = pthread_getschedparam(thisThread, &newPolicy, &params))!=0)
    return ALSA::ALSADebug().evaluateError(ret, "when trying to pthread_getschedparam\n");
  if(policy != newPolicy)
    return ALSA::ALSADebug().evaluateError(ALSA_SCHED_POLICY_ERROR, "requested scheduler policy is not correctly set\n");
  printf("ALSA::Stream::changeThreadPriority : New thread priority changed to %d\n", params.sched_priority);

  return 0;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60493936

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档