On Wed, 2001-11-28 at 15:51, Paul Davis wrote: <cut>
> > is there any existing code that uses poll(2) for full duplex and > demonstrates working operation? > > --p > <cut> I've attached the test code that I wrote with Jaroslav's modifications which uses poll. It still has the clicking problem I mentioned. -- Josh Green Smurf Sound Font Editor (http://smurf.sourceforge.net)
/* Full duplex ALSA test program Do whatever you want with it and use it at your own risk Josh Green <[EMAIL PROTECTED]> Fixes by Jaroslav Kysela November 28, 2001 */ #include <stdio.h> #include <alsa/asoundlib.h> #include <string.h> #include <sched.h> #define OK 0 #define FAIL 1 #define TRUE 1 #define FALSE 0 char *audiobuf = NULL; int audiobuf_bytes = 0; int period_size = 384; int buffer_size = 384 * 2; snd_pcm_t *cards[2] = { NULL }; int fdcount[2] = { 0 }; struct pollfd *ufds[2] = { NULL }; int setup_device (int index, char *device, int play) { int err; snd_pcm_t *handle; snd_pcm_hw_params_t *params; /* Hardware parameters */ snd_pcm_sw_params_t *swparams; /* Software parameters */ int thisbuf_bytes; /* this cards audio buffer size */ unsigned int rate; snd_pcm_uframes_t start_threshold, stop_threshold; /* Open output sound card */ if (err = snd_pcm_open (&handle, device, play ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK) < 0) { fprintf (stderr, "snd_pcm_open failed: %s\n", snd_strerror (err)); return (FAIL); } cards[index] = handle; snd_pcm_hw_params_alloca (¶ms); snd_pcm_sw_params_alloca (&swparams); snd_pcm_hw_params_any (handle, params); snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format (handle, params, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_channels (handle, params, 2); rate = snd_pcm_hw_params_set_rate_near (handle, params, 44100, 0); if (snd_pcm_hw_params_set_period_size (handle, params, period_size, 0) < 0) { fprintf (stderr, "Failed to set period size!\n"); return (FAIL); } if (snd_pcm_hw_params_set_buffer_size (handle, params, buffer_size) < 0) { fprintf (stderr, "Failed to set buffer size!\n"); return (FAIL); } err = snd_pcm_hw_params (handle, params); /* set software parameters */ snd_pcm_sw_params_current (handle, swparams); snd_pcm_sw_params_set_sleep_min (handle, swparams, 0); start_threshold = 0x7fffffff; snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); stop_threshold = buffer_size; snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold); snd_pcm_sw_params (handle, swparams); /* Prepare our buffer */ thisbuf_bytes = (period_size * (16 / 8) * 2) * 2; if (audiobuf_bytes == 0) { audiobuf = malloc (thisbuf_bytes); audiobuf_bytes = thisbuf_bytes; } else if (audiobuf_bytes != thisbuf_bytes) { fprintf (stderr, "audio buffers not same size (%d != %d)!\n", audiobuf_bytes, thisbuf_bytes); return (FAIL); } return (OK); } void setup_pollfds (void) { int count1, count2; count1 = snd_pcm_poll_descriptors_count (cards[0]); count2 = snd_pcm_poll_descriptors_count (cards[1]); fdcount[0] = count1; fdcount[1] = count2; ufds[0] = malloc (sizeof (struct pollfd) * (count1 + count2)); ufds[1] = (void *)ufds[0] + count1 * sizeof (struct pollfd); snd_pcm_poll_descriptors (cards[0], ufds[0], count1); snd_pcm_poll_descriptors (cards[1], ufds[1], count2); } void xrun_recovery() { int err; fprintf(stderr, "XRUN recovery\n"); if (err = snd_pcm_prepare(cards[0]) < 0) { fprintf (stderr, "Failed to prepare devices\n"); exit (1); } if (err = snd_pcm_writei (cards[0], audiobuf, period_size * 2) < 0) { fprintf (stderr, "Failed to write initial bytes\n"); exit (1); } fprintf (stderr, "Wrote %d start bytes\n", err); snd_pcm_start(cards[1]); } int main (void) { int i, r = 1; short revents; int err; struct sched_param schp; memset (&schp, 0, sizeof (schp)); schp.sched_priority = sched_get_priority_max (SCHED_FIFO); if (sched_setscheduler (0, SCHED_FIFO, &schp) != 0) fprintf (stderr, "Failed to run SCHED_FIFO\n"); /* Open output sound card */ if (setup_device (0, "plughw:0,0", TRUE) != OK) { fprintf (stderr, "Failed to setup output device\n"); exit (1); } /* Open input sound card */ if (setup_device (1, "plughw:0,0", FALSE) != OK) { fprintf (stderr, "Failed to setup input device\n"); exit (1); } setup_pollfds (); if (snd_pcm_link (cards[1], cards[0]) < 0) { fprintf (stderr, "Failed to link devices\n"); exit (1); } if (err = snd_pcm_prepare (cards[0]) < 0) { fprintf (stderr, "Failed to prepare devices\n"); exit (1); } if (err = snd_pcm_writei (cards[0], audiobuf, period_size * 2) < 0) { fprintf (stderr, "Failed to write initial bytes\n"); exit (1); } fprintf (stderr, "Wrote %d start bytes\n", err); snd_pcm_start (cards[1]); do { poll (ufds[r], fdcount[r], -1); for (i = fdcount[r]; i > 0; i--) { revents = ufds[r]->revents; if (revents & POLLERR) { snd_pcm_t *handle; snd_pcm_state_t state; if (revents & POLLOUT) handle = cards[0]; else handle = cards[1]; if ((state = snd_pcm_state (handle)) == SND_PCM_STATE_XRUN) { fprintf (stderr, "XRUN on %s\n", (revents & POLLOUT != 0) ? "output" : "input"); xrun_recovery(); r = 1; break; } else fprintf (stderr, "Bad state %d on %s\n", state, (revents & POLLOUT != 0) ? "output" : "input"); } else if (revents & POLLIN) { err = snd_pcm_readi (cards[1], audiobuf, period_size); if (err > 0 && err != period_size) fprintf (stderr, "read error: requested %i read %i\n", audiobuf_bytes, err); r = 0; break; } else if (revents & POLLOUT) { err = snd_pcm_writei (cards[0], audiobuf, period_size); if (err > 0 && err != period_size) fprintf (stderr, "write error: requested %i written %i\n", audiobuf_bytes, err); r = 1; break; } } } while (1); exit (0); }