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);
-
-}
-