Discussion:
[Portaudio] PortAudio OSX i/o buffer size
Ross Bencina
2009-05-04 17:06:52 UTC
Permalink
Hi Everyone

I'm looking for some feedback on an implementation detail I'm wanting to
change and would appreciate any feedback you're able to give...

First, a couple of definitions:
"framesPerBuffer": this size of the buffer passed to a PA callback
"host buffer size": the size of buffers passed between PA and the host.

While the list was down Bjorn and I had a discussion about the interaction
between the framesPerBuffer parameter and the latency parameters to
Pa_OpenStream. The OSX PA version currently works a bit differently from the
way PA works on Windows (the closest comparison is with the ASIO
implementation since both CoreAudio and ASIO are double-buffered). And I'm
hoping to change the OSX implementation to address that*

If I understand things correctly, the basic issue is that on OSX, the host
buffer size is never made larger than framesPerBuffer, even if the latency
values are set higher than 2*framesPerBufferDuration.

The way it works with ASIO is for the host buffer to be the highest integer
multiple of framesPerBuffer such that the host buffer duration is less than
or equal to the specified latency. eg:

host buffer frames = N * framesPerBuffer
choose max N integer such that: duration(N * framesPerBuffer) <= Output
Latency

(actually sometimes it can be more complicated than that due to restrictions
on ASIO buffer sizes imposed by certain drivers, but that's a separate
matter)...

---

*the reason I want to change it is because my app expects a fixed
framesPerBuffer to be passed to its callback, and at the same time to be
able to adjust audio buffering (ie latency) by changing PortAudio's latency
parameters to increase stability. I think that's a pretty common use case.

Bjorn made the point that because CoreAudio is a two-buffer system,
increasing the host buffer size will not necessarily resolve stability
problems if an additional layer of buffering is required (which I conceed in
some cases it might be), however, at the lower end of buffer sizes (32, 64,
128, 256, 512) it is desirable to to provide control over the host buffer
size independent of framesPerBuffer especially at higher sample rates. For
example Logic audio provides i/o buffer settings up to 1024 samples. The
behavior I'm seeing in my app is that it runs fine with 256 sample buffers
at 44100 but at higher sample rates and with certain external hardware, it
needs bigger buffers.

Another thing to consider is that higher host buffer sizes mean more timing
jitter (if you're responding to real-time events in the callback) however PA
provides buffer timestamps to deal with that. And in any case, if people
don't want timing jitter they can just set the latency as low as the buffer
size (or lower).

In conclusion, would like to investigate what will be involved in changing
the OSX implementation to implement the host buffer frames = N *
framesPerBuffer scheme I described above. Perhaps there are some problems
I'm not seeing? In any case I'm keen to get any feedback I can before I do
put much more time into this...

Thanks!

Ross.
Stéphane Letz
2009-05-05 10:20:02 UTC
Permalink
Post by Ross Bencina
Hi Everyone
I'm looking for some feedback on an implementation detail I'm
wanting to change and would appreciate any feedback you're able to
give...
"framesPerBuffer": this size of the buffer passed to a PA callback
"host buffer size": the size of buffers passed between PA and the host.
While the list was down Bjorn and I had a discussion about the
interaction between the framesPerBuffer parameter and the latency
parameters to Pa_OpenStream. The OSX PA version currently works a
bit differently from the way PA works on Windows (the closest
comparison is with the ASIO implementation since both CoreAudio and
ASIO are double-buffered). And I'm hoping to change the OSX
implementation to address that*
If I understand things correctly, the basic issue is that on OSX,
the host buffer size is never made larger than framesPerBuffer, even
if the latency values are set higher than 2*framesPerBufferDuration.
The way it works with ASIO is for the host buffer to be the highest
integer multiple of framesPerBuffer such that the host buffer
host buffer frames = N * framesPerBuffer
choose max N integer such that: duration(N * framesPerBuffer) <=
Output Latency
(actually sometimes it can be more complicated than that due to
restrictions on ASIO buffer sizes imposed by certain drivers, but
that's a separate matter)...
---
*the reason I want to change it is because my app expects a fixed
framesPerBuffer to be passed to its callback, and at the same time
to be able to adjust audio buffering (ie latency) by changing
PortAudio's latency parameters to increase stability. I think that's
a pretty common use case.
Bjorn made the point that because CoreAudio is a two-buffer system,
increasing the host buffer size will not necessarily resolve
stability problems if an additional layer of buffering is required
(which I conceed in some cases it might be), however, at the lower
end of buffer sizes (32, 64, 128, 256, 512) it is desirable to to
provide control over the host buffer size independent of
framesPerBuffer especially at higher sample rates. For example Logic
audio provides i/o buffer settings up to 1024 samples. The behavior
I'm seeing in my app is that it runs fine with 256 sample buffers at
44100 but at higher sample rates and with certain external hardware,
it needs bigger buffers.
Another thing to consider is that higher host buffer sizes mean more
timing jitter (if you're responding to real-time events in the
callback) however PA provides buffer timestamps to deal with that.
And in any case, if people don't want timing jitter they can just
set the latency as low as the buffer size (or lower).
In conclusion, would like to investigate what will be involved in
changing the OSX implementation to implement the host buffer frames
= N * framesPerBuffer scheme I described above. Perhaps there are
some problems I'm not seeing? In any case I'm keen to get any
feedback I can before I do put much more time into this...
Thanks!
Ross.
I'm not sure to grasp all the details but I guess explaining the way
OSX audio works might help again:

1) OSX use a "timer based callback model", thus there is a decoupling
between the size the kernel audio driver is using (usually a big DMA
buffer) and the buffer size the application is using. Consequently an
application can choose *any* buffer size it wants (more than a min
size that is something like 14 frames at 44.1 khz, up to a certain max
size of course)

2) the overall I/O model latency model is : input latency + input
latency offset + 2 * application buffer size + output latency offset +
output latency. This latency can be showed using Apple HALLab tool.
When an application changes it's buffer size, it then does change the
overall I/O model latency of course...

HTH,

St?phane
Ross Bencina
2009-05-13 10:24:02 UTC
Permalink
on Tuesday, May 05, 2009 St?phane Letz wrote:
I'm not sure to grasp all the details but I guess explaining the way
OSX audio works might help again:

1) OSX use a "timer based callback model", thus there is a decoupling
between the size the kernel audio driver is using (usually a big DMA
buffer) and the buffer size the application is using. Consequently an
application can choose *any* buffer size it wants (more than a min
size that is something like 14 frames at 44.1 khz, up to a certain max
size of course)
<<<

Thanks for the explanation St?phane. Does CoreAudio provide any control over
the size of this kernel "big DMA buffer"?

The behavior my users are reporting is that with a 256 frame PortAudio
buffer there are sometimes underruns and glitches, especially at high sample
rates with external hardware (I have never seen this with the built-in audio
on my MacBook). I was hoping to increase the size of the application buffer
to combat this (like increasing the ASIO buffer size on Windows).

Perhaps I will go to the CoreAudio list, but do you think 256 frames is ever
too small on OSX? Maybe there is something blocking in my callback code..

Thanks

Ross
Olivier Tristan
2009-05-13 10:27:33 UTC
Permalink
Post by Stéphane Letz
I'm not sure to grasp all the details but I guess explaining the way
1) OSX use a "timer based callback model", thus there is a decoupling
between the size the kernel audio driver is using (usually a big DMA
buffer) and the buffer size the application is using. Consequently an
application can choose *any* buffer size it wants (more than a min
size that is something like 14 frames at 44.1 khz, up to a certain max
size of course)
<<<
Thanks for the explanation St?phane. Does CoreAudio provide any
control over the size of this kernel "big DMA buffer"?
The behavior my users are reporting is that with a 256 frame PortAudio
buffer there are sometimes underruns and glitches, especially at high
sample rates with external hardware (I have never seen this with the
built-in audio on my MacBook). I was hoping to increase the size of
the application buffer to combat this (like increasing the ASIO buffer
size on Windows).
Perhaps I will go to the CoreAudio list, but do you think 256 frames
is ever too small on OSX? Maybe there is something blocking in my
callback code..
I would ask my users to try AULab with for example an Apple plugin see
if he got the same kind of underruns and glitches. It's only maybe an
issue with his soundcard.
--
Olivier Tristan
Ultimate Sound Bank
Stéphane Letz
2009-05-13 10:35:40 UTC
Permalink
Post by Stéphane Letz
I'm not sure to grasp all the details but I guess explaining the way
1) OSX use a "timer based callback model", thus there is a decoupling
between the size the kernel audio driver is using (usually a big DMA
buffer) and the buffer size the application is using. Consequently an
application can choose *any* buffer size it wants (more than a min
size that is something like 14 frames at 44.1 khz, up to a certain max
size of course)
<<<
Thanks for the explanation St?phane. Does CoreAudio provide any
control over the size of this kernel "big DMA buffer"?
No that I know of.
Post by Stéphane Letz
The behavior my users are reporting is that with a 256 frame
PortAudio buffer there are sometimes underruns and glitches,
especially at high sample rates with external hardware (I have never
seen this with the built-in audio on my MacBook). I was hoping to
increase the size of the application buffer to combat this (like
increasing the ASIO buffer size on Windows).
Perhaps I will go to the CoreAudio list, but do you think 256 frames
is ever too small on OSX? Maybe there is something blocking in my
callback code..
Thanks
Ross
256 should be quite OK, and yes your callback is not allowed to block...

How are those underruns and glitches detected? Does the PortAudio/OSX
code listen for the kAudioDeviceProcessorOverload property? I think it
should because this property is triggered by the audio driver and is
helpful to follow...

Stephane
Davy Wentzler
2009-05-13 10:56:59 UTC
Permalink
Hi,
Post by Stéphane Letz
Post by Ross Bencina
Thanks for the explanation St?phane. Does CoreAudio provide any
control over the size of this kernel "big DMA buffer"?
No that I know of.
I wrote Intel OSX drivers for Envy24 and Envy24HT cards and the 'big DMA
buffer size' is set up once and can't be changed.
setNumSampleFramesPerBuffer() is called by the drivers AudioEngine
subclass at init time to let the OS know which size it uses.

Kind regards,

Davy
Ross Bencina
2009-05-14 15:15:12 UTC
Permalink
Hi St?phane
256 should be quite OK, and yes your callback is not allowed to block...
<<<

This may not be avoidable if the problem is caused by (VST) plugins... in
which case increasing the buffer size might be better (for my users) than
nothing.
How are those underruns and glitches detected? Does the PortAudio/OSX
code listen for the kAudioDeviceProcessorOverload property? I think it
should because this property is triggered by the audio driver and is
helpful to follow...
<<<

A quick look at the code says PA uses kAudioDeviceProcessorOverload but I
have no idea how (Bjorn?)

I couldn't find any documentation on line about
kAudioDeviceProcessorOverload -- Is this only invoked when my callback
overloads/blocks? or can it happen due to OS level underruns?

Right now all I know is that my users say the audio is glitching. I don't
know what the cause is yet.. but given that Logic has i/o buffer sizes up to
1024 I've been guessing that providing user settable buffer sizes up to this
figure is a good idea.

Thanks

Ross.
Stéphane Letz
2009-05-14 15:29:10 UTC
Permalink
Post by Ross Bencina
Hi St?phane
256 should be quite OK, and yes your callback is not allowed to block...
<<<
This may not be avoidable if the problem is caused by (VST)
plugins... in which case increasing the buffer size might be better
(for my users) than nothing.
How are those underruns and glitches detected? Does the PortAudio/OSX
code listen for the kAudioDeviceProcessorOverload property? I think it
should because this property is triggered by the audio driver and is
helpful to follow...
<<<
A quick look at the code says PA uses kAudioDeviceProcessorOverload
but I have no idea how (Bjorn?)
I couldn't find any documentation on line about
kAudioDeviceProcessorOverload -- Is this only invoked when my
callback overloads/blocks? or can it happen due to OS level underruns?
Right now all I know is that my users say the audio is glitching. I
don't know what the cause is yet.. but given that Logic has i/o
buffer sizes up to 1024 I've been guessing that providing user
settable buffer sizes up to this figure is a good idea.
Thanks
Ross.
Frum AudioHardware.h

@constant kAudioDeviceProcessorOverload
A UInt32 where the value has no meaning. This
property exists so that
clients can be notified when the AudioDevice
detects that an IO cycle has
run past it's deadline. Note that the
notification for this property is
usually sent from the AudioDevice's IO thread.

So kAudioDeviceProcessorOverload is notified by the kernel side
(using some details i don't know exactly...) when the application
audio callback was not in time.

Stephane
bjorn at xowave.com ()
2009-05-15 01:17:32 UTC
Permalink
Post by Ross Bencina
Hi St?phane
256 should be quite OK, and yes your callback is not allowed to block...
<<<
This may not be avoidable if the problem is caused by (VST)
plugins... in which case increasing the buffer size might be better
(for my users) than nothing.
How are those underruns and glitches detected? Does the PortAudio/OSX
code listen for the kAudioDeviceProcessorOverload property? I think it
should because this property is triggered by the audio driver and is
helpful to follow...
<<<
A quick look at the code says PA uses kAudioDeviceProcessorOverload
but I have no idea how (Bjorn?)
I couldn't find any documentation on line about
kAudioDeviceProcessorOverload -- Is this only invoked when my
callback overloads/blocks? or can it happen due to OS level underruns?
Right now all I know is that my users say the audio is glitching. I
don't know what the cause is yet.. but given that Logic has i/o
buffer sizes up to 1024 I've been guessing that providing user
settable buffer sizes up to this figure is a good idea.
I have virtually no time at the moment, so I apologize for my cursory
following of this and other PA threads. Thank you Ross for taking the
lead on this issue, as far as I can tell you are on the right track
and asking the right questions.

kAudioDeviceProcessorOverload is misnamed: conditions exist where
audio droppouts can occur without CPU being at 100% and vice versa,
and this flag pertains to audio xruns, not the CPU -- at least that's
what I was lead to believe last time I researched it. Anyway, this
flag is one of several ways that PA/CA detects xruns. xruns are
detected in CA/PA in all the "right" ways, but I found it was not 100%
reliable. I vaguely recall that the reliability would depend on your
hardware and drivers, but I don't know if I had real evidence for that.

As for buffer size, which came up earlier: yes, apple has a formula
they recommend; however, I have repeatedly rejected it in favor of my
own testing and the testing of the PA community because there have
been releases of the OS with latency problems where xruns occur
regularly when you use the recommended formula, and this may happen
again. Logic was among the apps plagues by problems in 10.4.4, IIRC.

Finally, Core Audio has yet to find documentation online. This is a
constant frustration for newbies. Search your computer locally. I
forget where it is.

bjorn

-----------------------------
Bjorn Roche
XO Wave
Digital Audio Production and Post-Production Software
http://www.xowave.com
http://blog.bjornroche.com
http://myspace.com/xowave

Loading...