Module Name:    src
Committed By:   nia
Date:           Wed Apr 15 14:54:34 UTC 2020

Modified Files:
        src/lib/libossaudio: ossaudio.c
        src/sys/compat/ossaudio: ossaudio.c

Log Message:
ossaudio: Make SNDCTL_DSP_SPEED more robust when using invalid rates.

>From the perspective of reading the OSSv4 specification, NetBSD's
behaviour when an invalid sample rate is set makes no sense at all:
AUDIO_SETINFO simply returns an error code, and then we immediately
fall through to getting the sample rate, which is still set to the
legacy default of 8000 Hz.

Instead, what OSS applications generally expect is that they will be
able to receive the actual hardware sample rate. This is very, very
unlikely to be 8000 Hz on a modern machine.

No functional change when setting a sample rate between the supported
rates of 1000 and 192000 Hz. When a rate outside this range is requested,
the hardware rate is returned (on modern hardware, generally always 48000
Hz or a multiple of 48000 Hz).


To generate a diff of this commit:
cvs rdiff -u -r1.38 -r1.39 src/lib/libossaudio/ossaudio.c
cvs rdiff -u -r1.78 -r1.79 src/sys/compat/ossaudio/ossaudio.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libossaudio/ossaudio.c
diff -u src/lib/libossaudio/ossaudio.c:1.38 src/lib/libossaudio/ossaudio.c:1.39
--- src/lib/libossaudio/ossaudio.c:1.38	Sun Nov  3 11:13:45 2019
+++ src/lib/libossaudio/ossaudio.c	Wed Apr 15 14:54:34 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: ossaudio.c,v 1.38 2019/11/03 11:13:45 isaki Exp $	*/
+/*	$NetBSD: ossaudio.c,v 1.39 2020/04/15 14:54:34 nia Exp $	*/
 
 /*-
  * Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: ossaudio.c,v 1.38 2019/11/03 11:13:45 isaki Exp $");
+__RCSID("$NetBSD: ossaudio.c,v 1.39 2020/04/15 14:54:34 nia Exp $");
 
 /*
  * This is an OSS (Linux) sound API emulator.
@@ -95,7 +95,7 @@ static int
 audio_ioctl(int fd, unsigned long com, void *argp)
 {
 
-	struct audio_info tmpinfo;
+	struct audio_info tmpinfo, hwfmt;
 	struct audio_offset tmpoffs;
 	struct audio_buf_info bufinfo;
 	struct count_info cntinfo;
@@ -134,7 +134,35 @@ audio_ioctl(int fd, unsigned long com, v
 		AUDIO_INITINFO(&tmpinfo);
 		tmpinfo.play.sample_rate =
 		tmpinfo.record.sample_rate = INTARG;
-		(void) ioctl(fd, AUDIO_SETINFO, &tmpinfo);
+		/*
+		 * The default NetBSD behavior if an unsupported sample rate
+		 * is set is to return an error code and keep the rate at the
+		 * default of 8000 Hz.
+		 * 
+		 * However, OSS specifies that a sample rate supported by the
+		 * hardware is returned if the exact rate could not be set.
+		 * 
+		 * So, if the chosen sample rate is invalid, set and return
+		 * the current hardware rate.
+		 */
+		if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) {
+			/* Don't care that SETINFO failed the first time... */
+			errno = 0;
+			retval = ioctl(fd, AUDIO_GETFORMAT, &hwfmt);
+			if (retval < 0)
+				return retval;
+			retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
+			if (retval < 0)
+				return retval;
+			tmpinfo.play.sample_rate =
+			tmpinfo.record.sample_rate =
+			    (tmpinfo.mode == AUMODE_RECORD) ?
+			    hwfmt.record.sample_rate :
+			    hwfmt.play.sample_rate;
+			retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
+			if (retval < 0)
+				return retval;
+		}
 		/* FALLTHRU */
 	case SOUND_PCM_READ_RATE:
 		retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);

Index: src/sys/compat/ossaudio/ossaudio.c
diff -u src/sys/compat/ossaudio/ossaudio.c:1.78 src/sys/compat/ossaudio/ossaudio.c:1.79
--- src/sys/compat/ossaudio/ossaudio.c:1.78	Sun Nov  3 11:13:46 2019
+++ src/sys/compat/ossaudio/ossaudio.c	Wed Apr 15 14:54:34 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: ossaudio.c,v 1.78 2019/11/03 11:13:46 isaki Exp $	*/
+/*	$NetBSD: ossaudio.c,v 1.79 2020/04/15 14:54:34 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.78 2019/11/03 11:13:46 isaki Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ossaudio.c,v 1.79 2020/04/15 14:54:34 nia Exp $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -175,7 +175,7 @@ oss_ioctl_audio(struct lwp *l, const str
 	} */
 	file_t *fp;
 	u_long com;
-	struct audio_info tmpinfo;
+	struct audio_info tmpinfo, hwfmt;
 	struct audio_offset tmpoffs;
 	struct oss_audio_buf_info bufinfo;
 	struct oss_count_info cntinfo;
@@ -230,11 +230,41 @@ oss_ioctl_audio(struct lwp *l, const str
 		tmpinfo.play.sample_rate =
 		tmpinfo.record.sample_rate = idat;
 		DPRINTF(("%s: SNDCTL_DSP_SPEED > %d\n", __func__, idat));
-		error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
-		if (error) {
-			DPRINTF(("%s: SNDCTL_DSP_SPEED %d = %d\n",
-			     __func__, idat, error));
-			goto out;
+		/*
+		 * The default NetBSD behavior if an unsupported sample rate
+		 * is set is to return an error code and keep the rate at the
+		 * default of 8000 Hz.
+		 *
+		 * However, the OSS expectation is a sample rate supported by
+		 * the hardware is returned if the exact rate could not be set.
+		 *
+		 * So, if the chosen sample rate is invalid, set and return
+		 * the current hardware rate.
+		 */
+		if (ioctlf(fp, AUDIO_SETINFO, &tmpinfo) != 0) {
+			error = ioctlf(fp, AUDIO_GETFORMAT, &hwfmt);
+			if (error) {
+				DPRINTF(("%s: AUDIO_GETFORMAT %d\n",
+				     __func__, error));
+				goto out;
+			}
+			error = ioctlf(fp, AUDIO_GETINFO, &tmpinfo);
+			if (error) {
+				DPRINTF(("%s: AUDIO_GETINFO %d\n",
+				     __func__, error));
+				goto out;
+			}
+			tmpinfo.play.sample_rate =
+			tmpinfo.record.sample_rate =
+			    (tmpinfo.mode == AUMODE_RECORD) ?
+			    hwfmt.record.sample_rate :
+			    hwfmt.play.sample_rate;
+			error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
+			if (error) {
+				DPRINTF(("%s: SNDCTL_DSP_SPEED %d = %d\n",
+				     __func__, idat, error));
+				goto out;
+			}
 		}
 		/* FALLTHROUGH */
 	case OSS_SOUND_PCM_READ_RATE:

Reply via email to