Pa_GetDeviceInfo() 和 PaAsio_GetAvailableBufferSizes() 的行为

问题描述

我正在使用 portaudio 构建一个简单的应用程序,但是当涉及到 ASIO 驱动程序以及 Pa_GetDeviceInfo()PaAsio_GetAvailableBufferSizes()

的行为时,我无法完全解释

假设我使用外部应用程序以 48 kHz 的频率录制来自我的 ASIO 设备的音频。 此时,如果我运行 portaudio 附带的“pa_devs”示例,我会得到以下内容

[ Default ASIO Input,Default ASIO Output ]
Name                        = xxx
Host API                    = ASIO
Max inputs = 8,Max outputs = 8
Default low input latency   =   0.0196
Default low output latency  =   0.0196
Default high input latency  =   0.0196
Default high output latency =   0.0196
ASIO minimum buffer size    = 864
ASIO maximum buffer size    = 864
ASIO preferred buffer size  = 864
ASIO buffer granularity     = 0
Default sample rate         = 44100.00

现在,如果我以 192 kHz 进行第二次录音,然后再次运行“pa_devs”,我会得到:

[ Default ASIO Input,Max outputs = 8
Default low input latency   =   0.0784
Default low output latency  =   0.0784
Default high input latency  =   0.0784
Default high output latency =   0.0784
ASIO minimum buffer size    = 3456
ASIO maximum buffer size    = 3456
ASIO preferred buffer size  = 3456
ASIO buffer granularity     = 0
Default sample rate         = 44100.00

所以似乎正在发生的是缓冲区大小会根据采样率自动调整,以绝对保持固定的延迟:

864/48000 = 3456/192000 = 18 毫秒

现在真正的问题来了。与“pa_devs”相反,我自己的应用程序不会在录制之间启动和停止,而是一直在旁边运行。 但是,如果我的应用程序在录音之间调用 Pa_GetDeviceInfo()PaAsio_GetAvailableBufferSizes(),那么我总是会得到相同的延迟和相同的 ASIO 缓冲区大小。基本上它似乎没有看到外部录音应用程序改变了连续调用间的采样率。任何想法可能导致这种情况?

[edit]:使用 here 的 pyaudio 构建(支持 ASIO)作为不同的观察机制,我发现执行 pyaudio.PyAudio().get_device_info_by_index(N) 也总是返回相同的答案,即使采样率已更改(我也可以在 ASIO 控制面板上进行监控)

然而,作为一种不同的观察机制,我有一个 Audio Precision 盒子。在 ASIO 连接器设置上,只要在外部应用程序上开始录制,它就会立即反映采样率的任何变化和缓冲区大小的变化。为什么 pyaudio 和我自己的应用程序也没有收到更改通知

解决方法

至少现在我想我明白了问题的根本原因。我不太确定这是错误还是设计意图。

当设备的参数在外部发生变化(例如当前采样率或默认采样率)时,只要 所有之前对 Pa_Initialize() 的调用尚未被 Pa_Terminate() 关闭,最终会再次调用 Pa_Initialize()

因此,如果应用在启动时调用 Pa_Initialize(),它会从所有后续调用 Pa_GetDeviceInfo()PaAsio_GetAvailableBufferSizes() 中得到相同的回复,即使设备属性在此期间在外部发生了更改。

相反,应用似乎每次想要做任何事情时都应该成对调用 Pa_Initialize()Pa_Terminate(),就像 Pa_GetDeviceInfo() 一样简单。这似乎引发了进一步的问题:

  1. pyaudio 怎么样?它公开 terminate() 但不公开 initialize()。我还没有找到强制更新设备属性的方法。甚至 reload(pyaudio) 也无法解决问题。
  2. 同时运行并加载相同共享 portaudio 库的应用程序呢?如果他们对 Pa_Initialize()Pa_Terminate() 进行交错调用,他们大概不会得到正确的值?