[pulseaudio-discuss] spurious underflows?
David Henningsson
david.henningsson at canonical.com
Wed Jun 3 23:12:24 PDT 2015
On 2015-06-04 03:06, Andrew Kelley wrote:
> I open the audio playback device like this:
>
> pa_threaded_mainloop_lock(audio_hardware->main_loop);
>
> pa_sample_spec sample_spec;
> sample_spec.format = to_pulseaudio_sample_format(sample_format);
> sample_spec.rate = audio_device->default_sample_rate;
> sample_spec.channels = audio_device->channel_layout.channel_count;
> pa_channel_map channel_map =
> to_pulseaudio_channel_map(&audio_device->channel_layout);
>
> open_playback_device->stream =
> pa_stream_new(audio_hardware->pulse_context,
> "Genesis", &sample_spec, &channel_map);
> // error handling omitted
> pa_stream_set_state_callback(open_playback_device->stream,
> playback_stream_state_callback,
> open_playback_device);
> pa_stream_set_write_callback(open_playback_device->stream,
> playback_stream_write_callback,
> open_playback_device);
> pa_stream_set_underflow_callback(open_playback_device->stream,
> playback_stream_underflow_callback,
> open_playback_device);
>
> open_playback_device->bytes_per_frame =
> genesis_get_bytes_per_frame(sample_format,
> audio_device->channel_layout.channel_count);
> int bytes_per_second = open_playback_device->bytes_per_frame *
> audio_device->default_sample_rate;
> int buffer_length = open_playback_device->bytes_per_frame *
> ceil(latency * bytes_per_second /
> (double)open_playback_device->bytes_per_frame);
>
> open_playback_device->buffer_attr.maxlength = buffer_length;
> open_playback_device->buffer_attr.tlength = buffer_length;
> open_playback_device->buffer_attr.prebuf = 0;
> open_playback_device->buffer_attr.minreq = UINT32_MAX;
> open_playback_device->buffer_attr.fragsize = UINT32_MAX;
>
>
> pa_stream_connect_playback(open_playback_device->stream,
> open_playback_device->audio_device->name,
> &open_playback_device->buffer_attr,
> PA_STREAM_ADJUST_LATENCY, nullptr, nullptr);
> // error handling omitted
>
> while (!open_playback_device->stream_ready)
> pa_threaded_mainloop_wait(audio_hardware->main_loop);
>
> pa_threaded_mainloop_unlock(audio_hardware->main_loop);
>
>
> Here is some output from my program. When it prints UNDERRUN that means
> the underflow callback was called. The number is the number of seconds
> that the write callback took to fill the playback buffer. In this
> example the audio device is opened with latency set to 10ms, e.g. 0.01
> seconds. The percent is how long the callback took out of how long the
> buffer size is. So that first UNDERRUN makes sense, because the callback
> took 2x as long as it was supposed to. When an underrun occurs, the
> playback buffer is filled completely with silence. So why am I getting
> all these other underflow callbacks when the callback was well within
> the range of time which should have been fine? Any ideas of things I can
> do to troubleshoot?
If you set your total latency to 10 ms, minreq to -1, and include the
PA_STREAM_ADJUST_LATENCY flag, then the *total* latency is below 10 ms,
i e, including latency within PulseAudio itself.
PulseAudio will, for so small latency values, try to divide the 10 ms
into four periods of 2.5 ms each by default. After that these values
might be adjusted for various reasons.
If you want a *period* size of 10 ms, then you need to set minreq to 10
ms and tlength to something larger than 20 ms. But then again, PA is
free to change these values as it see fits (e g due to hardware
constraints).
Anyhow, if your callback is between 2.5 ms and (something less than) 10
ms, it's possible you get an underflow callback without there actually
being an audio glitch. There was a debate a while ago about whether it
would make sense to skip this underflow callback for this reason, but
IIRC, there was no consensus and thus the behaviour was not changed.
--
David Henningsson, Canonical Ltd.
https://launchpad.net/~diwic
More information about the pulseaudio-discuss
mailing list