例如,我想实时记录我的麦克风并进行处理。显示麦克风信号的示波器视图。
我已经尝试了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
都得到了不错的结果。为什么?
[另外,我查看了pavucontrol
和parec
的来源,事实证明它们都使用asynchronous
API,而我的两个示例程序都使用simple
API。因此,问题并不完全是由于使用1个API或其他API,因为parec
的行为类似于示例程序。
[调用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。 (请注意,使用简单API时会自动设置PA_STREAM_ADJUST_LATENCY
标志。)>
这应该使采样流更加流畅,但是由于pa_simple_read
正在阻塞(等待直到整个缓冲区被填满),即使您使用较小的缓冲区进行读取,您仍然会增加延迟。要摆脱这种额外的延迟,您需要使用异步API进行非阻塞读取。