All of lore.kernel.org
 help / color / mirror / Atom feed
From: Matthew Gregan <kinetik@flim.org>
To: alsa-devel@alsa-project.org
Subject: Immediate underrun with PulseAudio ALSA plugin when PA and ALSA buffer sizes differ
Date: Tue, 17 Jul 2012 09:38:55 +1200	[thread overview]
Message-ID: <20120716213855.GE7462@flim.org> (raw)

[-- Attachment #1: Type: text/plain, Size: 2497 bytes --]

I'm investigating an issue in Firefox's audio code when the PulseAudio ALSA
plugin is in use.  I posted about this on pulseaudio-discuss last week
(http://lists.freedesktop.org/archives/pulseaudio-discuss/2012-July/014091.html),
but I hoped I might have more success here.

Firefox requests a particular latency (100ms, 4410 frames at 44.1kHz) via
snd_pcm_set_params.  Inside the plugin (pcm_pulse.c:pulse_hw_params), that
value is used to set up buffer_attr.  When the PA stream is connected in
pcm_pulse.c:pulse_prepare, PA may configure the stream with larger
buffer_attr values (e.g. because the minimum sink latency has increased over
time due to underruns on the server, or because the sink hardware doesn't
support lower latency), but this isn't reflected in pcm->buffer_attr or
higher layers in ALSA (i.e. pcm->buffer_size is not updated).

The problem I'm faced with is that there doesn't appear to be a way to
detect and handle this issue at the ALSA API level, and requesting a too low
latency results in broken audio playback rather than a PCM setup failure or
a larger buffer than requested being used.

In the case of the PA server's minimum latency increasing over time, this
also means that a stream that was configured and running correctly may break
while running if PA increases the minimum latency above what the PCM was
originally configured with.

I've attached a simple testcase that uses snd_pcm_wait,
snd_pcm_avail_update, and snd_pcm_writei.  Run it with a latency argument
specified in milliseconds on the command line.  For my local machine, 55ms
works and 54ms fails immediately like so:

snd_pcm_wait wakes
snd_pcm_avail_update returns 4410
snd_pcm_writei writes 4410
snd_pcm_wait wakes immediately
snd_pcm_avail_update returns -EPIPE

(Note that when I reported this on pulseaudio-discuss, my server's minimum
latency was 45ms, and now pacmd list-sinks | grep configured\ latency
reports a minimum latency of 56ms)

I'd expect to see one of the following behaviours instead:
1. PCM setup fails due to requesting a too small buffer.
2. Buffer is silently raised during setup and snd_pcm_avail_update requests
   the correct number of frames.

Presumably this could be achieved by having the PA plugin report valid
values from pcm_pulse.c:pulse_hw_constraint, but I'm not sure how to query
the necessary values from the server.  This also wouldn't address the
problem where the buffer_attr changes over time, and I'm not sure what to do
about that case.

Thanks,
-mjg

[-- Attachment #2: latency.c --]
[-- Type: text/x-csrc, Size: 1500 bytes --]

#include <sys/time.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>

static double
ts(void)
{
  static struct timeval last;
  struct timeval now, dt;
  if (last.tv_sec == 0) {
    gettimeofday(&last, NULL);
  }
  gettimeofday(&now, NULL);
  timersub(&now, &last, &dt);
  last = now;
  return dt.tv_sec * 1000.0 + dt.tv_usec / 1000.0;
}

int
main(int argc, char * argv[])
{
  int r;
  snd_pcm_t * pcm;
  snd_pcm_uframes_t buffer_size, period_size;
  char silence[88200] = {0};

  if (argc != 2) {
    return 1;
  }

  r = snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0);
  assert(r == 0);

  r = snd_pcm_set_params(pcm, SND_PCM_FORMAT_S16_LE,
                         SND_PCM_ACCESS_RW_INTERLEAVED, 2, 44100, 1,
                         atoi(argv[1]) * 1000);
  assert(r == 0);

  r = snd_pcm_get_params(pcm, &buffer_size, &period_size);
  assert(r == 0);
  fprintf(stderr, "%.2f: buffer_size = %u, period_size = %u\n",
          ts(), (unsigned) buffer_size, (unsigned) period_size);
  assert(buffer_size <= sizeof(silence) / 4);

  for (;;) {
    snd_pcm_sframes_t avail, wrote = 0;

    snd_pcm_wait(pcm, -1);

    avail = snd_pcm_avail_update(pcm);
    if (avail == -EPIPE) {
      snd_pcm_recover(pcm, -EPIPE, 0);
      avail = snd_pcm_avail_update(pcm);
    }
    if (avail > 0) {
      wrote = snd_pcm_writei(pcm, silence, avail);
    }
    fprintf(stderr, "%.2f: avail = %d, wrote = %d\n", ts(), (int) avail, (int) wrote);
  }

  return 0;
}

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



             reply	other threads:[~2012-07-16 21:38 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-07-16 21:38 Matthew Gregan [this message]
2012-07-17  5:29 ` Immediate underrun with PulseAudio ALSA plugin when PA and ALSA buffer sizes differ Arun Raghavan
2012-07-17  6:22   ` David Henningsson
2012-07-18 22:14   ` Matthew Gregan
2012-07-19  8:56     ` David Henningsson
2012-07-30  5:49       ` [pulseaudio-discuss] " Matthew Gregan
2012-07-22  0:34     ` Raymond Yau
2012-07-17  7:36 ` Raymond Yau

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120716213855.GE7462@flim.org \
    --to=kinetik@flim.org \
    --cc=alsa-devel@alsa-project.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.