PortAudio / portaudio

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

WASAPI interprets a zero suggestedLatency in surprising ways #287

Closed PortAudio-admin closed 5 years ago

PortAudio-admin commented 5 years ago

Issue created by @dechamps

Using PortAudio latest master (0cdb346):

Opening a device in WASAPI Exclusive mode with framesPerBuffer = 480 and suggestedLatency = 0.0:

Opening PortAudio stream with...
...input parameters: none
...output parameters: PortAudio stream parameters for device index 23,
  6 channels, sample format 2147483649 [Float32, NonInterleaved], suggested latency 0s, host API specific: 56 bytes structure,
     type 13 [WASAPI], version 1, WASAPI specific: flags 5 [Exclusive, UseChannelMask],
     channel mask 63 [Front Left, Front Right, Front Center, Low Frequency, Back Left, Back Right],
     host processor output 0000000000000000, host processor input 0000000000000000,
     thread priority 0 [None], stream category 0 [Other], stream option 0 [None]
...sample rate: 48000 Hz
...frames per buffer: 480
...stream flags: 0
...stream callback: 00007FFB98B9EE56 (user data 000002C40B81CF80)
[PortAudio] WASAPI: IAudioClient2 set properties: IsOffload = 0, Category = 0, Options = 0
[PortAudio] wFormatTag     =WAVE_FORMAT_EXTENSIBLE
[PortAudio] SubFormat      =KSDATAFORMAT_SUBTYPE_PCM
[PortAudio] Samples.wValidBitsPerSample =24
[PortAudio] dwChannelMask  =0x3F
[PortAudio] nChannels      =6
[PortAudio] nSamplesPerSec =48000
[PortAudio] nAvgBytesPerSec=1152000
[PortAudio] nBlockAlign    =24
[PortAudio] wBitsPerSample =32
[PortAudio] cbSize         =22
[PortAudio] WASAPI::OpenStream(output): framesPerUser[ 480 ] framesPerHost[ 480 ] latency[ 10.00ms ] exclusive[ YES ] wow64_fix[ NO ] mode[ EVENT ]
PortAudio stream opened: 000002C40B85E4A0
Stream info: PortAudio stream info version 0, input latency 0s, output latency 0.01s, sample rate 48000 Hz

The same, but with suggestedLatency = 0.001:

Opening PortAudio stream with...
...input parameters: none
...output parameters: PortAudio stream parameters for device index 23,
  6 channels, sample format 2147483649 [Float32, NonInterleaved], suggested latency 0.001s, host API specific: 56 bytes structure,
     type 13 [WASAPI], version 1, WASAPI specific: flags 5 [Exclusive, UseChannelMask],
     channel mask 63 [Front Left, Front Right, Front Center, Low Frequency, Back Left, Back Right],
     host processor output 0000000000000000, host processor input 0000000000000000,
     thread priority 0 [None], stream category 0 [Other], stream option 0 [None]
...sample rate: 48000 Hz
...frames per buffer: 0
...stream flags: 0
...stream callback: 00007FFB98C21840 (user data 0000000000000000)
[PortAudio] WASAPI: CreateAudioClient: forcing POLL mode
[PortAudio] WASAPI: IAudioClient2 set properties: IsOffload = 0, Category = 0, Options = 0
[PortAudio] wFormatTag     =WAVE_FORMAT_EXTENSIBLE
[PortAudio] SubFormat      =KSDATAFORMAT_SUBTYPE_PCM
[PortAudio] Samples.wValidBitsPerSample =24
[PortAudio] dwChannelMask  =0x3F
[PortAudio] nChannels      =6
[PortAudio] nSamplesPerSec =48000
[PortAudio] nAvgBytesPerSec=1152000
[PortAudio] nBlockAlign    =24
[PortAudio] wBitsPerSample =32
[PortAudio] cbSize         =22
[PortAudio] WASAPI::OpenStream(output): framesPerUser[ 480 ] framesPerHost[ 1024 ] latency[ 21.33ms ] exclusive[ YES ] wow64_fix[ NO ] mode[ POLL ]
PortAudio stream opened: 000002C51D00DB10
Stream info: PortAudio stream info version 0, input latency 0s, output latency 0.0213333s, sample rate 48000 Hz

This behaviour is surprising - changing the suggested latency from zero to just 1 ms had the effect of putting the WASAPI code into a completely different mode (PULL instead of EVENT) and made the resulting stream latency jump from 10 ms to 20 ms.

PortAudio-admin commented 5 years ago

Comment by @dechamps

It seems that we will enter POLL mode (instead of EVENT mode) because the following condition is true:

((INT32)(params->suggestedLatency*100000.0) != 0/*0.01 msec granularity*/)

This will only be true if suggestedLatency is less than 10 s. Which is basically zero.

The commit that introduces this code is 9c7974c7, which states:

"advanced Event driven mode and extended the range of host buffer size which can operate in this mode up up to 20.66 ms, e.g. your device buffer size will vary in range 3 - 20.66 ms, if goes above then Poll driven mode is switched on automatically"

This seems to contradict the code.

PortAudio-admin commented 5 years ago

Comment by @dechamps

@dmitrykos who might know something about this, since he wrote the aforementioned commit.

PortAudio-admin commented 5 years ago

Comment by @dmitrykos

@edechamps, that was most probably a protection against some reported Vista's bug, may be in WOW64 mode when if Event mode was active the callback was never called by the OS.

My proposal is - try to omit this check completely

((INT32)(params->suggestedLatency*100000.0) != 0/*0.01 msec granularity*/)

and see if users report any problems.

I made tests on built-in audio (ALC) with UAC2 and several UAC1 USB DACs - all seems ok, no problem with callback. May be it does not make sense to keep this check any more and makes sense to let users fine tune latency with fine granulation. In my tests I was testing 3,6,9,11 ... 21 latencies with no problem at all.

I will create a merge request with this issue.

> This seems to contradict the code.

Yes, those changes were made on the fly. Let's normalize this area.

PortAudio-admin commented 5 years ago

Comment by @dechamps

@dmitrykos Agreed :) I think we should try to use EVENT as much as possible as that seems to be the most efficient way of doing things.

(One thing that I've also noticed is that EVENT is never used in full-duplex mode. Not sure if that's a fundamental limitation of how the code works of if that's something that's easily fixable.)

PortAudio-admin commented 5 years ago

Comment by @dmitrykos

Created merge request (http://app.assembla.com/spaces/portaudio/git/merge_requests/7097201), if all is ok, will merge it into a master.

PortAudio-admin commented 5 years ago

Issue closed by @dmitrykos

PortAudio-admin commented 5 years ago

Comment by @dmitrykos

> Not sure if that's a fundamental limitation of how the code works of if that's something that's easily fixable

@edechamps, there were numerous problems with Event mode when callbacks were not called, and etc. Basically it did not work on Vista. So the most feasible way was to force always Poll mode. You could try to relax that check and test in your application, if you have full-duplex behavior, and see if it works. If it is then may be enabling Event on Windows 10+ would make sense after thorough testing.