PulseAudio无法以一致的速率读取缓冲区

时间:2019-05-19 18:10:01

标签: linux audio pulseaudio

我想实时记录我的麦克风并进行处理,例如显示示波器视图的麦克风信号。

我尝试了3种方法从PulseAudio中获取数据,并且它们都执行相同的操作。我期望二进制流平稳,但是会有一种大致类似的模式:挂起〜300ms,打印一吨输出,重复。
3种不同的方式,2种不同的机器,相同的结果。

第一种方法是parec

第二种方法和第三种方法都是使用pulse-simple库的C和Haskell中的hello世界。

C: https://freedesktop.org/software/pulseaudio/doxygen/parec-simple_8c-example.html#a7

Haskell:

import Sound.Pulse.Simple
import Control.Monad
import System.IO

main = do

  s <- simpleNew Nothing "example" Record Nothing
       "this is an example application"
       (SampleSpec (F32 LittleEndian) 44100 1) Nothing Nothing


  forever $ do

  let numSamples = 4410
  xs <- simpleRead s $ numSamples :: IO [Float]

  putStrLn $ "hello"

  hFlush stdout

在循环主体中刷新标准输出没有影响。
在循环中添加延迟会改变性能,但并不能达到我想要的效果。

以某种方式pavucontrol VU计量器正确无误。我想念什么?

编辑:我发现在运行pavucontrol时,无论是在示例程序中还是在parec上,都能得到很好的结果。为什么?

我还查看了pavucontrolparec的来源,结果发现它们都使用asynchronous API,而我的2个示例程序都使用了simple API。因此,问题并不完全是由于使用了1个API或其他API,因为parec的行为类似于示例程序。

1 个答案:

答案 0 :(得分:1)

调用pa_simple_new时,请将fragsize参数的pa_buffer_attr字段设置为所需的等待时间(以字节为单位)。 PulseAudio将尝试实现该延迟,但可能无法达到该延迟,具体取决于硬件功能。

(pavucontrol可能要求较低的延迟。PulseAudio尝试达到所有当前正在运行的程序所要求的最低延迟,因此这就是在运行pavucontrol时记录延迟较低的原因。

在C中:

    pa_buffer_attr attr;
    attr.maxlength = (uint32_t) -1;
    attr.tlength = (uint32_t) -1;
    attr.prebuf = (uint32_t) -1;
    attr.minreq = (uint32_t) -1;
    attr.fragsize = 1600;

    pa = pa_simple_new(NULL,
                       argv[0],
                       PA_STREAM_RECORD,
                       NULL,
                       "record",
                       &ss,
                       NULL,
                       &attr,
                       &error);

有关更多信息,请参见LatencyControl。 (请注意,PA_STREAM_ADJUST_LATENCY标志是在使用简单API时自动设置的。)

这应该使采样流更加流畅,但是由于pa_simple_read正在阻塞(等待直到整个缓冲区被填满),即使您使用较小的缓冲区进行读取,您仍然会增加延迟。为了消除这种额外的延迟,您需要使用异步API进行非阻塞读取。