Update to latest tinyalsa

2c3a8e2 Add -Wall to Makefile and fix warnings
4ef9a57 tinyplay: add clean shutdown handler for ctrl-c
9bb8066 Merge pull request #15 from quantumdream/master
bad2b79 tinymix: Add support for passing control name
f51c05b mixer: Add mixer_ctl_{set,get}_bytes()
fcf66ab Merge pull request #16 from PeterMalkin/master
3d62222 Add pcm_wait() to the tinyalsa API.
f9678dd tinyplay: Add missing header file <string.h>
cde1f6f Fix several 'symbol defined but not used' warnings.
2a274a1 pcm: Add support for S8 and S24LE formats.
a5baefd tinymix: support setting of multiple control values

Change-Id: I3d5fe076753ce7d1f74dd3ebedc59202d29f4efd
diff --git a/include/tinyalsa/asoundlib.h b/include/tinyalsa/asoundlib.h
index a796a66..6148361 100644
--- a/include/tinyalsa/asoundlib.h
+++ b/include/tinyalsa/asoundlib.h
@@ -30,6 +30,7 @@
 #define ASOUNDLIB_H
 
 #include <sys/time.h>
+#include <stddef.h>
 
 #if defined(__cplusplus)
 extern "C" {
@@ -70,6 +71,8 @@
 enum pcm_format {
     PCM_FORMAT_S16_LE = 0,
     PCM_FORMAT_S32_LE,
+    PCM_FORMAT_S8,
+    PCM_FORMAT_S24_LE,
 
     PCM_FORMAT_MAX,
 };
@@ -163,6 +166,9 @@
 int pcm_start(struct pcm *pcm);
 int pcm_stop(struct pcm *pcm);
 
+/* Interrupt driven API */
+int pcm_wait(struct pcm *pcm, int timeout);
+
 /* Change avail_min after the stream has been opened with no need to stop the stream.
  * Only accepted if opened with PCM_MMAP and PCM_NOIRQ flags
  */
@@ -198,7 +204,9 @@
 int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent);
 
 int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id);
+int mixer_ctl_get_bytes(struct mixer_ctl *ctl, void *data, size_t len);
 int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value);
+int mixer_ctl_set_bytes(struct mixer_ctl *ctl, const void *data, size_t len);
 int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string);
 
 /* Determe range of integer mixer controls */
diff --git a/mixer.c b/mixer.c
index 9514528..f52bca9 100644
--- a/mixer.c
+++ b/mixer.c
@@ -317,6 +317,27 @@
     return 0;
 }
 
+int mixer_ctl_get_bytes(struct mixer_ctl *ctl, void *data, size_t len)
+{
+    struct snd_ctl_elem_value ev;
+    int ret;
+
+    if (!ctl || (len > ctl->info->count) || !len || !data ||
+        (ctl->info->type != SNDRV_CTL_ELEM_TYPE_BYTES))
+        return -EINVAL;
+
+    memset(&ev, 0, sizeof(ev));
+    ev.id.numid = ctl->info->id.numid;
+
+    ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
+    if (ret < 0)
+        return ret;
+
+    memcpy(data, ev.value.bytes.data, len);
+
+    return 0;
+}
+
 int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value)
 {
     struct snd_ctl_elem_value ev;
@@ -351,10 +372,24 @@
     return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
 }
 
+int mixer_ctl_set_bytes(struct mixer_ctl *ctl, const void *data, size_t len)
+{
+    struct snd_ctl_elem_value ev;
+
+    if (!ctl || (len > ctl->info->count) || !len || !data ||
+        (ctl->info->type != SNDRV_CTL_ELEM_TYPE_BYTES))
+        return -EINVAL;
+
+    memset(&ev, 0, sizeof(ev));
+    ev.id.numid = ctl->info->id.numid;
+
+    memcpy(ev.value.bytes.data, data, len);
+
+    return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
+}
+
 int mixer_ctl_get_range_min(struct mixer_ctl *ctl)
 {
-    int ret;
-
     if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
         return -EINVAL;
 
@@ -363,8 +398,6 @@
 
 int mixer_ctl_get_range_max(struct mixer_ctl *ctl)
 {
-    int ret;
-
     if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
         return -EINVAL;
 
@@ -382,8 +415,6 @@
 const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl,
                                       unsigned int enum_id)
 {
-    int ret;
-
     if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) ||
         (enum_id >= ctl->info->value.enumerated.items))
         return NULL;
diff --git a/pcm.c b/pcm.c
index 284a7ac..d841bd9 100644
--- a/pcm.c
+++ b/pcm.c
@@ -93,14 +93,6 @@
     }
 }
 
-static void param_set_max(struct snd_pcm_hw_params *p, int n, unsigned int val)
-{
-    if (param_is_interval(n)) {
-        struct snd_interval *i = param_to_interval(p, n);
-        i->max = val;
-    }
-}
-
 static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned int val)
 {
     if (param_is_interval(n)) {
@@ -190,6 +182,10 @@
     switch (format) {
     case PCM_FORMAT_S32_LE:
         return SNDRV_PCM_FORMAT_S32_LE;
+    case PCM_FORMAT_S8:
+        return SNDRV_PCM_FORMAT_S8;
+    case PCM_FORMAT_S24_LE:
+        return SNDRV_PCM_FORMAT_S24_LE;
     default:
     case PCM_FORMAT_S16_LE:
         return SNDRV_PCM_FORMAT_S16_LE;
@@ -741,7 +737,6 @@
 int pcm_wait(struct pcm *pcm, int timeout)
 {
     struct pollfd pfd;
-    unsigned short revents = 0;
     int err;
 
     pfd.fd = pcm->fd;
@@ -864,6 +859,5 @@
         count -= frames;
     }
 
-_end:
     return 0;
 }
diff --git a/tinycap.c b/tinycap.c
index d563309..8c9fcfb 100644
--- a/tinycap.c
+++ b/tinycap.c
@@ -31,6 +31,7 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <signal.h>
+#include <string.h>
 
 #define ID_RIFF 0x46464952
 #define ID_WAVE 0x45564157
@@ -153,6 +154,7 @@
 
     /* 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);
 
diff --git a/tinymix.c b/tinymix.c
index 6427a02..962450e 100644
--- a/tinymix.c
+++ b/tinymix.c
@@ -30,12 +30,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
+#include <string.h>
 
 static void tinymix_list_controls(struct mixer *mixer);
-static void tinymix_detail_control(struct mixer *mixer, unsigned int id,
+static void tinymix_detail_control(struct mixer *mixer, const char *control,
                                    int print_all);
-static void tinymix_set_value(struct mixer *mixer, unsigned int id,
-                              char *value);
+static void tinymix_set_value(struct mixer *mixer, const char *control,
+                              char **values, unsigned int num_values);
 static void tinymix_print_enum(struct mixer_ctl *ctl, int print_all);
 
 int main(int argc, char **argv)
@@ -63,9 +64,9 @@
     if (argc == 1)
         tinymix_list_controls(mixer);
     else if (argc == 2)
-        tinymix_detail_control(mixer, atoi(argv[1]), 1);
-    else if (argc == 3)
-        tinymix_set_value(mixer, atoi(argv[1]), argv[2]);
+        tinymix_detail_control(mixer, argv[1], 1);
+    else if (argc >= 3)
+        tinymix_set_value(mixer, argv[1], &argv[2], argc - 2);
     else
         printf("Usage: tinymix [-D card] [control id] [value to set]\n");
 
@@ -93,7 +94,7 @@
         type = mixer_ctl_get_type_string(ctl);
         num_values = mixer_ctl_get_num_values(ctl);
         printf("%d\t%s\t%d\t%-40s", i, type, num_values, name);
-        tinymix_detail_control(mixer, i, 0);
+        tinymix_detail_control(mixer, name, 0);
     }
 }
 
@@ -115,7 +116,7 @@
     }
 }
 
-static void tinymix_detail_control(struct mixer *mixer, unsigned int id,
+static void tinymix_detail_control(struct mixer *mixer, const char *control,
                                    int print_all)
 {
     struct mixer_ctl *ctl;
@@ -124,13 +125,16 @@
     unsigned int i;
     int min, max;
 
-    if (id >= mixer_get_num_ctls(mixer)) {
+    if (isdigit(control[0]))
+        ctl = mixer_get_ctl(mixer, atoi(control));
+    else
+        ctl = mixer_get_ctl_by_name(mixer, control);
+
+    if (!ctl) {
         fprintf(stderr, "Invalid mixer control\n");
         return;
     }
 
-    ctl = mixer_get_ctl(mixer, id);
-
     type = mixer_ctl_get_type(ctl);
     num_values = mixer_ctl_get_num_values(ctl);
 
@@ -168,30 +172,60 @@
     printf("\n");
 }
 
-static void tinymix_set_value(struct mixer *mixer, unsigned int id,
-                              char *string)
+static void tinymix_set_value(struct mixer *mixer, const char *control,
+                              char **values, unsigned int num_values)
 {
     struct mixer_ctl *ctl;
     enum mixer_ctl_type type;
-    unsigned int num_values;
+    unsigned int num_ctl_values;
     unsigned int i;
 
-    ctl = mixer_get_ctl(mixer, id);
+    if (isdigit(control[0]))
+        ctl = mixer_get_ctl(mixer, atoi(control));
+    else
+        ctl = mixer_get_ctl_by_name(mixer, control);
+
+    if (!ctl) {
+        fprintf(stderr, "Invalid mixer control\n");
+        return;
+    }
+
     type = mixer_ctl_get_type(ctl);
-    num_values = mixer_ctl_get_num_values(ctl);
+    num_ctl_values = mixer_ctl_get_num_values(ctl);
 
-    if (isdigit(string[0])) {
-        int value = atoi(string);
+    if (isdigit(values[0][0])) {
+        if (num_values == 1) {
+            /* Set all values the same */
+            int value = atoi(values[0]);
 
-        for (i = 0; i < num_values; i++) {
-            if (mixer_ctl_set_value(ctl, i, value)) {
-                fprintf(stderr, "Error: invalid value\n");
+            for (i = 0; i < num_ctl_values; i++) {
+                if (mixer_ctl_set_value(ctl, i, value)) {
+                    fprintf(stderr, "Error: invalid value\n");
+                    return;
+                }
+            }
+        } else {
+            /* Set multiple values */
+            if (num_values > num_ctl_values) {
+                fprintf(stderr,
+                        "Error: %d values given, but control only takes %d\n",
+                        num_values, num_ctl_values);
                 return;
             }
+            for (i = 0; i < num_values; i++) {
+                if (mixer_ctl_set_value(ctl, i, atoi(values[i]))) {
+                    fprintf(stderr, "Error: invalid value for index %d\n", i);
+                    return;
+                }
+            }
         }
     } else {
         if (type == MIXER_CTL_TYPE_ENUM) {
-            if (mixer_ctl_set_enum_by_string(ctl, string))
+            if (num_values != 1) {
+                fprintf(stderr, "Enclose strings in quotes and try again\n");
+                return;
+            }
+            if (mixer_ctl_set_enum_by_string(ctl, values[0]))
                 fprintf(stderr, "Error: invalid enum value\n");
         } else {
             fprintf(stderr, "Error: only enum types can be set with strings\n");
diff --git a/tinyplay.c b/tinyplay.c
index 3f76cc6..d7e7d46 100644
--- a/tinyplay.c
+++ b/tinyplay.c
@@ -30,6 +30,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <string.h>
+#include <signal.h>
 
 #define ID_RIFF 0x46464952
 #define ID_WAVE 0x45564157
@@ -56,10 +58,19 @@
     uint16_t bits_per_sample;
 };
 
+static int close = 0;
+
 void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels,
                  unsigned int rate, unsigned int bits, unsigned int period_size,
                  unsigned int period_count);
 
+void stream_close(int sig)
+{
+    /* allow the stream to be closed gracefully */
+    signal(sig, SIG_IGN);
+    close = 1;
+}
+
 int main(int argc, char **argv)
 {
     FILE *file;
@@ -189,6 +200,9 @@
 
     printf("Playing sample: %u ch, %u hz, %u bit\n", channels, rate, bits);
 
+    /* catch ctrl-c to shutdown cleanly */
+    signal(SIGINT, stream_close);
+
     do {
         num_read = fread(buffer, 1, size, file);
         if (num_read > 0) {
@@ -197,7 +211,7 @@
                 break;
             }
         }
-    } while (num_read > 0);
+    } while (!close && num_read > 0);
 
     free(buffer);
     pcm_close(pcm);