mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-12-15 08:56:36 -05: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 buffer_size;
|
||||||
snd_pcm_sframes_t period_size;
|
snd_pcm_sframes_t period_size;
|
||||||
signed short *samples;
|
|
||||||
snd_output_t *output = NULL;
|
snd_output_t *output = NULL;
|
||||||
|
|
||||||
static void generate_sine(signed short *samples, int count, double *_phase)
|
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;
|
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)
|
static void help(void)
|
||||||
{
|
{
|
||||||
int k;
|
int k;
|
||||||
|
|
@ -157,6 +305,8 @@ Usage: latency [OPTION]... [FILE]...
|
||||||
-f,--frequency sine wave frequency in Hz
|
-f,--frequency sine wave frequency in Hz
|
||||||
-b,--buffer ring buffer size in samples
|
-b,--buffer ring buffer size in samples
|
||||||
-p,--period period size in us
|
-p,--period period size in us
|
||||||
|
-m,--method tranfer method
|
||||||
|
|
||||||
");
|
");
|
||||||
printf("Recognized sample formats are:");
|
printf("Recognized sample formats are:");
|
||||||
for (k = 0; k < SND_PCM_FORMAT_LAST; ++(unsigned long) k) {
|
for (k = 0; k < SND_PCM_FORMAT_LAST; ++(unsigned long) k) {
|
||||||
|
|
@ -165,6 +315,10 @@ Usage: latency [OPTION]... [FILE]...
|
||||||
printf(" %s", s);
|
printf(" %s", s);
|
||||||
}
|
}
|
||||||
printf("\n");
|
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[])
|
int main(int argc, char *argv[])
|
||||||
|
|
@ -178,18 +332,17 @@ int main(int argc, char *argv[])
|
||||||
{"frequency", 1, NULL, 'f'},
|
{"frequency", 1, NULL, 'f'},
|
||||||
{"buffer", 1, NULL, 'b'},
|
{"buffer", 1, NULL, 'b'},
|
||||||
{"period", 1, NULL, 'p'},
|
{"period", 1, NULL, 'p'},
|
||||||
|
{"method", 1, NULL, 'm'},
|
||||||
{NULL, 0, NULL, 0},
|
{NULL, 0, NULL, 0},
|
||||||
};
|
};
|
||||||
snd_pcm_t *handle;
|
snd_pcm_t *handle;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
int err, morehelp, i, count;
|
int err, morehelp;
|
||||||
snd_pcm_hw_params_t *hwparams;
|
snd_pcm_hw_params_t *hwparams;
|
||||||
snd_pcm_sw_params_t *swparams;
|
snd_pcm_sw_params_t *swparams;
|
||||||
struct pollfd *ufds;
|
|
||||||
unsigned int events;
|
|
||||||
double phase;
|
double phase;
|
||||||
signed short *ptr;
|
int method = 0;
|
||||||
int cptr;
|
signed short *samples;
|
||||||
|
|
||||||
snd_pcm_hw_params_alloca(&hwparams);
|
snd_pcm_hw_params_alloca(&hwparams);
|
||||||
snd_pcm_sw_params_alloca(&swparams);
|
snd_pcm_sw_params_alloca(&swparams);
|
||||||
|
|
@ -197,7 +350,7 @@ int main(int argc, char *argv[])
|
||||||
morehelp = 0;
|
morehelp = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
int c;
|
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;
|
break;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
|
|
@ -231,6 +384,13 @@ int main(int argc, char *argv[])
|
||||||
period_time = period_time < 1000 ? 1000 : period_time;
|
period_time = period_time < 1000 ? 1000 : period_time;
|
||||||
period_time = period_time > 1000000 ? 1000000 : period_time;
|
period_time = period_time > 1000000 ? 1000000 : period_time;
|
||||||
break;
|
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("Playback device is %s\n", device);
|
||||||
printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels);
|
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("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) {
|
if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
|
||||||
printf("Playback open error: %s\n", snd_strerror(err));
|
printf("Playback open error: %s\n", snd_strerror(err));
|
||||||
|
|
@ -263,59 +424,15 @@ int main(int argc, char *argv[])
|
||||||
exit(EXIT_FAILURE);
|
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);
|
samples = malloc((period_size * channels * snd_pcm_format_width(format)) / 8);
|
||||||
if (samples == NULL) {
|
if (samples == NULL) {
|
||||||
printf("No enough memory\n");
|
printf("No enough memory\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
phase = 0;
|
err = transfer_methods[method].transfer_loop(handle, samples);
|
||||||
|
if (err < 0)
|
||||||
while (1) {
|
printf("Transfer failed: %s\n", snd_strerror(err));
|
||||||
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:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
snd_pcm_close(handle);
|
snd_pcm_close(handle);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue