alsa-lib/test/chmap.c
Takashi Iwai 0f36270dd3 Follow channel position definitions to mixer channel in mixer.h
mixer.h already contains some channel position definitions.
To be more consistent over all systems, better to follow the same
order for the new channel map, too.  But since UNKNOWN channel must be
zero but the definition in mixer.h contains -1 as UNKNOWN, simply
shift the value with 1.

If the conversion is required between SND_CHMAP and SND_MIXER_SCHN,
just increment/decrement 1.  Eventually I'll provide helper functions
for that...

Signed-off-by: Takashi Iwai <tiwai@suse.de>
2012-09-13 08:24:47 +02:00

251 lines
5 KiB
C

/*
* 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", "FR", "RL", "RR", "FC", "LFE", "SL", "SR", "RC",
"FLC", "FRC", "RLC", "RRC", "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 SND_CHMAP_UNKNOWN;
}
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(&params);
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;
}