[alsa-devel] Bug? poll() timeout in alsa-jack plugin

Sergey sergemp at mail.ru
Sun Apr 27 05:46:57 CEST 2014


Hello.

I'm trying to debug mozilla code, which uses poll() when playing sound
and works fine with regular alsa device, but plays no sound over
alsa-jack plugin. I narrowed it down to a small sample. In that sample
poll() returns 0 even when pcm can accept data. Please, help me to fix
either a bug in that sample, or a bug in alsa-plugins.

The problem is hardware-independent. To reproduce it you need:

1. install and start jack2 daemon:
  jackd -r -dalsa -dhw:0 -r44100 -p1024 -n2

2. add to .asoundrc:
  pcm.jackplug {
    type plug
    slave { pcm "jack" }
  }
  pcm.jack {
    type jack
    playback_ports {
      0 system:playback_1
      1 system:playback_2
    }
    capture_ports {
      0 system:capture_1
      1 system:capture_2
    }
  }

3. build and run the poll() code example
  gcc -o poll-example poll-example.c -lasound
  ./poll-example

According to the common sense as long as PCM is ready to receive data
it's expected that poll() returns 1 and writei() is called.
Instead poll() returns 0 and the code plays nothing.

---------- poll() code example ---------
#include <assert.h>
#include <poll.h>
#include <alsa/asoundlib.h>

short buffer[96000];

int main()
{
  snd_pcm_t *pcm;
  assert( snd_pcm_open(&pcm, "jackplug", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) == 0 );
  assert( snd_pcm_nonblock(pcm, 1) == 0 );
  assert( snd_pcm_set_params(pcm, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, 1/*channels*/, 48000/*rate*/, 1, 100000/*latency*/) == 0 );
  nfds_t nfds = snd_pcm_poll_descriptors_count(pcm);
  assert( nfds > 0 );
  struct pollfd *saved_fds = calloc(nfds, sizeof(struct pollfd));
  assert( snd_pcm_poll_descriptors(pcm, saved_fds, nfds) == nfds );

  // poll() and write(20)
  int timeout = 1000;
  int r = poll(saved_fds, nfds, timeout);
  fprintf(stderr, "poll=%d\n", r);
  if (r > 0)
  {
    unsigned short revents;
    r = snd_pcm_poll_descriptors_revents(pcm, saved_fds, nfds, &revents);
    fprintf(stderr, "snd_pcm_poll_descriptors_revents=%d\n", r);
    if (r == 0)
      fprintf(stderr, "snd_pcm_writei(20)=%d\n", snd_pcm_writei(pcm, buffer, 20));
  }

  // poll() and write(50)
  r = poll(saved_fds, nfds, timeout);
  fprintf(stderr, "poll=%d\n", r);
  if (r > 0)
  {
    unsigned short revents;
    r = snd_pcm_poll_descriptors_revents(pcm, saved_fds, nfds, &revents);
    fprintf(stderr, "snd_pcm_poll_descriptors_revents=%d\n", r);
    if (r == 0)
      fprintf(stderr, "snd_pcm_writei(50)=%d\n", snd_pcm_writei(pcm, buffer, 50));
  }

  // poll() and write(100)
  r = poll(saved_fds, nfds, timeout);
  fprintf(stderr, "poll=%d\n", r);
  if (r > 0)
  {
    unsigned short revents;
    r = snd_pcm_poll_descriptors_revents(pcm, saved_fds, nfds, &revents);
    fprintf(stderr, "snd_pcm_poll_descriptors_revents=%d\n", r);
    if (r == 0)
      fprintf(stderr, "snd_pcm_writei(100)=%d\n", snd_pcm_writei(pcm, buffer, 100));
  }

  assert( snd_pcm_close(pcm) == 0 );

  return 0;
}
---------- end of code example ---------

I tried to fix that in jack_pcm.c downloaded from
http://git.alsa-project.org/?p=alsa-plugins.git;a=blob;f=jack/pcm_jack.c

Making the first poll() return 1 was easy, I just added
  write(jack->fd, &i, 1);
to the end of snd_pcm_jack_prepare() function. But that haven't solved
the problem, because next call to snd_pcm_poll_descriptors_revents()
exhausts the socket and next poll() still returns 0.

Another guess was to define .transfer in snd_pcm_ioplug_callback_t and
handle read()s and write()s to polling socket there, but it seems that
.transfer is not called on writei() at all.

What's the correct approach?

Is there any official documentation about using poll() for ALSA? Or maybe
there're some manuals with meaning of snd_pcm_ioplug_callback_t fields?

-- 


More information about the Alsa-devel mailing list