Revert "Sync from GitHub"

Revert submission 1483902-sync tinyalsa

Reason for revert: b/174994516, b/175089243
Reverted Changes:
Id3370e3c7:fix build breakage
I296a47fcb:Sync from GitHub
I6b86da455:reorg file structure to match it on GitHub
I5155d7856:add const qualifier to the pcm_mask variables and ...

Change-Id: Ie050892efdadd2a8e199c5375611fae954c2de99
diff --git a/utils/optparse.h b/utils/optparse.h
deleted file mode 100644
index 3a577a7..0000000
--- a/utils/optparse.h
+++ /dev/null
@@ -1,403 +0,0 @@
-/* Optparse --- portable, reentrant, embeddable, getopt-like option parser
- *
- * This is free and unencumbered software released into the public domain.
- *
- * To get the implementation, define OPTPARSE_IMPLEMENTATION.
- * Optionally define OPTPARSE_API to control the API's visibility
- * and/or linkage (static, __attribute__, __declspec).
- *
- * The POSIX getopt() option parser has three fatal flaws. These flaws
- * are solved by Optparse.
- *
- * 1) Parser state is stored entirely in global variables, some of
- * which are static and inaccessible. This means only one thread can
- * use getopt(). It also means it's not possible to recursively parse
- * nested sub-arguments while in the middle of argument parsing.
- * Optparse fixes this by storing all state on a local struct.
- *
- * 2) The POSIX standard provides no way to properly reset the parser.
- * This means for portable code that getopt() is only good for one
- * run, over one argv with one option string. It also means subcommand
- * options cannot be processed with getopt(). Most implementations
- * provide a method to reset the parser, but it's not portable.
- * Optparse provides an optparse_arg() function for stepping over
- * subcommands and continuing parsing of options with another option
- * string. The Optparse struct itself can be passed around to
- * subcommand handlers for additional subcommand option parsing. A
- * full reset can be achieved by with an additional optparse_init().
- *
- * 3) Error messages are printed to stderr. This can be disabled with
- * opterr, but the messages themselves are still inaccessible.
- * Optparse solves this by writing an error message in its errmsg
- * field. The downside to Optparse is that this error message will
- * always be in English rather than the current locale.
- *
- * Optparse should be familiar with anyone accustomed to getopt(), and
- * it could be a nearly drop-in replacement. The option string is the
- * same and the fields have the same names as the getopt() global
- * variables (optarg, optind, optopt).
- *
- * Optparse also supports GNU-style long options with optparse_long().
- * The interface is slightly different and simpler than getopt_long().
- *
- * By default, argv is permuted as it is parsed, moving non-option
- * arguments to the end. This can be disabled by setting the `permute`
- * field to 0 after initialization.
- */
-#ifndef OPTPARSE_H
-#define OPTPARSE_H
-
-#ifndef OPTPARSE_API
-#  define OPTPARSE_API
-#endif
-
-struct optparse {
-    char **argv;
-    int permute;
-    int optind;
-    int optopt;
-    char *optarg;
-    char errmsg[64];
-    int subopt;
-};
-
-enum optparse_argtype {
-    OPTPARSE_NONE,
-    OPTPARSE_REQUIRED,
-    OPTPARSE_OPTIONAL
-};
-
-struct optparse_long {
-    const char *longname;
-    int shortname;
-    enum optparse_argtype argtype;
-};
-
-/**
- * Initializes the parser state.
- */
-OPTPARSE_API
-void optparse_init(struct optparse *options, char **argv);
-
-/**
- * Read the next option in the argv array.
- * @param optstring a getopt()-formatted option string.
- * @return the next option character, -1 for done, or '?' for error
- *
- * Just like getopt(), a character followed by no colons means no
- * argument. One colon means the option has a required argument. Two
- * colons means the option takes an optional argument.
- */
-OPTPARSE_API
-int optparse(struct optparse *options, const char *optstring);
-
-/**
- * Handles GNU-style long options in addition to getopt() options.
- * This works a lot like GNU's getopt_long(). The last option in
- * longopts must be all zeros, marking the end of the array. The
- * longindex argument may be NULL.
- */
-OPTPARSE_API
-int optparse_long(struct optparse *options,
-                  const struct optparse_long *longopts,
-                  int *longindex);
-
-/**
- * Used for stepping over non-option arguments.
- * @return the next non-option argument, or NULL for no more arguments
- *
- * Argument parsing can continue with optparse() after using this
- * function. That would be used to parse the options for the
- * subcommand returned by optparse_arg(). This function allows you to
- * ignore the value of optind.
- */
-OPTPARSE_API
-char *optparse_arg(struct optparse *options);
-
-/* Implementation */
-#ifdef OPTPARSE_IMPLEMENTATION
-
-#define OPTPARSE_MSG_INVALID "invalid option"
-#define OPTPARSE_MSG_MISSING "option requires an argument"
-#define OPTPARSE_MSG_TOOMANY "option takes no arguments"
-
-static int
-optparse_error(struct optparse *options, const char *msg, const char *data)
-{
-    unsigned p = 0;
-    const char *sep = " -- '";
-    while (*msg)
-        options->errmsg[p++] = *msg++;
-    while (*sep)
-        options->errmsg[p++] = *sep++;
-    while (p < sizeof(options->errmsg) - 2 && *data)
-        options->errmsg[p++] = *data++;
-    options->errmsg[p++] = '\'';
-    options->errmsg[p++] = '\0';
-    return '?';
-}
-
-OPTPARSE_API
-void
-optparse_init(struct optparse *options, char **argv)
-{
-    options->argv = argv;
-    options->permute = 1;
-    options->optind = 1;
-    options->subopt = 0;
-    options->optarg = 0;
-    options->errmsg[0] = '\0';
-}
-
-static int
-optparse_is_dashdash(const char *arg)
-{
-    return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] == '\0';
-}
-
-static int
-optparse_is_shortopt(const char *arg)
-{
-    return arg != 0 && arg[0] == '-' && arg[1] != '-' && arg[1] != '\0';
-}
-
-static int
-optparse_is_longopt(const char *arg)
-{
-    return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] != '\0';
-}
-
-static void
-optparse_permute(struct optparse *options, int index)
-{
-    char *nonoption = options->argv[index];
-    int i;
-    for (i = index; i < options->optind - 1; i++)
-        options->argv[i] = options->argv[i + 1];
-    options->argv[options->optind - 1] = nonoption;
-}
-
-static int
-optparse_argtype(const char *optstring, char c)
-{
-    int count = OPTPARSE_NONE;
-    if (c == ':')
-        return -1;
-    for (; *optstring && c != *optstring; optstring++);
-    if (!*optstring)
-        return -1;
-    if (optstring[1] == ':')
-        count += optstring[2] == ':' ? 2 : 1;
-    return count;
-}
-
-OPTPARSE_API
-int
-optparse(struct optparse *options, const char *optstring)
-{
-    int type;
-    char *next;
-    char *option = options->argv[options->optind];
-    options->errmsg[0] = '\0';
-    options->optopt = 0;
-    options->optarg = 0;
-    if (option == 0) {
-        return -1;
-    } else if (optparse_is_dashdash(option)) {
-        options->optind++; /* consume "--" */
-        return -1;
-    } else if (!optparse_is_shortopt(option)) {
-        if (options->permute) {
-            int index = options->optind++;
-            int r = optparse(options, optstring);
-            optparse_permute(options, index);
-            options->optind--;
-            return r;
-        } else {
-            return -1;
-        }
-    }
-    option += options->subopt + 1;
-    options->optopt = option[0];
-    type = optparse_argtype(optstring, option[0]);
-    next = options->argv[options->optind + 1];
-    switch (type) {
-    case -1: {
-        char str[2] = {0, 0};
-        str[0] = option[0];
-        options->optind++;
-        return optparse_error(options, OPTPARSE_MSG_INVALID, str);
-    }
-    case OPTPARSE_NONE:
-        if (option[1]) {
-            options->subopt++;
-        } else {
-            options->subopt = 0;
-            options->optind++;
-        }
-        return option[0];
-    case OPTPARSE_REQUIRED:
-        options->subopt = 0;
-        options->optind++;
-        if (option[1]) {
-            options->optarg = option + 1;
-        } else if (next != 0) {
-            options->optarg = next;
-            options->optind++;
-        } else {
-            char str[2] = {0, 0};
-            str[0] = option[0];
-            options->optarg = 0;
-            return optparse_error(options, OPTPARSE_MSG_MISSING, str);
-        }
-        return option[0];
-    case OPTPARSE_OPTIONAL:
-        options->subopt = 0;
-        options->optind++;
-        if (option[1])
-            options->optarg = option + 1;
-        else
-            options->optarg = 0;
-        return option[0];
-    }
-    return 0;
-}
-
-OPTPARSE_API
-char *
-optparse_arg(struct optparse *options)
-{
-    char *option = options->argv[options->optind];
-    options->subopt = 0;
-    if (option != 0)
-        options->optind++;
-    return option;
-}
-
-static int
-optparse_longopts_end(const struct optparse_long *longopts, int i)
-{
-    return !longopts[i].longname && !longopts[i].shortname;
-}
-
-static void
-optparse_from_long(const struct optparse_long *longopts, char *optstring)
-{
-    char *p = optstring;
-    int i;
-    for (i = 0; !optparse_longopts_end(longopts, i); i++) {
-        if (longopts[i].shortname) {
-            int a;
-            *p++ = longopts[i].shortname;
-            for (a = 0; a < (int)longopts[i].argtype; a++)
-                *p++ = ':';
-        }
-    }
-    *p = '\0';
-}
-
-/* Unlike strcmp(), handles options containing "=". */
-static int
-optparse_longopts_match(const char *longname, const char *option)
-{
-    const char *a = option, *n = longname;
-    if (longname == 0)
-        return 0;
-    for (; *a && *n && *a != '='; a++, n++)
-        if (*a != *n)
-            return 0;
-    return *n == '\0' && (*a == '\0' || *a == '=');
-}
-
-/* Return the part after "=", or NULL. */
-static char *
-optparse_longopts_arg(char *option)
-{
-    for (; *option && *option != '='; option++);
-    if (*option == '=')
-        return option + 1;
-    else
-        return 0;
-}
-
-static int
-optparse_long_fallback(struct optparse *options,
-                       const struct optparse_long *longopts,
-                       int *longindex)
-{
-    int result;
-    char optstring[96 * 3 + 1]; /* 96 ASCII printable characters */
-    optparse_from_long(longopts, optstring);
-    result = optparse(options, optstring);
-    if (longindex != 0) {
-        *longindex = -1;
-        if (result != -1) {
-            int i;
-            for (i = 0; !optparse_longopts_end(longopts, i); i++)
-                if (longopts[i].shortname == options->optopt)
-                    *longindex = i;
-        }
-    }
-    return result;
-}
-
-OPTPARSE_API
-int
-optparse_long(struct optparse *options,
-              const struct optparse_long *longopts,
-              int *longindex)
-{
-    int i;
-    char *option = options->argv[options->optind];
-    if (option == 0) {
-        return -1;
-    } else if (optparse_is_dashdash(option)) {
-        options->optind++; /* consume "--" */
-        return -1;
-    } else if (optparse_is_shortopt(option)) {
-        return optparse_long_fallback(options, longopts, longindex);
-    } else if (!optparse_is_longopt(option)) {
-        if (options->permute) {
-            int index = options->optind++;
-            int r = optparse_long(options, longopts, longindex);
-            optparse_permute(options, index);
-            options->optind--;
-            return r;
-        } else {
-            return -1;
-        }
-    }
-
-    /* Parse as long option. */
-    options->errmsg[0] = '\0';
-    options->optopt = 0;
-    options->optarg = 0;
-    option += 2; /* skip "--" */
-    options->optind++;
-    for (i = 0; !optparse_longopts_end(longopts, i); i++) {
-        const char *name = longopts[i].longname;
-        if (optparse_longopts_match(name, option)) {
-            char *arg;
-            if (longindex)
-                *longindex = i;
-            options->optopt = longopts[i].shortname;
-            arg = optparse_longopts_arg(option);
-            if (longopts[i].argtype == OPTPARSE_NONE && arg != 0) {
-                return optparse_error(options, OPTPARSE_MSG_TOOMANY, name);
-            } if (arg != 0) {
-                options->optarg = arg;
-            } else if (longopts[i].argtype == OPTPARSE_REQUIRED) {
-                options->optarg = options->argv[options->optind];
-                if (options->optarg == 0)
-                    return optparse_error(options, OPTPARSE_MSG_MISSING, name);
-                else
-                    options->optind++;
-            }
-            return options->optopt;
-        }
-    }
-    return optparse_error(options, OPTPARSE_MSG_INVALID, option);
-}
-
-#endif /* OPTPARSE_IMPLEMENTATION */
-#endif /* OPTPARSE_H */
diff --git a/utils/tinycap.c b/utils/tinycap.c
index 7d4b8a4..b0c1908 100644
--- a/utils/tinycap.c
+++ b/utils/tinycap.c
@@ -32,10 +32,7 @@
 #include <stdint.h>
 #include <signal.h>
 #include <string.h>
-#include <limits.h>
-
-#define OPTPARSE_IMPLEMENTATION
-#include "optparse.h"
+#include <time.h>
 
 #define ID_RIFF 0x46464952
 #define ID_WAVE 0x45564157
@@ -61,18 +58,15 @@
 };
 
 int capturing = 1;
-int prinfo = 1;
 
 unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device,
                             unsigned int channels, unsigned int rate,
                             enum pcm_format format, unsigned int period_size,
-                            unsigned int period_count, unsigned int capture_time);
+                            unsigned int period_count, unsigned int cap_time);
 
-void sigint_handler(int sig)
+void sigint_handler(int sig __unused)
 {
-    if (sig == SIGINT){
-        capturing = 0;
-    }
+    capturing = 0;
 }
 
 int main(int argc, char **argv)
@@ -82,67 +76,65 @@
     unsigned int card = 0;
     unsigned int device = 0;
     unsigned int channels = 2;
-    unsigned int rate = 48000;
+    unsigned int rate = 44100;
     unsigned int bits = 16;
     unsigned int frames;
     unsigned int period_size = 1024;
     unsigned int period_count = 4;
-    unsigned int capture_time = UINT_MAX;
+    unsigned int cap_time = 0;
     enum pcm_format format;
-    int no_header = 0, c;
-    struct optparse opts;
 
     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] [-t time_in_seconds]\n\n"
-                "Use -- for filename to send raw PCM to stdout\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] [-T capture time]\n", argv[0]);
         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;
-        }
+    file = fopen(argv[1], "wb");
+    if (!file) {
+        fprintf(stderr, "Unable to create file '%s'\n", argv[1]);
+        return 1;
     }
 
     /* parse command line arguments */
-    optparse_init(&opts, argv + 1);
-    while ((c = optparse(&opts, "D:d:c:r:b:p:n:t:")) != -1) {
-        switch (c) {
-        case 'd':
-            device = atoi(opts.optarg);
-            break;
-        case 'c':
-            channels = atoi(opts.optarg);
-            break;
-        case 'r':
-            rate = atoi(opts.optarg);
-            break;
-        case 'b':
-            bits = atoi(opts.optarg);
-            break;
-        case 'D':
-            card = atoi(opts.optarg);
-            break;
-        case 'p':
-            period_size = atoi(opts.optarg);
-            break;
-        case 'n':
-            period_count = atoi(opts.optarg);
-            break;
-        case 't':
-            capture_time = atoi(opts.optarg);
-            break;
-        case '?':
-            fprintf(stderr, "%s\n", opts.errmsg);
-            return EXIT_FAILURE;
+    argv += 2;
+    while (*argv) {
+        if (strcmp(*argv, "-d") == 0) {
+            argv++;
+            if (*argv)
+                device = atoi(*argv);
+        } else if (strcmp(*argv, "-c") == 0) {
+            argv++;
+            if (*argv)
+                channels = atoi(*argv);
+        } else if (strcmp(*argv, "-r") == 0) {
+            argv++;
+            if (*argv)
+                rate = atoi(*argv);
+        } else if (strcmp(*argv, "-b") == 0) {
+            argv++;
+            if (*argv)
+                bits = atoi(*argv);
+        } else if (strcmp(*argv, "-D") == 0) {
+            argv++;
+            if (*argv)
+                card = atoi(*argv);
+        } else if (strcmp(*argv, "-p") == 0) {
+            argv++;
+            if (*argv)
+                period_size = atoi(*argv);
+        } else if (strcmp(*argv, "-n") == 0) {
+            argv++;
+            if (*argv)
+                period_count = atoi(*argv);
+        } else if (strcmp(*argv, "-T") == 0) {
+            argv++;
+            if (*argv)
+                cap_time = atoi(*argv);
         }
+        if (*argv)
+            argv++;
     }
 
     header.riff_id = ID_RIFF;
@@ -176,26 +168,22 @@
     header.data_id = ID_DATA;
 
     /* leave enough room for header */
-    if (!no_header) {
-        fseek(file, sizeof(struct wav_header), SEEK_SET);
-    }
+    fseek(file, sizeof(struct wav_header), SEEK_SET);
 
     /* install signal handler and begin capturing */
     signal(SIGINT, sigint_handler);
+    signal(SIGHUP, sigint_handler);
+    signal(SIGTERM, sigint_handler);
     frames = capture_sample(file, card, device, header.num_channels,
                             header.sample_rate, format,
-                            period_size, period_count, capture_time);
-    if (prinfo) {
-        printf("Captured %u frames\n", frames);
-    }
+                            period_size, period_count, cap_time);
+    printf("Captured %u frames\n", frames);
 
     /* write header now all information is known */
-    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);
-    }
+    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);
 
@@ -205,15 +193,16 @@
 unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device,
                             unsigned int channels, unsigned int rate,
                             enum pcm_format format, unsigned int period_size,
-                            unsigned int period_count, unsigned int capture_time)
+                            unsigned int period_count, unsigned int cap_time)
 {
     struct pcm_config config;
     struct pcm *pcm;
     char *buffer;
     unsigned int size;
-    unsigned int frames_read;
-    unsigned int total_frames_read;
-    unsigned int bytes_per_frame;
+    unsigned int bytes_read = 0;
+    unsigned int frames = 0;
+    struct timespec end;
+    struct timespec now;
 
     memset(&config, 0, sizeof(config));
     config.channels = channels;
@@ -236,32 +225,34 @@
     buffer = malloc(size);
     if (!buffer) {
         fprintf(stderr, "Unable to allocate %u bytes\n", size);
+        free(buffer);
         pcm_close(pcm);
         return 0;
     }
 
-    if (prinfo) {
-        printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate,
+    printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate,
            pcm_format_to_bits(format));
-    }
 
-    bytes_per_frame = pcm_frames_to_bytes(pcm, 1);
-    total_frames_read = 0;
-    frames_read = 0;
-    while (capturing) {
-        frames_read = pcm_readi(pcm, buffer, pcm_get_buffer_size(pcm));
-        total_frames_read += frames_read;
-        if ((total_frames_read / rate) >= capture_time) {
-            capturing = 0;
-        }
-        if (fwrite(buffer, bytes_per_frame, frames_read, file) != frames_read) {
+    clock_gettime(CLOCK_MONOTONIC, &now);
+    end.tv_sec = now.tv_sec + cap_time;
+    end.tv_nsec = now.tv_nsec;
+
+    while (capturing && !pcm_read(pcm, buffer, size)) {
+        if (fwrite(buffer, 1, size, file) != size) {
             fprintf(stderr,"Error capturing sample\n");
             break;
         }
+        bytes_read += size;
+        if (cap_time) {
+            clock_gettime(CLOCK_MONOTONIC, &now);
+            if (now.tv_sec > end.tv_sec ||
+                (now.tv_sec == end.tv_sec && now.tv_nsec >= end.tv_nsec))
+                break;
+        }
     }
 
+    frames = pcm_bytes_to_frames(pcm, bytes_read);
     free(buffer);
     pcm_close(pcm);
-    return total_frames_read;
+    return frames;
 }
-
diff --git a/utils/tinymix.c b/utils/tinymix.c
index 41ca269..789c4af 100644
--- a/utils/tinymix.c
+++ b/utils/tinymix.c
@@ -32,118 +32,97 @@
 #include <stdlib.h>
 #include <ctype.h>
 #include <string.h>
-#include <limits.h>
+#include <getopt.h>
+#include <errno.h>
 
-#define OPTPARSE_IMPLEMENTATION
-#include "optparse.h"
-
-static void tinymix_list_controls(struct mixer *mixer, int print_all);
-
-static void tinymix_detail_control(struct mixer *mixer, const char *control);
-
+static void tinymix_list_controls(struct mixer *mixer);
+static int tinymix_detail_control(struct mixer *mixer, const char *control,
+                                  int prefix, int print_all);
 static int tinymix_set_value(struct mixer *mixer, const char *control,
                              char **values, unsigned int num_values);
+static void tinymix_print_enum(struct mixer_ctl *ctl, const char *space,
+                               int print_all);
 
-static void tinymix_print_enum(struct mixer_ctl *ctl);
+static const char *tinymix_short_options = "D:atvh";
+static struct option tinymix_long_options[] = {
+    {"device",	   required_argument, 0, 'D'},
+    {"all-values", no_argument,       0, 'a'},
+    {"tabs-only",  no_argument,       0, 't'},
+    {"value-only", no_argument,       0, 'v'},
+    {"help",       no_argument,       0, 'h'},
+    {0,            0,                 0, 0}
+};
 
-void usage(void)
-{
-    printf("usage: tinymix [options] <command>\n");
-    printf("options:\n");
-    printf("\t-h, --help        : prints this help message and exits\n");
-    printf("\t-v, --version     : prints this version of tinymix and exits\n");
-    printf("\t-D, --card NUMBER : specifies the card number of the mixer\n");
-    printf("commands:\n");
-    printf("\tget NAME|ID       : prints the values of a control\n");
-    printf("\tset NAME|ID VALUE : sets the value of a control\n");
-    printf("\tcontrols          : lists controls of the mixer\n");
-    printf("\tcontents          : lists controls of the mixer and their contents\n");
-}
+static int g_tabs_only = 0;
+static int g_all_values = 0;
+static int g_value_only = 0;
 
-void version(void)
-{
-    printf("tinymix version 2.0 (tinyalsa version %s)\n", TINYALSA_VERSION_STRING);
+static void usage (void) {
+    fprintf(stderr,
+"tinymix [options] [control name/#] [value to set]\n"
+"    options:\n"
+"    --device|-D <card#>   - use the given card # instead of 0.\n"
+"    --all-values|-a       - show all possible values/ranges for control.\n"
+"    --tabs-only|-t        - separate all output columns/values with tabs.\n"
+"    --value-only|-v       - show only the value for the selected control.\n"
+            );
 }
 
 int main(int argc, char **argv)
 {
     struct mixer *mixer;
-    int card = 0, c;
-    char *cmd;
-    struct optparse opts;
-    static struct optparse_long long_options[] = {
-        { "card",    'D', OPTPARSE_REQUIRED },
-        { "version", 'v', OPTPARSE_NONE     },
-        { "help",    'h', OPTPARSE_NONE     },
-        { 0, 0, 0 }
-    };
+    int card = 0;
+    int ret = 0;
 
-    optparse_init(&opts, argv);
-    /* Detect the end of the options. */
-    while ((c = optparse_long(&opts, long_options, NULL)) != -1) {
-        switch (c) {
+    while (1) {
+        int option_index = 0;
+        int option_char = 0;
+
+        option_char = getopt_long(argc, argv, tinymix_short_options,
+                                  tinymix_long_options, &option_index);
+        if (option_char == -1)
+            break;
+
+        switch (option_char) {
         case 'D':
-            card = atoi(opts.optarg);
+            card = atoi(optarg);
+            break;
+        case 'a':
+            g_all_values = 1;
+            break;
+        case 't':
+            g_tabs_only = 1;
+            break;
+        case 'v':
+            g_value_only = 1;
             break;
         case 'h':
             usage();
-            return EXIT_SUCCESS;
-        case 'v':
-            version();
-            return EXIT_SUCCESS;
-        case '?':
-            fprintf(stderr, "%s\n", opts.errmsg);
-            return EXIT_FAILURE;
+            return 0;
+        default:
+            usage();
+            return EINVAL;
         }
     }
 
     mixer = mixer_open(card);
     if (!mixer) {
         fprintf(stderr, "Failed to open mixer\n");
-        return EXIT_FAILURE;
+        return ENODEV;
     }
 
-    cmd = argv[opts.optind];
-    if (cmd == NULL) {
-        fprintf(stderr, "no command specified (see --help)\n");
-        mixer_close(mixer);
-        return EXIT_FAILURE;
-    } else if (strcmp(cmd, "get") == 0) {
-        if ((opts.optind + 1) >= argc) {
-            fprintf(stderr, "no control specified\n");
-            mixer_close(mixer);
-            return EXIT_FAILURE;
-        }
-        tinymix_detail_control(mixer, argv[opts.optind + 1]);
-        printf("\n");
-    } else if (strcmp(cmd, "set") == 0) {
-        if ((opts.optind + 1) >= argc) {
-            fprintf(stderr, "no control specified\n");
-            mixer_close(mixer);
-            return EXIT_FAILURE;
-        }
-        if ((opts.optind + 2) >= argc) {
-            fprintf(stderr, "no value(s) specified\n");
-            mixer_close(mixer);
-            return EXIT_FAILURE;
-        }
-        int res = tinymix_set_value(mixer, argv[opts.optind + 1], &argv[opts.optind + 2], argc - opts.optind - 2);
-        if (res != 0) {
-            mixer_close(mixer);
-            return EXIT_FAILURE;
-        }
-    } else if (strcmp(cmd, "controls") == 0) {
-        tinymix_list_controls(mixer, 0);
-    } else if (strcmp(cmd, "contents") == 0) {
-        tinymix_list_controls(mixer, 1);
-    } else {
-        fprintf(stderr, "unknown command '%s' (see --help)\n", cmd);
-        mixer_close(mixer);
-        return EXIT_FAILURE;
+    if (argc == optind) {
+        printf("Mixer name: '%s'\n", mixer_get_name(mixer));
+        tinymix_list_controls(mixer);
+    } else if (argc == optind + 1) {
+        ret = tinymix_detail_control(mixer, argv[optind], !g_value_only, !g_value_only);
+    } else if (argc >= optind + 2) {
+        ret = tinymix_set_value(mixer, argv[optind], &argv[optind + 1], argc - optind - 1);
     }
 
     mixer_close(mixer);
-    return EXIT_SUCCESS;
+
+    return ret;
 }
 
 static int isnumber(const char *str) {
@@ -156,7 +135,7 @@
     return strlen(end) == 0;
 }
 
-static void tinymix_list_controls(struct mixer *mixer, int print_all)
+static void tinymix_list_controls(struct mixer *mixer)
 {
     struct mixer_ctl *ctl;
     const char *name, *type;
@@ -167,41 +146,53 @@
 
     printf("Number of controls: %u\n", num_ctls);
 
-    if (print_all)
-        printf("ctl\ttype\tnum\t%-40svalue\n", "name");
+    if (g_tabs_only)
+        printf("ctl\ttype\tnum\tname\tvalue");
     else
-        printf("ctl\ttype\tnum\t%-40s\n", "name");
-
+        printf("ctl\ttype\tnum\t%-40s value\n", "name");
+    if (g_all_values)
+        printf("\trange/values\n");
+    else
+        printf("\n");
     for (i = 0; i < num_ctls; i++) {
         ctl = mixer_get_ctl(mixer, i);
 
         name = mixer_ctl_get_name(ctl);
         type = mixer_ctl_get_type_string(ctl);
         num_values = mixer_ctl_get_num_values(ctl);
-        printf("%u\t%s\t%u\t%-40s", i, type, num_values, name);
-        if (print_all)
-            tinymix_detail_control(mixer, name);
-        printf("\n");
+        if (g_tabs_only)
+            printf("%d\t%s\t%d\t%s\t", i, type, num_values, name);
+        else
+            printf("%d\t%s\t%d\t%-40s ", i, type, num_values, name);
+        tinymix_detail_control(mixer, name, 0, g_all_values);
     }
 }
 
-static void tinymix_print_enum(struct mixer_ctl *ctl)
+static void tinymix_print_enum(struct mixer_ctl *ctl, const char *space,
+                               int print_all)
 {
     unsigned int num_enums;
     unsigned int i;
-    unsigned int value;
     const char *string;
+    int control_value = mixer_ctl_get_value(ctl, 0);
 
-    num_enums = mixer_ctl_get_num_enums(ctl);
-    value = mixer_ctl_get_value(ctl, 0);
-
-    for (i = 0; i < num_enums; i++) {
-        string = mixer_ctl_get_enum_string(ctl, i);
-        printf("%s%s, ", value == i ? "> " : "", string);
+    if (print_all) {
+        num_enums = mixer_ctl_get_num_enums(ctl);
+        for (i = 0; i < num_enums; i++) {
+            string = mixer_ctl_get_enum_string(ctl, i);
+            printf("%s%s%s",
+                   control_value == (int)i ? ">" : "", string,
+                   (i < num_enums - 1) ? space : "");
+        }
+    }
+    else {
+        string = mixer_ctl_get_enum_string(ctl, control_value);
+        printf("%s", string);
     }
 }
 
-static void tinymix_detail_control(struct mixer *mixer, const char *control)
+static int tinymix_detail_control(struct mixer *mixer, const char *control,
+                                  int prefix, int print_all)
 {
     struct mixer_ctl *ctl;
     enum mixer_ctl_type type;
@@ -210,6 +201,9 @@
     int min, max;
     int ret;
     char *buf = NULL;
+    size_t len;
+    unsigned int tlv_header_size = 0;
+    const char *space = g_tabs_only ? "\t" : " ";
 
     if (isnumber(control))
         ctl = mixer_get_ctl(mixer, atoi(control));
@@ -217,28 +211,35 @@
         ctl = mixer_get_ctl_by_name(mixer, control);
 
     if (!ctl) {
-        fprintf(stderr, "Invalid mixer control\n");
-        return;
+        fprintf(stderr, "Invalid mixer control: %s\n", control);
+        return ENOENT;
     }
 
     type = mixer_ctl_get_type(ctl);
     num_values = mixer_ctl_get_num_values(ctl);
 
-    if ((type == MIXER_CTL_TYPE_BYTE) && (num_values > 0)) {
-        buf = calloc(1, num_values);
+    if (type == MIXER_CTL_TYPE_BYTE) {
+        if (mixer_ctl_is_access_tlv_rw(ctl)) {
+            tlv_header_size = TLV_HEADER_SIZE;
+        }
+        buf = calloc(1, num_values + tlv_header_size);
         if (buf == NULL) {
-            fprintf(stderr, "Failed to alloc mem for bytes %u\n", num_values);
-            return;
+            fprintf(stderr, "Failed to alloc mem for bytes %d\n", num_values);
+            return ENOENT;
         }
 
-        ret = mixer_ctl_get_array(ctl, buf, num_values);
+        len = num_values;
+        ret = mixer_ctl_get_array(ctl, buf, len + tlv_header_size);
         if (ret < 0) {
             fprintf(stderr, "Failed to mixer_ctl_get_array\n");
             free(buf);
-            return;
+            return ENOENT;
         }
     }
 
+    if (prefix)
+        printf("%s:%s", mixer_ctl_get_name(ctl), space);
+
     for (i = 0; i < num_values; i++) {
         switch (type)
         {
@@ -249,44 +250,62 @@
             printf("%s", mixer_ctl_get_value(ctl, i) ? "On" : "Off");
             break;
         case MIXER_CTL_TYPE_ENUM:
-            tinymix_print_enum(ctl);
+            tinymix_print_enum(ctl, space, print_all);
             break;
         case MIXER_CTL_TYPE_BYTE:
-            printf(" %02x", buf[i]);
+            /* skip printing TLV header if exists */
+            printf(" %02x", buf[i + tlv_header_size]);
             break;
         default:
             printf("unknown");
             break;
-        };
-        if ((i + 1) < num_values) {
-           printf(", ");
+        }
+
+        if (i < num_values - 1)
+            printf("%s", space);
+    }
+
+    if (print_all) {
+        if (type == MIXER_CTL_TYPE_INT) {
+            min = mixer_ctl_get_range_min(ctl);
+            max = mixer_ctl_get_range_max(ctl);
+            printf("%s(dsrange %d->%d)", space, min, max);
         }
     }
 
-    if (type == MIXER_CTL_TYPE_INT) {
-        min = mixer_ctl_get_range_min(ctl);
-        max = mixer_ctl_get_range_max(ctl);
-        printf(" (range %d->%d)", min, max);
-    }
-
     free(buf);
+
+    printf("\n");
+    return 0;
 }
 
 static void tinymix_set_byte_ctl(struct mixer_ctl *ctl,
-                                 char **values, unsigned int num_values)
+    char **values, unsigned int num_values)
 {
     int ret;
     char *buf;
     char *end;
     unsigned int i;
     long n;
+    unsigned int *tlv, tlv_size;
+    unsigned int tlv_header_size = 0;
 
-    buf = calloc(1, num_values);
+    if (mixer_ctl_is_access_tlv_rw(ctl)) {
+        tlv_header_size = TLV_HEADER_SIZE;
+    }
+
+    tlv_size = num_values + tlv_header_size;
+
+    buf = calloc(1, tlv_size);
     if (buf == NULL) {
-        fprintf(stderr, "set_byte_ctl: Failed to alloc mem for bytes %u\n", num_values);
+        fprintf(stderr, "set_byte_ctl: Failed to alloc mem for bytes %d\n", num_values);
         exit(EXIT_FAILURE);
     }
 
+    tlv = (unsigned int *)buf;
+    tlv[0] = 0;
+    tlv[1] = num_values;
+
     for (i = 0; i < num_values; i++) {
         errno = 0;
         n = strtol(values[i], &end, 0);
@@ -304,10 +323,11 @@
                 values[i]);
             goto fail;
         }
-        buf[i] = n;
+        /* start filling after the TLV header */
+        buf[i + tlv_header_size] = n;
     }
 
-    ret = mixer_ctl_set_array(ctl, buf, num_values);
+    ret = mixer_ctl_set_array(ctl, buf, tlv_size);
     if (ret < 0) {
         fprintf(stderr, "Failed to set binary control\n");
         goto fail;
@@ -321,163 +341,13 @@
     exit(EXIT_FAILURE);
 }
 
-static int is_int(const char *value)
-{
-    return (value[0] >= '0') || (value[0] <= '9');
-}
-
-struct parsed_int
-{
-  /** Wether or not the integer was valid. */
-  int valid;
-  /** The value of the parsed integer. */
-  int value;
-  /** The number of characters that were parsed. */
-  unsigned int length;
-  /** The number of characters remaining in the string. */
-  unsigned int remaining_length;
-  /** The remaining characters (or suffix) of the integer. */
-  const char* remaining;
-};
-
-static struct parsed_int parse_int(const char* str)
-{
-  struct parsed_int out = {
-    0 /* valid */,
-    0 /* value */,
-    0 /* length */,
-    0 /* remaining length */,
-    "" /* remaining characters */
-  };
-
-  unsigned int max = strlen(str);
-
-  for (unsigned int i = 0; i < max; i++) {
-
-    char c = str[i];
-
-    if ((c < '0') || (c > '9')) {
-      break;
-    }
-
-    out.value *= 10;
-    out.value += c - '0';
-
-    out.length++;
-  }
-
-  out.valid = out.length > 0;
-  out.remaining_length = max - out.length;
-  out.remaining = str + out.length;
-
-  return out;
-}
-
-struct control_value
-{
-    int value;
-    int is_percent;
-    int is_relative;
-};
-
-static struct control_value to_control_value(const char* value_string)
-{
-    struct parsed_int parsed_int = parse_int(value_string);
-
-    struct control_value out = {
-        0 /* value */,
-        0 /* is percent */,
-        0 /* is relative */
-    };
-
-    out.value = parsed_int.value;
-
-    unsigned int i = 0;
-
-    if (parsed_int.remaining[i] == '%') {
-      out.is_percent = 1;
-      i++;
-    }
-
-    if (parsed_int.remaining[i] == '+') {
-      out.is_relative = 1;
-    } else if (parsed_int.remaining[i] == '-') {
-      out.is_relative = 1;
-      out.value *= -1;
-    }
-
-    return out;
-}
-
-static int set_control_value(struct mixer_ctl* ctl, unsigned int i, const struct control_value* value)
-{
-    int next_value = value->value;
-
-    if (value->is_relative) {
-
-        int prev_value = value->is_percent ? mixer_ctl_get_percent(ctl, i)
-                                           : mixer_ctl_get_value(ctl, i);
-
-        if (prev_value < 0) {
-          return prev_value;
-        }
-
-        next_value += prev_value;
-    }
-
-    return value->is_percent ? mixer_ctl_set_percent(ctl, i, next_value)
-                             : mixer_ctl_set_value(ctl, i, next_value);
-}
-
-static int set_control_values(struct mixer_ctl* ctl,
-                              char** values,
-                              unsigned int num_values)
-{
-    unsigned int num_ctl_values = mixer_ctl_get_num_values(ctl);
-
-    if (num_values == 1) {
-
-        /* Set all values the same */
-        struct control_value value = to_control_value(values[0]);
-
-        for (unsigned int i = 0; i < num_values; i++) {
-            int res = set_control_value(ctl, i, &value);
-            if (res != 0) {
-                fprintf(stderr, "Error: invalid value\n");
-                return -1;
-            }
-        }
-
-    } else {
-
-        /* Set multiple values */
-        if (num_values > num_ctl_values) {
-            fprintf(stderr,
-                    "Error: %u values given, but control only takes %u\n",
-                    num_values, num_ctl_values);
-            return -1;
-        }
-
-        for (unsigned int i = 0; i < num_values; i++) {
-
-            struct control_value v = to_control_value(values[i]);
-
-            int res = set_control_value(ctl, i, &v);
-            if (res != 0) {
-                fprintf(stderr, "Error: invalid value for index %u\n", i);
-                return -1;
-            }
-        }
-    }
-
-    return 0;
-}
-
 static int 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_ctl_values;
+    unsigned int i;
 
     if (isnumber(control))
         ctl = mixer_get_ctl(mixer, atoi(control));
@@ -485,35 +355,59 @@
         ctl = mixer_get_ctl_by_name(mixer, control);
 
     if (!ctl) {
-        fprintf(stderr, "Invalid mixer control\n");
-        return -1;
+        fprintf(stderr, "Invalid mixer control: %s\n", control);
+        return ENOENT;
     }
 
     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, values, num_values);
-        return 0;
+        return ENOENT;
     }
 
-    if (is_int(values[0])) {
-        set_control_values(ctl, values, num_values);
+    if (isnumber(values[0])) {
+        if (num_values == 1) {
+            /* Set all values the same */
+            int value = atoi(values[0]);
+
+            for (i = 0; i < num_ctl_values; i++) {
+                if (mixer_ctl_set_value(ctl, i, value)) {
+                    fprintf(stderr, "Error: invalid value\n");
+                    return EINVAL;
+                }
+            }
+        } else {
+            /* Set multiple values */
+            if (num_values > num_ctl_values) {
+                fprintf(stderr,
+                        "Error: %u values given, but control only takes %u\n",
+                        num_values, num_ctl_values);
+                return EINVAL;
+            }
+            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 EINVAL;
+                }
+            }
+        }
     } else {
         if (type == MIXER_CTL_TYPE_ENUM) {
             if (num_values != 1) {
                 fprintf(stderr, "Enclose strings in quotes and try again\n");
-                return -1;
+                return EINVAL;
             }
             if (mixer_ctl_set_enum_by_string(ctl, values[0])) {
                 fprintf(stderr, "Error: invalid enum value\n");
-                return -1;
+                return EINVAL;
             }
         } else {
             fprintf(stderr, "Error: only enum types can be set with strings\n");
-            return -1;
+            return EINVAL;
         }
     }
 
     return 0;
 }
-
diff --git a/utils/tinypcminfo.c b/utils/tinypcminfo.c
index 3116b7c..4eb0afa 100644
--- a/utils/tinypcminfo.c
+++ b/utils/tinypcminfo.c
@@ -31,9 +31,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#define OPTPARSE_IMPLEMENTATION
-#include "optparse.h"
-
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
 #endif
@@ -105,39 +102,34 @@
     unsigned int device = 0;
     unsigned int card = 0;
     int i;
-    struct optparse opts;
-    struct optparse_long long_options[] = {
-        { "help",   'h', OPTPARSE_NONE     },
-        { "card",   'D', OPTPARSE_REQUIRED },
-        { "device", 'd', OPTPARSE_REQUIRED },
-        { 0, 0, 0 }
-    };
 
-    (void)argc; /* silence -Wunused-parameter */
+    if (argc < 3) {
+        fprintf(stderr, "Usage: %s -D card -d device\n", argv[0]);
+        return 1;
+    }
+
     /* parse command line arguments */
-    optparse_init(&opts, argv);
-    while ((i = optparse_long(&opts, long_options, NULL)) != -1) {
-        switch (i) {
-        case 'D':
-            card = atoi(opts.optarg);
-            break;
-        case 'd':
-            device = atoi(opts.optarg);
-            break;
-        case 'h':
-            fprintf(stderr, "Usage: %s -D card -d device\n", argv[0]);
-            return 0;
-        case '?':
-            fprintf(stderr, "%s\n", opts.errmsg);
-            return EXIT_FAILURE;
+    argv += 1;
+    while (*argv) {
+        if (strcmp(*argv, "-D") == 0) {
+            argv++;
+            if (*argv)
+                card = atoi(*argv);
         }
+        if (strcmp(*argv, "-d") == 0) {
+            argv++;
+            if (*argv)
+                device = atoi(*argv);
+        }
+        if (*argv)
+            argv++;
     }
 
     printf("Info for card %u, device %u:\n", card, device);
 
     for (i = 0; i < 2; i++) {
         struct pcm_params *params;
-        const struct pcm_mask *m;
+        struct pcm_mask *m;
         unsigned int min;
         unsigned int max;
 
diff --git a/utils/tinyplay.c b/utils/tinyplay.c
index 2689158..0354df6 100644
--- a/utils/tinyplay.c
+++ b/utils/tinyplay.c
@@ -32,38 +32,7 @@
 #include <stdint.h>
 #include <string.h>
 #include <signal.h>
-
-#define OPTPARSE_IMPLEMENTATION
-#include "optparse.h"
-
-struct cmd {
-    const char *filename;
-    const char *filetype;
-    unsigned int card;
-    unsigned int device;
-    int flags;
-    struct pcm_config config;
-    unsigned int bits;
-};
-
-void cmd_init(struct cmd *cmd)
-{
-    cmd->filename = NULL;
-    cmd->filetype = NULL;
-    cmd->card = 0;
-    cmd->device = 0;
-    cmd->flags = PCM_OUT;
-    cmd->config.period_size = 1024;
-    cmd->config.period_count = 2;
-    cmd->config.channels = 2;
-    cmd->config.rate = 48000;
-    cmd->config.format = PCM_FORMAT_S16_LE;
-    cmd->config.silence_threshold = cmd->config.period_size * cmd->config.period_count;
-    cmd->config.silence_size = 0;
-    cmd->config.stop_threshold = cmd->config.period_size * cmd->config.period_count;
-    cmd->config.start_threshold = cmd->config.period_size;
-    cmd->bits = 16;
-}
+#include <endian.h>
 
 #define ID_RIFF 0x46464952
 #define ID_WAVE 0x45564157
@@ -90,128 +59,11 @@
     uint16_t bits_per_sample;
 };
 
-struct ctx {
-    struct pcm *pcm;
-
-    struct riff_wave_header wave_header;
-    struct chunk_header chunk_header;
-    struct chunk_fmt chunk_fmt;
-
-    FILE *file;
-};
-
-int ctx_init(struct ctx* ctx, const struct cmd *cmd)
-{
-    unsigned int bits = cmd->bits;
-    struct pcm_config config = cmd->config;
-
-    if (cmd->filename == NULL) {
-        fprintf(stderr, "filename not specified\n");
-        return -1;
-    }
-    if (strcmp(cmd->filename, "-") == 0) {
-        ctx->file = stdin;
-    } else {
-        ctx->file = fopen(cmd->filename, "rb");
-    }
-
-    if (ctx->file == NULL) {
-        fprintf(stderr, "failed to open '%s'\n", cmd->filename);
-        return -1;
-    }
-
-    if ((cmd->filetype != NULL) && (strcmp(cmd->filetype, "wav") == 0)) {
-        if (fread(&ctx->wave_header, sizeof(ctx->wave_header), 1, ctx->file) != 1){
-            fprintf(stderr, "error: '%s' does not contain a riff/wave header\n", cmd->filename);
-            fclose(ctx->file);
-            return -1;
-        }
-        if ((ctx->wave_header.riff_id != ID_RIFF) ||
-            (ctx->wave_header.wave_id != ID_WAVE)) {
-            fprintf(stderr, "error: '%s' is not a riff/wave file\n", cmd->filename);
-            fclose(ctx->file);
-            return -1;
-        }
-        unsigned int more_chunks = 1;
-        do {
-            if (fread(&ctx->chunk_header, sizeof(ctx->chunk_header), 1, ctx->file) != 1){
-                fprintf(stderr, "error: '%s' does not contain a data chunk\n", cmd->filename);
-                fclose(ctx->file);
-                return -1;
-            }
-            switch (ctx->chunk_header.id) {
-            case ID_FMT:
-                if (fread(&ctx->chunk_fmt, sizeof(ctx->chunk_fmt), 1, ctx->file) != 1){
-                    fprintf(stderr, "error: '%s' has incomplete format chunk\n", cmd->filename);
-                    fclose(ctx->file);
-                    return -1;
-                }
-                /* If the format header is larger, skip the rest */
-                if (ctx->chunk_header.sz > sizeof(ctx->chunk_fmt))
-                    fseek(ctx->file, ctx->chunk_header.sz - sizeof(ctx->chunk_fmt), SEEK_CUR);
-                break;
-            case ID_DATA:
-                /* Stop looking for chunks */
-                more_chunks = 0;
-                break;
-            default:
-                /* Unknown chunk, skip bytes */
-                fseek(ctx->file, ctx->chunk_header.sz, SEEK_CUR);
-            }
-        } while (more_chunks);
-        config.channels = ctx->chunk_fmt.num_channels;
-        config.rate = ctx->chunk_fmt.sample_rate;
-        bits = ctx->chunk_fmt.bits_per_sample;
-    }
-
-    if (bits == 8) {
-        config.format = PCM_FORMAT_S8;
-    } else if (bits == 16) {
-        config.format = PCM_FORMAT_S16_LE;
-    } else if (bits == 24) {
-        config.format = PCM_FORMAT_S24_3LE;
-    } else if (bits == 32) {
-        config.format = PCM_FORMAT_S32_LE;
-    } else {
-        fprintf(stderr, "bit count '%u' not supported\n", bits);
-        fclose(ctx->file);
-        return -1;
-    }
-
-    ctx->pcm = pcm_open(cmd->card,
-                        cmd->device,
-                        cmd->flags,
-                        &config);
-    if (ctx->pcm == NULL) {
-        fprintf(stderr, "failed to allocate memory for pcm\n");
-        fclose(ctx->file);
-        return -1;
-    } else if (!pcm_is_ready(ctx->pcm)) {
-        fprintf(stderr, "failed to open for pcm %u,%u\n", cmd->card, cmd->device);
-        fclose(ctx->file);
-        pcm_close(ctx->pcm);
-        return -1;
-    }
-
-    return 0;
-}
-
-void ctx_free(struct ctx *ctx)
-{
-    if (ctx == NULL) {
-        return;
-    }
-    if (ctx->pcm != NULL) {
-        pcm_close(ctx->pcm);
-    }
-    if (ctx->file != NULL) {
-        fclose(ctx->file);
-    }
-}
-
 static int close = 0;
 
-int play_sample(struct ctx *ctx);
+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, uint32_t data_sz);
 
 void stream_close(int sig)
 {
@@ -220,126 +72,94 @@
     close = 1;
 }
 
-void print_usage(const char *argv0)
-{
-    fprintf(stderr, "usage: %s file.wav [options]\n", argv0);
-    fprintf(stderr, "options:\n");
-    fprintf(stderr, "-D | --card   <card number>    The card to receive the audio\n");
-    fprintf(stderr, "-d | --device <device number>  The device to receive the audio\n");
-    fprintf(stderr, "-p | --period-size <size>      The size of the PCM's period\n");
-    fprintf(stderr, "-n | --period-count <count>    The number of PCM periods\n");
-    fprintf(stderr, "-i | --file-type <file-type >  The type of file to read (raw or wav)\n");
-    fprintf(stderr, "-c | --channels <count>        The amount of channels per frame\n");
-    fprintf(stderr, "-r | --rate <rate>             The amount of frames per second\n");
-    fprintf(stderr, "-b | --bits <bit-count>        The number of bits in one sample\n");
-    fprintf(stderr, "-M | --mmap                    Use memory mapped IO to play audio\n");
-}
-
 int main(int argc, char **argv)
 {
-    int c;
-    struct cmd cmd;
-    struct ctx ctx;
-    struct optparse opts;
-    struct optparse_long long_options[] = {
-        { "card",         'D', OPTPARSE_REQUIRED },
-        { "device",       'd', OPTPARSE_REQUIRED },
-        { "period-size",  'p', OPTPARSE_REQUIRED },
-        { "period-count", 'n', OPTPARSE_REQUIRED },
-        { "file-type",    'i', OPTPARSE_REQUIRED },
-        { "channels",     'c', OPTPARSE_REQUIRED },
-        { "rate",         'r', OPTPARSE_REQUIRED },
-        { "bits",         'b', OPTPARSE_REQUIRED },
-        { "mmap",         'M', OPTPARSE_NONE     },
-        { "help",         'h', OPTPARSE_NONE     },
-        { 0, 0, 0 }
-    };
+    FILE *file;
+    struct riff_wave_header riff_wave_header;
+    struct chunk_header chunk_header;
+    struct chunk_fmt chunk_fmt;
+    unsigned int device = 0;
+    unsigned int card = 0;
+    unsigned int period_size = 1024;
+    unsigned int period_count = 4;
+    char *filename;
+    int more_chunks = 1;
 
     if (argc < 2) {
-        print_usage(argv[0]);
-        return EXIT_FAILURE;
+        fprintf(stderr, "Usage: %s file.wav [-D card] [-d device] [-p period_size]"
+                " [-n n_periods] \n", argv[0]);
+        return 1;
     }
 
-    cmd_init(&cmd);
-    optparse_init(&opts, argv);
-    while ((c = optparse_long(&opts, long_options, NULL)) != -1) {
-        switch (c) {
-        case 'D':
-            if (sscanf(opts.optarg, "%u", &cmd.card) != 1) {
-                fprintf(stderr, "failed parsing card number '%s'\n", argv[1]);
-                return EXIT_FAILURE;
-            }
+    filename = argv[1];
+    file = fopen(filename, "rb");
+    if (!file) {
+        fprintf(stderr, "Unable to open file '%s'\n", filename);
+        return 1;
+    }
+
+    fread(&riff_wave_header, sizeof(riff_wave_header), 1, file);
+    if ((riff_wave_header.riff_id != ID_RIFF) ||
+        (riff_wave_header.wave_id != ID_WAVE)) {
+        fprintf(stderr, "Error: '%s' is not a riff/wave file\n", filename);
+        fclose(file);
+        return 1;
+    }
+
+    do {
+        fread(&chunk_header, sizeof(chunk_header), 1, file);
+
+        switch (chunk_header.id) {
+        case ID_FMT:
+            fread(&chunk_fmt, sizeof(chunk_fmt), 1, file);
+            /* If the format header is larger, skip the rest */
+            if (chunk_header.sz > sizeof(chunk_fmt))
+                fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
             break;
-        case 'd':
-            if (sscanf(opts.optarg, "%u", &cmd.device) != 1) {
-                fprintf(stderr, "failed parsing device number '%s'\n", argv[1]);
-                return EXIT_FAILURE;
-            }
+        case ID_DATA:
+            /* Stop looking for chunks */
+            more_chunks = 0;
+            chunk_header.sz = le32toh(chunk_header.sz);
             break;
-        case 'p':
-            if (sscanf(opts.optarg, "%u", &cmd.config.period_size) != 1) {
-                fprintf(stderr, "failed parsing period size '%s'\n", argv[1]);
-                return EXIT_FAILURE;
-            }
-            break;
-        case 'n':
-            if (sscanf(opts.optarg, "%u", &cmd.config.period_count) != 1) {
-                fprintf(stderr, "failed parsing period count '%s'\n", argv[1]);
-                return EXIT_FAILURE;
-            }
-            break;
-        case 'c':
-            if (sscanf(opts.optarg, "%u", &cmd.config.channels) != 1) {
-                fprintf(stderr, "failed parsing channel count '%s'\n", argv[1]);
-                return EXIT_FAILURE;
-            }
-            break;
-        case 'r':
-            if (sscanf(opts.optarg, "%u", &cmd.config.rate) != 1) {
-                fprintf(stderr, "failed parsing rate '%s'\n", argv[1]);
-                return EXIT_FAILURE;
-            }
-            break;
-        case 'i':
-            cmd.filetype = opts.optarg;
-            break;
-        case 'h':
-            print_usage(argv[0]);
-            return EXIT_SUCCESS;
-        case '?':
-            fprintf(stderr, "%s\n", opts.errmsg);
-            return EXIT_FAILURE;
+        default:
+            /* Unknown chunk, skip bytes */
+            fseek(file, chunk_header.sz, SEEK_CUR);
         }
-    }
-    cmd.filename = optparse_arg(&opts);
+    } while (more_chunks);
 
-    if (cmd.filename != NULL && cmd.filetype == NULL &&
-        (cmd.filetype = strrchr(cmd.filename, '.')) != NULL) {
-        cmd.filetype++;
+    /* parse command line arguments */
+    argv += 2;
+    while (*argv) {
+        if (strcmp(*argv, "-d") == 0) {
+            argv++;
+            if (*argv)
+                device = atoi(*argv);
+        }
+        if (strcmp(*argv, "-p") == 0) {
+            argv++;
+            if (*argv)
+                period_size = atoi(*argv);
+        }
+        if (strcmp(*argv, "-n") == 0) {
+            argv++;
+            if (*argv)
+                period_count = atoi(*argv);
+        }
+        if (strcmp(*argv, "-D") == 0) {
+            argv++;
+            if (*argv)
+                card = atoi(*argv);
+        }
+        if (*argv)
+            argv++;
     }
 
-    cmd.config.silence_threshold = cmd.config.period_size * cmd.config.period_count;
-    cmd.config.stop_threshold = cmd.config.period_size * cmd.config.period_count;
-    cmd.config.start_threshold = cmd.config.period_size;
+    play_sample(file, card, device, chunk_fmt.num_channels, chunk_fmt.sample_rate,
+                chunk_fmt.bits_per_sample, period_size, period_count, chunk_header.sz);
 
-    if (ctx_init(&ctx, &cmd) < 0) {
-        return EXIT_FAILURE;
-    }
+    fclose(file);
 
-    /* TODO get parameters from context */
-    printf("playing '%s': %u ch, %u hz, %u bit\n",
-           cmd.filename,
-           cmd.config.channels,
-           cmd.config.rate,
-           cmd.bits);
-
-    if (play_sample(&ctx) < 0) {
-        ctx_free(&ctx);
-        return EXIT_FAILURE;
-    }
-
-    ctx_free(&ctx);
-    return EXIT_SUCCESS;
+    return 0;
 }
 
 int check_param(struct pcm_params *params, unsigned int param, unsigned int value,
@@ -366,70 +186,93 @@
     return is_within_bounds;
 }
 
-int sample_is_playable(const struct cmd *cmd)
+int sample_is_playable(unsigned int card, unsigned int device, unsigned int channels,
+                        unsigned int rate, unsigned int bits, unsigned int period_size,
+                        unsigned int period_count)
 {
     struct pcm_params *params;
     int can_play;
 
-    params = pcm_params_get(cmd->card, cmd->device, PCM_OUT);
+    params = pcm_params_get(card, device, PCM_OUT);
     if (params == NULL) {
-        fprintf(stderr, "unable to open PCM %u,%u\n", cmd->card, cmd->device);
+        fprintf(stderr, "Unable to open PCM device %u.\n", device);
         return 0;
     }
 
-    can_play = check_param(params, PCM_PARAM_RATE, cmd->config.rate, "sample rate", "hz");
-    can_play &= check_param(params, PCM_PARAM_CHANNELS, cmd->config.channels, "sample", " channels");
-    can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, cmd->bits, "bits", " bits");
-    can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, cmd->config.period_size, "period size",
-                            " frames");
-    can_play &= check_param(params, PCM_PARAM_PERIODS, cmd->config.period_count, "period count",
-                            " frames");
+    can_play = check_param(params, PCM_PARAM_RATE, rate, "Sample rate", "Hz");
+    can_play &= check_param(params, PCM_PARAM_CHANNELS, channels, "Sample", " channels");
+    can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, bits, "Bitrate", " bits");
+    can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, period_size, "Period size", " frames");
+    can_play &= check_param(params, PCM_PARAM_PERIODS, period_count, "Period count", " periods");
 
     pcm_params_free(params);
 
     return can_play;
 }
 
-int play_sample(struct ctx *ctx)
+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, uint32_t data_sz)
 {
+    struct pcm_config config;
+    struct pcm *pcm;
     char *buffer;
-    size_t buffer_size = 0;
-    size_t num_read = 0;
-    size_t remaining_data_size = ctx->chunk_header.sz;
-    size_t read_size = 0;
-    const struct pcm_config *config = pcm_get_config(ctx->pcm);
+    unsigned int size, read_sz;
+    int num_read;
 
-    if (config == NULL) {
-        fprintf(stderr, "unable to get pcm config\n");
-        return -1;
+    memset(&config, 0, sizeof(config));
+    config.channels = channels;
+    config.rate = rate;
+    config.period_size = period_size;
+    config.period_count = period_count;
+    if (bits == 32)
+        config.format = PCM_FORMAT_S32_LE;
+    else if (bits == 24)
+        config.format = PCM_FORMAT_S24_3LE;
+    else if (bits == 16)
+        config.format = PCM_FORMAT_S16_LE;
+    config.start_threshold = 0;
+    config.stop_threshold = 0;
+    config.silence_threshold = 0;
+
+    if (!sample_is_playable(card, device, channels, rate, bits, period_size, period_count)) {
+        return;
     }
 
-    buffer_size = pcm_frames_to_bytes(ctx->pcm, config->period_size);
-    buffer = malloc(buffer_size);
+    pcm = pcm_open(card, device, PCM_OUT, &config);
+    if (!pcm || !pcm_is_ready(pcm)) {
+        fprintf(stderr, "Unable to open PCM device %u (%s)\n",
+                device, pcm_get_error(pcm));
+        return;
+    }
+
+    size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
+    buffer = malloc(size);
     if (!buffer) {
-        fprintf(stderr, "unable to allocate %zu bytes\n", buffer_size);
-        return -1;
+        fprintf(stderr, "Unable to allocate %d bytes\n", size);
+        free(buffer);
+        pcm_close(pcm);
+        return;
     }
 
+    printf("Playing sample: %u ch, %u hz, %u bit %u bytes\n", channels, rate, bits, data_sz);
+
     /* catch ctrl-c to shutdown cleanly */
     signal(SIGINT, stream_close);
 
     do {
-        read_size = remaining_data_size > buffer_size ? buffer_size : remaining_data_size;
-        num_read = fread(buffer, 1, read_size, ctx->file);
+        read_sz = size < data_sz ? size : data_sz;
+        num_read = fread(buffer, 1, read_sz, file);
         if (num_read > 0) {
-            if (pcm_writei(ctx->pcm, buffer,
-                pcm_bytes_to_frames(ctx->pcm, num_read)) < 0) {
-                fprintf(stderr, "error playing sample\n");
+            if (pcm_write(pcm, buffer, num_read)) {
+                fprintf(stderr, "Error playing sample\n");
                 break;
             }
-            remaining_data_size -= num_read;
+            data_sz -= num_read;
         }
-    } while (!close && num_read > 0 && remaining_data_size > 0);
-
-    pcm_wait(ctx->pcm, -1);
+    } while (!close && num_read > 0 && data_sz > 0);
 
     free(buffer);
-    return 0;
+    pcm_close(pcm);
 }
 
diff --git a/utils/tinywavinfo.c b/utils/tinywavinfo.c
deleted file mode 100644
index a74ca7d..0000000
--- a/utils/tinywavinfo.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/* tinywavinfo.c
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are met:
-**     * Redistributions of source code must retain the above copyright
-**       notice, this list of conditions and the following disclaimer.
-**     * Redistributions in binary form must reproduce the above copyright
-**       notice, this list of conditions and the following disclaimer in the
-**       documentation and/or other materials provided with the distribution.
-**     * Neither the name of The Android Open Source Project nor the names of
-**       its contributors may be used to endorse or promote products derived
-**       from this software without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
-** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
-** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
-** DAMAGE.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <signal.h>
-#include <math.h>
-
-#define ID_RIFF 0x46464952
-#define ID_WAVE 0x45564157
-#define ID_FMT  0x20746d66
-#define ID_DATA 0x61746164
-
-struct riff_wave_header {
-    uint32_t riff_id;
-    uint32_t riff_sz;
-    uint32_t wave_id;
-};
-
-struct chunk_header {
-    uint32_t id;
-    uint32_t sz;
-};
-
-struct chunk_fmt {
-    uint16_t audio_format;
-    uint16_t num_channels;
-    uint32_t sample_rate;
-    uint32_t byte_rate;
-    uint16_t block_align;
-    uint16_t bits_per_sample;
-};
-
-static int close = 0;
-
-void analyse_sample(FILE *file, unsigned int channels, unsigned int bits,
-                    unsigned int data_chunk_size);
-
-void stream_close(int sig)
-{
-    /* allow the stream to be closed gracefully */
-    signal(sig, SIG_IGN);
-    close = 1;
-}
-
-size_t xfread(void *ptr, size_t size, size_t nmemb, FILE *stream)
-{
-    size_t sz = fread(ptr, size, nmemb, stream);
-
-    if (sz != nmemb && ferror(stream)) {
-        fprintf(stderr, "Error: fread failed\n");
-        exit(1);
-    }
-    return sz;
-}
-
-int main(int argc, char **argv)
-{
-    FILE *file;
-    struct riff_wave_header riff_wave_header;
-    struct chunk_header chunk_header;
-    struct chunk_fmt chunk_fmt;
-    char *filename;
-    int more_chunks = 1;
-
-    if (argc < 2) {
-        fprintf(stderr, "Usage: %s file.wav \n", argv[0]);
-        return 1;
-    }
-
-    filename = argv[1];
-    file = fopen(filename, "rb");
-    if (!file) {
-        fprintf(stderr, "Unable to open file '%s'\n", filename);
-        return 1;
-    }
-
-    xfread(&riff_wave_header, sizeof(riff_wave_header), 1, file);
-    if ((riff_wave_header.riff_id != ID_RIFF) ||
-        (riff_wave_header.wave_id != ID_WAVE)) {
-        fprintf(stderr, "Error: '%s' is not a riff/wave file\n", filename);
-        fclose(file);
-        return 1;
-    }
-
-    do {
-        xfread(&chunk_header, sizeof(chunk_header), 1, file);
-
-        switch (chunk_header.id) {
-        case ID_FMT:
-            xfread(&chunk_fmt, sizeof(chunk_fmt), 1, file);
-            /* If the format header is larger, skip the rest */
-            if (chunk_header.sz > sizeof(chunk_fmt))
-                fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
-            break;
-        case ID_DATA:
-            /* Stop looking for chunks */
-            more_chunks = 0;
-            break;
-        default:
-            /* Unknown chunk, skip bytes */
-            fseek(file, chunk_header.sz, SEEK_CUR);
-        }
-    } while (more_chunks);
-
-    printf("Input File       : %s \n", filename);
-    printf("Channels         : %u \n", chunk_fmt.num_channels);
-    printf("Sample Rate      : %u \n", chunk_fmt.sample_rate);
-    printf("Bits per sample  : %u \n\n", chunk_fmt.bits_per_sample);
-
-    analyse_sample(file, chunk_fmt.num_channels, chunk_fmt.bits_per_sample,
-                    chunk_header.sz);
-
-    fclose(file);
-
-    return 0;
-}
-
-void analyse_sample(FILE *file, unsigned int channels, unsigned int bits,
-                    unsigned int data_chunk_size)
-{
-    void *buffer;
-    int size;
-    int num_read;
-    int i;
-    unsigned int ch;
-    int frame_size = 1024;
-    unsigned int bytes_per_sample = 0;
-    float *power;
-    int total_sample_per_channel;
-    float normalization_factor;
-
-    if (bits == 32)
-        bytes_per_sample = 4;
-    else if (bits == 16)
-        bytes_per_sample = 2;
-
-    normalization_factor = (float)pow(2.0, (bits-1));
-
-    size = channels * bytes_per_sample * frame_size;
-
-    buffer = malloc(size);
-    if (!buffer) {
-        fprintf(stderr, "Unable to allocate %d bytes\n", size);
-        free(buffer);
-        return;
-    }
-
-    power = (float *) calloc(channels, sizeof(float));
-
-    total_sample_per_channel = data_chunk_size / (channels * bytes_per_sample);
-
-    /* catch ctrl-c to shutdown cleanly */
-    signal(SIGINT, stream_close);
-
-    do {
-        num_read = xfread(buffer, 1, size, file);
-        if (num_read > 0) {
-            if (2 == bytes_per_sample) {
-                short *buffer_ptr = (short *)buffer;
-                for (i = 0; i < num_read; i += channels) {
-                    for (ch = 0; ch < channels; ch++) {
-                        int temp = *buffer_ptr++;
-                        /* Signal Normalization */
-                        float f = (float) temp / normalization_factor;
-                        *(power + ch) += (float) (f * f);
-                    }
-                }
-            }
-            if (4 == bytes_per_sample) {
-                int *buffer_ptr = (int *)buffer;
-                for (i = 0; i < num_read; i += channels) {
-                    for (ch = 0; ch < channels; ch++) {
-                        int temp = *buffer_ptr++;
-                        /* Signal Normalization */
-                        float f = (float) temp / normalization_factor;
-                        *(power + ch) += (float) (f * f);
-                    }
-                }
-            }
-        }
-    }while (!close && num_read > 0);
-
-    for (ch = 0; ch < channels; ch++) {
-        float average_power = 10 * log10((*(power + ch)) / total_sample_per_channel);
-        if(isinf (average_power)) {
-            printf("Channel [%2u] Average Power : NO signal or ZERO signal\n", ch);
-        } else {
-            printf("Channel [%2u] Average Power : %.2f dB\n", ch, average_power);
-        }
-    }
-
-    free(buffer);
-    free(power);
-
-}
-