Module Name: src
Committed By: isaki
Date: Wed May 8 14:36:12 UTC 2019
Modified Files:
src/usr.bin/audiocfg: audiocfg.1 audiodev.c audiodev.h main.c
Log Message:
Update respond to isaki-audio2 branch.
- Extend list command to display supported hardware formats.
- Add set command to set hardware format.
- Use correct /dev/audioctl instead of /dev/audio.
To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/usr.bin/audiocfg/audiocfg.1
cvs rdiff -u -r1.6 -r1.7 src/usr.bin/audiocfg/audiodev.c
cvs rdiff -u -r1.4 -r1.5 src/usr.bin/audiocfg/audiodev.h
cvs rdiff -u -r1.7 -r1.8 src/usr.bin/audiocfg/main.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/usr.bin/audiocfg/audiocfg.1
diff -u src/usr.bin/audiocfg/audiocfg.1:1.3 src/usr.bin/audiocfg/audiocfg.1:1.4
--- src/usr.bin/audiocfg/audiocfg.1:1.3 Wed Sep 1 09:17:31 2010
+++ src/usr.bin/audiocfg/audiocfg.1 Wed May 8 14:36:12 2019
@@ -1,4 +1,4 @@
-.\" $NetBSD: audiocfg.1,v 1.3 2010/09/01 09:17:31 wiz Exp $
+.\" $NetBSD: audiocfg.1,v 1.4 2019/05/08 14:36:12 isaki Exp $
.\"
.\" Copyright (c) 2010 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -40,6 +40,14 @@
.Cm default
.Ar index
.Nm
+.Cm set
+.Ar index
+.Ar direction
+.Ar encoding
+.Ar precision
+.Ar channels
+.Ar sample_rate
+.Nm
.Cm test
.Ar index
.Sh DESCRIPTION
@@ -51,6 +59,25 @@ Run with
.Dq Cm list ,
it lists the available audio devices and shows the currently selected
default audio device.
+.Pp
+Run with
+.Dq Cm set ,
+if sets the hardware format.
+The
+.Ar direction
+is represented by either of 'p'(playback) or 'r'(record), or both of them,
+indicates direction you want to set to.
+The remaining parameters
+.Ar encoding ,
+.Ar precision ,
+.Ar channels
+and
+.Ar sample_rate
+indicate the hardware format you want to set to.
+These parameters must be selected from the candidates displayed by
+.Nm
+.Cm list .
+.Pp
Called with
.Dq Cm test ,
it plays a tone of 2 seconds for each channel of the device with the index
Index: src/usr.bin/audiocfg/audiodev.c
diff -u src/usr.bin/audiocfg/audiodev.c:1.6 src/usr.bin/audiocfg/audiodev.c:1.7
--- src/usr.bin/audiocfg/audiodev.c:1.6 Sat Mar 5 22:10:39 2016
+++ src/usr.bin/audiocfg/audiodev.c Wed May 8 14:36:12 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: audiodev.c,v 1.6 2016/03/05 22:10:39 mrg Exp $ */
+/* $NetBSD: audiodev.c,v 1.7 2019/05/08 14:36:12 isaki Exp $ */
/*
* Copyright (c) 2010 Jared D. McNeill <[email protected]>
@@ -31,6 +31,7 @@
#include <sys/stat.h>
#include <sys/drvctlio.h>
+#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <stdio.h>
@@ -47,51 +48,23 @@ static TAILQ_HEAD(audiodevhead, audiodev
#define AUDIODEV_SAMPLE_RATE 44100
-static unsigned int
-audiodev_probe_pchans(struct audiodev *adev)
-{
- audio_info_t info;
- unsigned int nchans = 0, n;
- int error;
-
- AUDIO_INITINFO(&info);
- info.play.sample_rate = AUDIODEV_SAMPLE_RATE;
- info.play.precision = 16;
- info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
- info.play.channels = 1;
- info.mode = AUMODE_PLAY;
- error = ioctl(adev->fd, AUDIO_SETINFO, &info);
- if (error == -1)
- return 0;
- nchans = 1;
-
- for (n = 2; n <= 16; n += 2) {
- info.play.channels = n;
- error = ioctl(adev->fd, AUDIO_SETINFO, &info);
- if (error == -1)
- break;
- nchans = info.play.channels;
- }
-
- return nchans;
-}
-
static int
audiodev_getinfo(struct audiodev *adev)
{
struct stat st;
+ struct audiofmt *f;
+ audio_format_query_t query;
+ int i;
- if (stat(adev->path, &st) == -1)
+ if (stat(adev->ctlpath, &st) == -1)
return -1;
adev->dev = st.st_rdev;
- if (stat(_PATH_AUDIO, &st) != -1 && st.st_rdev == adev->dev)
+ if (stat(_PATH_AUDIOCTL, &st) != -1 && st.st_rdev == adev->dev)
adev->defaultdev = true;
- adev->fd = open(adev->path, O_RDWR);
+ adev->fd = open(adev->ctlpath, O_RDONLY);
if (adev->fd == -1) {
- adev->fd = open(adev->path, O_WRONLY);
- if (adev->fd == -1)
return -1;
}
if (ioctl(adev->fd, AUDIO_GETDEV, &adev->audio_device) == -1) {
@@ -99,7 +72,29 @@ audiodev_getinfo(struct audiodev *adev)
return -1;
}
- adev->pchan = audiodev_probe_pchans(adev);
+ for (i = 0; ;i++) {
+ memset(&query, 0, sizeof(query));
+ query.index = i;
+ if (ioctl(adev->fd, AUDIO_QUERYFORMAT, &query) == -1) {
+ if (errno == ENODEV) {
+ /* QUERYFORMAT not supported. */
+ break;
+ }
+ if (errno == EINVAL)
+ break;
+ close(adev->fd);
+ return -1;
+ }
+
+ f = calloc(1, sizeof(*f));
+ f->fmt = query.fmt;
+ TAILQ_INSERT_TAIL(&adev->formats, f, next);
+ }
+
+ if (ioctl(adev->fd, AUDIO_GETFORMAT, &adev->info) == -1) {
+ close(adev->fd);
+ return -1;
+ }
return 0;
}
@@ -115,8 +110,10 @@ audiodev_add(const char *pdev, const cha
strlcpy(adev->pxname, pdev, sizeof(adev->pxname));
strlcpy(adev->xname, dev, sizeof(adev->xname));
- snprintf(adev->path, sizeof(adev->path) - 1, "/dev/%s", dev);
+ snprintf(adev->path, sizeof(adev->path), "/dev/%s", dev);
+ snprintf(adev->ctlpath, sizeof(adev->ctlpath), "/dev/audioctl%d", unit);
adev->unit = unit;
+ TAILQ_INIT(&adev->formats);
if (audiodev_getinfo(adev) == -1) {
free(adev);
@@ -124,8 +121,16 @@ audiodev_add(const char *pdev, const cha
}
#ifdef DEBUG
- printf("[%c] %s: %s\n", adev->defaultdev ? '*' : ' ',
- adev->path, adev->audio_device.name);
+ printf("DEBUG: [%c] %s(%s): %s\n", adev->defaultdev ? '*' : ' ',
+ adev->path, adev->ctlpath, adev->audio_device.name);
+ struct audiofmt *f;
+ TAILQ_FOREACH(f, &adev->formats, next) {
+ printf("DEBUG: enc%d, %d/%d, %dch\n",
+ f->fmt.encoding,
+ f->fmt.validbits,
+ f->fmt.precision,
+ f->fmt.channels);
+ }
#endif
TAILQ_INSERT_TAIL(&audiodevlist, adev, next);
@@ -207,13 +212,13 @@ audiodev_set_default(struct audiodev *ad
char audioctlpath[PATH_MAX+1];
char mixerpath[PATH_MAX+1];
- snprintf(audiopath, sizeof(audiopath) - 1,
+ snprintf(audiopath, sizeof(audiopath),
_PATH_AUDIO "%u", adev->unit);
- snprintf(soundpath, sizeof(soundpath) - 1,
+ snprintf(soundpath, sizeof(soundpath),
_PATH_SOUND "%u", adev->unit);
- snprintf(audioctlpath, sizeof(audioctlpath) - 1,
+ snprintf(audioctlpath, sizeof(audioctlpath),
_PATH_AUDIOCTL "%u", adev->unit);
- snprintf(mixerpath, sizeof(mixerpath) - 1,
+ snprintf(mixerpath, sizeof(mixerpath),
_PATH_MIXER "%u", adev->unit);
unlink(_PATH_AUDIO);
@@ -242,33 +247,92 @@ audiodev_set_default(struct audiodev *ad
}
int
+audiodev_set_param(struct audiodev *adev, int mode,
+ const char *encname, unsigned int prec, unsigned int ch, unsigned int freq)
+{
+ struct audio_info ai;
+ int setmode;
+ u_int enc;
+
+ setmode = 0;
+ ai = adev->info;
+
+ for (enc = 0; enc < encoding_max; enc++) {
+ if (strcmp(encname, encoding_names[enc]) == 0)
+ break;
+ }
+ if (enc >= encoding_max) {
+ fprintf(stderr, "unknown encoding name: %s\n", encname);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((ai.mode & mode & AUMODE_PLAY)) {
+ setmode |= AUMODE_PLAY;
+ ai.play.encoding = enc;
+ ai.play.precision = prec;
+ ai.play.channels = ch;
+ ai.play.sample_rate = freq;
+ }
+ if ((ai.mode & mode & AUMODE_RECORD)) {
+ setmode |= AUMODE_RECORD;
+ ai.record.encoding = enc;
+ ai.record.precision = prec;
+ ai.record.channels = ch;
+ ai.record.sample_rate = freq;
+ }
+
+ if (setmode == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ai.mode = setmode;
+ printf("setting %s to %s:%u, %uch, %uHz\n",
+ adev->xname, encname, prec, ch, freq);
+ if (ioctl(adev->fd, AUDIO_SETFORMAT, &ai) == -1) {
+ perror("ioctl AUDIO_SETFORMAT");
+ return -1;
+ }
+ return 0;
+}
+
+int
audiodev_test(struct audiodev *adev, unsigned int chanmask)
{
audio_info_t info;
int16_t *buf;
size_t buflen;
off_t off;
- int rv = 0;
+ int fd;
+ int rv = -1;
+
+ fd = open(adev->path, O_WRONLY);
+ if (fd == -1) {
+ perror("open");
+ return -1;
+ }
AUDIO_INITINFO(&info);
info.play.sample_rate = AUDIODEV_SAMPLE_RATE;
- info.play.channels = adev->pchan;
+ info.play.channels = adev->info.play.channels;
info.play.precision = 16;
info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
info.mode = AUMODE_PLAY;
- if (ioctl(adev->fd, AUDIO_SETINFO, &info) == -1) {
+ if (ioctl(fd, AUDIO_SETINFO, &info) == -1) {
perror("ioctl AUDIO_SETINFO");
- return -1;
+ goto abort;
}
- if (ioctl(adev->fd, AUDIO_GETINFO, &info) == -1) {
+ if (ioctl(fd, AUDIO_GETINFO, &info) == -1) {
perror("ioctl AUDIO_GETINFO");
- return -1;
+ goto abort;
}
dtmf_new(&buf, &buflen, info.play.sample_rate, 2,
- adev->pchan, chanmask, 350.0, 440.0);
- if (buf == NULL)
- return -1;
+ adev->info.play.channels, chanmask, 350.0, 440.0);
+ if (buf == NULL) {
+ goto abort;
+ }
off = 0;
while (buflen > 0) {
@@ -278,10 +342,9 @@ audiodev_test(struct audiodev *adev, uns
wlen = info.play.buffer_size;
if (wlen > buflen)
wlen = buflen;
- ret = write(adev->fd, (char *)buf + off, wlen);
+ ret = write(fd, (char *)buf + off, wlen);
if (ret == -1) {
perror("write");
- rv = -1;
goto done;
}
wlen = ret;
@@ -289,11 +352,16 @@ audiodev_test(struct audiodev *adev, uns
buflen -= wlen;
}
- if (ioctl(adev->fd, AUDIO_DRAIN) == -1)
+ if (ioctl(fd, AUDIO_DRAIN) == -1) {
perror("ioctl AUDIO_DRAIN");
+ goto done;
+ }
+ rv = 0;
done:
free(buf);
+abort:
+ close(fd);
return rv;
}
Index: src/usr.bin/audiocfg/audiodev.h
diff -u src/usr.bin/audiocfg/audiodev.h:1.4 src/usr.bin/audiocfg/audiodev.h:1.5
--- src/usr.bin/audiocfg/audiodev.h:1.4 Sun Aug 11 06:31:00 2013
+++ src/usr.bin/audiocfg/audiodev.h Wed May 8 14:36:12 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: audiodev.h,v 1.4 2013/08/11 06:31:00 dholland Exp $ */
+/* $NetBSD: audiodev.h,v 1.5 2019/05/08 14:36:12 isaki Exp $ */
/*
* Copyright (c) 2010 Jared D. McNeill <[email protected]>
@@ -35,19 +35,25 @@
#include <stdbool.h>
+struct audiofmt {
+ struct audio_format fmt;
+ TAILQ_ENTRY(audiofmt) next;
+};
+
struct audiodev {
char pxname[16]; /* hw (parent) device */
char xname[16]; /* audio(4) device */
uint16_t unit;
char path[PATH_MAX+1];
+ char ctlpath[PATH_MAX+1];
int fd;
dev_t dev;
bool defaultdev;
- unsigned pchan;
-
audio_device_t audio_device;
+ TAILQ_HEAD(, audiofmt) formats;
+ struct audio_info info;
TAILQ_ENTRY(audiodev) next;
};
@@ -56,6 +62,12 @@ int audiodev_refresh(void);
unsigned int audiodev_count(void);
struct audiodev * audiodev_get(unsigned int);
int audiodev_set_default(struct audiodev *);
+int audiodev_set_param(struct audiodev *, int,
+ const char *, unsigned int, unsigned int,
+ unsigned int);
int audiodev_test(struct audiodev *, unsigned int);
+extern const char * encoding_names[];
+extern u_int encoding_max;
+
#endif /* !_HAVE_AUDIODEV_H */
Index: src/usr.bin/audiocfg/main.c
diff -u src/usr.bin/audiocfg/main.c:1.7 src/usr.bin/audiocfg/main.c:1.8
--- src/usr.bin/audiocfg/main.c:1.7 Mon Aug 12 14:03:18 2013
+++ src/usr.bin/audiocfg/main.c Wed May 8 14:36:12 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: main.c,v 1.7 2013/08/12 14:03:18 joerg Exp $ */
+/* $NetBSD: main.c,v 1.8 2019/05/08 14:36:12 isaki Exp $ */
/*
* Copyright (c) 2010 Jared D. McNeill <[email protected]>
@@ -40,15 +40,43 @@
__dead static void
usage(const char *p)
{
- fprintf(stderr, "usage: %s list\n", p);
+ fprintf(stderr, "usage: %s list [<index>]\n", p);
fprintf(stderr, " %s default <index>\n", p);
+ fprintf(stderr, " %s set <index> [p|r] <enc> <prec> <ch> <freq>\n",
+ p);
fprintf(stderr, " %s test <index>\n", p);
exit(EXIT_FAILURE);
}
+const char *encoding_names[] = {
+ "none",
+ AudioEmulaw,
+ AudioEalaw,
+ "pcm16",
+ "pcm8",
+ AudioEadpcm,
+ AudioEslinear_le,
+ AudioEslinear_be,
+ AudioEulinear_le,
+ AudioEulinear_be,
+ AudioEslinear,
+ AudioEulinear,
+ AudioEmpeg_l1_stream,
+ AudioEmpeg_l1_packets,
+ AudioEmpeg_l1_system,
+ AudioEmpeg_l2_stream,
+ AudioEmpeg_l2_packets,
+ AudioEmpeg_l2_system,
+ AudioEac3,
+};
+u_int encoding_max = __arraycount(encoding_names);
+
static void
print_audiodev(struct audiodev *adev, int i)
{
+ struct audiofmt *f;
+ int j;
+
assert(adev != NULL);
printf("%u: [%c] %s @ %s: ",
@@ -57,8 +85,54 @@ print_audiodev(struct audiodev *adev, in
printf("%s", adev->audio_device.name);
if (strlen(adev->audio_device.version) > 0)
printf(" %s", adev->audio_device.version);
- printf(", %u playback channel%s\n",
- adev->pchan, adev->pchan == 1 ? "" : "s");
+ printf("\n");
+ printf(" playback: ");
+ if ((adev->info.mode & AUMODE_PLAY))
+ printf("%uch, %uHz\n",
+ adev->info.play.channels, adev->info.play.sample_rate);
+ else
+ printf("unavailable\n");
+ printf(" record: ");
+ if ((adev->info.mode & AUMODE_RECORD))
+ printf("%uch, %uHz\n",
+ adev->info.record.channels, adev->info.record.sample_rate);
+ else
+ printf("unavailable\n");
+
+ TAILQ_FOREACH(f, &adev->formats, next) {
+ printf(" ");
+ if (f->fmt.priority < 0)
+ printf("( ) ");
+ else if ((f->fmt.mode & (AUMODE_PLAY | AUMODE_RECORD))
+ == (AUMODE_PLAY | AUMODE_RECORD))
+ printf("(PR) ");
+ else if ((f->fmt.mode & AUMODE_PLAY))
+ printf("(P-) ");
+ else if ((f->fmt.mode & AUMODE_RECORD))
+ printf("(-R) ");
+
+ if (f->fmt.encoding < encoding_max)
+ printf("%s", encoding_names[f->fmt.encoding]);
+ else
+ printf("unknown_encoding_%d", f->fmt.encoding);
+ printf(" %d/%d, %dch, ",
+ f->fmt.validbits,
+ f->fmt.precision,
+ f->fmt.channels);
+ if (f->fmt.frequency_type == 0) {
+ printf("%d-%dHz",
+ f->fmt.frequency[0],
+ f->fmt.frequency[1]);
+ } else {
+ for (j = 0; j < (int)f->fmt.frequency_type; j++) {
+ printf("%s%d",
+ (j == 0) ? "{ " : ", ",
+ f->fmt.frequency[j]);
+ }
+ printf(" }");
+ }
+ printf("\n");
+ }
}
int
@@ -66,6 +140,12 @@ main(int argc, char *argv[])
{
struct audiodev *adev;
unsigned int n, i;
+ unsigned int j;
+ const char *enc;
+ unsigned int prec;
+ unsigned int ch;
+ unsigned int freq;
+ int mode;
if (audiodev_refresh() == -1)
return EXIT_FAILURE;
@@ -74,10 +154,17 @@ main(int argc, char *argv[])
usage(argv[0]);
/* NOTREACHED */
- if (strcmp(argv[1], "list") == 0) {
+ if (strcmp(argv[1], "list") == 0 && argc == 2) {
n = audiodev_count();
for (i = 0; i < n; i++)
print_audiodev(audiodev_get(i), i);
+ } else if (strcmp(argv[1], "list") == 0 && argc == 3) {
+ errno = 0;
+ i = strtoul(argv[2], NULL, 10);
+ if (errno)
+ usage(argv[0]);
+ /* NOTREACHED */
+ print_audiodev(audiodev_get(i), i);
} else if (strcmp(argv[1], "default") == 0 && argc == 3) {
if (*argv[2] < '0' || *argv[2] > '9')
usage(argv[0]);
@@ -97,6 +184,51 @@ main(int argc, char *argv[])
perror("couldn't set default device");
return EXIT_FAILURE;
}
+ } else if (strcmp(argv[1], "set") == 0 && argc == 8) {
+ /* XXX bad commandline... */
+ /* audiocfg set <index> [p|r] <enc> <prec> <ch> <freq> */
+ if (*argv[2] < '0' || *argv[2] > '9')
+ usage(argv[0]);
+ /* NOTREACHED */
+ errno = 0;
+ i = strtoul(argv[2], NULL, 10);
+ if (errno)
+ usage(argv[0]);
+ /* NOTREACHED */
+ adev = audiodev_get(i);
+ if (adev == NULL) {
+ fprintf(stderr, "no such device\n");
+ return EXIT_FAILURE;
+ }
+
+ mode = 0;
+ for (j = 0; j < strlen(argv[3]); j++) {
+ if (argv[3][j] == 'p')
+ mode |= AUMODE_PLAY;
+ else if (argv[3][j] == 'r')
+ mode |= AUMODE_RECORD;
+ else
+ usage(argv[0]);
+ }
+ enc = argv[4];
+ prec = strtoul(argv[5], NULL, 10);
+ if (errno)
+ usage(argv[0]);
+ errno = 0;
+ ch = strtoul(argv[6], NULL, 10);
+ if (errno)
+ usage(argv[0]);
+ /* NOTREACHED */
+ errno = 0;
+ freq = strtoul(argv[7], NULL, 10);
+ if (errno)
+ usage(argv[0]);
+ /* NOTREACHED */
+
+ if (audiodev_set_param(adev, mode, enc, prec, ch, freq) == -1) {
+ perror("couldn't set parameter");
+ return EXIT_FAILURE;
+ }
} else if (strcmp(argv[1], "test") == 0 && argc == 3) {
if (*argv[2] < '0' || *argv[2] > '9')
usage(argv[0]);
@@ -112,7 +244,7 @@ main(int argc, char *argv[])
return EXIT_FAILURE;
}
print_audiodev(adev, i);
- for (i = 0; i < adev->pchan; i++) {
+ for (i = 0; i < adev->info.play.channels; i++) {
printf(" testing channel %d...", i);
fflush(stdout);
if (audiodev_test(adev, 1 << i) == -1)