Changes to show the different transfer methods

This commit is contained in:
Jaroslav Kysela 2001-10-17 17:50:16 +00:00
parent 76abb9738e
commit 56778fa89d

View file

@ -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;