Blame axfer/subcmd-list.c

Packit Service a9274b
// SPDX-License-Identifier: GPL-2.0
Packit Service a9274b
//
Packit Service a9274b
// subcmd-list.c - operations for list sub command.
Packit Service a9274b
//
Packit Service a9274b
// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
Packit Service a9274b
//
Packit Service a9274b
// Licensed under the terms of the GNU General Public License, version 2.
Packit Service a9274b
Packit Service a9274b
#include "subcmd.h"
Packit Service a9274b
#include "misc.h"
Packit Service a9274b
Packit Service a9274b
#include <getopt.h>
Packit Service a9274b
#include <stdbool.h>
Packit Service a9274b
Packit Service a9274b
enum list_op {
Packit Service a9274b
	LIST_OP_DEVICE = 0,
Packit Service a9274b
	LIST_OP_PCM,
Packit Service a9274b
	LIST_OP_HELP,
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
static int dump_device(snd_ctl_t *handle, const char *id, const char *name,
Packit Service a9274b
		       snd_pcm_stream_t direction, snd_pcm_info_t *info)
Packit Service a9274b
{
Packit Service a9274b
	unsigned int count;
Packit Service a9274b
	int i;
Packit Service a9274b
	int err;
Packit Service a9274b
Packit Service a9274b
	printf("card %i: %s [%s], device %i: %s [%s]\n",
Packit Service a9274b
	       snd_pcm_info_get_card(info), id, name,
Packit Service a9274b
	       snd_pcm_info_get_device(info), snd_pcm_info_get_id(info),
Packit Service a9274b
	       snd_pcm_info_get_name(info));
Packit Service a9274b
Packit Service a9274b
	count = snd_pcm_info_get_subdevices_count(info);
Packit Service a9274b
	printf("  Subdevices: %i/%u\n",
Packit Service a9274b
	       snd_pcm_info_get_subdevices_avail(info), count);
Packit Service a9274b
Packit Service a9274b
	for (i = 0; i < count; ++i) {
Packit Service a9274b
		snd_pcm_info_set_subdevice(info, i);
Packit Service a9274b
Packit Service a9274b
		err = snd_ctl_pcm_info(handle, info);
Packit Service a9274b
		if (err < 0) {
Packit Service a9274b
			printf("control digital audio playback info (%i): %s",
Packit Service a9274b
			       snd_pcm_info_get_card(info), snd_strerror(err));
Packit Service a9274b
			continue;
Packit Service a9274b
		}
Packit Service a9274b
Packit Service a9274b
		printf("  Subdevice #%i: %s\n",
Packit Service a9274b
		       i, snd_pcm_info_get_subdevice_name(info));
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int dump_devices(snd_ctl_t *handle, const char *id, const char *name,
Packit Service a9274b
			snd_pcm_stream_t direction)
Packit Service a9274b
{
Packit Service a9274b
	snd_pcm_info_t *info;
Packit Service a9274b
	int device = -1;
Packit Service a9274b
	int err;
Packit Service a9274b
Packit Service a9274b
	err = snd_pcm_info_malloc(&info;;
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return err;
Packit Service a9274b
Packit Service a9274b
	while (1) {
Packit Service a9274b
		err = snd_ctl_pcm_next_device(handle, &device);
Packit Service a9274b
		if (err < 0)
Packit Service a9274b
			break;
Packit Service a9274b
		if (device < 0)
Packit Service a9274b
			break;
Packit Service a9274b
Packit Service a9274b
		snd_pcm_info_set_device(info, device);
Packit Service a9274b
		snd_pcm_info_set_subdevice(info, 0);
Packit Service a9274b
		snd_pcm_info_set_stream(info, direction);
Packit Service a9274b
		err = snd_ctl_pcm_info(handle, info);
Packit Service a9274b
		if (err < 0)
Packit Service a9274b
			continue;
Packit Service a9274b
Packit Service a9274b
		err = dump_device(handle, id, name, direction, info);
Packit Service a9274b
		if (err < 0)
Packit Service a9274b
			break;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	free(info);
Packit Service a9274b
	return err;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int list_devices(snd_pcm_stream_t direction)
Packit Service a9274b
{
Packit Service a9274b
	int card = -1;
Packit Service a9274b
	char name[32];
Packit Service a9274b
	snd_ctl_t *handle;
Packit Service a9274b
	snd_ctl_card_info_t *info;
Packit Service a9274b
	int err;
Packit Service a9274b
Packit Service a9274b
	err = snd_ctl_card_info_malloc(&info;;
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return err;
Packit Service a9274b
Packit Service a9274b
	// Not found.
Packit Service a9274b
	if (snd_card_next(&card) < 0 || card < 0)
Packit Service a9274b
		goto end;
Packit Service a9274b
Packit Service a9274b
	printf("**** List of %s Hardware Devices ****\n",
Packit Service a9274b
	       snd_pcm_stream_name(direction));
Packit Service a9274b
Packit Service a9274b
	while (card >= 0) {
Packit Service a9274b
		sprintf(name, "hw:%d", card);
Packit Service a9274b
		err = snd_ctl_open(&handle, name, 0);
Packit Service a9274b
		if (err < 0) {
Packit Service a9274b
			printf("control open (%i): %s",
Packit Service a9274b
			       card, snd_strerror(err));
Packit Service a9274b
		} else {
Packit Service a9274b
			err = snd_ctl_card_info(handle, info);
Packit Service a9274b
			if (err < 0) {
Packit Service a9274b
				printf("control hardware info (%i): %s",
Packit Service a9274b
				       card, snd_strerror(err));
Packit Service a9274b
			} else {
Packit Service a9274b
				err = dump_devices(handle,
Packit Service a9274b
					snd_ctl_card_info_get_id(info),
Packit Service a9274b
					snd_ctl_card_info_get_name(info),
Packit Service a9274b
					direction);
Packit Service a9274b
			}
Packit Service a9274b
			snd_ctl_close(handle);
Packit Service a9274b
		}
Packit Service a9274b
Packit Service a9274b
		if (err < 0)
Packit Service a9274b
			break;
Packit Service a9274b
Packit Service a9274b
		// Go to next.
Packit Service a9274b
		if (snd_card_next(&card) < 0) {
Packit Service a9274b
			printf("snd_card_next");
Packit Service a9274b
			break;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
end:
Packit Service a9274b
	free(info);
Packit Service a9274b
	return err;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int list_pcms(snd_pcm_stream_t direction)
Packit Service a9274b
{
Packit Service a9274b
	static const char *const filters[] = {
Packit Service a9274b
		[SND_PCM_STREAM_CAPTURE]	= "Input",
Packit Service a9274b
		[SND_PCM_STREAM_PLAYBACK]	= "Output",
Packit Service a9274b
	};
Packit Service a9274b
	const char *filter;
Packit Service a9274b
	void **hints;
Packit Service a9274b
	void **n;
Packit Service a9274b
	char *io;
Packit Service a9274b
	char *name;
Packit Service a9274b
	char *desc;
Packit Service a9274b
Packit Service a9274b
	if (snd_device_name_hint(-1, "pcm", &hints) < 0)
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
Packit Service a9274b
	filter = filters[direction];
Packit Service a9274b
Packit Service a9274b
	for (n = hints; *n != NULL; ++n) {
Packit Service a9274b
		io = snd_device_name_get_hint(*n, "IOID");
Packit Service a9274b
		if (io != NULL && strcmp(io, filter) != 0) {
Packit Service a9274b
			free(io);
Packit Service a9274b
			continue;
Packit Service a9274b
		}
Packit Service a9274b
Packit Service a9274b
		name = snd_device_name_get_hint(*n, "NAME");
Packit Service a9274b
		desc = snd_device_name_get_hint(*n, "DESC");
Packit Service a9274b
Packit Service a9274b
		printf("%s\n", name);
Packit Service a9274b
		if (desc == NULL) {
Packit Service a9274b
			free(name);
Packit Service a9274b
			free(desc);
Packit Service a9274b
			continue;
Packit Service a9274b
		}
Packit Service a9274b
Packit Service a9274b
Packit Service a9274b
		printf("    ");
Packit Service a9274b
		while (*desc) {
Packit Service a9274b
			if (*desc == '\n')
Packit Service a9274b
				printf("\n    ");
Packit Service a9274b
			else
Packit Service a9274b
				putchar(*desc);
Packit Service a9274b
			desc++;
Packit Service a9274b
		}
Packit Service a9274b
		putchar('\n');
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	snd_device_name_free_hint(hints);
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void print_help(void)
Packit Service a9274b
{
Packit Service a9274b
	printf(
Packit Service a9274b
"Usage:\n"
Packit Service a9274b
"  axfer list DIRECTION TARGET\n"
Packit Service a9274b
"\n"
Packit Service a9274b
"  where:\n"
Packit Service a9274b
"    DIRECTION = capture | playback\n"
Packit Service a9274b
"    TARGET = device | pcm\n"
Packit Service a9274b
	);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
// Backward compatibility to aplay(1).
Packit Service a9274b
static bool decide_operation(int argc, char *const *argv, enum list_op *op)
Packit Service a9274b
{
Packit Service a9274b
	static const char *s_opts = "hlL";
Packit Service a9274b
	static const struct option l_opts[] = {
Packit Service a9274b
		{"list-devices",	0, NULL, 'l'},
Packit Service a9274b
		{"list-pcms",		0, NULL, 'L'},
Packit Service a9274b
		{NULL,			0, NULL, 0}
Packit Service a9274b
	};
Packit Service a9274b
Packit Service a9274b
	optind = 0;
Packit Service a9274b
	opterr = 0;
Packit Service a9274b
	while (1) {
Packit Service a9274b
		int c = getopt_long(argc, argv, s_opts, l_opts, NULL);
Packit Service a9274b
		if (c < 0)
Packit Service a9274b
			break;
Packit Service a9274b
		if (c == 'l') {
Packit Service a9274b
			*op = LIST_OP_DEVICE;
Packit Service a9274b
			return true;
Packit Service a9274b
		}
Packit Service a9274b
		if (c == 'L') {
Packit Service a9274b
			*op = LIST_OP_PCM;
Packit Service a9274b
			return true;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return false;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int detect_operation(int argc, char *const *argv, enum list_op *op)
Packit Service a9274b
{
Packit Service a9274b
	static const char *const ops[] = {
Packit Service a9274b
		[LIST_OP_DEVICE] = "device",
Packit Service a9274b
		[LIST_OP_PCM] = "pcm",
Packit Service a9274b
	};
Packit Service a9274b
	int i;
Packit Service a9274b
Packit Service a9274b
	if (argc < 2)
Packit Service a9274b
		return false;
Packit Service a9274b
Packit Service a9274b
	for (i = 0; i < ARRAY_SIZE(ops); ++i) {
Packit Service a9274b
		if (!strcmp(argv[1], ops[i])) {
Packit Service a9274b
			*op = i;
Packit Service a9274b
			return true;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return false;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
int subcmd_list(int argc, char *const *argv, snd_pcm_stream_t direction)
Packit Service a9274b
{
Packit Service a9274b
	enum list_op op = LIST_OP_HELP;
Packit Service a9274b
	int err = 0;
Packit Service a9274b
Packit Service a9274b
	// Renewed command system.
Packit Service a9274b
	if (!detect_operation(argc, argv, &op) &&
Packit Service a9274b
	    !decide_operation(argc, argv, &op))
Packit Service a9274b
			err = -EINVAL;
Packit Service a9274b
Packit Service a9274b
	if (op == LIST_OP_DEVICE)
Packit Service a9274b
		err = list_devices(direction);
Packit Service a9274b
	else if (op == LIST_OP_PCM)
Packit Service a9274b
		err = list_pcms(direction);
Packit Service a9274b
	else
Packit Service a9274b
		print_help();
Packit Service a9274b
Packit Service a9274b
	return err;
Packit Service a9274b
}