Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/lib/libossaudio ossaudio(3): Add initial support for the OSS...



details:   https://anonhg.NetBSD.org/src/rev/7fc23a0635aa
branches:  trunk
changeset: 1015217:7fc23a0635aa
user:      nia <nia%NetBSD.org@localhost>
date:      Sat Oct 17 23:23:06 2020 +0000

description:
ossaudio(3): Add initial support for the OSSv4.1 Mixer API

One or two calls from this API were supported previously and have been
moved to the correct place.

Mapping the controls correctly is a difficult task. There is a define
hidden in the OSS headers that would allow an AUDIO_MIXER_SET control
to be represented perfectly, but it seems to _only_ exist there, and
no software supports it. So for now only one member of a set can be
set at a time - unfortunate. I've hidden code that should unlock
doing this the proper way under #notyet.

I'm not too happy with the way this code is managing file descriptors.
Currently it has to open a new fd for each ioctl due to OSSv4 deciding
to specify the device number in a structure rather than in the filename.
In the future, we could reuse the file descriptor if the correct one is
detected open.

This allows the mixer programs provided with the OSSv4 sources to compile
and work cleanly. I've observed problems with it failing to work on
secondary devices, and should investigate this later. There may be
a fd leak somewhere.

diffstat:

 lib/libossaudio/ossaudio.c  |  678 +++++++++++++++++++++++++++++++++++--------
 lib/libossaudio/soundcard.h |  154 +++++++++-
 2 files changed, 696 insertions(+), 136 deletions(-)

diffs (truncated from 946 to 300 lines):

diff -r b573319b0831 -r 7fc23a0635aa lib/libossaudio/ossaudio.c
--- a/lib/libossaudio/ossaudio.c        Sat Oct 17 23:08:57 2020 +0000
+++ b/lib/libossaudio/ossaudio.c        Sat Oct 17 23:23:06 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ossaudio.c,v 1.48 2020/10/16 20:24:35 nia Exp $        */
+/*     $NetBSD: ossaudio.c,v 1.49 2020/10/17 23:23:06 nia Exp $        */
 
 /*-
  * Copyright (c) 1997, 2020 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: ossaudio.c,v 1.48 2020/10/16 20:24:35 nia Exp $");
+__RCSID("$NetBSD: ossaudio.c,v 1.49 2020/10/17 23:23:06 nia Exp $");
 
 /*
  * This is an Open Sound System compatibility layer, which provides
@@ -49,6 +49,7 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <limits.h>
 #include <stdarg.h>
 #include <stdbool.h>
 
@@ -66,6 +67,9 @@
 
 static struct audiodevinfo *getdevinfo(int);
 
+static int getmixercount(void);
+static int getmixercontrolcount(int);
+
 static int getvol(u_int, u_char);
 static void setvol(int, int, bool);
 
@@ -73,7 +77,8 @@
 static void setblocksize(int, struct audio_info *);
 
 static int audio_ioctl(int, unsigned long, void *);
-static int mixer_ioctl(int, unsigned long, void *);
+static int mixer_oss3_ioctl(int, unsigned long, void *);
+static int mixer_oss4_ioctl(int, unsigned long, void *);
 static int opaque_to_enum(struct audiodevinfo *, audio_mixer_name_t *, int);
 static int enum_to_ord(struct audiodevinfo *, int);
 static int enum_to_mask(struct audiodevinfo *, int);
@@ -93,7 +98,9 @@
        if (IOCGROUP(com) == 'P')
                return audio_ioctl(fd, com, argp);
        else if (IOCGROUP(com) == 'M')
-               return mixer_ioctl(fd, com, argp);
+               return mixer_oss3_ioctl(fd, com, argp);
+       else if (IOCGROUP(com) == 'X')
+               return mixer_oss4_ioctl(fd, com, argp);
        else
                return ioctl(fd, com, argp);
 }
@@ -105,17 +112,9 @@
        struct audio_info tmpinfo, hwfmt;
        struct audio_offset tmpoffs;
        struct audio_buf_info bufinfo;
-       struct audio_format_query fmtq;
        struct audio_errinfo *tmperrinfo;
        struct count_info cntinfo;
        struct audio_encoding tmpenc;
-       struct oss_sysinfo tmpsysinfo;
-       struct oss_audioinfo *tmpaudioinfo;
-       audio_device_t tmpaudiodev;
-       struct stat tmpstat;
-       dev_t devno;
-       char version[32] = "4.01";
-       char license[16] = "NetBSD";
        u_int u;
        u_int encoding;
        u_int precision;
@@ -123,9 +122,7 @@
        static int totalperrors = 0;
        static int totalrerrors = 0;
        int idat, idata;
-       int props;
        int retval;
-       int newfd;
 
        idat = 0;
 
@@ -589,117 +586,6 @@
                cntinfo.ptr = tmpoffs.offset;
                *(struct count_info *)argp = cntinfo;
                break;
-       case SNDCTL_SYSINFO:
-               strlcpy(tmpsysinfo.product, "OSS/NetBSD",
-                   sizeof tmpsysinfo.product);
-               strlcpy(tmpsysinfo.version, version, sizeof tmpsysinfo.version);
-               strlcpy(tmpsysinfo.license, license, sizeof tmpsysinfo.license);
-               tmpsysinfo.versionnum = SOUND_VERSION;
-               memset(tmpsysinfo.options, 0, 8);
-               tmpsysinfo.numaudios = OSS_MAX_AUDIO_DEVS;
-               tmpsysinfo.numaudioengines = 1;
-               memset(tmpsysinfo.openedaudio, 0, sizeof(tmpsysinfo.openedaudio));
-               tmpsysinfo.numsynths = 1;
-               tmpsysinfo.nummidis = -1;
-               tmpsysinfo.numtimers = -1;
-               tmpsysinfo.nummixers = 1;
-               tmpsysinfo.numcards = 1;
-               memset(tmpsysinfo.openedmidi, 0, sizeof(tmpsysinfo.openedmidi));
-               *(struct oss_sysinfo *)argp = tmpsysinfo;
-               break;
-       case SNDCTL_ENGINEINFO:
-       case SNDCTL_AUDIOINFO:
-               devno = 0;
-               tmpaudioinfo = (struct oss_audioinfo*)argp;
-               if (tmpaudioinfo == NULL)
-                       return EINVAL;
-
-               /*
-                * Takes the audio dev node as input, since this ioctl is
-                * supposed to work on the OSS /dev/mixer to query all
-                * all available audio devices.
-                *
-                * If the input device is -1, guess the device related to
-                * the open mixer device.
-                */
-               if (tmpaudioinfo->dev < 0) {
-                       fstat(fd, &tmpstat);
-                       if ((tmpstat.st_rdev & 0xff00) == 0x2a00)
-                               devno = tmpstat.st_rdev & 0xff;
-                       if (devno >= 0x80)
-                               tmpaudioinfo->dev = devno & 0x7f;
-               }
-               if (tmpaudioinfo->dev < 0)
-                       tmpaudioinfo->dev = 0;
-
-               snprintf(tmpaudioinfo->devnode, OSS_DEVNODE_SIZE,
-                   "/dev/audio%d", tmpaudioinfo->dev);
-
-               if ((newfd = open(tmpaudioinfo->devnode, O_WRONLY)) < 0) {
-                       if ((newfd = open(tmpaudioinfo->devnode, O_RDONLY)) < 0) {
-                               return newfd;
-                       }
-               }
-
-               retval = ioctl(newfd, AUDIO_GETDEV, &tmpaudiodev);
-               if (retval < 0) {
-                       close(newfd);
-                       return retval;
-               }
-               retval = ioctl(newfd, AUDIO_GETPROPS, &props);
-               if (retval < 0) {
-                       close(newfd);
-                       return retval;
-               }
-               idat = DSP_CAP_TRIGGER;
-               if (props & AUDIO_PROP_FULLDUPLEX)
-                       idat |= DSP_CAP_DUPLEX;
-               if (props & AUDIO_PROP_MMAP)
-                       idat |= DSP_CAP_MMAP;
-               if (props & AUDIO_PROP_CAPTURE)
-                       idat |= PCM_CAP_INPUT;
-               if (props & AUDIO_PROP_PLAYBACK)
-                       idat |= PCM_CAP_OUTPUT;
-               snprintf(tmpaudioinfo->name, sizeof(tmpaudioinfo->name),
-                   "%s %s", tmpaudiodev.name, tmpaudiodev.version);
-               tmpaudioinfo->busy = 0;
-               tmpaudioinfo->pid = -1;
-               tmpaudioinfo->caps = idat;
-               ioctl(newfd, SNDCTL_DSP_GETFMTS, &tmpaudioinfo->iformats);
-               tmpaudioinfo->oformats = tmpaudioinfo->iformats;
-               tmpaudioinfo->magic = -1; /* reserved for "internal use" */
-               memset(tmpaudioinfo->cmd, 0, sizeof(tmpaudioinfo->cmd));
-               tmpaudioinfo->card_number = -1;
-               memset(tmpaudioinfo->song_name, 0,
-                   sizeof(tmpaudioinfo->song_name));
-               memset(tmpaudioinfo->label, 0, sizeof(tmpaudioinfo->label));
-               tmpaudioinfo->port_number = 0;
-               tmpaudioinfo->mixer_dev = tmpaudioinfo->dev;
-               tmpaudioinfo->legacy_device = tmpaudioinfo->dev;
-               tmpaudioinfo->enabled = 1;
-               tmpaudioinfo->flags = -1; /* reserved for "future versions" */
-               tmpaudioinfo->min_rate = 1000;
-               tmpaudioinfo->max_rate = 192000;
-               tmpaudioinfo->nrates = 0;
-               tmpaudioinfo->min_channels = 1;
-               tmpaudioinfo->max_channels = 2;
-               for (fmtq.index = 0; ioctl(newfd, AUDIO_QUERYFORMAT, &fmtq) != -1; ++fmtq.index) {
-                       if (fmtq.fmt.channels > (unsigned)tmpaudioinfo->max_channels)
-                               tmpaudioinfo->max_channels = fmtq.fmt.channels;
-               }
-               tmpaudioinfo->binding = -1; /* reserved for "future versions" */
-               tmpaudioinfo->rate_source = -1;
-               /*
-                * 'handle' is supposed to be globally unique. The closest
-                * we have to that is probably device nodes.
-                */
-               strlcpy(tmpaudioinfo->handle, tmpaudioinfo->devnode,
-                   sizeof(tmpaudioinfo->handle));
-               tmpaudioinfo->next_play_engine = 0;
-               tmpaudioinfo->next_rec_engine = 0;
-               argp = tmpaudioinfo;
-               close(newfd);
-               break;
        case SNDCTL_DSP_SETPLAYVOL:
                setvol(fd, INTARG, false);
                /* FALLTHRU */
@@ -938,8 +824,8 @@
        return di;
 }
 
-int
-mixer_ioctl(int fd, unsigned long com, void *argp)
+static int
+mixer_oss3_ioctl(int fd, unsigned long com, void *argp)
 {
        struct audiodevinfo *di;
        struct mixer_info *omi;
@@ -1095,6 +981,544 @@
 }
 
 static int
+mixer_oss4_ioctl(int fd, unsigned long com, void *argp)
+{
+       oss_audioinfo *tmpai;
+       oss_mixext *ext;
+       oss_mixext_root root;
+       oss_mixer_enuminfo *ei;
+       oss_mixer_value *mv;
+       oss_mixerinfo *mi;
+       oss_sysinfo sysinfo;
+       dev_t devno;
+       struct stat tmpstat;
+       struct audio_device dev;
+       struct audio_format_query fmtq;
+       struct mixer_devinfo mdi;
+       struct mixer_ctrl mc;
+       char devname[32];
+       size_t len;
+       int newfd = -1, tmperrno;
+       int i, noffs;
+       int retval;
+       int props, caps;
+
+       /*
+        * Note: it is difficult to translate the NetBSD concept of a "set"
+        * mixer control type to the OSSv4 API, as far as I can tell.
+        *
+        * This means they are treated like enums, i.e. only one entry in the
+        * set can be selected at a time.
+        */
+
+       switch (com) {
+       case SNDCTL_AUDIOINFO:
+       case SNDCTL_ENGINEINFO:
+               devno = 0;
+               tmpai = (struct oss_audioinfo*)argp;
+               if (tmpai == NULL) {
+                       errno = EINVAL;
+                       return -1;
+               }
+
+               /*
+                * If the input device is -1, guess the device related to
+                * the open mixer device.
+                */
+               if (tmpai->dev < 0) {
+                       fstat(fd, &tmpstat);
+                       if ((tmpstat.st_rdev & 0xff00) == 0x2a00)
+                               devno = tmpstat.st_rdev & 0xff;
+                       if (devno >= 0x80)
+                               tmpai->dev = devno & 0x7f;
+               }
+               if (tmpai->dev < 0)
+                       tmpai->dev = 0;
+
+               snprintf(tmpai->devnode, sizeof(tmpai->devnode),
+                   "/dev/audio%d", tmpai->dev);
+
+               if ((newfd = open(tmpai->devnode, O_WRONLY)) < 0) {
+                       if ((newfd = open(tmpai->devnode, O_RDONLY)) < 0) {
+                               return newfd;
+                       }
+               }
+
+               retval = ioctl(newfd, AUDIO_GETDEV, &dev);
+               if (retval < 0) {
+                       tmperrno = errno;
+                       close(newfd);
+                       errno = tmperrno;
+                       return retval;
+               }
+               retval = ioctl(newfd, AUDIO_GETPROPS, &props);
+               if (retval < 0) {
+                       tmperrno = errno;
+                       close(newfd);
+                       errno = tmperrno;
+                       return retval;
+               }
+               caps = DSP_CAP_TRIGGER;
+               if (props & AUDIO_PROP_FULLDUPLEX)
+                       caps |= DSP_CAP_DUPLEX;
+               if (props & AUDIO_PROP_MMAP)
+                       caps |= DSP_CAP_MMAP;



Home | Main Index | Thread Index | Old Index