From 56778fa89d97c0d27bd1d2bf927922f7c663f04b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 17 Oct 2001 17:50:16 +0000 Subject: [PATCH] Changes to show the different transfer methods --- test/pcm.c | 225 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 171 insertions(+), 54 deletions(-) diff --git a/test/pcm.c b/test/pcm.c index 998a8b83..f2c6b4c8 100644 --- a/test/pcm.c +++ b/test/pcm.c @@ -22,7 +22,6 @@ double freq = 440; /* sinus wave frequency in Hz */ snd_pcm_sframes_t buffer_size; snd_pcm_sframes_t period_size; -signed short *samples; snd_output_t *output = NULL; static void generate_sine(signed short *samples, int count, double *_phase) @@ -145,6 +144,155 @@ static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams) return 0; } +/* + * Underrun and suspend recovery + */ + +static int xrun_recovery(snd_pcm_t *handle, int err) +{ + if (err = -EPIPE) { /* underrun */ + err = snd_pcm_prepare(handle); + if (err < 0) + printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err)); + return 0; + } else if (err = -ESTRPIPE) { + while ((err = snd_pcm_resume(handle)) == -EAGAIN) + sleep(1); /* wait until suspend flag is released */ + if (err < 0) { + err = snd_pcm_prepare(handle); + if (err < 0) + printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err)); + } + return 0; + } + return err; +} + +/* + * Transfer method - write only + */ + +static int write_loop(snd_pcm_t *handle, signed short *samples) +{ + int ufds_count; + struct pollfd *ufds; + double phase = 0; + signed short *ptr; + int err, count, cptr; + + while (1) { + generate_sine(ptr = samples, cptr = period_size, &phase); + while (cptr > 0) { + err = snd_pcm_writei(handle, ptr, cptr); + if (err == -EAGAIN) + continue; + if (err < 0) { + if (xrun_recovery(handle, err) < 0) { + printf("Write error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + break; /* skip one period */ + } + ptr += err * channels; + cptr -= err; + } + } +} + +/* + * Transfer method - write and wait for room in buffer using poll + */ + +static int wait_for_poll(struct pollfd *ufds, int count) +{ + int i; + unsigned int events; + + while (1) { + poll(ufds, count, -1); + for (i = 0; i < count; i++) { + events = ufds[i].revents; + if (events & POLLERR) { + printf("Poll - POLLERR detected\n"); + return -EIO; + } + if (events & POLLOUT) + return 0; + } + } +} + +static int write_and_poll_loop(snd_pcm_t *handle, signed short *samples) +{ + int ufds_count; + struct pollfd *ufds; + double phase = 0; + signed short *ptr; + int err, count, cptr; + + count = snd_pcm_poll_descriptors_count (handle); + if (count <= 0) { + printf("Invalid poll descriptors count\n"); + return count; + } + + ufds = malloc(sizeof(struct pollfd) * count); + if (ufds == NULL) { + printf("No enough memory\n"); + return err;; + } + if ((err = snd_pcm_poll_descriptors(handle, ufds, count)) < 0) { + printf("Unable to obtain poll descriptors for playback: %s\n", snd_strerror(err)); + return err; + } + + while (1) { + err = wait_for_poll(ufds, count); + if (err < 0) { + printf("Wait for poll failed\n"); + return err; + } + + generate_sine(ptr = samples, cptr = period_size, &phase); + while (cptr > 0) { + err = snd_pcm_writei(handle, ptr, cptr); + if (err < 0) { + if (xrun_recovery(handle, err) < 0) { + printf("Write error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + break; /* skip one period */ + } + ptr += err * channels; + cptr -= err; + if (cptr == 0) + break; + /* it is possible, that initial buffer cannot store */ + /* all data from last period, so wait awhile */ + err = wait_for_poll(ufds, count); + if (err < 0) { + printf("Wait for poll failed\n"); + return err; + } + } + } +} + +/* + * + */ + +struct transfer_method { + const char *name; + int (*transfer_loop)(snd_pcm_t *handle, signed short *samples); +}; + +static struct transfer_method transfer_methods[] = { + { "write", write_loop }, + { "write_and_poll", write_and_poll_loop }, + { NULL, NULL } +}; + static void help(void) { int k; @@ -157,6 +305,8 @@ Usage: latency [OPTION]... [FILE]... -f,--frequency sine wave frequency in Hz -b,--buffer ring buffer size in samples -p,--period period size in us +-m,--method tranfer method + "); printf("Recognized sample formats are:"); for (k = 0; k < SND_PCM_FORMAT_LAST; ++(unsigned long) k) { @@ -165,6 +315,10 @@ Usage: latency [OPTION]... [FILE]... printf(" %s", s); } printf("\n"); + printf("Recognized tranfer methods are:"); + for (k = 0; transfer_methods[k].name; k++) + printf(" %s", transfer_methods[k].name); + printf("\n"); } int main(int argc, char *argv[]) @@ -178,18 +332,17 @@ int main(int argc, char *argv[]) {"frequency", 1, NULL, 'f'}, {"buffer", 1, NULL, 'b'}, {"period", 1, NULL, 'p'}, + {"method", 1, NULL, 'm'}, {NULL, 0, NULL, 0}, }; snd_pcm_t *handle; char *buffer; - int err, morehelp, i, count; + int err, morehelp; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; - struct pollfd *ufds; - unsigned int events; double phase; - signed short *ptr; - int cptr; + int method = 0; + signed short *samples; snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); @@ -197,7 +350,7 @@ int main(int argc, char *argv[]) morehelp = 0; while (1) { int c; - if ((c = getopt_long(argc, argv, "hD:r:c:f:b:p:", long_option, NULL)) < 0) + if ((c = getopt_long(argc, argv, "hD:r:c:f:b:p:m:", long_option, NULL)) < 0) break; switch (c) { case 'h': @@ -231,6 +384,13 @@ int main(int argc, char *argv[]) period_time = period_time < 1000 ? 1000 : period_time; period_time = period_time > 1000000 ? 1000000 : period_time; break; + case 'm': + for (method = 0; transfer_methods[method].name; method++) + if (!strcasecmp(transfer_methods[method].name, optarg)) + break; + if (transfer_methods[method].name == NULL) + method = 0; + break; } } @@ -248,6 +408,7 @@ int main(int argc, char *argv[]) printf("Playback device is %s\n", device); printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels); printf("Sine wave rate is %.4fHz\n", freq); + printf("Using transfer method: %s\n", transfer_methods[method].name); if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { printf("Playback open error: %s\n", snd_strerror(err)); @@ -263,59 +424,15 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - count = snd_pcm_poll_descriptors_count (handle); - if (count <= 0) { - printf("Invalid poll descriptors count\n"); - exit(EXIT_FAILURE); - } - ufds = malloc(sizeof(struct pollfd) * count); - if (ufds == NULL) { - printf("No enough memory\n"); - exit(EXIT_FAILURE); - } - if ((err = snd_pcm_poll_descriptors(handle, ufds, count)) < 0) { - printf("Unable to obtain poll descriptors for playback: %s\n", snd_strerror(err)); - exit(EXIT_FAILURE); - } - samples = malloc((period_size * channels * snd_pcm_format_width(format)) / 8); if (samples == NULL) { printf("No enough memory\n"); exit(EXIT_FAILURE); } - phase = 0; - - while (1) { - poll(ufds, count, -1); - for (i = 0; i < count; i++) { - events = ufds[i].revents; - if (events & POLLOUT) - goto __write; - } - continue; - - __write: - generate_sine(ptr = samples, cptr = period_size, &phase); - while (cptr > 0) { - err = snd_pcm_writei(handle, ptr, cptr); - if (err < 0) { - printf("Write error: %s\n", snd_strerror(err)); - exit(EXIT_FAILURE); - } - ptr += err * channels; - cptr -= err; - while (1) { - poll(ufds, count, -1); - for (i = 0; i < count; i++) { - events = ufds[i].revents; - if (events & POLLOUT) - goto __write1; - } - } - __write1: - } - } + err = transfer_methods[method].transfer_loop(handle, samples); + if (err < 0) + printf("Transfer failed: %s\n", snd_strerror(err)); snd_pcm_close(handle); return 0; -- 2.47.1