Wed Apr 15 14:54:34 2020 UTC ()
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).


(nia)
diff -r1.38 -r1.39 src/lib/libossaudio/ossaudio.c
diff -r1.78 -r1.79 src/sys/compat/ossaudio/ossaudio.c

cvs diff -r1.38 -r1.39 src/lib/libossaudio/Attic/ossaudio.c (expand / switch to unified diff)

--- src/lib/libossaudio/Attic/ossaudio.c 2019/11/03 11:13:45 1.38
+++ src/lib/libossaudio/Attic/ossaudio.c 2020/04/15 14:54:34 1.39
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ossaudio.c,v 1.38 2019/11/03 11:13:45 isaki Exp $ */ 1/* $NetBSD: ossaudio.c,v 1.39 2020/04/15 14:54:34 nia Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -17,27 +17,27 @@ @@ -17,27 +17,27 @@
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29#include <sys/cdefs.h> 29#include <sys/cdefs.h>
30__RCSID("$NetBSD: ossaudio.c,v 1.38 2019/11/03 11:13:45 isaki Exp $"); 30__RCSID("$NetBSD: ossaudio.c,v 1.39 2020/04/15 14:54:34 nia Exp $");
31 31
32/* 32/*
33 * This is an OSS (Linux) sound API emulator. 33 * This is an OSS (Linux) sound API emulator.
34 * It provides the essentials of the API. 34 * It provides the essentials of the API.
35 */ 35 */
36 36
37/* XXX This file is essentially the same as sys/compat/ossaudio.c. 37/* XXX This file is essentially the same as sys/compat/ossaudio.c.
38 * With some preprocessor magic it could be the same file. 38 * With some preprocessor magic it could be the same file.
39 */ 39 */
40 40
41#include <string.h> 41#include <string.h>
42#include <sys/types.h> 42#include <sys/types.h>
43#include <sys/ioctl.h> 43#include <sys/ioctl.h>
@@ -85,27 +85,27 @@ _oss_ioctl(int fd, unsigned long com, .. @@ -85,27 +85,27 @@ _oss_ioctl(int fd, unsigned long com, ..
85 85
86 if (IOCGROUP(com) == 'P') 86 if (IOCGROUP(com) == 'P')
87 return audio_ioctl(fd, com, argp); 87 return audio_ioctl(fd, com, argp);
88 else if (IOCGROUP(com) == 'M') 88 else if (IOCGROUP(com) == 'M')
89 return mixer_ioctl(fd, com, argp); 89 return mixer_ioctl(fd, com, argp);
90 else 90 else
91 return ioctl(fd, com, argp); 91 return ioctl(fd, com, argp);
92} 92}
93 93
94static int 94static int
95audio_ioctl(int fd, unsigned long com, void *argp) 95audio_ioctl(int fd, unsigned long com, void *argp)
96{ 96{
97 97
98 struct audio_info tmpinfo; 98 struct audio_info tmpinfo, hwfmt;
99 struct audio_offset tmpoffs; 99 struct audio_offset tmpoffs;
100 struct audio_buf_info bufinfo; 100 struct audio_buf_info bufinfo;
101 struct count_info cntinfo; 101 struct count_info cntinfo;
102 struct audio_encoding tmpenc; 102 struct audio_encoding tmpenc;
103 struct oss_sysinfo tmpsysinfo; 103 struct oss_sysinfo tmpsysinfo;
104 struct oss_audioinfo *tmpaudioinfo; 104 struct oss_audioinfo *tmpaudioinfo;
105 audio_device_t tmpaudiodev; 105 audio_device_t tmpaudiodev;
106 struct stat tmpstat; 106 struct stat tmpstat;
107 dev_t devno; 107 dev_t devno;
108 char version[32] = "4.01"; 108 char version[32] = "4.01";
109 char license[16] = "NetBSD"; 109 char license[16] = "NetBSD";
110 u_int u; 110 u_int u;
111 u_int encoding; 111 u_int encoding;
@@ -124,27 +124,55 @@ audio_ioctl(int fd, unsigned long com, v @@ -124,27 +124,55 @@ audio_ioctl(int fd, unsigned long com, v
124 break; 124 break;
125 case SNDCTL_DSP_SYNC: 125 case SNDCTL_DSP_SYNC:
126 retval = ioctl(fd, AUDIO_DRAIN, 0); 126 retval = ioctl(fd, AUDIO_DRAIN, 0);
127 if (retval < 0) 127 if (retval < 0)
128 return retval; 128 return retval;
129 break; 129 break;
130 case SNDCTL_DSP_POST: 130 case SNDCTL_DSP_POST:
131 /* This call is merely advisory, and may be a nop. */ 131 /* This call is merely advisory, and may be a nop. */
132 break; 132 break;
133 case SNDCTL_DSP_SPEED: 133 case SNDCTL_DSP_SPEED:
134 AUDIO_INITINFO(&tmpinfo); 134 AUDIO_INITINFO(&tmpinfo);
135 tmpinfo.play.sample_rate = 135 tmpinfo.play.sample_rate =
136 tmpinfo.record.sample_rate = INTARG; 136 tmpinfo.record.sample_rate = INTARG;
137 (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo); 137 /*
 138 * The default NetBSD behavior if an unsupported sample rate
 139 * is set is to return an error code and keep the rate at the
 140 * default of 8000 Hz.
 141 *
 142 * However, OSS specifies that a sample rate supported by the
 143 * hardware is returned if the exact rate could not be set.
 144 *
 145 * So, if the chosen sample rate is invalid, set and return
 146 * the current hardware rate.
 147 */
 148 if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) {
 149 /* Don't care that SETINFO failed the first time... */
 150 errno = 0;
 151 retval = ioctl(fd, AUDIO_GETFORMAT, &hwfmt);
 152 if (retval < 0)
 153 return retval;
 154 retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
 155 if (retval < 0)
 156 return retval;
 157 tmpinfo.play.sample_rate =
 158 tmpinfo.record.sample_rate =
 159 (tmpinfo.mode == AUMODE_RECORD) ?
 160 hwfmt.record.sample_rate :
 161 hwfmt.play.sample_rate;
 162 retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
 163 if (retval < 0)
 164 return retval;
 165 }
138 /* FALLTHRU */ 166 /* FALLTHRU */
139 case SOUND_PCM_READ_RATE: 167 case SOUND_PCM_READ_RATE:
140 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 168 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
141 if (retval < 0) 169 if (retval < 0)
142 return retval; 170 return retval;
143 INTARG = GETPRINFO(&tmpinfo, sample_rate); 171 INTARG = GETPRINFO(&tmpinfo, sample_rate);
144 break; 172 break;
145 case SNDCTL_DSP_STEREO: 173 case SNDCTL_DSP_STEREO:
146 AUDIO_INITINFO(&tmpinfo); 174 AUDIO_INITINFO(&tmpinfo);
147 tmpinfo.play.channels = 175 tmpinfo.play.channels =
148 tmpinfo.record.channels = INTARG ? 2 : 1; 176 tmpinfo.record.channels = INTARG ? 2 : 1;
149 (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo); 177 (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo);
150 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 178 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);

cvs diff -r1.78 -r1.79 src/sys/compat/ossaudio/ossaudio.c (expand / switch to unified diff)

--- src/sys/compat/ossaudio/ossaudio.c 2019/11/03 11:13:46 1.78
+++ src/sys/compat/ossaudio/ossaudio.c 2020/04/15 14:54:34 1.79
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ossaudio.c,v 1.78 2019/11/03 11:13:46 isaki Exp $ */ 1/* $NetBSD: ossaudio.c,v 1.79 2020/04/15 14:54:34 nia Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1997, 2008 The NetBSD Foundation, Inc. 4 * Copyright (c) 1997, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -17,27 +17,27 @@ @@ -17,27 +17,27 @@
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29#include <sys/cdefs.h> 29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: ossaudio.c,v 1.78 2019/11/03 11:13:46 isaki Exp $"); 30__KERNEL_RCSID(0, "$NetBSD: ossaudio.c,v 1.79 2020/04/15 14:54:34 nia Exp $");
31 31
32#include <sys/param.h> 32#include <sys/param.h>
33#include <sys/proc.h> 33#include <sys/proc.h>
34#include <sys/systm.h> 34#include <sys/systm.h>
35#include <sys/file.h> 35#include <sys/file.h>
36#include <sys/vnode.h> 36#include <sys/vnode.h>
37#include <sys/filedesc.h> 37#include <sys/filedesc.h>
38#include <sys/ioctl.h> 38#include <sys/ioctl.h>
39#include <sys/mount.h> 39#include <sys/mount.h>
40#include <sys/kernel.h> 40#include <sys/kernel.h>
41#include <sys/audioio.h> 41#include <sys/audioio.h>
42#include <sys/midiio.h> 42#include <sys/midiio.h>
43#include <sys/kauth.h> 43#include <sys/kauth.h>
@@ -165,27 +165,27 @@ compat_ossaudio_modcmd(modcmd_t cmd, voi @@ -165,27 +165,27 @@ compat_ossaudio_modcmd(modcmd_t cmd, voi
165 } 165 }
166} 166}
167 167
168int 168int
169oss_ioctl_audio(struct lwp *l, const struct oss_sys_ioctl_args *uap, register_t *retval) 169oss_ioctl_audio(struct lwp *l, const struct oss_sys_ioctl_args *uap, register_t *retval)
170{ 170{
171 /* { 171 /* {
172 syscallarg(int) fd; 172 syscallarg(int) fd;
173 syscallarg(u_long) com; 173 syscallarg(u_long) com;
174 syscallarg(void *) data; 174 syscallarg(void *) data;
175 } */ 175 } */
176 file_t *fp; 176 file_t *fp;
177 u_long com; 177 u_long com;
178 struct audio_info tmpinfo; 178 struct audio_info tmpinfo, hwfmt;
179 struct audio_offset tmpoffs; 179 struct audio_offset tmpoffs;
180 struct oss_audio_buf_info bufinfo; 180 struct oss_audio_buf_info bufinfo;
181 struct oss_count_info cntinfo; 181 struct oss_count_info cntinfo;
182 struct audio_encoding tmpenc; 182 struct audio_encoding tmpenc;
183 u_int u; 183 u_int u;
184 u_int encoding; 184 u_int encoding;
185 u_int precision; 185 u_int precision;
186 int idat, idata; 186 int idat, idata;
187 int error = 0; 187 int error = 0;
188 int (*ioctlf)(file_t *, u_long, void *); 188 int (*ioctlf)(file_t *, u_long, void *);
189 189
190 if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) 190 if ((fp = fd_getfile(SCARG(uap, fd))) == NULL)
191 return (EBADF); 191 return (EBADF);
@@ -220,31 +220,61 @@ oss_ioctl_audio(struct lwp *l, const str @@ -220,31 +220,61 @@ oss_ioctl_audio(struct lwp *l, const str
220 /* This call is merely advisory, and may be a nop. */ 220 /* This call is merely advisory, and may be a nop. */
221 break; 221 break;
222 case OSS_SNDCTL_DSP_SPEED: 222 case OSS_SNDCTL_DSP_SPEED:
223 AUDIO_INITINFO(&tmpinfo); 223 AUDIO_INITINFO(&tmpinfo);
224 error = copyin(SCARG(uap, data), &idat, sizeof idat); 224 error = copyin(SCARG(uap, data), &idat, sizeof idat);
225 if (error) { 225 if (error) {
226 DPRINTF(("%s: SNDCTL_DSP_SPEED %d\n", 226 DPRINTF(("%s: SNDCTL_DSP_SPEED %d\n",
227 __func__, error)); 227 __func__, error));
228 goto out; 228 goto out;
229 } 229 }
230 tmpinfo.play.sample_rate = 230 tmpinfo.play.sample_rate =
231 tmpinfo.record.sample_rate = idat; 231 tmpinfo.record.sample_rate = idat;
232 DPRINTF(("%s: SNDCTL_DSP_SPEED > %d\n", __func__, idat)); 232 DPRINTF(("%s: SNDCTL_DSP_SPEED > %d\n", __func__, idat));
233 error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo); 233 /*
234 if (error) { 234 * The default NetBSD behavior if an unsupported sample rate
235 DPRINTF(("%s: SNDCTL_DSP_SPEED %d = %d\n", 235 * is set is to return an error code and keep the rate at the
236 __func__, idat, error)); 236 * default of 8000 Hz.
237 goto out; 237 *
 238 * However, the OSS expectation is a sample rate supported by
 239 * the hardware is returned if the exact rate could not be set.
 240 *
 241 * So, if the chosen sample rate is invalid, set and return
 242 * the current hardware rate.
 243 */
 244 if (ioctlf(fp, AUDIO_SETINFO, &tmpinfo) != 0) {
 245 error = ioctlf(fp, AUDIO_GETFORMAT, &hwfmt);
 246 if (error) {
 247 DPRINTF(("%s: AUDIO_GETFORMAT %d\n",
 248 __func__, error));
 249 goto out;
 250 }
 251 error = ioctlf(fp, AUDIO_GETINFO, &tmpinfo);
 252 if (error) {
 253 DPRINTF(("%s: AUDIO_GETINFO %d\n",
 254 __func__, error));
 255 goto out;
 256 }
 257 tmpinfo.play.sample_rate =
 258 tmpinfo.record.sample_rate =
 259 (tmpinfo.mode == AUMODE_RECORD) ?
 260 hwfmt.record.sample_rate :
 261 hwfmt.play.sample_rate;
 262 error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
 263 if (error) {
 264 DPRINTF(("%s: SNDCTL_DSP_SPEED %d = %d\n",
 265 __func__, idat, error));
 266 goto out;
 267 }
238 } 268 }
239 /* FALLTHROUGH */ 269 /* FALLTHROUGH */
240 case OSS_SOUND_PCM_READ_RATE: 270 case OSS_SOUND_PCM_READ_RATE:
241 error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); 271 error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
242 if (error) { 272 if (error) {
243 DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", 273 DPRINTF(("%s: AUDIO_GETBUFINFO %d\n",
244 __func__, error)); 274 __func__, error));
245 goto out; 275 goto out;
246 } 276 }
247 idat = GETPRINFO(&tmpinfo, sample_rate); 277 idat = GETPRINFO(&tmpinfo, sample_rate);
248 DPRINTF(("%s: SNDCTL_PCM_READ_RATE < %d\n", __func__, idat)); 278 DPRINTF(("%s: SNDCTL_PCM_READ_RATE < %d\n", __func__, idat));
249 error = copyout(&idat, SCARG(uap, data), sizeof idat); 279 error = copyout(&idat, SCARG(uap, data), sizeof idat);
250 if (error) { 280 if (error) {