mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-13 00:55:42 +01:00
e88216ba64
Original aplay implementation has a feature to output two types of list; devices and PCMs. The list of devices is a result to query sound card and pcm component structured maintained in kernel land. The list of PCMs is a result to parse runtime configuration files in alsa-lib. Entries in the former list is corresponding to ALSA PCM character device ('/dev/snd/pcm%uC%uD[p|c]'), while entries in the latter list includes some 'virtual' instances in application runtime. This commit adds an implementation for the above functionality. This is executed by taking 'list' sub-command. A 'device' option has the same effect as '--list-devices' and '-L' of aplay. A 'pcm' option has the same effect as '--list-pcms' and '-l' of aplay. In both cases, an additional option is required for stream direction. Below is examples of new command system for this sub-command. $ axfer list device -C (= arecord --list-devices) $ axfer list pcm -P (= aplay -l) Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
193 lines
4.2 KiB
C
193 lines
4.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
// main.c - an entry point for this program.
|
|
//
|
|
// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
|
|
//
|
|
// Originally written as 'aplay', by Michael Beck and Jaroslav Kysela.
|
|
//
|
|
// Licensed under the terms of the GNU General Public License, version 2.
|
|
|
|
#include "subcmd.h"
|
|
#include "misc.h"
|
|
|
|
#include "version.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
enum subcmds {
|
|
SUBCMD_TRANSFER = 0,
|
|
SUBCMD_LIST,
|
|
SUBCMD_HELP,
|
|
SUBCMD_VERSION,
|
|
};
|
|
|
|
static void print_version(const char *const cmdname)
|
|
{
|
|
printf("%s: version %s\n", cmdname, SND_UTIL_VERSION_STR);
|
|
}
|
|
|
|
static void print_help(void)
|
|
{
|
|
printf("help\n");
|
|
}
|
|
|
|
static void decide_subcmd(int argc, char *const *argv, enum subcmds *subcmd)
|
|
{
|
|
static const char *const subcmds[] = {
|
|
[SUBCMD_TRANSFER] = "transfer",
|
|
[SUBCMD_LIST] = "list",
|
|
[SUBCMD_HELP] = "help",
|
|
[SUBCMD_VERSION] = "version",
|
|
};
|
|
static const struct {
|
|
const char *const name;
|
|
enum subcmds subcmd;
|
|
} long_opts[] = {
|
|
{"--list-devices", SUBCMD_LIST},
|
|
{"--list-pcms", SUBCMD_LIST},
|
|
{"--help", SUBCMD_HELP},
|
|
{"--version", SUBCMD_VERSION},
|
|
};
|
|
static const struct {
|
|
unsigned char c;
|
|
enum subcmds subcmd;
|
|
} short_opts[] = {
|
|
{'l', SUBCMD_LIST},
|
|
{'L', SUBCMD_LIST},
|
|
{'h', SUBCMD_HELP},
|
|
};
|
|
char *pos;
|
|
int i, j;
|
|
|
|
if (argc == 1) {
|
|
*subcmd = SUBCMD_HELP;
|
|
return;
|
|
}
|
|
|
|
// sub-command system.
|
|
for (i = 0; i < ARRAY_SIZE(subcmds); ++i) {
|
|
if (!strcmp(argv[1], subcmds[i])) {
|
|
*subcmd = i;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Original command system. For long options.
|
|
for (i = 0; i < ARRAY_SIZE(long_opts); ++i) {
|
|
for (j = 0; j < argc; ++j) {
|
|
if (!strcmp(long_opts[i].name, argv[j])) {
|
|
*subcmd = long_opts[i].subcmd;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Original command system. For short options.
|
|
for (i = 1; i < argc; ++i) {
|
|
// Pick up short options only.
|
|
if (argv[i][0] != '-' || argv[i][0] == '\0' ||
|
|
argv[i][1] == '-' || argv[i][1] == '\0')
|
|
continue;
|
|
for (pos = argv[i]; *pos != '\0'; ++pos) {
|
|
for (j = 0; j < ARRAY_SIZE(short_opts); ++j) {
|
|
if (*pos == short_opts[j].c) {
|
|
*subcmd = short_opts[j].subcmd;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*subcmd = SUBCMD_TRANSFER;
|
|
}
|
|
|
|
static bool decide_direction(int argc, char *const *argv,
|
|
snd_pcm_stream_t *direction)
|
|
{
|
|
static const struct {
|
|
const char *const name;
|
|
snd_pcm_stream_t direction;
|
|
} long_opts[] = {
|
|
{"--capture", SND_PCM_STREAM_CAPTURE},
|
|
{"--playback", SND_PCM_STREAM_PLAYBACK},
|
|
};
|
|
static const struct {
|
|
unsigned char c;
|
|
snd_pcm_stream_t direction;
|
|
} short_opts[] = {
|
|
{'C', SND_PCM_STREAM_CAPTURE},
|
|
{'P', SND_PCM_STREAM_PLAYBACK},
|
|
};
|
|
static const char *const aliases[] = {
|
|
[SND_PCM_STREAM_CAPTURE] = "arecord",
|
|
[SND_PCM_STREAM_PLAYBACK] = "aplay",
|
|
};
|
|
int i, j;
|
|
char *pos;
|
|
|
|
// Original command system. For long options.
|
|
for (i = 0; i < ARRAY_SIZE(long_opts); ++i) {
|
|
for (j = 0; j < argc; ++j) {
|
|
if (!strcmp(long_opts[i].name, argv[j])) {
|
|
*direction = long_opts[i].direction;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Original command system. For short options.
|
|
for (i = 1; i < argc; ++i) {
|
|
// Pick up short options only.
|
|
if (argv[i][0] != '-' || argv[i][0] == '\0' ||
|
|
argv[i][1] == '-' || argv[i][1] == '\0')
|
|
continue;
|
|
for (pos = argv[i]; *pos != '\0'; ++pos) {
|
|
for (j = 0; j < ARRAY_SIZE(short_opts); ++j) {
|
|
if (*pos == short_opts[j].c) {
|
|
*direction = short_opts[j].direction;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If not decided yet, judge according to command name.
|
|
for (i = 0; i < ARRAY_SIZE(aliases); ++i) {
|
|
for (pos = argv[0] + strlen(argv[0]); pos != argv[0]; --pos) {
|
|
if (strstr(pos, aliases[i]) != NULL) {
|
|
*direction = i;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int main(int argc, char *const *argv)
|
|
{
|
|
snd_pcm_stream_t direction;
|
|
enum subcmds subcmd;
|
|
int err = 0;
|
|
|
|
if (!decide_direction(argc, argv, &direction))
|
|
subcmd = SUBCMD_HELP;
|
|
else
|
|
decide_subcmd(argc, argv, &subcmd);
|
|
|
|
if (subcmd == SUBCMD_TRANSFER)
|
|
printf("execute 'transfer' subcmd.\n");
|
|
else if (subcmd == SUBCMD_LIST)
|
|
err = subcmd_list(argc, argv, direction);
|
|
else if (subcmd == SUBCMD_VERSION)
|
|
print_version(argv[0]);
|
|
else
|
|
print_help();
|
|
if (err < 0)
|
|
return EXIT_FAILURE;
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|