Discussion:
[Portaudio] Setting ASIO buffer sizes (Windows)
John Emmas
2012-11-10 13:04:49 UTC
Permalink
Hi - I'm one of the lead developers for Harrison's 'Mixbus' DAW. I work mostly on the Windows version.

I think I might have mentioned before that Mixbus uses a backend module called 'Jack' to communicate with the audio drivers. On Windows, Jack communicates with the hardware via PortAudio. Jack adjusts the program latency by modifying the audio buffer size.

We've found a strange problem when working with ASIO hardware. Most ASIO drivers provide a 'control panel' app which allows you to inspect various settings - such as he current buffer size and the preferred buffer size. We're finding that the ASIO buffer size is only correct at 44.1Kz. At 48KHz, whatever buffer size we request seems to get added to the ASIO device's preferred buffer size. So if the preferred buffer size is 512 samples and we request 256 samples we actually get 768 samples. At 44.1K we get the 256 samples that we requested.

Jack's developer (Stephane) has looked through the Jack code but he can't find anything that would make the sample rate interfere with what he's sending to PortAudio so we're guessing that the problem must either lie with PortAudio or ASIO (we've checked that Mixbus is requesting the buffer size correctly). But given that we can reproduce the problem with multiple ASIO drivers from different manufacturers, it kinda looks like PortAudio might be the culprit.

Are there any known issues between PortAudio and ASIO, at sample rates other than 44.1KHz? Or does this even seem like the kind of problem that PortAudio could cause??

John
Ross Bencina
2012-11-11 01:05:55 UTC
Permalink
Hi John,

Firstly, I need to know what SVN revision (or snapshot date) you are
referring to. There were some changes to the way PA selects a host
buffer size in r1775 (September 10, 2011).
Post by John Emmas
Jack
adjusts the program latency by modifying the audio buffer size.
Throughout your email you talk about modifying the buffer size, however
there is no direct way to modify the ASIO buffer size programatically.
Therefore I'm unsure about what you are talking about. Can you please be
more specific about this.

Some questions:

- does Jack limit the audio buffer size to only those sizes that the
ASIO driver is reporting as available?

- are you sure that you are selecting a buffer size that is reported as
supported by the driver?
Post by John Emmas
We've found a strange problem when working with ASIO hardware. Most
ASIO drivers provide a 'control panel' app which allows you to
inspect various settings - such as he current buffer size and the
preferred buffer size.
Can you be specific about what hardware you're using? aside from
ASIO4ALL (which seems to me to often report bogus values) I have not
found that "most" drivers report these values.

The drivers I have seen only allow you to select a specific buffer size
and therefore the client application has absolutely no choice but to use
that buffer size (ie preferred = min = max)
Post by John Emmas
We're finding that the ASIO buffer size is
only correct at 44.1Kz. At 48KHz, whatever buffer size we request
seems to get added to the ASIO device's preferred buffer size.
Are you sure that the buffer size is available as a supported driver
buffer size?
Post by John Emmas
So if
the preferred buffer size is 512 samples and we request 256 samples
we actually get 768 samples. At 44.1K we get the 256 samples that we
requested.
What do you mean by "request"? And how do you know what you "actually get"?
Post by John Emmas
Jack's developer (Stephane) has looked through the Jack code but he
can't find anything that would make the sample rate interfere with
what he's sending to PortAudio so we're guessing that the problem
must either lie with PortAudio or ASIO
There is not really any such thing as "ASIO" that could be blamed. ASIO
is just a driver interface specification. Every driver is potentially
different.
Post by John Emmas
(we've checked that Mixbus is requesting the buffer size correctly).
Once again, PortAudio doesn't provide any direct portable way to request
a host buffer size so it's hard for me to take this at face value. You
gave me the impression that Jack was the one requesting the PA buffer
size, so where does Mixbus come into it?
Post by John Emmas
But given that we can
reproduce the problem with multiple ASIO drivers from different
manufacturers
OK.
Post by John Emmas
it kinda looks like PortAudio might be the culprit.
That's possible, however there is no code in PA that would make the
sample rate and the buffer size interact.

Please can you provide a simple test case that isolates the issue?

Thanks,

Ross
Post by John Emmas
Hi - I'm one of the lead developers for Harrison's 'Mixbus' DAW. I
work mostly on the Windows version.
I think I might have mentioned before that Mixbus uses a backend
module called 'Jack' to communicate with the audio drivers. On
Windows, Jack communicates with the hardware via PortAudio. Jack
adjusts the program latency by modifying the audio buffer size.
We've found a strange problem when working with ASIO hardware. Most
ASIO drivers provide a 'control panel' app which allows you to
inspect various settings - such as he current buffer size and the
preferred buffer size. We're finding that the ASIO buffer size is
only correct at 44.1Kz. At 48KHz, whatever buffer size we request
seems to get added to the ASIO device's preferred buffer size. So if
the preferred buffer size is 512 samples and we request 256 samples
we actually get 768 samples. At 44.1K we get the 256 samples that we
requested.
Jack's developer (Stephane) has looked through the Jack code but he
can't find anything that would make the sample rate interfere with
what he's sending to PortAudio so we're guessing that the problem
must either lie with PortAudio or ASIO (we've checked that Mixbus is
requesting the buffer size correctly). But given that we can
reproduce the problem with multiple ASIO drivers from different
manufacturers, it kinda looks like PortAudio might be the culprit.
Are there any known issues between PortAudio and ASIO, at sample
rates other than 44.1KHz? Or does this even seem like the kind of
problem that PortAudio could cause??
John _______________________________________________ Portaudio
mailing list Portaudio at music.columbia.edu
http://music.columbia.edu/mailman/listinfo/portaudio
Bernd Casper BCA
2012-11-11 05:48:09 UTC
Permalink
Hello,

I can confirm the strange values displayed by ASIO4All, when Jack is started via command line and talks to ASIO4All via portaudio. We had this "issue" appearing in the past, in the jOrgan community. We came to the assumption, ASIO4All may just *display* bogus values.

BR
Bernd.

----- Folgende Nachricht wurde empfangen -----

Absender: Ross Bencina
Empf?nger: Portaudio Mailing List
Zeit: 2012-11-11, 02:05:55
Betreff: Re: [Portaudio] Setting ASIO buffer sizes (Windows)
Post by Ross Bencina
Hi John,
Firstly, I need to know what SVN revision (or snapshot date) you are
referring to. There were some changes to the way PA selects a host
buffer size in r1775 (September 10, 2011).
Post by John Emmas
Jack
adjusts the program latency by modifying the audio buffer size.
Throughout your email you talk about modifying the buffer size, however
there is no direct way to modify the ASIO buffer size programatically.
Therefore I'm unsure about what you are talking about. Can you please be
more specific about this.
- does Jack limit the audio buffer size to only those sizes that the
ASIO driver is reporting as available?
- are you sure that you are selecting a buffer size that is reported as
supported by the driver?
Post by John Emmas
We've found a strange problem when working with ASIO hardware. Most
ASIO drivers provide a 'control panel' app which allows you to
inspect various settings - such as he current buffer size and the
preferred buffer size.
Can you be specific about what hardware you're using? aside from
ASIO4ALL (which seems to me to often report bogus values) I have not
found that "most" drivers report these values.
The drivers I have seen only allow you to select a specific buffer size
and therefore the client application has absolutely no choice but to use
that buffer size (ie preferred = min = max)
Post by John Emmas
We're finding that the ASIO buffer size is
only correct at 44.1Kz. At 48KHz, whatever buffer size we request
seems to get added to the ASIO device's preferred buffer size.
Are you sure that the buffer size is available as a supported driver
buffer size?
Post by John Emmas
So if
the preferred buffer size is 512 samples and we request 256 samples
we actually get 768 samples. At 44.1K we get the 256 samples that we
requested.
What do you mean by "request"? And how do you know what you "actually get"?
Post by John Emmas
Jack's developer (Stephane) has looked through the Jack code but he
can't find anything that would make the sample rate interfere with
what he's sending to PortAudio so we're guessing that the problem
must either lie with PortAudio or ASIO
There is not really any such thing as "ASIO" that could be blamed. ASIO
is just a driver interface specification. Every driver is potentially
different.
Post by John Emmas
(we've checked that Mixbus is requesting the buffer size correctly).
Once again, PortAudio doesn't provide any direct portable way to request
a host buffer size so it's hard for me to take this at face value. You
gave me the impression that Jack was the one requesting the PA buffer
size, so where does Mixbus come into it?
Post by John Emmas
But given that we can
reproduce the problem with multiple ASIO drivers from different
manufacturers
OK.
Post by John Emmas
it kinda looks like PortAudio might be the culprit.
That's possible, however there is no code in PA that would make the
sample rate and the buffer size interact.
Please can you provide a simple test case that isolates the issue?
Thanks,
Ross
Post by John Emmas
Hi - I'm one of the lead developers for Harrison's 'Mixbus' DAW. I
work mostly on the Windows version.
I think I might have mentioned before that Mixbus uses a backend
module called 'Jack' to communicate with the audio drivers. On
Windows, Jack communicates with the hardware via PortAudio. Jack
adjusts the program latency by modifying the audio buffer size.
We've found a strange problem when working with ASIO hardware. Most
ASIO drivers provide a 'control panel' app which allows you to
inspect various settings - such as he current buffer size and the
preferred buffer size. We're finding that the ASIO buffer size is
only correct at 44.1Kz. At 48KHz, whatever buffer size we request
seems to get added to the ASIO device's preferred buffer size. So if
the preferred buffer size is 512 samples and we request 256 samples
we actually get 768 samples. At 44.1K we get the 256 samples that we
requested.
Jack's developer (Stephane) has looked through the Jack code but he
can't find anything that would make the sample rate interfere with
what he's sending to PortAudio so we're guessing that the problem
must either lie with PortAudio or ASIO (we've checked that Mixbus is
requesting the buffer size correctly). But given that we can
reproduce the problem with multiple ASIO drivers from different
manufacturers, it kinda looks like PortAudio might be the culprit.
Are there any known issues between PortAudio and ASIO, at sample
rates other than 44.1KHz? Or does this even seem like the kind of
problem that PortAudio could cause??
John _______________________________________________ Portaudio
mailing list Portaudio at music.columbia.edu
http://music.columbia.edu/mailman/listinfo/portaudio
_______________________________________________
Portaudio mailing list
Portaudio at music.columbia.edu
http://music.columbia.edu/mailman/listinfo/portaudio
John Emmas
2012-11-11 08:17:34 UTC
Permalink
Many thanks for such a comprehensive reply Ross. I'll be working away from home for a few days so I might need to let Stephane deal with this (he now has a bit more information). However, to answer your points:-
Firstly, I need to know what SVN revision (or snapshot date) you are referring to. There were some changes to the way PA selects a host buffer size in r1775 (September 10, 2011).
Stephane should know - but I'm pretty sure it'll be circa 2012 (i.e. more recent than Sep 2011).
Throughout your email you talk about modifying the buffer size, however there is no direct way to modify the ASIO buffer size programatically. Therefore I'm unsure about what you are talking about. Can you please be more specific about this.
Actually, that's quite interesting because I can see two functions in PortAudio that seem to suggest otherwise:-

ASIOCreateBuffers() - and,
SelectHostBufferSize()

However, I've already established with Stephane that neither of them gets called by Jack. The only time Jack requests a specific buffer size is when it first calls Pa_OpenStream(). From what I can tell, Pa_OpenStream() requests the buffer sizes it would like - but they aren't necessarily the sizes that it subsequently gets - and therein lies the problem.... Is there any way to tell what buffer sizes actually got allocated? I assume there must be but I can't find a PortAudio call that will return that information.
- does Jack limit the audio buffer size to only those sizes that the ASIO driver is reporting as available?
- are you sure that you are selecting a buffer size that is reported as supported by the driver?
As far as we know, we're selecting valid buffer sizes - but the situation is complicated by having Asio4All in the equation (see below).
Can you be specific about what hardware you're using? aside from ASIO4ALL (which seems to me to often report bogus values) I have not found that "most" drivers report these values.
The drivers I have seen only allow you to select a specific buffer size and therefore the client application has absolutely no choice but to use that buffer size (ie preferred = min = max)
Right, here's where it gets complicated. I first discovered this problem when using Asio4All. Nobody else had ever reported it so I assumed it must be some quirk of Asio4All. Knowing that Asio4All isn't really a true ASIO driver I dismissed the problem as a one-off. However, one of our customers is using an Audiophile 2496 interface from M-Audio (which we're led to believe is a genuine ASIO device). He's using the current M-Audio driver and he's reporting exactly the same problem (buffer sizes get set correctly at 44.1K but not at any other sample rate).

Both cases (Asio4All and M-Audio) provide a small 'control panel' applet that let's you see the current buffer setting. Both applets indicate that the requested size is only set correctly at 44.1K. Our customer is able to access his Audiophile 2496 I/O using other DAWs but they don't exhibit this problem.
Are you sure that the buffer size is available as a supported driver buffer size?
We're reasonably sure. Both applets allow a user to select various sizes (usually in powers of 2) from 64 samples up to about 2048 samples).
What do you mean by "request"? And how do you know what you "actually get"?
Mixbus allows the user to request a buffer size based on the minimum and maximum values returned by PaAsio_GetAvaialableLatencyValues(). At 48KHz the user might select (say) 256 samples - but if he opens the small applet he can see that the size actually allocated was 512 samples.
There is not really any such thing as "ASIO" that could be blamed. ASIO is just a driver interface specification. Every driver is potentially different.
And bear in mind that we have many other people using ASIO who haven't reported this problem at all. That's why we need to find out if it's a general problem or if it's a quirk of these two particular drivers. However, the fact that our customer doesn't get the same problem when he uses other DAWs (with the same driver) suggests that the problem must be with Mixbus, PortAudio or Jack.
Post by John Emmas
it kinda looks like PortAudio might be the culprit.
That's possible, however there is no code in PA that would make the sample rate and the buffer size interact.
Please can you provide a simple test case that isolates the issue?
Perhaps Stephane might be able to do that? Jack can be operated from a command line and hopefully I've given enough information to reproduce the problem. Even if you don't have any ASIO hardware available, the problem is very obvious, even with Asio4All. Thanks for all your help so far Ross.

One more thing that might be helpful.... I've noticed a preprocessor directive called PA_LOG_API_CALLS. If defined at compile time, this will output the requested buffer sizes when Pa_OpenStream() gets called. I've asked Stephane to produce a build with PA_LOG_API_CALLS defined so we can check whether the requested sizes are indeed correct. One question though - where does the log output go? To a file or to the console?

John
Robert Bielik
2012-11-11 12:57:30 UTC
Permalink
Post by John Emmas
However, I've already established with Stephane that neither of them gets called by Jack. The only time Jack requests a specific buffer size is when it first calls Pa_OpenStream(). From what I can tell, Pa_OpenStream() requests the buffer sizes it would like - but they aren't necessarily the sizes that it subsequently gets - and therein lies the problem.... Is there any way to tell what buffer sizes actually got allocated? I assume there must be but I can't find a PortAudio call that will return that information.
This has, I think, been raised earlier (by me too a long time ago), and I think that at least all APIs would be able to provide an upper bound for the buffer size sent to the callback (as part of PaStreamInfo). Maybe we should add a ticket for this (if there isn't one before) ?

Regards,
/Rob
Ross Bencina
2012-11-11 13:40:54 UTC
Permalink
Hi Robert,
Post by Robert Bielik
Post by John Emmas
However, I've already established with Stephane that neither of them
gets called by Jack. The only time Jack requests a specific buffer
size is when it first calls Pa_OpenStream(). From what I can tell,
Pa_OpenStream() requests the buffer sizes it would like - but they
aren't necessarily the sizes that it subsequently gets - and therein
lies the problem.... Is there any way to tell what buffer sizes
actually got allocated? I assume there must be but I can't find a
PortAudio call that will return that information.
The reason there is no such call is that there is no uniform description
of the buffer sizes. It's an implementation detail of each host API and
most of them are different.

There is PaStreamInfo for getting the stream latency, and this will
reflect the host buffer size in a portable way:
http://portaudio.com/docs/v19-doxydocs/structPaStreamInfo.html
Post by Robert Bielik
This has, I think, been raised earlier (by me too a long time ago), and
I think that at least all APIs would be able to provide an upper bound
for the buffer size sent to the callback (as part of PaStreamInfo).
That's true. However that wouldn't help John because he's requesting a
fixed buffer size to the callback, so that would be the value he'd see.
Post by Robert Bielik
Maybe we should add a ticket for this (if there isn't one before) ?
Sure. Something like "Feature request: add maxCallbackFramesPerBuffer to
PaStreamInfo"

Ross.
Robert Bielik
2012-11-11 15:54:51 UTC
Permalink
That's true. However that wouldn't help John because he's requesting a fixed buffer size to the callback, so that would be the value he'd see.
Post by Robert Bielik
Maybe we should add a ticket for this (if there isn't one before) ?
Sure. Something like "Feature request: add maxCallbackFramesPerBuffer to PaStreamInfo"
Or maybe "callbackFramesPerBuffer" together with a flag denoting if it is exact or just an upper bound ? I can see at least that ASIO/CoreAudio/WASAPI and WDMKS would be able to give an exact frame count. Not sure about ALSA/WMME and DirectSound.

Regards,
/Rob
Ross Bencina
2012-11-12 01:46:59 UTC
Permalink
Post by Robert Bielik
Post by Ross Bencina
Sure. Something like "Feature request: add
maxCallbackFramesPerBuffer to PaStreamInfo"
Post by Robert Bielik
Or maybe "callbackFramesPerBuffer" together with a flag denoting if it
is exact or just an upper bound ?
I'm not super-keen on that.

Keep in mind that the user should be writing portable software that
works with all PA implementations. Giving the user many special cases to
deal with is against the general design principles of the API.

Providing a hint as to the upper bounds of the buffer size is one thing.

Providing a choice about whether it is a fixed size is potentially
creating to paths in the client code. What is the benefit there?
Post by Robert Bielik
I can see at least that
ASIO/CoreAudio/WASAPI and WDMKS would be able to give an exact frame
count. Not sure about ALSA/WMME and DirectSound.
My understanding was that WASAPI is the same as DirectSound: the
callback size can vary unless the user requests a fixed framesPerBuffer.
I remember a long discussion with Dmitry about this where we changed the
latency algorithms to support very closely matched latencies at the
expense of variable size callback buffers.

Of course I could be wrong.

Ross.
Robert Bielik
2012-11-13 05:49:02 UTC
Permalink
Post by Ross Bencina
Providing a hint as to the upper bounds of the buffer size is one thing.
Providing a choice about whether it is a fixed size is potentially creating to paths in the client code. What is the benefit there?
I can just provide my view on why I needed to know. In a project I used PA as the backend, but software and drivers up-path needed to be provided with an exact frame count, and also in a timely fashion, i.e. I could've buffered up data so I could provide N size buffers at regular time intervals up-path, but that would've introduced unneccesary additional latency, and also higher code complexity. By allowing a more direct path to the PA backend (by knowing the buffer size), all that could be eliminated.

Regards,
/Rob
Ross Bencina
2012-11-13 05:52:25 UTC
Permalink
Hi Rob,
Post by Robert Bielik
Post by Ross Bencina
Providing a hint as to the upper bounds of the buffer size is one thing.
Providing a choice about whether it is a fixed size is potentially
creating to paths in the client code. What is the benefit there?
I can just provide my view on why I needed to know. In a project I used
PA as the backend, but software and drivers up-path needed to be
provided with an exact frame count, and also in a timely fashion, i.e. I
could've buffered up data so I could provide N size buffers at regular
time intervals up-path, but that would've introduced unneccesary
additional latency, and also higher code complexity. By allowing a more
direct path to the PA backend (by knowing the buffer size), all that
could be eliminated.
Maybe I'm missing something, but the idea is that if you require an
exact frame count then you should request an exact frame count from
PortAudio. The whole point of "frames per buffer unspecified" is that
you don't care what the value is -- that you are able to accomodate any
value.

Is there a reason why you can't just request a specific framesPerBuffer
from PortAudio in the first place?

Ross.
Robert Bielik
2012-11-13 18:44:28 UTC
Permalink
Maybe I'm missing something, but the idea is that if you require an exact frame count then you should request an exact frame count from PortAudio. The whole point of "frames per buffer unspecified" is that you don't care what the value is -- that you are able to accomodate any value.
Is there a reason why you can't just request a specific framesPerBuffer from PortAudio in the first place?
If that specific framesPerBuffer count can be guaranteed to be directly forwarded to the device, i.e. with *no* internal buffering inside PA (which induces large timing jitter), then no, there's no reason not to. But I'm fairly sure I cannot get those guarantees (at least when it comes to ASIO + WDMKS which were my main API targets on Windows). I could be wrong though :)

Regards,
/Rob
Ross Bencina
2012-11-14 02:01:17 UTC
Permalink
Hi Rob,
Post by Robert Bielik
Post by Ross Bencina
Is there a reason why you can't just request a specific
framesPerBuffer from PortAudio in the first place?
If that specific framesPerBuffer count can be guaranteed to be directly
forwarded to the device, i.e. with *no* internal buffering inside PA
(which induces large timing jitter), then no, there's no reason not to.
With ASIO you do this by ensuring that you request a supported buffer
size (PaAsio_GetAvailableBufferSizes): pass this as framesPerBuffer to
Pa_OpenStream() -- then specify a latency value smaller than
framesPerBuffer/sampleRate (0 will work). A similar approach should work
on OSX (and I'm pretty sure that it does).

The reason that this works is that PA guarantees that the callback will
get 100% CPU time where possible, so it should not use a buffer smaller
than framesPerBuffer for the host buffer if it is able to use
framesPerBuffer -- you ensure that framsPerBuffer is usable by
requesting a value that you know will work.

For WMME and DirectSound there are host-API-specific parameters for
Pa_OpenStream to specify the low level buffering parameters precisely.

For other host APIs I don't know.
Post by Robert Bielik
But I'm fairly sure I cannot get those guarantees (at least when it
comes to ASIO + WDMKS which were my main API targets on Windows). I
could be wrong though :)
You are wrong for ASIO as I described above. For WDMKS I have no idea
but if it is double-buffered then it should work with the logic above.
If it uses some other buffering strategy then we should consider adding
a host-api specific low-level buffer parameters to Pa_OpenStream like
WMME and DirectSound.

So as you can see we already have mechanism to getting the exact
buffering you need. It is not portable.

...

That said, I can see some reason for having a portable way to discover
the *maximum* callback frame count when frames per buffer is
unspecified. Although I would argue that things like cache effects
should guide client-side buffer allocation more so than the maximum PA
callback buffer size. Whether this buffer size is fixed or not is not so
interesting except in cases like yours where some downstream client
imposes additional restrictions (in which case, I still maintain you
should not be using frames per buffer unspecified).

Perhaps instead of having a flag in the stream info that tells the
client whether the callback frames per buffer is fixed, it would be
better to have a flag that tells PA whether to *guarantee* that frames
per buffer is fixed in a frames per buffer unspecified stream.

Ross.
Robert Bielik
2012-11-14 16:49:57 UTC
Permalink
Post by Robert Bielik
Post by Ross Bencina
Is there a reason why you can't just request a specific
framesPerBuffer from PortAudio in the first place?
If that specific framesPerBuffer count can be guaranteed to be directly
forwarded to the device, i.e. with *no* internal buffering inside PA
(which induces large timing jitter), then no, there's no reason not to.
With ASIO you do this by ensuring that you request a supported buffer size (PaAsio_GetAvailableBufferSizes): pass this as framesPerBuffer to Pa_OpenStream() -- then specify a latency value smaller than framesPerBuffer/sampleRate (0 will work). A similar approach should work on OSX (and I'm pretty sure that it does).
I see, thanks Ross, will test that. But is there a similar getter function for Mac ?
You are wrong for ASIO as I described above. For WDMKS I have no idea but if it is double-buffered then it should work with the logic above. If it uses some other buffering strategy then we should consider adding a host-api specific low-level buffer parameters to Pa_OpenStream like WMME and DirectSound.
Hmm.. well, problem with WDMKS is that you don't always know what buffer size the device will support, until you try open it up (which is done in OpenStream), specifically in WaveRT case which is subject to address alignment restrictions.

Regards,
/Rob
Ross Bencina
2012-11-15 03:23:18 UTC
Permalink
Post by Robert Bielik
Post by Ross Bencina
With ASIO you do this by ensuring that you request a supported buffer
size (PaAsio_GetAvailableBufferSizes): pass this as framesPerBuffer to
Pa_OpenStream() -- then specify a latency value smaller than
framesPerBuffer/sampleRate (0 will work). A similar approach should
work on OSX (and I'm pretty sure that it does).
I see, thanks Ross, will test that. But is there a similar getter function for Mac ?
PaMacCore_GetBufferSizeRange()
Post by Robert Bielik
Post by Ross Bencina
You are wrong for ASIO as I described above. For WDMKS I have no idea
but if it is double-buffered then it should work with the logic above.
If it uses some other buffering strategy then we should consider
adding a host-api specific low-level buffer parameters to
Pa_OpenStream like WMME and DirectSound.
Hmm.. well, problem with WDMKS is that you don't always know what buffer
size the device will support, until you try open it up (which is done in
OpenStream), specifically in WaveRT case which is subject to address
alignment restrictions.
I see.

So there is no practical way to query for supported buffer sizes without
opening it?

In that case, how do you implement the PA default latency info without
knowing the supported buffer sizes?

Ross.
Robert Bielik
2012-11-15 17:29:39 UTC
Permalink
Post by Ross Bencina
I see.
So there is no practical way to query for supported buffer sizes without opening it?
No, there is no way to know for sure without opening the pin on the KS filter.
Post by Ross Bencina
In that case, how do you implement the PA default latency info without knowing the supported buffer sizes?
Nominally devices accept a buffer size which is near to the desired (or default) latency, but it may not be exactly that which you have requested. In the case of WaveRT, the driver has the possibility to adjust the requested buffer size to one that it can handle (f.i. I can query for 384 frames/buffer but get 512) this info is then returned back to the client code.

In WaveCyclic case, it is more forgiving, I have not yet encountered a driver that rejected a requested buffer size (when it at least is aligned with frame boundaries), unless the size is too small (as given by KSPROPERTY_CONNECTION_ALLOCATORFRAMING property, if supported).

There is a possibility to improve the WaveCyclic case if the driver supports querying of KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX, where the driver can report the exact sizes of the buffer. I have not given this part of the WDM KS code much thought though.

Still, the pin has to be opened to query for those properties.

Regards,
/Rob

Ross Bencina
2012-11-11 13:31:16 UTC
Permalink
Hi John,

First up, I tried to reproduce the problem you describe with ASIO4ALL
and could not.

My first guess is that there is a problem with the suggested latency
parameters that Jack is passing to Pa_OpenStream(). I recommend setting
them to 0 when using the ASIO host API. That will force the lowest
practical latency, which is recent versions of PA/ASIO will correspond
to the framesPerBuffer parameter to Pa_OpenStream().
Post by John Emmas
Post by Ross Bencina
Throughout your email you talk about modifying the buffer size,
however there is no direct way to modify the ASIO buffer size
programatically. Therefore I'm unsure about what you are talking
about. Can you please be more specific about this.
Actually, that's quite interesting because I can see two functions in
PortAudio that seem to suggest otherwise:-
ASIOCreateBuffers() - and, SelectHostBufferSize()
What I meant was that the PortAudio API provides Jack with no direct way
of specifying the host buffer size. The framesPerBuffer parameter to
Pa_OpenStream() is not directly used as the host buffer size.
Post by John Emmas
However, I've already established with Stephane that neither of them
gets called by Jack. The only time Jack requests a specific buffer
size is when it first calls Pa_OpenStream(). From what I can tell,
Pa_OpenStream() requests the buffer sizes it would like
As I tried to explain, the buffer size passed to Pa_OpenStream() does
not map directly to the host buffer size you receive. The mapping logic
is in SelectHostBufferSize and as you can see, there is a long comment
there documenting the algorithm used.
SelectHostBufferSizeForSpecifiedUserFramesPerBuffer() should be being
used in this case.
Post by John Emmas
- but they
aren't necessarily the sizes that it subsequently gets - and therein
lies the problem.... Is there any way to tell what buffer sizes
actually got allocated?
As I said in my later email, this is a function of the client buffer
size (Pa_OpenStream() framesPerBuffer parameter) and the suggested
latency parameters.
Post by John Emmas
I assume there must be but I can't find a
PortAudio call that will return that information.
It's a low level detail. Pretty much every host API has a different
buffering model so PortAudio abstracts this. The algorithms involved are
documented here:

https://www.assembla.com/spaces/portaudio/wiki/BufferingLatencyAndTimingImplementationGuidelines

My guess is that the latency parameters to Pa_OpenStream that Jack is
using are higher than framesPerBuffer * (1.0 / sampleRate)
Post by John Emmas
Post by Ross Bencina
- does Jack limit the audio buffer size to only those sizes that
the ASIO driver is reporting as available?
- are you sure that you are selecting a buffer size that is
reported as supported by the driver?
As far as we know, we're selecting valid buffer sizes - but the
situation is complicated by having Asio4All in the equation (see
below).
I recommend instrumenting the code to print the result of
SelectHostBufferSize() and see whether this matches what the driver is
reporting. I would also be good to find out what
targetBufferingLatencyFrames is since this is the main variable (aside
from userFramesPerBuffer) that would be used.
Post by John Emmas
Post by Ross Bencina
Can you be specific about what hardware you're using? aside from
ASIO4ALL (which seems to me to often report bogus values) I have
not found that "most" drivers report these values.
The drivers I have seen only allow you to select a specific buffer
size and therefore the client application has absolutely no choice
but to use that buffer size (ie preferred = min = max)
Right, here's where it gets complicated. I first discovered this
problem when using Asio4All. Nobody else had ever reported it so I
assumed it must be some quirk of Asio4All. Knowing that Asio4All
isn't really a true ASIO driver I dismissed the problem as a one-off.
However, one of our customers is using an Audiophile 2496 interface
from M-Audio (which we're led to believe is a genuine ASIO device).
He's using the current M-Audio driver and he's reporting exactly the
same problem (buffer sizes get set correctly at 44.1K but not at any
other sample rate).
Both cases (Asio4All and M-Audio) provide a small 'control panel'
applet that let's you see the current buffer setting. Both applets
indicate that the requested size is only set correctly at 44.1K. Our
customer is able to access his Audiophile 2496 I/O using other DAWs
but they don't exhibit this problem.
Post by Ross Bencina
Are you sure that the buffer size is available as a supported
driver buffer size?
We're reasonably sure. Both applets allow a user to select various
sizes (usually in powers of 2) from 64 samples up to about 2048
samples).
The ASIO API reports the buffer size using 4 parameters:

min, preferred, max, bufferGranularity

You can read about these in the ASIO API documentation.

How a control panel applet might provide a single parameter that maps to
all of these is indeterminate.

I've seen some drivers do this:

min = preferred = max

In the case of ASIO4ALL it looks like the slider in the applet is
setting the "preferred" value only. PortAudio will ignore the ASIO
preferred size if you specify a framesPerBuffer parameter to Pa_OpenStream()
Post by John Emmas
Post by Ross Bencina
What do you mean by "request"? And how do you know what you
"actually get"?
Mixbus allows the user to request a buffer size based on the minimum
and maximum values returned by PaAsio_GetAvaialableLatencyValues().
You havn't said how you request it. Is it passed as the framesPerBuffer
parameter to Pa_OpenStream? You also need to request a latency using
inputParameters->suggestedLatency and
outputParameters->suggestedLatency. These combined with framesPerBuffer
determine the host buffer size.
Post by John Emmas
At 48KHz the user might select (say) 256 samples - but if he opens
the small applet he can see that the size actually allocated was 512
samples.
For what it's worth, I don't see that behavior with ASIO4ALL here at the
moment although I have seen some weird stuff in the past.
Post by John Emmas
Post by Ross Bencina
There is not really any such thing as "ASIO" that could be blamed.
ASIO is just a driver interface specification. Every driver is
potentially different.
And bear in mind that we have many other people using ASIO who
haven't reported this problem at all. That's why we need to find out
if it's a general problem or if it's a quirk of these two particular
drivers. However, the fact that our customer doesn't get the same
problem when he uses other DAWs (with the same driver) suggests that
the problem must be with Mixbus, PortAudio or Jack.
Post by Ross Bencina
Post by John Emmas
it kinda looks like PortAudio might be the culprit.
That's possible, however there is no code in PA that would make the
sample rate and the buffer size interact.
Please can you provide a simple test case that isolates the issue?
Perhaps Stephane might be able to do that? Jack can be operated from
a command line and hopefully I've given enough information to
reproduce the problem. Even if you don't have any ASIO hardware
available, the problem is very obvious, even with Asio4All. Thanks
for all your help so far Ross.
One more thing that might be helpful.... I've noticed a preprocessor
directive called PA_LOG_API_CALLS. If defined at compile time, this
will output the requested buffer sizes when Pa_OpenStream() gets
called. I've asked Stephane to produce a build with PA_LOG_API_CALLS
defined so we can check whether the requested sizes are indeed
correct.
That's a good idea. I'd be most interested to see what latency
parameters are being passed to Pa_OpenStream().
Post by John Emmas
One question though - where does the log output go? To a
file or to the console?
By default to the console. It is possible to replace the default logging
function (to write to a file for example) by calling
PaUtil_SetDebugPrintFunction().

Ross.
Stéphane Letz
2012-11-11 13:41:29 UTC
Permalink
The code is there : https://github.com/jackaudio/jack2/blob/master/windows/portaudio/JackPortAudioDriver.cpp

Basically Pa_OpenStream is used with defaultLowInputLatency and defaultLowOutputLatency.

St?phane
Post by Ross Bencina
Hi John,
First up, I tried to reproduce the problem you describe with ASIO4ALL and could not.
My first guess is that there is a problem with the suggested latency parameters that Jack is passing to Pa_OpenStream(). I recommend setting them to 0 when using the ASIO host API. That will force the lowest practical latency, which is recent versions of PA/ASIO will correspond to the framesPerBuffer parameter to Pa_OpenStream().
Post by John Emmas
Post by Ross Bencina
Throughout your email you talk about modifying the buffer size,
however there is no direct way to modify the ASIO buffer size
programatically. Therefore I'm unsure about what you are talking
about. Can you please be more specific about this.
Actually, that's quite interesting because I can see two functions in
PortAudio that seem to suggest otherwise:-
ASIOCreateBuffers() - and, SelectHostBufferSize()
What I meant was that the PortAudio API provides Jack with no direct way of specifying the host buffer size. The framesPerBuffer parameter to Pa_OpenStream() is not directly used as the host buffer size.
Post by John Emmas
However, I've already established with Stephane that neither of them
gets called by Jack. The only time Jack requests a specific buffer
size is when it first calls Pa_OpenStream(). From what I can tell,
Pa_OpenStream() requests the buffer sizes it would like
As I tried to explain, the buffer size passed to Pa_OpenStream() does not map directly to the host buffer size you receive. The mapping logic is in SelectHostBufferSize and as you can see, there is a long comment there documenting the algorithm used. SelectHostBufferSizeForSpecifiedUserFramesPerBuffer() should be being used in this case.
Post by John Emmas
- but they
aren't necessarily the sizes that it subsequently gets - and therein
lies the problem.... Is there any way to tell what buffer sizes
actually got allocated?
As I said in my later email, this is a function of the client buffer size (Pa_OpenStream() framesPerBuffer parameter) and the suggested latency parameters.
Post by John Emmas
I assume there must be but I can't find a
PortAudio call that will return that information.
https://www.assembla.com/spaces/portaudio/wiki/BufferingLatencyAndTimingImplementationGuidelines
My guess is that the latency parameters to Pa_OpenStream that Jack is using are higher than framesPerBuffer * (1.0 / sampleRate)
Post by John Emmas
Post by Ross Bencina
- does Jack limit the audio buffer size to only those sizes that
the ASIO driver is reporting as available?
- are you sure that you are selecting a buffer size that is
reported as supported by the driver?
As far as we know, we're selecting valid buffer sizes - but the
situation is complicated by having Asio4All in the equation (see
below).
I recommend instrumenting the code to print the result of SelectHostBufferSize() and see whether this matches what the driver is reporting. I would also be good to find out what targetBufferingLatencyFrames is since this is the main variable (aside from userFramesPerBuffer) that would be used.
Post by John Emmas
Post by Ross Bencina
Can you be specific about what hardware you're using? aside from
ASIO4ALL (which seems to me to often report bogus values) I have
not found that "most" drivers report these values.
The drivers I have seen only allow you to select a specific buffer
size and therefore the client application has absolutely no choice
but to use that buffer size (ie preferred = min = max)
Right, here's where it gets complicated. I first discovered this
problem when using Asio4All. Nobody else had ever reported it so I
assumed it must be some quirk of Asio4All. Knowing that Asio4All
isn't really a true ASIO driver I dismissed the problem as a one-off.
However, one of our customers is using an Audiophile 2496 interface
from M-Audio (which we're led to believe is a genuine ASIO device).
He's using the current M-Audio driver and he's reporting exactly the
same problem (buffer sizes get set correctly at 44.1K but not at any
other sample rate).
Both cases (Asio4All and M-Audio) provide a small 'control panel'
applet that let's you see the current buffer setting. Both applets
indicate that the requested size is only set correctly at 44.1K. Our
customer is able to access his Audiophile 2496 I/O using other DAWs
but they don't exhibit this problem.
Post by Ross Bencina
Are you sure that the buffer size is available as a supported driver buffer size?
We're reasonably sure. Both applets allow a user to select various
sizes (usually in powers of 2) from 64 samples up to about 2048
samples).
min, preferred, max, bufferGranularity
You can read about these in the ASIO API documentation.
How a control panel applet might provide a single parameter that maps to all of these is indeterminate.
min = preferred = max
In the case of ASIO4ALL it looks like the slider in the applet is setting the "preferred" value only. PortAudio will ignore the ASIO preferred size if you specify a framesPerBuffer parameter to Pa_OpenStream()
Post by John Emmas
Post by Ross Bencina
What do you mean by "request"? And how do you know what you
"actually get"?
Mixbus allows the user to request a buffer size based on the minimum
and maximum values returned by PaAsio_GetAvaialableLatencyValues().
You havn't said how you request it. Is it passed as the framesPerBuffer parameter to Pa_OpenStream? You also need to request a latency using inputParameters->suggestedLatency and outputParameters->suggestedLatency. These combined with framesPerBuffer determine the host buffer size.
Post by John Emmas
At 48KHz the user might select (say) 256 samples - but if he opens
the small applet he can see that the size actually allocated was 512
samples.
For what it's worth, I don't see that behavior with ASIO4ALL here at the moment although I have seen some weird stuff in the past.
Post by John Emmas
Post by Ross Bencina
There is not really any such thing as "ASIO" that could be blamed.
ASIO is just a driver interface specification. Every driver is
potentially different.
And bear in mind that we have many other people using ASIO who
haven't reported this problem at all. That's why we need to find out
if it's a general problem or if it's a quirk of these two particular
drivers. However, the fact that our customer doesn't get the same
problem when he uses other DAWs (with the same driver) suggests that
the problem must be with Mixbus, PortAudio or Jack.
Post by Ross Bencina
Post by John Emmas
it kinda looks like PortAudio might be the culprit.
That's possible, however there is no code in PA that would make the
sample rate and the buffer size interact.
Please can you provide a simple test case that isolates the issue?
Perhaps Stephane might be able to do that? Jack can be operated from
a command line and hopefully I've given enough information to
reproduce the problem. Even if you don't have any ASIO hardware
available, the problem is very obvious, even with Asio4All. Thanks
for all your help so far Ross.
One more thing that might be helpful.... I've noticed a preprocessor
directive called PA_LOG_API_CALLS. If defined at compile time, this
will output the requested buffer sizes when Pa_OpenStream() gets
called. I've asked Stephane to produce a build with PA_LOG_API_CALLS
defined so we can check whether the requested sizes are indeed
correct.
That's a good idea. I'd be most interested to see what latency parameters are being passed to Pa_OpenStream().
Post by John Emmas
One question though - where does the log output go? To a
file or to the console?
By default to the console. It is possible to replace the default logging function (to write to a file for example) by calling PaUtil_SetDebugPrintFunction().
Ross.
_______________________________________________
Portaudio mailing list
Portaudio at music.columbia.edu
http://music.columbia.edu/mailman/listinfo/portaudio
Ross Bencina
2012-11-11 14:09:36 UTC
Permalink
Hi St?phane,
The code is there :https://github.com/jackaudio/jack2/blob/master/windows/portaudio/JackPortAudioDriver.cpp
Basically Pa_OpenStream is used with defaultLowInputLatency and defaultLowOutputLatency.
That would explain the behavior John is seeing. You're requesting
latency higher than the buffer_size in two ways:

- default latency is computed off the preferred buffer size, which is
not necessarily what John is "requesting" as buffer_size.

- default latency is computed relative to defaultSampleRate (usually
44.1k). If you're using a higher sample rate then the default latency
parameter will be higher than you need/want.

See pa_asio.cpp line 1231:

double defaultLowLatency = paAsioDriver.info.bufferPreferredSize /
deviceInfo->defaultSampleRate.

Even at 44.1k this is not going to give John the behavior he is
expecting unless he's also passing bufferPreferredSize to Pa_OpenStream.

Using the default latencies in this situation is not very good.
I would be inclined to extend Jack to allow the user to specify the
latencies.

For PA/ASIO with fixed framesPerBuffer it should be enough to pass 0 for
the suggested latencies, but this is not really good advice for
portability to other host APIs.

Ross.
Ross Bencina
2012-11-11 06:33:43 UTC
Permalink
Hi Again John,
Post by John Emmas
We're finding that the ASIO buffer size is only correct at 44.1Kz.
At 48KHz, whatever buffer size we request seems to get added to the
ASIO device's preferred buffer size. So if the preferred buffer size
is 512 samples and we request 256 samples we actually get 768
samples. At 44.1K we get the 256 samples that we requested.
Thinking about this further:

As I said earlier, there is no way to request a particular host buffer
size from PortAudio/ASIO.

The host buffer size will be a function of the requested client buffer
size (framesPerBuffer parameter to OpenStream) and also a function of
the suggested latency parameters.

Therefore the most likely cause is going to be the suggested latency
parameters, or possibly their implementation in PA.

But first make sure you're building Jack against a recent version of
PortAudio.

Ross.
Loading...