Source-Changes-HG archive

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

[src/trunk]: src ossaudio: If the user's channel count is rejected, use the h...



details:   https://anonhg.NetBSD.org/src/rev/567d0b22c2f3
branches:  trunk
changeset: 930862:567d0b22c2f3
user:      nia <nia%NetBSD.org@localhost>
date:      Wed Apr 15 16:39:06 2020 +0000

description:
ossaudio: If the user's channel count is rejected, use the hardware count

diffstat:

 lib/libossaudio/ossaudio.c     |  63 ++++++++++++++++++++++++++++++++++++-----
 sys/compat/ossaudio/ossaudio.c |  61 ++++++++++++++++++++++++++++++++++++----
 2 files changed, 109 insertions(+), 15 deletions(-)

diffs (198 lines):

diff -r a6d108ce1bb1 -r 567d0b22c2f3 lib/libossaudio/ossaudio.c
--- a/lib/libossaudio/ossaudio.c        Wed Apr 15 16:28:28 2020 +0000
+++ b/lib/libossaudio/ossaudio.c        Wed Apr 15 16:39:06 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ossaudio.c,v 1.40 2020/04/15 15:25:33 nia Exp $        */
+/*     $NetBSD: ossaudio.c,v 1.41 2020/04/15 16:39:06 nia Exp $        */
 
 /*-
  * Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: ossaudio.c,v 1.40 2020/04/15 15:25:33 nia Exp $");
+__RCSID("$NetBSD: ossaudio.c,v 1.41 2020/04/15 16:39:06 nia Exp $");
 
 /*
  * This is an OSS (Linux) sound API emulator.
@@ -63,6 +63,7 @@
 
 static struct audiodevinfo *getdevinfo(int);
 
+static void setchannels(int, int, int);
 static void setblocksize(int, struct audio_info *);
 
 static int audio_ioctl(int, unsigned long, void *);
@@ -350,12 +351,10 @@
                INTARG = idat;
                break;
        case SNDCTL_DSP_CHANNELS:
-               AUDIO_INITINFO(&tmpinfo);
-               tmpinfo.play.channels = INTARG;
-               (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo);
-               AUDIO_INITINFO(&tmpinfo);
-               tmpinfo.record.channels = INTARG;
-               (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo);
+               retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
+               if (retval < 0)
+                       return retval;
+               setchannels(fd, tmpinfo.mode, INTARG);
                /* FALLTHRU */
        case SOUND_PCM_READ_CHANNELS:
                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
@@ -1049,6 +1048,54 @@
 }
 
 /*
+ * When AUDIO_SETINFO fails to set a channel count, the application's chosen
+ * number is out of range of what the kernel allows.
+ *
+ * When this happens, we use the current hardware settings. This is just in
+ * case an application is abusing SNDCTL_DSP_CHANNELS - OSSv4 always sets and
+ * returns a reasonable value, even if it wasn't what the user requested.
+ *
+ * XXX: If a device is opened for both playback and recording, and supports
+ * fewer channels for recording than playback, applications that do both will
+ * behave very strangely. OSS doesn't allow for reporting separate channel
+ * counts for recording and playback. This could be worked around by always
+ * mixing recorded data up to the same number of channels as is being used
+ * for playback.
+ */
+static void
+setchannels(int fd, int mode, int nchannels)
+{
+       struct audio_info tmpinfo, hwfmt;
+
+       if (ioctl(fd, AUDIO_GETFORMAT, &hwfmt) < 0) {
+               errno = 0;
+               hwfmt.record.channels = hwfmt.play.channels = 2;
+       }
+
+       if (mode & AUMODE_PLAY) {
+               AUDIO_INITINFO(&tmpinfo);
+               tmpinfo.play.channels = nchannels;
+               if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) {
+                       errno = 0;
+                       AUDIO_INITINFO(&tmpinfo);
+                       tmpinfo.play.channels = hwfmt.play.channels;
+                       (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo);
+               }
+       }
+
+       if (mode & AUMODE_RECORD) {
+               AUDIO_INITINFO(&tmpinfo);
+               tmpinfo.record.channels = nchannels;
+               if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) {
+                       errno = 0;
+                       AUDIO_INITINFO(&tmpinfo);
+                       tmpinfo.record.channels = hwfmt.record.channels;
+                       (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo);
+               }
+       }
+}
+
+/*
  * Check that the blocksize is a power of 2 as OSS wants.
  * If not, set it to be.
  */
diff -r a6d108ce1bb1 -r 567d0b22c2f3 sys/compat/ossaudio/ossaudio.c
--- a/sys/compat/ossaudio/ossaudio.c    Wed Apr 15 16:28:28 2020 +0000
+++ b/sys/compat/ossaudio/ossaudio.c    Wed Apr 15 16:39:06 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ossaudio.c,v 1.80 2020/04/15 15:25:33 nia Exp $        */
+/*     $NetBSD: ossaudio.c,v 1.81 2020/04/15 16:39:06 nia Exp $        */
 
 /*-
  * Copyright (c) 1997, 2008 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ossaudio.c,v 1.80 2020/04/15 15:25:33 nia Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ossaudio.c,v 1.81 2020/04/15 16:39:06 nia Exp $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -68,6 +68,7 @@
 static int enum_to_ord(struct audiodevinfo *di, int enm);
 static int enum_to_mask(struct audiodevinfo *di, int enm);
 
+static void setchannels(file_t *, int, int);
 static void setblocksize(file_t *, struct audio_info *);
 
 #ifdef AUDIO_DEBUG
@@ -487,15 +488,13 @@
                             __func__, error));
                        goto out;
                }
-               tmpinfo.play.channels =
-               tmpinfo.record.channels = idat;
-               DPRINTF(("%s: SNDCTL_DSP_CHANNELS > %d\n", __func__, idat));
-               error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
+               error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
                if (error) {
-                       DPRINTF(("%s: AUDIO_SETINFO %d\n",
+                       DPRINTF(("%s: AUDIO_GETBUFINFO %d\n",
                             __func__, error));
                        goto out;
                }
+               setchannels(fp, tmpinfo.mode, idat);
                /* FALLTHROUGH */
        case OSS_SOUND_PCM_READ_CHANNELS:
                error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
@@ -1532,6 +1531,54 @@
 }
 
 /*
+ * When AUDIO_SETINFO fails to set a channel count, the application's chosen
+ * number is out of range of what the kernel allows.
+ *
+ * When this happens, we use the current hardware settings. This is just in
+ * case an application is abusing SNDCTL_DSP_CHANNELS - OSSv4 always sets and
+ * returns a reasonable value, even if it wasn't what the user requested.
+ *
+ * XXX: If a device is opened for both playback and recording, and supports
+ * fewer channels for recording than playback, applications that do both will
+ * behave very strangely. OSS doesn't allow for reporting separate channel
+ * counts for recording and playback. This could be worked around by always
+ * mixing recorded data up to the same number of channels as is being used
+ * for playback.
+ */
+static void
+setchannels(file_t *fp, int mode, int nchannels)
+{
+       struct audio_info tmpinfo, hwfmt;
+       int (*ioctlf)(file_t *, u_long, void *);
+
+       ioctlf = fp->f_ops->fo_ioctl;
+
+       if (ioctlf(fp, AUDIO_GETFORMAT, &hwfmt) < 0) {
+               hwfmt.record.channels = hwfmt.play.channels = 2;
+       }
+
+       if (mode & AUMODE_PLAY) {
+               AUDIO_INITINFO(&tmpinfo);
+               tmpinfo.play.channels = nchannels;
+               if (ioctlf(fp, AUDIO_SETINFO, &tmpinfo) < 0) {
+                       AUDIO_INITINFO(&tmpinfo);
+                       tmpinfo.play.channels = hwfmt.play.channels;
+                       (void)ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
+               }
+       }
+
+       if (mode & AUMODE_RECORD) {
+               AUDIO_INITINFO(&tmpinfo);
+               tmpinfo.record.channels = nchannels;
+               if (ioctlf(fp, AUDIO_SETINFO, &tmpinfo) < 0) {
+                       AUDIO_INITINFO(&tmpinfo);
+                       tmpinfo.record.channels = hwfmt.record.channels;
+                       (void)ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
+               }
+       }
+}
+
+/*
  * Check that the blocksize is a power of 2 as OSS wants.
  * If not, set it to be.
  */



Home | Main Index | Thread Index | Old Index