PortAudio / portaudio

PortAudio is a cross-platform, open-source C language library for real-time audio input and output.
Other
1.43k stars 297 forks source link

WDM-KS fails to open WaveRT devices with suggestedLatency=0 #761

Closed dechamps closed 1 year ago

dechamps commented 1 year ago

Describe the bug If the following conditions are true:

Then Pa_OpenStream() will fail.

To Reproduce

  1. Change examples/paex_sine.c:
    • Set suggestedLatency to zero.
    • Set device to the index of a WDM-KS device that happens to use WaveRT.
      • Virtual Audio Cable can be used to emulate a WaveRT device, as well as WavePci and WaveCyclic for comparison.
  2. Run the example.

Expected behavior The example runs and plays sound for 5 seconds.

Actual behavior Pa_OpenStream() fails with the following debug output:

 0.072: OpenStream:sampleRate = 44100.000000
 0.072: OpenStream:framesPerBuffer = 64
 0.072: Pin create result = 0x00000000
 0.072: Render pin frames: 0
 0.072: Output frames chosen:0
 0.072: Failed to get buffer with notification
 0.073: Failed to get buffer without notification
 0.073: Buffer size on 128 byte boundary, still fails :(
 0.073: Failed to get output buffer (with notification)
TerminateHostApis in
TerminateHostApis out
An error occurred while using the portaudio stream
Error number: -9999
Error message: Unanticipated host error

Desktop:

Additional context

dechamps commented 1 year ago

Digging further, the PortAudio WDM-KS code is issuing a KSRTAUDIO_BUFFER_PROPERTY request with a RequestedBufferSize of zero in this case.

Now in theory this is supposed to work, according to the Microsoft docs linked above and the KSPROPERTY_RTAUDIO_BUFFER docs:

The value that the client writes into the RequestedBufferSize member is not binding on the driver. However, the driver must specify a buffer size that is as close as possible to the requested size, taking into account the buffer size constraints on the driver itself. The driver allocates a buffer of a different size if the hardware cannot handle the requested size or the system is low on memory.

the actual size of the buffer is the requested size rounded (up or down) to the nearest sample or other hardware-constrained boundary. The actual size must be at least the requested size

Theoretically, according to the above, the driver should accept zero and then return the smallest buffer size it supports. It could be that there is an undocumented constraint that this parameter cannot be zero.

RossBencina commented 1 year ago

Something is fishy here.

You have written:

 0.072: OpenStream:framesPerBuffer = 64

And later,

PortAudio WDM-KS code is issuing a KSRTAUDIO_BUFFER_PROPERTY request with a RequestedBufferSize of zero in this case.

There's no way the code should be requesting zero buffer size if framesPerBuffer is 64. The only scenario where RequestedBufferSize could reasonably be zero is if suggestedLatency is 0 and framesPerBuffer is paFramesPerBufferUnspecified (or any other constant that indicates unspecified buffer size).

A second comment: if this is a workaround for KSRTAUDIO_BUFFER_PROPERTY/RequestedBufferSize behavior, then the clamp to 1 if 0 should be performed just prior to the KSRTAUDIO_BUFFER_PROPERTY command.

RossBencina commented 1 year ago

I've created a separate issue regarding taking framesPerBuffer into account. Let's keep that as a separate issue: https://github.com/PortAudio/portaudio/issues/764

philburk commented 1 year ago

Thanks for finding this issue.

Theoretically, according to the above, the driver should accept zero

I'm not sure that follows from the doc. A buffer size of zero may just be an unreasonable or illegal value. The is definitely a bug. But I don't know if the bug is in PortAudio or WDMKS. But in any event, we should avoid passing zero to WDMKS.