mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Changes to show the different transfer methods
This commit is contained in:
parent
76abb9738e
commit
56778fa89d
1 changed files with 171 additions and 54 deletions
225
test/pcm.c
225
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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue