--help help
--version print current version
---list-devices list all soundcards and digital audio devices
--C, --card=# select card # or card id (0-%i), defaults to 0
+-l,--list-devices list all soundcards and digital audio devices
+-L,--list-pcms list all PCMs defined
+
+-P, --pcm=NAME select PCM by name
+ or
+-C, --card=# select card # (0-%i) or id, defaults to 0
-D, --device=# select device #, defaults to 0
--S, --subdevice=# select subdevice #, defaults to first available
--P, --direct don't use plugins for this PCM
--H, --pcm-channels=# channels for last specified PCM
--h, --bind-channel=C,S bind stream channel C to PCM channel S
+-S, --subdevice=# select subdevice #, defaults to first free
+-i, --direct don't use plugins for this PCM
+
-q, --quiet quiet mode
-t, --file-type TYPE file type (voc, wav or raw)
-c, --channels=# channels
-d, --duration=# interrupt after # seconds
-e, --frame-mode use frame mode instead of default fragment mode
-M, --mmap mmap stream
--Q, --multi-direct don't use plugins on top of multi
-N, --nonblock nonblocking mode
-F, --fragment-length=# fragment length is # milliseconds
-B, --buffer-length=# buffer length is # milliseconds
}
}
+static void pcm_list(void)
+{
+ snd_config_t *conf;
+ int err = snd_config_update();
+ if (err < 0)
+ error("snd_pcm_update: %s\n", snd_strerror(err));
+ err = snd_config_search(snd_config, "pcm", &conf);
+ if (err < 0)
+ return;
+ fprintf(stderr, "PCM list:\n");
+ snd_config_save(conf, stderr);
+}
+
static void version(void)
{
fprintf(stderr, "%s: version " SND_UTIL_VERSION_STR " by Jaroslav Kysela <perex@suse.cz>\n", command);
int main(int argc, char *argv[])
{
int option_index;
- char *short_options = "lC:D:S:H:h:qt:c:f:r:d:eMPQA:B:F:NvI";
+ char *short_options = "lLP:C:D:S:iqt:c:f:r:d:eMNF:A:B:vI";
static struct option long_options[] = {
{"help", 0, 0, OPT_HELP},
{"version", 0, 0, OPT_VERSION},
{"list-devices", 0, 0, 'l'},
+ {"list-pcms", 0, 0, 'L'},
+ {"pcm", 1, 0, 'P'},
{"card", 1, 0, 'C'},
{"device", 1, 0, 'D'},
{"subdevice", 1, 0, 'S'},
- {"pcm-channels", 1, 0, 'H'},
- {"bind-channel", 1, 0, 'h'},
+ {"direct", 0, 0, 'i'},
{"quiet", 0, 0, 'q'},
{"file-type", 1, 0, 't'},
{"channels", 1, 0, 'c'},
{"duration", 1, 0 ,'d'},
{"frame-mode", 0, 0, 'e'},
{"mmap", 0, 0, 'M'},
- {"direct", 0, 0, 'P'},
- {"multi-direct", 0, 0, 'Q'},
{"nonblock", 0, 0, 'N'},
{"fragment-length", 1, 0, 'F'},
- {"buffer-length", 1, 0, 'B'},
{"min-avail", 1, 0, 'A'},
+ {"buffer-length", 1, 0, 'B'},
{"verbose", 0, 0, 'v'},
{"separate-channels", 0, 0, 'I'},
{0, 0, 0, 0}
};
- int binds_pcm[32];
- int binds_client_channel[32];
- int binds_slave_channel[32];
- int pcms_card[32];
- int pcms_dev[32];
- int pcms_subdev[32];
- size_t pcms_channels[32];
- int pcms_direct[32];
int direct = 0;
- int multi_direct = 0;
-
- int pcm_card = 0, pcm_dev = 0, pcm_subdev = -1, pcm_channels = -1;
- int tmp, err, c, client_channel, slave_channel;
- int pcm;
- int pcms_count = 0, binds_count = 0;
- int multi;
- char *ptr, *beg;
-
- int get_pcm() {
- int pcm;
- if (pcm_channels < 0)
- pcm_channels = rformat.channels;
- for (pcm = 0; pcm < pcms_count; ++pcm) {
- if (pcms_card[pcm] == pcm_card &&
- pcms_dev[pcm] == pcm_dev &&
- pcms_subdev[pcm] == pcm_subdev)
- break;
- }
- if (pcm == pcms_count) {
- pcms_card[pcm] = pcm_card;
- pcms_dev[pcm] = pcm_dev;
- pcms_subdev[pcm] = pcm_subdev;
- pcms_channels[pcm] = pcm_channels;
- pcms_direct[pcm] = direct;
- direct = 0;
- pcms_count++;
- } else if (pcm_channels != pcms_channels[pcm]) {
- error("different channels count specified for the same pcm\n");
- exit(1);
- }
- return pcm;
- }
+ char *pcm_name = NULL;
+ int pcm_card = -1, pcm_dev = -1, pcm_subdev = -1;
+ int tmp, err, c;
command = argv[0];
file_type = FORMAT_DEFAULT;
case 'l':
device_list();
return 0;
+ case 'L':
+ pcm_list();
+ return 0;
+ case 'P':
+ if (pcm_card >= 0 || pcm_dev >=0 || pcm_dev >=0 ||
+ direct) {
+ error("-P cannot be used together with -C, -D, -S or -i\n");
+ return -1;
+ }
+ pcm_name = optarg;
+ break;
case 'C':
+ if (pcm_name) {
+ error("-P cannot be used together with -C, -D, -S or -i\n");
+ return -1;
+ }
pcm_card = snd_card_name(optarg);
if (pcm_card < 0) {
error("soundcard '%s' not found\n", optarg);
}
break;
case 'D':
+ if (pcm_name) {
+ error("-P cannot be used together with -C, -D, -S or -i\n");
+ return -1;
+ }
pcm_dev = atoi(optarg);
if (pcm_dev < 0 || pcm_dev > 32) {
error("device %i is invalid\n", pcm_dev);
}
break;
case 'S':
+ if (pcm_name) {
+ error("-P cannot be used together with -C, -D, -S or -i\n");
+ return -1;
+ }
pcm_subdev = atoi(optarg);
if (pcm_subdev < 0 || pcm_subdev > 32) {
error("subdevice %i is invalid\n", pcm_subdev);
return 1;
}
break;
- case 'H':
- pcm_channels = atoi(optarg);
- if (pcm_channels < 1 || pcm_channels > 32) {
- error("value %i for channels is invalid\n", pcm_channels);
- return 1;
- }
- break;
- case 'h':
- client_channel = strtol(optarg, &ptr, 10);
- if (*ptr != ',' || ptr == optarg) {
- error("invalid channel binding syntax\n");
- return 1;
- }
- beg = ptr + 1;
- slave_channel = strtol(beg, &ptr, 10);
- if (*ptr || ptr == optarg) {
- error("invalid channel binding syntax\n");
- return 1;
- }
- if (client_channel >= rformat.channels) {
- error("attempt to bind unavailable channel %d\n", client_channel);
- return 1;
- }
- if (slave_channel >= pcm_channels) {
- error("attempt to bind to an unavailable PCM channel %d\n", slave_channel);
- return 1;
+ case 'i':
+ if (pcm_name) {
+ error("-P cannot be used together with -C, -D, -S or -i\n");
+ return -1;
}
- pcm = get_pcm();
- binds_pcm[binds_count] = pcm;
- binds_client_channel[binds_count] = client_channel;
- binds_slave_channel[binds_count] = slave_channel;
- ++binds_count;
+ direct = 1;
break;
case 'q':
quiet_mode = 1;
case 'M':
mmap_flag = 1;
break;
- case 'P':
- direct = 1;
- break;
- case 'Q':
- multi_direct = 1;
- break;
case 'N':
nonblock = 1;
open_mode |= SND_PCM_NONBLOCK;
}
}
- if (binds_count == 0) {
- pcm = get_pcm();
- for (c = 0; c < rformat.channels; ++c) {
- if (c > pcm_channels) {
- error("attempt to bind to an unavailable PCM channel %d\n", c);
- return 1;
- }
- binds_pcm[binds_count] = pcm;
- binds_client_channel[binds_count] = c;
- binds_slave_channel[binds_count] = c;
- binds_count++;
- }
- }
-
- if (!quiet_mode)
- version();
-
- assert(pcms_count > 0);
-
- multi = 0;
- if (pcms_count != 1 || rformat.channels != binds_count ||
- pcm_channels != binds_count)
- multi = 1;
+ if (pcm_name)
+ err = snd_pcm_open(&handle, pcm_name, stream, open_mode);
else {
- char mask[binds_count];
- memset(mask, 0, sizeof(mask));
- for (c = 0; c < binds_count; ++c) {
- if (binds_client_channel[c] != binds_slave_channel[c]) {
- multi = 1;
- break;
- }
- if (mask[c]) {
- multi = 1;
- break;
- }
- mask[c] = 1;
- }
+ if (pcm_card < 0)
+ pcm_card = 0;
+ if (pcm_dev < 0)
+ pcm_dev = 0;
+ if (direct)
+ err = snd_pcm_hw_open_subdevice(&handle, pcm_card, pcm_dev, pcm_subdev, stream, open_mode);
+ else
+ err = snd_pcm_plug_open_subdevice(&handle, pcm_card, pcm_dev, pcm_subdev, stream, open_mode);
}
- if (!quiet_mode) {
- for (pcm = 0; pcm < pcms_count; ++pcm) {
- char *cardname;
- if ((err = snd_card_get_longname(pcms_card[pcm], &cardname)) < 0) {
- error("unable to obtain longname: %s\n", snd_strerror(err));
- return 1;
- }
- fprintf(stderr, "Using soundcard '%s'\n", cardname);
- free(cardname);
- }
+ if (err < 0) {
+ error("audio open error: %s\n", snd_strerror(err));
+ return 1;
}
- {
- snd_pcm_t *handles[pcms_count];
- for (pcm = 0; pcm < pcms_count; ++pcm) {
- if (pcms_direct[pcm])
- err = snd_pcm_hw_open_subdevice(&handles[pcm], pcms_card[pcm], pcms_dev[pcm], pcms_subdev[pcm], stream, open_mode);
- else
- err = snd_pcm_plug_open_subdevice(&handles[pcm], pcms_card[pcm], pcms_dev[pcm], pcms_subdev[pcm], stream, open_mode);
- if (err < 0) {
- error("audio open error: %s\n", snd_strerror(err));
- return 1;
- }
- }
- if (multi) {
- err = snd_pcm_multi_create(&handle, pcms_count, handles, pcms_channels, binds_count, binds_client_channel, binds_pcm, binds_slave_channel, 1);
- if (err < 0) {
- error("audio open error: %s\n", snd_strerror(err));
- return 1;
- }
- if (!multi_direct) {
- snd_pcm_t *h = handle;
- err = snd_pcm_plug_create(&handle, h, 1);
- if (err < 0) {
- error("audio open error: %s\n", snd_strerror(err));
- return 1;
- }
- }
- } else {
- handle = handles[0];
- }
- }
if (nonblock) {
err = snd_pcm_nonblock(handle, 1);
if (err < 0) {