Takashi Iwai
8a90d87ca6
- backport from upstream tree: * lots of patches to support the new chmap API * fix segfault in rate plugin error path * add a couple of test programs * fix inifinte loop in htimestamp of dmix & co OBS-URL: https://build.opensuse.org/request/show/138456 OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa?expand=0&rev=113
289 lines
6.3 KiB
Diff
289 lines
6.3 KiB
Diff
From 3fc13d6f5b08edee49b106cd711d51bf3aef6ab7 Mon Sep 17 00:00:00 2001
|
|
From: Takashi Iwai <tiwai@suse.de>
|
|
Date: Mon, 30 Jul 2012 15:50:44 +0200
|
|
Subject: [PATCH 04/30] Add test/chmap program
|
|
|
|
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
---
|
|
test/Makefile.am | 3
|
|
test/chmap.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
2 files changed, 256 insertions(+), 1 deletion(-)
|
|
create mode 100644 test/chmap.c
|
|
|
|
--- a/test/Makefile.am
|
|
+++ b/test/Makefile.am
|
|
@@ -2,7 +2,7 @@ SUBDIRS=. lsb
|
|
|
|
check_PROGRAMS=control pcm pcm_min latency seq \
|
|
playmidi1 timer rawmidi midiloop \
|
|
- oldapi queue_timer namehint client_event_filter
|
|
+ oldapi queue_timer namehint client_event_filter chmap
|
|
|
|
control_LDADD=../src/libasound.la
|
|
pcm_LDADD=../src/libasound.la
|
|
@@ -18,6 +18,7 @@ queue_timer_LDADD=../src/libasound.la
|
|
namehint_LDADD=../src/libasound.la
|
|
client_event_filter_LDADD=../src/libasound.la
|
|
code_CFLAGS=-Wall -pipe -g -O2
|
|
+chmap_LDADD=../src/libasound.la
|
|
|
|
INCLUDES=-I$(top_srcdir)/include
|
|
AM_CFLAGS=-Wall -pipe -g
|
|
--- /dev/null
|
|
+++ b/test/chmap.c
|
|
@@ -0,0 +1,254 @@
|
|
+/*
|
|
+ * channel mapping API test program
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <ctype.h>
|
|
+#include <getopt.h>
|
|
+#include "../include/asoundlib.h"
|
|
+
|
|
+static void usage(void)
|
|
+{
|
|
+ printf("usage: chmap [options] query\n"
|
|
+ " chmap [options] get\n"
|
|
+ " chmap [options] set CH0 CH1 CH2...\n"
|
|
+ "options:\n"
|
|
+ " -D device Specify PCM device to handle\n"
|
|
+ " -f format PCM format\n"
|
|
+ " -c channels Channels\n"
|
|
+ " -r rate Sample rate\n");
|
|
+}
|
|
+
|
|
+static const char * const chname[] = {
|
|
+ "Unknown",
|
|
+ "FL", "FC", "FR",
|
|
+ "FLC", "FRC", "RL", "RC", "RR",
|
|
+ "RLC", "RRC", "SL", "SR", "LFE",
|
|
+ "FLW", "FRW", "FLH",
|
|
+ "FCH", "FCH", "FRH",
|
|
+ "TC"
|
|
+};
|
|
+
|
|
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
|
+
|
|
+static void print_channels(int channels, int *map)
|
|
+{
|
|
+ int i;
|
|
+ printf(" ");
|
|
+ for (i = 0; i < channels; i++) {
|
|
+ unsigned int c = *map++;
|
|
+ if (c >= ARRAY_SIZE(chname))
|
|
+ printf(" Ch%d", c);
|
|
+ else
|
|
+ printf(" %s", chname[c]);
|
|
+ }
|
|
+ printf("\n");
|
|
+}
|
|
+
|
|
+static int to_channel(const char *name)
|
|
+{
|
|
+ unsigned int i;
|
|
+
|
|
+ if (isdigit(*name))
|
|
+ return atoi(name);
|
|
+ for (i = 0; i < ARRAY_SIZE(chname); i++)
|
|
+ if (!strcmp(chname[i], name))
|
|
+ return i;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const char *chmap_type(int type)
|
|
+{
|
|
+ switch (type) {
|
|
+ case SND_CHMAP_NONE:
|
|
+ return "None";
|
|
+ case SND_CHMAP_FIXED:
|
|
+ return "Fixed";
|
|
+ case SND_CHMAP_VAR:
|
|
+ return "Variable";
|
|
+ case SND_CHMAP_PAIRED:
|
|
+ return "Paired";
|
|
+ default:
|
|
+ return "Unknown";
|
|
+ }
|
|
+}
|
|
+
|
|
+static int query_chmaps(snd_pcm_t *pcm)
|
|
+{
|
|
+ int **maps = snd_pcm_query_chmaps(pcm);
|
|
+ int **p, *v;
|
|
+
|
|
+ if (!maps) {
|
|
+ printf("Cannot query maps\n");
|
|
+ return 1;
|
|
+ }
|
|
+ for (p = maps; (v = *p) != NULL; p++) {
|
|
+ printf("Type = %s, Channels = %d\n", chmap_type(v[0]), v[1]);
|
|
+ print_channels(v[1], v + 2);
|
|
+ }
|
|
+ snd_pcm_free_chmaps(maps);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int setup_pcm(snd_pcm_t *pcm, int format, int channels, int rate)
|
|
+{
|
|
+ snd_pcm_hw_params_t *params;
|
|
+
|
|
+ snd_pcm_hw_params_alloca(¶ms);
|
|
+ if (snd_pcm_hw_params_any(pcm, params) < 0) {
|
|
+ printf("Cannot init hw_params\n");
|
|
+ return -1;
|
|
+ }
|
|
+ if (format != SND_PCM_FORMAT_UNKNOWN) {
|
|
+ if (snd_pcm_hw_params_set_format(pcm, params, format) < 0) {
|
|
+ printf("Cannot set format %s\n",
|
|
+ snd_pcm_format_name(format));
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ if (channels > 0) {
|
|
+ if (snd_pcm_hw_params_set_channels(pcm, params, channels) < 0) {
|
|
+ printf("Cannot set channels %d\n", channels);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ if (rate > 0) {
|
|
+ if (snd_pcm_hw_params_set_rate_near(pcm, params, (unsigned int *)&rate, 0) < 0) {
|
|
+ printf("Cannot set rate %d\n", rate);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ if (snd_pcm_hw_params(pcm, params) < 0) {
|
|
+ printf("Cannot set hw_params\n");
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int get_chmap(snd_pcm_t *pcm, int format, int channels, int rate)
|
|
+{
|
|
+ int *map;
|
|
+
|
|
+ if (setup_pcm(pcm, format, channels, rate))
|
|
+ return 1;
|
|
+ map = snd_pcm_get_chmap(pcm);
|
|
+ if (!map) {
|
|
+ printf("Cannot get chmap\n");
|
|
+ return 1;
|
|
+ }
|
|
+ printf("Channels = %d\n", *map);
|
|
+ print_channels(*map, map + 1);
|
|
+ free(map);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int set_chmap(snd_pcm_t *pcm, int format, int channels, int rate,
|
|
+ int nargs, char **arg)
|
|
+{
|
|
+ int i;
|
|
+ int *map;
|
|
+
|
|
+ if (channels && channels != nargs) {
|
|
+ printf("Inconsistent channels %d vs %d\n", channels, nargs);
|
|
+ return 1;
|
|
+ }
|
|
+ if (!channels) {
|
|
+ if (!nargs) {
|
|
+ printf("No channels are given\n");
|
|
+ return 1;
|
|
+ }
|
|
+ channels = nargs;
|
|
+ }
|
|
+ if (setup_pcm(pcm, format, channels, rate))
|
|
+ return 1;
|
|
+ map = malloc(sizeof(int) * channels + 1);
|
|
+ if (!map) {
|
|
+ printf("cannot malloc\n");
|
|
+ return 1;
|
|
+ }
|
|
+ *map = channels;
|
|
+ for (i = 0; i < channels; i++)
|
|
+ map[i + 1] = to_channel(arg[i]);
|
|
+ if (snd_pcm_set_chmap(pcm, map) < 0) {
|
|
+ printf("Cannot set chmap\n");
|
|
+ return 1;
|
|
+ }
|
|
+ free(map);
|
|
+
|
|
+ map = snd_pcm_get_chmap(pcm);
|
|
+ if (!map) {
|
|
+ printf("Cannot get chmap\n");
|
|
+ return 1;
|
|
+ }
|
|
+ printf("Get channels = %d\n", *map);
|
|
+ print_channels(*map, map + 1);
|
|
+ free(map);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int main(int argc, char **argv)
|
|
+{
|
|
+ char *device = NULL;
|
|
+ int stream = SND_PCM_STREAM_PLAYBACK;
|
|
+ int format = SND_PCM_FORMAT_UNKNOWN;
|
|
+ int channels = 0;
|
|
+ int rate = 0;
|
|
+ snd_pcm_t *pcm;
|
|
+ int c;
|
|
+
|
|
+ while ((c = getopt(argc, argv, "D:s:f:c:r:")) != -1) {
|
|
+ switch (c) {
|
|
+ case 'D':
|
|
+ device = optarg;
|
|
+ break;
|
|
+ case 's':
|
|
+ if (*optarg == 'c' || *optarg == 'C')
|
|
+ stream = SND_PCM_STREAM_CAPTURE;
|
|
+ else
|
|
+ stream = SND_PCM_STREAM_PLAYBACK;
|
|
+ break;
|
|
+ case 'f':
|
|
+ format = snd_pcm_format_value(optarg);
|
|
+ break;
|
|
+ case 'c':
|
|
+ channels = atoi(optarg);
|
|
+ break;
|
|
+ case 'r':
|
|
+ rate = atoi(optarg);
|
|
+ break;
|
|
+ default:
|
|
+ usage();
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (argc <= optind) {
|
|
+ usage();
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if (!device) {
|
|
+ printf("No device is specified\n");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if (snd_pcm_open(&pcm, device, stream, SND_PCM_NONBLOCK) < 0) {
|
|
+ printf("Cannot open PCM stream %s for %s\n", device,
|
|
+ snd_pcm_stream_name(stream));
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ switch (*argv[optind]) {
|
|
+ case 'q':
|
|
+ return query_chmaps(pcm);
|
|
+ case 'g':
|
|
+ return get_chmap(pcm, format, channels, rate);
|
|
+ case 's':
|
|
+ return set_chmap(pcm, format, channels, rate,
|
|
+ argc - optind - 1, argv + optind + 1);
|
|
+ }
|
|
+ usage();
|
|
+ return 1;
|
|
+}
|