Source-Changes-HG archive

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

[src/trunk]: src ossaudio: Make SNDCTL_DSP_SPEED more robust when using inval...



details:   https://anonhg.NetBSD.org/src/rev/6818edf71b14
branches:  trunk
changeset: 930850:6818edf71b14
user:      nia <nia%NetBSD.org@localhost>
date:      Wed Apr 15 14:54:34 2020 +0000

description:
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).

diffstat:

 lib/libossaudio/ossaudio.c     |  36 +++++++++++++++++++++++++++++---
 sys/compat/ossaudio/ossaudio.c |  46 ++++++++++++++++++++++++++++++++++-------
 2 files changed, 70 insertions(+), 12 deletions(-)

diffs (138 lines):

diff -r 972edcdb8a75 -r 6818edf71b14 lib/libossaudio/ossaudio.c
--- a/lib/libossaudio/ossaudio.c        Wed Apr 15 13:33:13 2020 +0000
+++ b/lib/libossaudio/ossaudio.c        Wed Apr 15 14:54:34 2020 +0000
@@ -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 @@
 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_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);
diff -r 972edcdb8a75 -r 6818edf71b14 sys/compat/ossaudio/ossaudio.c
--- a/sys/compat/ossaudio/ossaudio.c    Wed Apr 15 13:33:13 2020 +0000
+++ b/sys/compat/ossaudio/ossaudio.c    Wed Apr 15 14:54:34 2020 +0000
@@ -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 @@
        } */
        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 @@
                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:



Home | Main Index | Thread Index | Old Index