Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F168979859
D53188.id164551.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D53188.id164551.diff
View Options
diff --git a/tests/sys/sound/Makefile b/tests/sys/sound/Makefile
--- a/tests/sys/sound/Makefile
+++ b/tests/sys/sound/Makefile
@@ -3,11 +3,13 @@
TESTSDIR= ${TESTSBASE}/sys/sound
ATF_TESTS_C+= pcm_read_write
+ATF_TESTS_C+= polling
ATF_TESTS_C+= sndstat
CFLAGS+= -I${SRCTOP}/sys
LDFLAGS+= -lnv
CFLAGS.pcm_read_write.c+= -Wno-cast-align
+CFLAGS.polling.c+= -Wno-cast-align
.include <bsd.test.mk>
diff --git a/tests/sys/sound/oss.h b/tests/sys/sound/oss.h
new file mode 100644
--- /dev/null
+++ b/tests/sys/sound/oss.h
@@ -0,0 +1,156 @@
+#include <sys/soundcard.h>
+
+#include <fcntl.h>
+#include <err.h>
+
+typedef int32_t sample_t;
+
+typedef struct config {
+ const char *device;
+ int channels;
+ int fd;
+ int format;
+ int frag;
+ int sample_count;
+ int sample_rate;
+ int sample_size;
+ int chsamples;
+ int mmap;
+ int caps;
+ void *mbuf;
+ oss_audioinfo audio_info;
+ audio_buf_info buffer_info;
+} config_t;
+
+void
+oss_init(config_t *config);
+
+static inline void
+check_error(const int value, const char *message)
+{
+ if (value == -1)
+ err(1, "OSS error: %s\n", message);
+}
+
+static inline int
+size2frag(int x)
+{
+ int frag = 0;
+
+ while ((1 << frag) < x)
+ ++frag;
+
+ return (frag);
+}
+
+void
+oss_init(config_t *config)
+{
+ int error, tmp, min_frag;
+
+ /* Open the device for read and write */
+ config->fd = open(config->device, O_RDWR);
+ check_error(config->fd, "open");
+
+ /* Get device information */
+ config->audio_info.dev = -1;
+ error = ioctl(config->fd, SNDCTL_ENGINEINFO, &(config->audio_info));
+ check_error(error, "SNDCTL_ENGINEINFO");
+ if (config->audio_info.min_rate > config->sample_rate ||
+ config->sample_rate > config->audio_info.max_rate) {
+ errx(1, "%s doesn't support chosen samplerate of %dHz!\n",
+ config->device, config->sample_rate);
+ }
+ if (config->channels < 1)
+ config->channels = config->audio_info.max_channels;
+
+ /*
+ * If device is going to be used in mmap mode, disable all format
+ * conversions. Official OSS documentation states error code should not
+ * be checked.
+ * http://manuals.opensound.com/developer/mmap_test.c.html#LOC10
+ */
+ if (config->mmap) {
+ tmp = 0;
+ ioctl(config->fd, SNDCTL_DSP_COOKEDMODE, &tmp);
+ }
+
+ /*
+ * Set number of channels. If number of channels is chosen to the value
+ * near the one wanted, save it in config
+ */
+ tmp = config->channels;
+ error = ioctl(config->fd, SNDCTL_DSP_CHANNELS, &tmp);
+ check_error(error, "SNDCTL_DSP_CHANNELS");
+ /* Or check if tmp is close enough? */
+ if (tmp != config->channels) {
+ errx(1, "%s doesn't support chosen channel count of %d set "
+ "to %d!\n", config->device, config->channels, tmp);
+ }
+ config->channels = tmp;
+
+ /* Set format, or bit size: 8, 16, 24 or 32 bit sample */
+ tmp = config->format;
+ error = ioctl(config->fd, SNDCTL_DSP_SETFMT, &tmp);
+ check_error(error, "SNDCTL_DSP_SETFMT");
+ if (tmp != config->format) {
+ errx(1, "%s doesn't support chosen sample format!\n",
+ config->device);
+ }
+
+ /* Most common values for samplerate (in kHz): 44.1, 48, 88.2, 96 */
+ tmp = config->sample_rate;
+ error = ioctl(config->fd, SNDCTL_DSP_SPEED, &tmp);
+ check_error(error, "SNDCTL_DSP_SPEED");
+
+ /* Get and check device capabilities */
+ error = ioctl(config->fd, SNDCTL_DSP_GETCAPS, &(config->audio_info.caps));
+ check_error(error, "SNDCTL_DSP_GETCAPS");
+ if (!(config->audio_info.caps & PCM_CAP_DUPLEX))
+ errx(1, "Device doesn't support full duplex!\n");
+
+ if (config->mmap) {
+ if (!(config->audio_info.caps & PCM_CAP_TRIGGER))
+ errx(1, "Device doesn't support triggering!\n");
+ if (!(config->audio_info.caps & PCM_CAP_MMAP))
+ errx(1, "Device doesn't support mmap mode!\n");
+ }
+
+ /*
+ * If desired frag is smaller than minimum, based on number of channels
+ * and format (size in bits: 8, 16, 24, 32), set that as frag. Buffer
+ * size is 2^frag, but the real size of the buffer will be read when
+ * the configuration of the device is successful
+ */
+ min_frag = size2frag(config->sample_size * config->channels);
+
+ if (config->frag < min_frag)
+ config->frag = min_frag;
+
+ /*
+ * Allocate buffer in fragments. Total buffer will be split in number
+ * of fragments (2 by default)
+ */
+ if (config->buffer_info.fragments < 0)
+ config->buffer_info.fragments = 2;
+ tmp = ((config->buffer_info.fragments) << 16) | config->frag;
+ error = ioctl(config->fd, SNDCTL_DSP_SETFRAGMENT, &tmp);
+ check_error(error, "SNDCTL_DSP_SETFRAGMENT");
+
+ /* When all is set and ready to go, get the size of buffer */
+ error = ioctl(config->fd, SNDCTL_DSP_GETOSPACE, &(config->buffer_info));
+ check_error(error, "SNDCTL_DSP_GETOSPACE");
+ if (config->buffer_info.bytes < 1) {
+ errx(1, "OSS buffer error: buffer size can not be %d\n",
+ config->buffer_info.bytes);
+ }
+ config->sample_count = config->buffer_info.bytes / config->sample_size;
+ config->chsamples = config->sample_count / config->channels;
+
+ /* Get device capabilities */
+ tmp = config->caps;
+ if (ioctl(config->fd, SNDCTL_DSP_GETCAPS, &tmp) == 0)
+ config->caps = tmp;
+ else
+ config->caps = 0;
+}
diff --git a/tests/sys/sound/polling.c b/tests/sys/sound/polling.c
new file mode 100644
--- /dev/null
+++ b/tests/sys/sound/polling.c
@@ -0,0 +1,216 @@
+/*-
+ * Copyright (c) 2025 Goran Mekić
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/event.h>
+#include <sys/mman.h>
+#include "oss.h"
+
+#include <atf-c.h>
+
+#include <poll.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static int format = AFMT_S32_NE;
+
+static void
+oss_split(config_t *config, sample_t *input, sample_t *output)
+{
+ int channel, index, i;
+
+ for (i = 0; i < config->sample_count; ++i) {
+ channel = i % config->channels;
+ index = i / config->channels;
+ output[channel * index] = input[i];
+ }
+}
+
+static void
+oss_merge(config_t *config, sample_t *input, sample_t *output)
+{
+ int channel, index;
+
+ for (channel = 0; channel < config->channels; ++channel) {
+ for (index = 0; index < config->chsamples; ++index) {
+ output[index * config->channels + channel] =
+ input[channel * index];
+ }
+ }
+}
+
+static int
+process_audio(config_t *config, int8_t *ibuf, int8_t *obuf, sample_t *channels, int bytes)
+{
+ int ret;
+
+ ret = read(config->fd, ibuf, bytes);
+ if (ret < bytes) {
+ return (1);
+ }
+ oss_split(config, (sample_t *)ibuf, channels);
+ /* All processing will happen here */
+ oss_merge(config, channels, (sample_t *)obuf);
+ ret = write(config->fd, obuf, bytes);
+ if (ret < bytes) {
+ return (1);
+ }
+ return (0);
+}
+
+ATF_TC(poll_kqueue);
+ATF_TC_HEAD(poll_kqueue, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test DSP polling via kqueue(2)");
+ atf_tc_set_md_var(tc, "require.kmods", "snd_dummy");
+}
+
+ATF_TC_BODY(poll_kqueue, tc)
+{
+ int i, rc, kq, bytes;
+ int8_t *ibuf, *obuf;
+ sample_t *channels;
+ struct kevent event = {};
+ config_t config = {
+ .device = "/dev/dsp",
+ .channels = -1,
+ .format = format,
+ .frag = -1,
+ .sample_rate = 48000,
+ .sample_size = sizeof(sample_t),
+ .buffer_info.fragments = -1,
+ .mmap = 0,
+ .caps = 0,
+ };
+
+ oss_init(&config);
+ bytes = config.buffer_info.bytes;
+
+ /*
+ * Allocate input and output buffers so that their size match frag_size
+ */
+ ibuf = malloc(bytes);
+ obuf = malloc(bytes);
+ channels = malloc(bytes);
+
+ kq = kqueue();
+ ATF_REQUIRE(kq != -1);
+ EV_SET(&event, config.fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0, 0);
+ rc = kevent(kq, &event, 1, 0, 0, 0);
+ ATF_REQUIRE(rc != -1);
+ for (i = 0; i < 10; ++i) {
+ rc = kevent(kq, 0, 0, &event, 1, 0);
+ ATF_REQUIRE(rc != -1);
+ ATF_REQUIRE(event.data != 0);
+ ATF_REQUIRE((event.flags & EV_ERROR) == 0);
+ rc = process_audio(&config, ibuf, obuf, channels, bytes);
+ ATF_REQUIRE(rc == 0);
+ }
+ close(kq);
+ free(channels);
+ free(obuf);
+ free(ibuf);
+ close(config.fd);
+}
+
+ATF_TC(poll_poll);
+ATF_TC_HEAD(poll_poll, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test DSP polling via poll(2)");
+ atf_tc_set_md_var(tc, "require.kmods", "snd_dummy");
+}
+
+ATF_TC_BODY(poll_poll, tc)
+{
+ struct pollfd pfds[1];
+ int i, rc, bytes;
+ int8_t *ibuf, *obuf;
+ sample_t *channels;
+ config_t config = {
+ .device = "/dev/dsp",
+ .channels = -1,
+ .format = format,
+ .frag = -1,
+ .sample_rate = 48000,
+ .sample_size = sizeof(sample_t),
+ .buffer_info.fragments = -1,
+ .mmap = 0,
+ .caps = 0,
+ };
+
+ oss_init(&config);
+ bytes = config.buffer_info.bytes;
+ ibuf = malloc(bytes);
+ obuf = malloc(bytes);
+ channels = malloc(bytes);
+
+ for (i = 0; i < 10; ++i) {
+ pfds[0].fd = config.fd;
+ pfds[0].events = POLLIN;
+ rc = poll(pfds, sizeof(pfds) / sizeof(struct pollfd), -1);
+ ATF_REQUIRE(rc != -1);
+ if (pfds[0].revents != 0) {
+ rc = process_audio(&config, ibuf, obuf, channels, bytes);
+ ATF_REQUIRE(rc != -1);
+ }
+ }
+}
+
+ATF_TC(poll_select);
+ATF_TC_HEAD(poll_select, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test DSP polling via select(2)");
+ atf_tc_set_md_var(tc, "require.kmods", "snd_dummy");
+}
+
+ATF_TC_BODY(poll_select, tc)
+{
+ fd_set fds;
+ int i, rc, bytes;
+ int8_t *ibuf, *obuf;
+ sample_t *channels;
+ config_t config = {
+ .device = "/dev/dsp",
+ .channels = -1,
+ .format = format,
+ .frag = -1,
+ .sample_rate = 48000,
+ .sample_size = sizeof(sample_t),
+ .buffer_info.fragments = -1,
+ .mmap = 0,
+ .caps = 0,
+ };
+
+ oss_init(&config);
+ bytes = config.buffer_info.bytes;
+ ibuf = malloc(bytes);
+ obuf = malloc(bytes);
+ channels = malloc(bytes);
+
+ for (i = 0; i < 10; ++i) {
+ FD_ZERO(&fds);
+ FD_SET(config.fd, &fds);
+ rc = select(config.fd + 1, &fds, NULL, NULL, NULL);
+ ATF_REQUIRE(rc >= 0);
+ if (FD_ISSET(config.fd, &fds)) {
+ rc = process_audio(&config, ibuf, obuf, channels, bytes);
+ ATF_REQUIRE(rc == 0);
+ }
+ }
+
+ free(channels);
+ free(obuf);
+ free(ibuf);
+ close(config.fd);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, poll_kqueue);
+ ATF_TP_ADD_TC(tp, poll_poll);
+ ATF_TP_ADD_TC(tp, poll_select);
+
+ return (atf_no_error());
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Sep 1, 1:13 AM (9 h, 1 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37739786
Default Alt Text
D53188.id164551.diff (9 KB)
Attached To
Mode
D53188: sound tests: Test polling
Attached
Detach File
Event Timeline
Log In to Comment