1 /*- 2 * Copyright (c) 2020 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Nia Alarie. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/audioio.h> 31 #include <soundcard.h> 32 #include <fcntl.h> 33 #include <stdbool.h> 34 #include <stdio.h> 35 #include <math.h> 36 #include <atf-c.h> 37 38 ATF_TC(oss_dsp_init); 39 ATF_TC_HEAD(oss_dsp_init, tc) 40 { 41 atf_tc_set_md_var(tc, "descr", "Tests dsp init ioctls"); 42 } 43 44 ATF_TC_BODY(oss_dsp_init, tc) 45 { 46 struct audio_info hwinfo; 47 struct audio_info info; 48 int fd, channels, fmt, rate; 49 50 if ((fd = open("/dev/audio", O_WRONLY)) == -1) 51 atf_tc_skip("Audio device unavailable for playback"); 52 53 if (ioctl(fd, AUDIO_GETFORMAT, &hwinfo) < 0) { 54 atf_tc_fail("ioctl AUDIO_GETFORMAT failed"); 55 close(fd); 56 } 57 58 /* Verify SNDCTL_DSP_CHANNELS sets the device to mono. */ 59 60 channels = 1; 61 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) 62 atf_tc_fail("ioctl SNDCTL_DSP_CHANNELS (1) failed"); 63 ATF_REQUIRE_EQ(channels, 1); 64 65 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 66 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 67 ATF_REQUIRE_EQ(info.play.channels, 1); 68 69 /* Verify SNDCTL_DSP_CHANNELS sets the device to stereo. */ 70 71 channels = 2; 72 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) 73 atf_tc_fail("ioctl SNDCTL_DSP_CHANNELS (2) failed"); 74 ATF_REQUIRE_EQ(channels, 2); 75 76 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 77 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 78 ATF_REQUIRE_EQ(info.play.channels, 2); 79 80 /* 81 * Verify an invalid argument to SNDCTL_DSP_CHANNELS leaves the device 82 * at the hardware channel count. 83 */ 84 85 channels = 0; 86 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) 87 atf_tc_fail("ioctl SNDCTL_DSP_CHANNELS (0) failed"); 88 ATF_REQUIRE_EQ(channels, (int)hwinfo.play.channels); 89 90 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 91 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 92 ATF_REQUIRE_EQ(info.play.channels, hwinfo.play.channels); 93 94 /* 95 * SNDCTL_DSP_STEREO is an older alternative to SNDCTL_DSP_CHANNELS 96 * that simply takes a boolean argument. 97 */ 98 99 /* Set the device to mono with SNDCTL_DSP_STEREO = 0 */ 100 101 channels = 0; 102 if (ioctl(fd, SNDCTL_DSP_STEREO, &channels) < 0) 103 atf_tc_fail("ioctl SNDCTL_DSP_STEREO (0) failed"); 104 ATF_REQUIRE_EQ(channels, 0); 105 106 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 107 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 108 109 ATF_REQUIRE_EQ(info.play.channels, 1); 110 111 /* Set the device to stereo with SNDCTL_DSP_STEREO = 1 */ 112 113 channels = 1; 114 if (ioctl(fd, SNDCTL_DSP_STEREO, &channels) < 0) 115 atf_tc_fail("ioctl SNDCTL_DSP_STEREO (1) failed"); 116 ATF_REQUIRE_EQ(channels, 1); 117 118 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 119 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 120 ATF_REQUIRE_EQ(info.play.channels, 2); 121 122 /* Verify SNDCTL_DSP_SETFMT works with common audio formats */ 123 124 fmt = AFMT_MU_LAW; 125 if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) < 0) 126 atf_tc_fail("ioctl SNDCTL_DSP_SETFMT (AFMT_MU_LAW) failed"); 127 ATF_REQUIRE_EQ(fmt, AFMT_MU_LAW); 128 129 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 130 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 131 ATF_REQUIRE_EQ(info.play.encoding, AUDIO_ENCODING_ULAW); 132 ATF_REQUIRE_EQ(info.play.precision, 8); 133 134 fmt = AFMT_A_LAW; 135 if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) < 0) 136 atf_tc_fail("ioctl SNDCTL_DSP_SETFMT (AFMT_A_LAW) failed"); 137 ATF_REQUIRE_EQ(fmt, AFMT_A_LAW); 138 139 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 140 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 141 ATF_REQUIRE_EQ(info.play.encoding, AUDIO_ENCODING_ALAW); 142 ATF_REQUIRE_EQ(info.play.precision, 8); 143 144 fmt = AFMT_S16_LE; 145 if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) < 0) 146 atf_tc_fail("ioctl SNDCTL_DSP_SETFMT (AFMT_S16_LE) failed"); 147 ATF_REQUIRE_EQ(fmt, AFMT_S16_LE); 148 149 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 150 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 151 ATF_REQUIRE_EQ(info.play.encoding, AUDIO_ENCODING_SLINEAR_LE); 152 ATF_REQUIRE_EQ(info.play.precision, 16); 153 154 fmt = AFMT_S16_BE; 155 if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) < 0) 156 atf_tc_fail("ioctl SNDCTL_DSP_SETFMT (AFMT_S16_BE) failed"); 157 ATF_REQUIRE_EQ(fmt, AFMT_S16_BE); 158 159 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 160 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 161 ATF_REQUIRE_EQ(info.play.encoding, AUDIO_ENCODING_SLINEAR_BE); 162 ATF_REQUIRE_EQ(info.play.precision, 16); 163 164 fmt = AFMT_U16_LE; 165 if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) < 0) 166 atf_tc_fail("ioctl SNDCTL_DSP_SETFMT (AFMT_U16_LE) failed"); 167 ATF_REQUIRE_EQ(fmt, AFMT_U16_LE); 168 169 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 170 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 171 ATF_REQUIRE_EQ(info.play.encoding, AUDIO_ENCODING_ULINEAR_LE); 172 ATF_REQUIRE_EQ(info.play.precision, 16); 173 174 fmt = AFMT_U16_BE; 175 if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) < 0) 176 atf_tc_fail("ioctl SNDCTL_DSP_SETFMT (AFMT_U16_BE) failed"); 177 ATF_REQUIRE_EQ(fmt, AFMT_U16_BE); 178 179 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 180 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 181 ATF_REQUIRE_EQ(info.play.encoding, AUDIO_ENCODING_ULINEAR_BE); 182 ATF_REQUIRE_EQ(info.play.precision, 16); 183 184 fmt = AFMT_S32_LE; 185 if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) < 0) 186 atf_tc_fail("ioctl SNDCTL_DSP_SETFMT (AFMT_S32_LE) failed"); 187 ATF_REQUIRE_EQ(fmt, AFMT_S32_LE); 188 189 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 190 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 191 ATF_REQUIRE_EQ(info.play.encoding, AUDIO_ENCODING_SLINEAR_LE); 192 ATF_REQUIRE_EQ(info.play.precision, 32); 193 194 /* Verify some supported sample rates. */ 195 196 rate = 8000; 197 if (ioctl(fd, SNDCTL_DSP_SPEED, &rate) < 0) 198 atf_tc_fail("ioctl SNDCTL_DSP_SPEED (8000) failed"); 199 200 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 201 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 202 ATF_REQUIRE_EQ(rate, (int)info.play.sample_rate); 203 204 rate = 32000; 205 if (ioctl(fd, SNDCTL_DSP_SPEED, &rate) < 0) 206 atf_tc_fail("ioctl SNDCTL_DSP_SPEED (32000) failed"); 207 208 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 209 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 210 ATF_REQUIRE_EQ(info.play.sample_rate, 32000); 211 ATF_REQUIRE_EQ(rate, (int)info.play.sample_rate); 212 213 rate = 44100; 214 if (ioctl(fd, SNDCTL_DSP_SPEED, &rate) < 0) 215 atf_tc_fail("ioctl SNDCTL_DSP_SPEED (44100) failed"); 216 217 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 218 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 219 ATF_REQUIRE_EQ(info.play.sample_rate, 44100); 220 ATF_REQUIRE_EQ(rate, (int)info.play.sample_rate); 221 222 rate = 48000; 223 if (ioctl(fd, SNDCTL_DSP_SPEED, &rate) < 0) 224 atf_tc_fail("ioctl SNDCTL_DSP_SPEED (48000) failed"); 225 226 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 227 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 228 ATF_REQUIRE_EQ(info.play.sample_rate, 48000); 229 ATF_REQUIRE_EQ(rate, (int)info.play.sample_rate); 230 231 rate = 96000; 232 if (ioctl(fd, SNDCTL_DSP_SPEED, &rate) < 0) 233 atf_tc_fail("ioctl SNDCTL_DSP_SPEED (96000) failed"); 234 235 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 236 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 237 ATF_REQUIRE_EQ(info.play.sample_rate, 96000); 238 ATF_REQUIRE_EQ(rate, (int)info.play.sample_rate); 239 240 rate = 192000; 241 if (ioctl(fd, SNDCTL_DSP_SPEED, &rate) < 0) 242 atf_tc_fail("ioctl SNDCTL_DSP_SPEED (192000) failed"); 243 244 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 245 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 246 ATF_REQUIRE_EQ(info.play.sample_rate, 192000); 247 ATF_REQUIRE_EQ(rate, (int)info.play.sample_rate); 248 249 /* 250 * and some unsupported sample rates... "best effort" 251 */ 252 253 /* closest supported rate is 1000 */ 254 rate = 900; 255 if (ioctl(fd, SNDCTL_DSP_SPEED, &rate) < 0) 256 atf_tc_fail("ioctl SNDCTL_DSP_SPEED (900) failed"); 257 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 258 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 259 ATF_REQUIRE((fabs(900.0 - info.play.sample_rate) / 900.0) < 0.2); 260 ATF_REQUIRE_EQ(rate, (int)info.play.sample_rate); 261 262 /* closest supported rate is 192000 */ 263 rate = 197000; 264 if (ioctl(fd, SNDCTL_DSP_SPEED, &rate) < 0) 265 atf_tc_fail("ioctl SNDCTL_DSP_SPEED (197000) failed"); 266 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 267 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 268 ATF_REQUIRE((fabs(197000.0 - info.play.sample_rate) / 197000.0) < 0.2); 269 ATF_REQUIRE_EQ(rate, (int)info.play.sample_rate); 270 271 /* 0 should return the hardware rate. */ 272 273 rate = 0; 274 if (ioctl(fd, SNDCTL_DSP_SPEED, &rate) < 0) 275 atf_tc_fail("ioctl SNDCTL_DSP_SPEED (0) failed"); 276 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 277 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 278 ATF_REQUIRE_EQ(hwinfo.play.sample_rate, info.play.sample_rate); 279 280 close(fd); 281 } 282 283 ATF_TC(oss_dsp_trigger_read); 284 ATF_TC_HEAD(oss_dsp_trigger_read, tc) 285 { 286 atf_tc_set_md_var(tc, "descr", "Tests SNDCTL_DSP_SETTRIGGER correctly " 287 "changes the recording pause state"); 288 } 289 290 ATF_TC_BODY(oss_dsp_trigger_read, tc) 291 { 292 struct audio_info info; 293 int fd, bits; 294 295 #if defined(__sparc__) 296 atf_tc_skip("PR port-sparc/55876"); 297 #endif 298 299 if ((fd = open("/dev/audio", O_RDONLY)) == -1) 300 atf_tc_skip("Audio device unavailable for recording"); 301 302 /* pause everything ... */ 303 304 bits = 0; 305 if (ioctl(fd, SNDCTL_DSP_SETTRIGGER, &bits) < 0) 306 atf_tc_fail("ioctl SNDCTL_DSP_SETTRIGGER (0) failed"); 307 308 if (ioctl(fd, SNDCTL_DSP_GETTRIGGER, &bits) < 0) 309 atf_tc_fail("ioctl SNDCTL_DSP_GETTRIGGER failed"); 310 ATF_REQUIRE_EQ(bits, 0); 311 312 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 313 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 314 315 ATF_REQUIRE_EQ(info.record.pause, 1); 316 317 /* unpause everything ... */ 318 319 bits = PCM_ENABLE_INPUT; 320 if (ioctl(fd, SNDCTL_DSP_SETTRIGGER, &bits) < 0) 321 atf_tc_fail("ioctl SNDCTL_DSP_SETTRIGGER " 322 "(PCM_ENABLE_INPUT) failed"); 323 324 if (ioctl(fd, SNDCTL_DSP_GETTRIGGER, &bits) < 0) 325 atf_tc_fail("ioctl SNDCTL_DSP_GETTRIGGER failed"); 326 ATF_REQUIRE_EQ(bits, PCM_ENABLE_INPUT); 327 328 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 329 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 330 331 ATF_REQUIRE_EQ(info.record.pause, 0); 332 333 close(fd); 334 } 335 336 ATF_TC(oss_dsp_trigger_write); 337 ATF_TC_HEAD(oss_dsp_trigger_write, tc) 338 { 339 atf_tc_set_md_var(tc, "descr", "Tests SNDCTL_DSP_SETTRIGGER correctly " 340 "changes the playback pause state"); 341 } 342 343 ATF_TC_BODY(oss_dsp_trigger_write, tc) 344 { 345 struct audio_info info; 346 int fd, bits; 347 348 if ((fd = open("/dev/audio", O_WRONLY)) == -1) 349 atf_tc_skip("Audio device unavailable for playback"); 350 351 /* pause everything ... */ 352 353 bits = 0; 354 if (ioctl(fd, SNDCTL_DSP_SETTRIGGER, &bits) < 0) 355 atf_tc_fail("ioctl SNDCTL_DSP_SETTRIGGER (0) failed"); 356 357 if (ioctl(fd, SNDCTL_DSP_GETTRIGGER, &bits) < 0) 358 atf_tc_fail("ioctl SNDCTL_DSP_GETTRIGGER failed"); 359 ATF_REQUIRE_EQ(bits, 0); 360 361 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 362 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 363 364 ATF_REQUIRE_EQ(info.play.pause, 1); 365 366 /* unpause everything ... */ 367 368 bits = PCM_ENABLE_OUTPUT; 369 if (ioctl(fd, SNDCTL_DSP_SETTRIGGER, &bits) < 0) 370 atf_tc_fail("ioctl SNDCTL_DSP_SETTRIGGER " 371 "(PCM_ENABLE_OUTPUT) failed"); 372 373 if (ioctl(fd, SNDCTL_DSP_GETTRIGGER, &bits) < 0) 374 atf_tc_fail("ioctl SNDCTL_DSP_GETTRIGGER failed"); 375 ATF_REQUIRE_EQ(bits, PCM_ENABLE_OUTPUT); 376 377 if (ioctl(fd, AUDIO_GETBUFINFO, &info) < 0) 378 atf_tc_fail("ioctl AUDIO_GETBUFINFO failed"); 379 380 ATF_REQUIRE_EQ(info.play.pause, 0); 381 382 close(fd); 383 } 384 385 ATF_TC(oss_dsp_caps); 386 ATF_TC_HEAD(oss_dsp_caps, tc) 387 { 388 atf_tc_set_md_var(tc, "descr", "Verifies that OSS device capabilities " 389 "are the same as native capabilities"); 390 } 391 392 ATF_TC_BODY(oss_dsp_caps, tc) 393 { 394 unsigned i; 395 char dev[16]; 396 bool dev_tested = false; 397 int fd; 398 int caps, props, fmts; 399 400 for (i = 0; i < 16; ++i) { 401 (void)snprintf(dev, sizeof(dev), "/dev/audio%u", i); 402 403 if ((fd = open(dev, O_WRONLY)) == -1) { 404 if ((fd = open(dev, O_RDONLY)) == -1) 405 break; 406 } 407 408 if (ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) < 0) 409 atf_tc_fail("ioctl SNDCTL_DSP_GETCAPS failed"); 410 411 if (ioctl(fd, AUDIO_GETPROPS, &props) < 0) 412 atf_tc_fail("ioctl AUDIO_GETPROPS failed"); 413 414 ATF_REQUIRE(!(caps & DSP_CAP_DUPLEX) == 415 !(props & AUDIO_PROP_FULLDUPLEX)); 416 417 ATF_REQUIRE(!(caps & DSP_CAP_MMAP) == 418 !(props & AUDIO_PROP_MMAP)); 419 420 ATF_REQUIRE(!(caps & DSP_CAP_INPUT) == 421 !(props & AUDIO_PROP_CAPTURE)); 422 423 ATF_REQUIRE(!(caps & DSP_CAP_OUTPUT) == 424 !(props & AUDIO_PROP_PLAYBACK)); 425 426 /* Trigger is always supported in this implementation. */ 427 ATF_REQUIRE(caps & DSP_CAP_TRIGGER); 428 429 if (ioctl(fd, SNDCTL_DSP_GETFMTS, &fmts) < 0) 430 atf_tc_fail("ioctl SNDCTL_DSP_GETFMTS failed"); 431 432 /* All supported by the kernel mixer. */ 433 ATF_REQUIRE(fmts & AFMT_MU_LAW); 434 ATF_REQUIRE(fmts & AFMT_A_LAW); 435 ATF_REQUIRE(fmts & AFMT_S8); 436 ATF_REQUIRE(fmts & AFMT_U8); 437 ATF_REQUIRE(fmts & AFMT_S16_LE); 438 ATF_REQUIRE(fmts & AFMT_S16_BE); 439 ATF_REQUIRE(fmts & AFMT_U16_LE); 440 ATF_REQUIRE(fmts & AFMT_U16_BE); 441 ATF_REQUIRE(fmts & AFMT_S32_LE); 442 ATF_REQUIRE(fmts & AFMT_S32_BE); 443 444 /* Sanity test... */ 445 ATF_REQUIRE_EQ(fmts & AFMT_MPEG, 0); 446 447 close(fd); 448 449 dev_tested = true; 450 } 451 452 if (!dev_tested) 453 atf_tc_skip("No testable audio device available"); 454 } 455 456 ATF_TP_ADD_TCS(tp) 457 { 458 ATF_TP_ADD_TC(tp, oss_dsp_init); 459 ATF_TP_ADD_TC(tp, oss_dsp_caps); 460 ATF_TP_ADD_TC(tp, oss_dsp_trigger_read); 461 ATF_TP_ADD_TC(tp, oss_dsp_trigger_write); 462 463 return atf_no_error(); 464 } 465 466