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/c92c8950137f
branches: trunk
changeset: 1009186:c92c8950137f
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 6056f0406256 -r c92c8950137f 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 6056f0406256 -r c92c8950137f 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