Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

add a simple app to maintain the symlinks for audio devices in /dev, so

that it's easy to change the "default" audio device.  eg:

# audiocfg
0: [*] audio0: HD Audio
1: [ ] audio1: HD Audio
2: [ ] audio2: Pseudo Audio
# audiocfg 1
setting default audio device to audio1
# audiocfg
0: [ ] audio0: HD Audio
1: [*] audio1: HD Audio
2: [ ] audio2: Pseudo Audio

written by jared.  thanks!

(there's a separate patch in the works to give "HD Audio" a better name.)


this is not enabled yet, but will be soon.

it also needs a manual page.  any takers?
  • Loading branch information...
commit c5335654aaa932ff5e421861784e7f4d0d6cb677 1 parent a2bca40
mrg authored
View
10 usr.bin/audiocfg/Makefile
@@ -0,0 +1,10 @@
+PROG= audiocfg
+SRCS= audiodev.c drvctl.c
+SRCS+= main.c
+NOMAN= # defined
+WARNS= 3
+
+LDADD+= -lprop
+DPADD+= $(LIBPROP)
+
+.include <bsd.prog.mk>
View
204 usr.bin/audiocfg/audiodev.c
@@ -0,0 +1,204 @@
+/* $NetBSD: audiodev.c,v 1.1.1.1 2010/08/30 02:19:47 mrg Exp $ */
+
+/*
+ * Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/drvctlio.h>
+
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "audiodev.h"
+#include "drvctl.h"
+
+static TAILQ_HEAD(audiodevhead, audiodev) audiodevlist =
+ TAILQ_HEAD_INITIALIZER(audiodevlist);
+
+static int
+audiodev_getinfo(struct audiodev *adev)
+{
+ struct stat st;
+
+ if (stat(adev->path, &st) == -1)
+ return -1;
+ adev->dev = st.st_rdev;
+
+ if (stat(_PATH_AUDIO, &st) != -1 && st.st_rdev == adev->dev)
+ adev->defaultdev = true;
+
+ adev->fd = open(adev->path, O_RDWR);
+ if (adev->fd == -1)
+ return -1;
+ if (ioctl(adev->fd, AUDIO_GETDEV, &adev->audio_device) == -1) {
+ close(adev->fd);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+audiodev_add(const char *dev, unsigned int unit)
+{
+ struct audiodev *adev;
+
+ adev = calloc(1, sizeof(*adev));
+ if (adev == NULL)
+ return -1;
+
+ strlcpy(adev->xname, dev, sizeof(adev->xname));
+ snprintf(adev->path, sizeof(adev->path) - 1, "/dev/%s", dev);
+ adev->unit = unit;
+
+ if (audiodev_getinfo(adev) == -1) {
+ free(adev);
+ return -1;
+ }
+
+#ifdef DEBUG
+ printf("[%c] %s: %s\n", adev->defaultdev ? '*' : ' ',
+ adev->path, adev->audio_device.name);
+#endif
+
+ TAILQ_INSERT_TAIL(&audiodevlist, adev, next);
+
+ return 0;
+}
+
+static void
+audiodev_cb(void *args, const char *dev, unsigned int unit)
+{
+ audiodev_add(dev, unit);
+}
+
+int
+audiodev_refresh(void)
+{
+ struct audiodev *adev;
+ int fd, error;
+
+ fd = open(DRVCTLDEV, O_RDWR);
+ if (fd == -1) {
+ perror("open " DRVCTLDEV);
+ return -1;
+ }
+
+ while (!TAILQ_EMPTY(&audiodevlist)) {
+ adev = TAILQ_FIRST(&audiodevlist);
+ if (adev->fd != -1)
+ close(adev->fd);
+ TAILQ_REMOVE(&audiodevlist, adev, next);
+ free(adev);
+ }
+
+ error = drvctl_foreach(fd, "audio", audiodev_cb, NULL);
+ if (error == -1) {
+ perror("drvctl");
+ return -1;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+unsigned int
+audiodev_count(void)
+{
+ struct audiodev *adev;
+ unsigned int n;
+
+ n = 0;
+ TAILQ_FOREACH(adev, &audiodevlist, next)
+ ++n;
+
+ return n;
+}
+
+struct audiodev *
+audiodev_get(unsigned int i)
+{
+ struct audiodev *adev;
+ unsigned int n;
+
+ n = 0;
+ TAILQ_FOREACH(adev, &audiodevlist, next) {
+ if (n == i)
+ return adev;
+ ++n;
+ }
+
+ return NULL;
+}
+
+int
+audiodev_set_default(struct audiodev *adev)
+{
+ char audiopath[PATH_MAX+1];
+ char soundpath[PATH_MAX+1];
+ char audioctlpath[PATH_MAX+1];
+ char mixerpath[PATH_MAX+1];
+
+ snprintf(audiopath, sizeof(audiopath) - 1,
+ _PATH_AUDIO "%u", adev->unit);
+ snprintf(soundpath, sizeof(soundpath) - 1,
+ _PATH_SOUND "%u", adev->unit);
+ snprintf(audioctlpath, sizeof(audioctlpath) - 1,
+ _PATH_AUDIOCTL "%u", adev->unit);
+ snprintf(mixerpath, sizeof(mixerpath) - 1,
+ _PATH_MIXER "%u", adev->unit);
+
+ unlink(_PATH_AUDIO);
+ unlink(_PATH_SOUND);
+ unlink(_PATH_AUDIOCTL);
+ unlink(_PATH_MIXER);
+
+ if (symlink(audiopath, _PATH_AUDIO) == -1) {
+ perror("symlink " _PATH_AUDIO);
+ return -1;
+ }
+ if (symlink(soundpath, _PATH_SOUND) == -1) {
+ perror("symlink " _PATH_SOUND);
+ return -1;
+ }
+ if (symlink(audioctlpath, _PATH_AUDIOCTL) == -1) {
+ perror("symlink " _PATH_AUDIOCTL);
+ return -1;
+ }
+ if (symlink(mixerpath, _PATH_MIXER) == -1) {
+ perror("symlink " _PATH_MIXER);
+ return -1;
+ }
+
+ return 0;
+}
View
57 usr.bin/audiocfg/audiodev.h
@@ -0,0 +1,57 @@
+/* $NetBSD: audiodev.h,v 1.1.1.1 2010/08/30 02:19:47 mrg Exp $ */
+
+/*
+ * Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _HAVE_AUDIODEV_H
+#define _HAVE_AUDIODEV_H
+
+#include <sys/audioio.h>
+#include <sys/queue.h>
+#include <sys/syslimits.h>
+
+#include <stdbool.h>
+
+struct audiodev {
+ char xname[16];
+ uint16_t unit;
+ char path[PATH_MAX+1];
+
+ int fd;
+ dev_t dev;
+ bool defaultdev;
+
+ audio_device_t audio_device;
+
+ TAILQ_ENTRY(audiodev) next;
+};
+
+int audiodev_refresh(void);
+unsigned int audiodev_count(void);
+struct audiodev * audiodev_get(unsigned int);
+int audiodev_set_default(struct audiodev *);
+
+#endif /* !_HAVE_AUDIODEV_H */
View
140 usr.bin/audiocfg/drvctl.c
@@ -0,0 +1,140 @@
+/* $NetBSD: drvctl.c,v 1.1.1.1 2010/08/30 02:19:47 mrg Exp $ */
+
+/*
+ * Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "drvctl.h"
+
+static int
+drvctl_list(int fd, const char *name, struct devlistargs *laa)
+{
+ size_t children;
+
+ memset(laa, 0, sizeof(*laa));
+ strlcpy(laa->l_devname, name, sizeof(laa->l_devname));
+ if (ioctl(fd, DRVLISTDEV, laa) == -1)
+ return -1;
+ children = laa->l_children;
+ laa->l_childname = malloc(children * sizeof(laa->l_childname[0]));
+ if (laa->l_childname == NULL)
+ return -1;
+ if (ioctl(fd, DRVLISTDEV, laa) == -1)
+ return -1;
+ return 0;
+}
+
+static bool
+drvctl_get_properties(int fd, const char *devnode, prop_dictionary_t *props)
+{
+ prop_dictionary_t command_dict;
+ prop_dictionary_t args_dict;
+ prop_dictionary_t results_dict;
+ int8_t perr;
+ int error;
+ bool rv;
+
+ command_dict = prop_dictionary_create();
+ args_dict = prop_dictionary_create();
+
+ prop_dictionary_set_cstring_nocopy(command_dict, "drvctl-command",
+ "get-properties");
+ prop_dictionary_set_cstring_nocopy(args_dict, "device-name", devnode);
+ prop_dictionary_set(command_dict, "drvctl-arguments", args_dict);
+ prop_object_release(args_dict);
+
+ error = prop_dictionary_sendrecv_ioctl(command_dict, fd,
+ DRVCTLCOMMAND, &results_dict);
+ prop_object_release(command_dict);
+ if (error)
+ return false;
+
+ rv = prop_dictionary_get_int8(results_dict, "drvctl-error", &perr);
+ if (rv == false || perr != 0) {
+ prop_object_release(results_dict);
+ return false;
+ }
+
+ if (props) {
+ prop_dictionary_t result_data;
+ result_data = prop_dictionary_get(results_dict,
+ "drvctl-result-data");
+ if (result_data)
+ *props = prop_dictionary_copy(result_data);
+ }
+
+ prop_object_release(results_dict);
+
+ return true;
+}
+
+static int
+drvctl_search(int fd, const char *curnode, const char *dvname,
+ void (*callback)(void *, const char *, unsigned int), void *args)
+{
+ struct devlistargs laa;
+ unsigned int i;
+ uint32_t unit;
+ bool rv;
+
+ if (drvctl_list(fd, curnode, &laa) == -1)
+ return -1;
+
+ for (i = 0; i < laa.l_children; i++) {
+ prop_dictionary_t props = NULL;
+ const char *curdvname;
+
+ rv = drvctl_get_properties(fd, laa.l_childname[i], &props);
+ if (rv == false || props == NULL)
+ continue;
+ rv = prop_dictionary_get_cstring_nocopy(props,
+ "device-driver", &curdvname);
+ if (rv == true && strcmp(curdvname, dvname) == 0) {
+ rv = prop_dictionary_get_uint32(props,
+ "device-unit", &unit);
+ if (rv == true)
+ callback(args, laa.l_childname[i], unit);
+ }
+ prop_object_release(props);
+
+ if (drvctl_search(fd, laa.l_childname[i], dvname,
+ callback, args) == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+drvctl_foreach(int fd, const char *dvname,
+ void (*callback)(void *, const char *, unsigned int), void *args)
+{
+ return drvctl_search(fd, "", dvname, callback, args);
+}
View
38 usr.bin/audiocfg/drvctl.h
@@ -0,0 +1,38 @@
+/* $NetBSD: drvctl.h,v 1.1.1.1 2010/08/30 02:19:47 mrg Exp $ */
+
+/*
+ * Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _HAVE_DRVCTL_H
+#define _HAVE_DRVCTL_H
+
+#include <sys/ioctl.h>
+#include <sys/drvctlio.h>
+
+int drvctl_foreach(int, const char *,
+ void (*)(void *, const char *, unsigned int), void *);
+
+#endif /* !_HAVE_DRVCTL_H */
View
91 usr.bin/audiocfg/main.c
@@ -0,0 +1,91 @@
+/* $NetBSD: main.c,v 1.1.1.1 2010/08/30 02:19:47 mrg Exp $ */
+
+/*
+ * Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "audiodev.h"
+#include "drvctl.h"
+
+static void
+usage(const char *p)
+{
+ fprintf(stderr, "usage: %s [index]\n", p);
+ exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct audiodev *adev;
+ unsigned int n, i;
+
+ if (audiodev_refresh() == -1)
+ return EXIT_FAILURE;
+
+ switch (argc) {
+ case 1:
+ n = audiodev_count();
+ for (i = 0; i < n; i++) {
+ adev = audiodev_get(i);
+ printf("%u: [%c] %s: %s\n",
+ i, adev->defaultdev ? '*' : ' ',
+ adev->xname, adev->audio_device.name);
+ }
+ break;
+ case 2:
+ if (*argv[1] < '0' || *argv[1] > '9')
+ usage(argv[0]);
+ /* NOTREACHED */
+ errno = 0;
+ i = strtoul(argv[1], NULL, 10);
+ if (errno)
+ usage(argv[0]);
+ /* NOTREACHED */
+ adev = audiodev_get(i);
+ if (adev == NULL) {
+ fprintf(stderr, "no such device\n");
+ return EXIT_FAILURE;
+ }
+ printf("setting default audio device to %s\n", adev->xname);
+ if (audiodev_set_default(adev) == -1) {
+ perror("couldn't set default device");
+ return EXIT_FAILURE;
+ }
+ break;
+ default:
+ usage(argv[0]);
+ /* NOTREACHED */
+ }
+
+ return EXIT_SUCCESS;
+}
Please sign in to comment.
Something went wrong with that request. Please try again.