Blame axfer/subcmd-list.c

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