aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/tinyalsa/asoundlib.h15
-rw-r--r--mixer.c8
-rw-r--r--pcm.c26
-rw-r--r--tinycap.c43
-rw-r--r--tinymix.c85
5 files changed, 146 insertions, 31 deletions
diff --git a/include/tinyalsa/asoundlib.h b/include/tinyalsa/asoundlib.h
index 5c08577..ea8e23d 100644
--- a/include/tinyalsa/asoundlib.h
+++ b/include/tinyalsa/asoundlib.h
@@ -58,13 +58,9 @@ struct pcm;
#define PCM_MONOTONIC 0x00000008 /* see pcm_get_htimestamp */
/* 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
@@ -144,10 +140,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);
@@ -163,9 +155,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.
* The clock is CLOCK_MONOTONIC if flag PCM_MONOTONIC was specified in pcm_open,
* otherwise the clock is CLOCK_REALTIME.
@@ -192,6 +181,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);
diff --git a/mixer.c b/mixer.c
index 4568cca..b6c854f 100644
--- a/mixer.c
+++ b/mixer.c
@@ -383,12 +383,20 @@ 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;
break;
case SNDRV_CTL_ELEM_TYPE_INTEGER:
+ if ((value < mixer_ctl_get_range_min(ctl)) ||
+ (value > mixer_ctl_get_range_max(ctl))) {
+ return -EINVAL;
+ }
+
ev.value.integer.value[id] = value;
break;
diff --git a/pcm.c b/pcm.c
index 8195c7c..1a5254b 100644
--- a/pcm.c
+++ b/pcm.c
@@ -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;
@@ -747,11 +752,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);
@@ -767,6 +785,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;
}
@@ -947,6 +966,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,
diff --git a/tinycap.c b/tinycap.c
index 7429750..b9ae251 100644
--- a/tinycap.c
+++ b/tinycap.c
@@ -57,6 +57,7 @@ struct wav_header {
};
int capturing = 1;
+int prinfo = 1;
unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device,
unsigned int channels, unsigned int rate,
@@ -81,17 +82,25 @@ int main(int argc, char **argv)
unsigned int period_size = 1024;
unsigned int period_count = 4;
enum pcm_format format;
+ int no_header = 0;
if (argc < 2) {
- fprintf(stderr, "Usage: %s file.wav [-D card] [-d device] [-c channels] "
- "[-r rate] [-b bits] [-p period_size] [-n n_periods]\n", argv[0]);
+ fprintf(stderr, "Usage: %s {file.wav | --} [-D card] [-d device] [-c channels] "
+ "[-r rate] [-b bits] [-p period_size] [-n n_periods]\n\n"
+ "Use -- for filename to send raw PCM to stdout\n", argv[0]);
return 1;
}
- file = fopen(argv[1], "wb");
- if (!file) {
- fprintf(stderr, "Unable to create file '%s'\n", argv[1]);
- return 1;
+ if (strcmp(argv[1],"--") == 0) {
+ file = stdout;
+ prinfo = 0;
+ no_header = 1;
+ } else {
+ file = fopen(argv[1], "wb");
+ if (!file) {
+ fprintf(stderr, "Unable to create file '%s'\n", argv[1]);
+ return 1;
+ }
}
/* parse command line arguments */
@@ -160,20 +169,26 @@ int main(int argc, char **argv)
header.data_id = ID_DATA;
/* leave enough room for header */
- fseek(file, sizeof(struct wav_header), SEEK_SET);
+ if (!no_header) {
+ fseek(file, sizeof(struct wav_header), SEEK_SET);
+ }
/* install signal handler and begin capturing */
signal(SIGINT, sigint_handler);
frames = capture_sample(file, card, device, header.num_channels,
header.sample_rate, format,
period_size, period_count);
- printf("Captured %d frames\n", frames);
+ if (prinfo) {
+ printf("Captured %d frames\n", frames);
+ }
/* write header now all information is known */
- header.data_sz = frames * header.block_align;
- header.riff_sz = header.data_sz + sizeof(header) - 8;
- fseek(file, 0, SEEK_SET);
- fwrite(&header, sizeof(struct wav_header), 1, file);
+ if (!no_header) {
+ header.data_sz = frames * header.block_align;
+ header.riff_sz = header.data_sz + sizeof(header) - 8;
+ fseek(file, 0, SEEK_SET);
+ fwrite(&header, sizeof(struct wav_header), 1, file);
+ }
fclose(file);
@@ -216,8 +231,10 @@ unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device,
return 0;
}
- printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate,
+ if (prinfo) {
+ printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate,
pcm_format_to_bits(format));
+ }
while (capturing && !pcm_read(pcm, buffer, size)) {
if (fwrite(buffer, 1, size, file) != size) {
diff --git a/tinymix.c b/tinymix.c
index afc2fee..fa3defc 100644
--- a/tinymix.c
+++ b/tinymix.c
@@ -27,10 +27,13 @@
*/
#include <tinyalsa/asoundlib.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
+#include <limits.h>
+#include <errno.h>
static void tinymix_list_controls(struct mixer *mixer);
static void tinymix_detail_control(struct mixer *mixer, const char *control,
@@ -127,6 +130,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 +147,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 +175,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 +194,61 @@ 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 int is_int(char *value)
+{
+ char* end;
+ long int result;
+
+ errno = 0;
+ result = strtol(value, &end, 10);
+
+ if (result == LONG_MIN || result == LONG_MAX)
+ return 0;
+
+ return errno == 0 && *end == '\0';
+}
+
static void tinymix_set_value(struct mixer *mixer, const char *control,
char **values, unsigned int num_values)
{
@@ -196,7 +270,12 @@ 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 (isdigit(values[0][0])) {
+ if (type == MIXER_CTL_TYPE_BYTE) {
+ tinymix_set_byte_ctl(ctl, control, values, num_values);
+ return;
+ }
+
+ if (is_int(values[0])) {
if (num_values == 1) {
/* Set all values the same */
int value = atoi(values[0]);