diff options
-rw-r--r-- | include/tinyalsa/asoundlib.h | 15 | ||||
-rw-r--r-- | mixer.c | 3 | ||||
-rw-r--r-- | pcm.c | 26 | ||||
-rw-r--r-- | tinymix.c | 67 |
4 files changed, 94 insertions, 17 deletions
diff --git a/include/tinyalsa/asoundlib.h b/include/tinyalsa/asoundlib.h index 3d20b94..01a6303 100644 --- a/include/tinyalsa/asoundlib.h +++ b/include/tinyalsa/asoundlib.h @@ -57,13 +57,9 @@ struct pcm; */ /* PCM runtime states */ -#define PCM_STATE_OPEN 0 -#define PCM_STATE_SETUP 1 -#define PCM_STATE_PREPARED 2 -#define PCM_STATE_RUNNING 3 +#define PCM_STATE_RUNNING 3 #define PCM_STATE_XRUN 4 #define PCM_STATE_DRAINING 5 -#define PCM_STATE_PAUSED 6 #define PCM_STATE_SUSPENDED 7 #define PCM_STATE_DISCONNECTED 8 @@ -143,10 +139,6 @@ unsigned int pcm_params_get_min(struct pcm_params *pcm_params, unsigned int pcm_params_get_max(struct pcm_params *pcm_params, enum pcm_param param); -/* Set and get config */ -int pcm_get_config(struct pcm *pcm, struct pcm_config *config); -int pcm_set_config(struct pcm *pcm, struct pcm_config *config); - /* Returns a human readable reason for the last error */ const char *pcm_get_error(struct pcm *pcm); @@ -162,9 +154,6 @@ unsigned int pcm_get_buffer_size(struct pcm *pcm); unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames); unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes); -/* Returns the pcm latency in ms */ -unsigned int pcm_get_latency(struct pcm *pcm); - /* Returns available frames in pcm buffer and corresponding time stamp. * For an input stream, frames available are frames ready for the * application to read. @@ -189,6 +178,8 @@ int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, unsigned int *frames); int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames); +/* Prepare the PCM substream to be triggerable */ +int pcm_prepare(struct pcm *pcm); /* Start and stop a PCM channel that doesn't transfer data */ int pcm_start(struct pcm *pcm); int pcm_stop(struct pcm *pcm); @@ -383,6 +383,9 @@ int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value) if (ret < 0) return ret; + if (value > mixer_ctl_get_range_max(ctl)) + value = mixer_ctl_get_range_max(ctl); + switch (ctl->info->type) { case SNDRV_CTL_ELEM_TYPE_BOOLEAN: ev.value.integer.value[id] = !!value; @@ -159,6 +159,7 @@ struct pcm { int fd; unsigned int flags; int running:1; + int prepared:1; int underruns; unsigned int buffer_size; unsigned int boundary; @@ -386,14 +387,16 @@ int pcm_write(struct pcm *pcm, const void *data, unsigned int count) for (;;) { if (!pcm->running) { - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE)) - return oops(pcm, errno, "cannot prepare channel"); + int prepare_error = pcm_prepare(pcm); + if (prepare_error) + return prepare_error; if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) return oops(pcm, errno, "cannot write initial data"); pcm->running = 1; return 0; } if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { + pcm->prepared = 0; pcm->running = 0; if (errno == EPIPE) { /* we failed to make our window -- try to restart if we are @@ -429,6 +432,7 @@ int pcm_read(struct pcm *pcm, void *data, unsigned int count) } } if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) { + pcm->prepared = 0; pcm->running = 0; if (errno == EPIPE) { /* we failed to make our window -- try to restart */ @@ -582,6 +586,7 @@ int pcm_close(struct pcm *pcm) if (pcm->fd >= 0) close(pcm->fd); + pcm->prepared = 0; pcm->running = 0; pcm->buffer_size = 0; pcm->fd = -1; @@ -736,11 +741,24 @@ int pcm_is_ready(struct pcm *pcm) return pcm->fd >= 0; } -int pcm_start(struct pcm *pcm) +int pcm_prepare(struct pcm *pcm) { + if (pcm->prepared) + return 0; + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0) return oops(pcm, errno, "cannot prepare channel"); + pcm->prepared = 1; + return 0; +} + +int pcm_start(struct pcm *pcm) +{ + int prepare_error = pcm_prepare(pcm); + if (prepare_error) + return prepare_error; + if (pcm->flags & PCM_MMAP) pcm_sync_ptr(pcm, 0); @@ -756,6 +774,7 @@ int pcm_stop(struct pcm *pcm) if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0) return oops(pcm, errno, "cannot stop channel"); + pcm->prepared = 0; pcm->running = 0; return 0; } @@ -936,6 +955,7 @@ int pcm_mmap_write(struct pcm *pcm, const void *buffer, unsigned int bytes) err = pcm_wait(pcm, time); if (err < 0) { + pcm->prepared = 0; pcm->running = 0; fprintf(stderr, "wait error: hw 0x%x app 0x%x avail 0x%x\n", (unsigned int)pcm->mmap_status->hw_ptr, @@ -27,6 +27,7 @@ */ #include <tinyalsa/asoundlib.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <ctype.h> @@ -127,6 +128,9 @@ static void tinymix_detail_control(struct mixer *mixer, const char *control, unsigned int num_values; unsigned int i; int min, max; + int ret; + char buf[512] = { 0 }; + size_t len; if (isdigit(control[0])) ctl = mixer_get_ctl(mixer, atoi(control)); @@ -141,6 +145,19 @@ static void tinymix_detail_control(struct mixer *mixer, const char *control, type = mixer_ctl_get_type(ctl); num_values = mixer_ctl_get_num_values(ctl); + if (type == MIXER_CTL_TYPE_BYTE) { + len = num_values; + if (len > sizeof(buf)) { + fprintf(stderr, "Truncating get to %zu bytes\n", sizeof(buf)); + len = sizeof(buf); + } + ret = mixer_ctl_get_array(ctl, buf, len); + if (ret < 0) { + fprintf(stderr, "Failed to mixer_ctl_get_array\n"); + return; + } + } + if (print_all) printf("%s:", mixer_ctl_get_name(ctl)); @@ -156,8 +173,8 @@ static void tinymix_detail_control(struct mixer *mixer, const char *control, case MIXER_CTL_TYPE_ENUM: tinymix_print_enum(ctl, print_all); break; - case MIXER_CTL_TYPE_BYTE: - printf(" 0x%02x", mixer_ctl_get_value(ctl, i)); + case MIXER_CTL_TYPE_BYTE: + printf("%02x", buf[i]); break; default: printf(" unknown"); @@ -175,6 +192,47 @@ static void tinymix_detail_control(struct mixer *mixer, const char *control, printf("\n"); } +static void tinymix_set_byte_ctl(struct mixer_ctl *ctl, const char *control, + char **values, unsigned int num_values) +{ + int ret; + char buf[512] = { 0 }; + char *end; + int i; + long n; + + if (num_values > sizeof(buf)) { + fprintf(stderr, "Truncating set to %zu bytes\n", sizeof(buf)); + num_values = sizeof(buf); + } + + for (i = 0; i < num_values; i++) { + errno = 0; + n = strtol(values[i], &end, 0); + if (*end) { + fprintf(stderr, "%s not an integer\n", values[i]); + exit(EXIT_FAILURE); + } + if (errno) { + fprintf(stderr, "strtol: %s: %s\n", values[i], + strerror(errno)); + exit(EXIT_FAILURE); + } + if (n < 0 || n > 0xff) { + fprintf(stderr, "%s should be between [0, 0xff]\n", + values[i]); + exit(EXIT_FAILURE); + } + buf[i] = n; + } + + ret = mixer_ctl_set_array(ctl, buf, num_values); + if (ret < 0) { + fprintf(stderr, "Failed to set binary control\n"); + exit(EXIT_FAILURE); + } +} + static void tinymix_set_value(struct mixer *mixer, const char *control, char **values, unsigned int num_values) { @@ -196,6 +254,11 @@ static void tinymix_set_value(struct mixer *mixer, const char *control, type = mixer_ctl_get_type(ctl); num_ctl_values = mixer_ctl_get_num_values(ctl); + if (type == MIXER_CTL_TYPE_BYTE) { + tinymix_set_byte_ctl(ctl, control, values, num_values); + return; + } + if (isdigit(values[0][0])) { if (num_values == 1) { /* Set all values the same */ |