Page MenuHomeFreeBSD

D53029.id164047.diff
No OneTemporary

D53029.id164047.diff

diff --git a/share/examples/sound/oss/audio.c b/share/examples/sound/oss/audio.c
--- a/share/examples/sound/oss/audio.c
+++ b/share/examples/sound/oss/audio.c
@@ -32,15 +32,21 @@
#include <sys/soundcard.h>
#include <err.h>
-#include <errno.h>
#include <fcntl.h>
+#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <sys/event.h>
+
+#define EXAMPLE_LOOP 0
+#define EXAMPLE_SELECT 1
+#define EXAMPLE_POLL 2
+#define EXAMPLE_KQUEUE 3
#ifndef SAMPLE_SIZE
-#define SAMPLE_SIZE 16
+#define SAMPLE_SIZE 32
#endif
/* Format can be unsigned, in which case replace S with U */
@@ -248,11 +254,33 @@
config->chsamples = config->sample_count / config->channels;
}
+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) {
+ fprintf(stderr, "Requested %d bytes, but read %d!\n", bytes, ret);
+ 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) {
+ fprintf(stderr, "Requested %d bytes, but wrote %d!\n", bytes, ret);
+ return (1);
+ }
+ return (0);
+}
+
int
main(int argc, char *argv[])
{
- int ret, bytes;
+ int fd, ret, bytes, example;
int8_t *ibuf, *obuf;
+ sample_t *channels;
config_t config = {
.device = "/dev/dsp",
.channels = -1,
@@ -264,16 +292,30 @@
.mmap = 0,
};
+ if (argc != 2)
+ errx(1, "Usage: %s <example>", argv[0]);
+
+ if (strcmp(argv[1], "loop") == 0)
+ example = EXAMPLE_LOOP;
+ else if (strcmp(argv[1], "select") == 0)
+ example = EXAMPLE_SELECT;
+ else if (strcmp(argv[1], "poll") == 0)
+ example = EXAMPLE_POLL;
+ else if (strcmp(argv[1], "kqueue") == 0)
+ example = EXAMPLE_KQUEUE;
+ else
+ errx(1, "Unknown example: %s", argv[1]);
+
/* Initialize device */
oss_init(&config);
+ bytes = config.buffer_info.bytes;
/*
* Allocate input and output buffers so that their size match frag_size
*/
- bytes = config.buffer_info.bytes;
ibuf = malloc(bytes);
obuf = malloc(bytes);
- sample_t *channels = malloc(bytes);
+ channels = malloc(bytes);
printf("bytes: %d, fragments: %d, fragsize: %d, fragstotal: %d, "
"samples: %d\n",
@@ -281,24 +323,60 @@
config.buffer_info.fragsize, config.buffer_info.fragstotal,
config.sample_count);
- /* Minimal engine: read input and copy it to the output */
- for (;;) {
- ret = read(config.fd, ibuf, bytes);
- if (ret < bytes) {
- fprintf(stderr, "Requested %d bytes, but read %d!\n",
- bytes, ret);
- break;
+ if (example == EXAMPLE_LOOP) {
+ for (;;) {
+ printf("Loop processing\n");
+ if (process_audio(&config, ibuf, obuf, channels, bytes) != 0)
+ break;
}
- 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) {
- fprintf(stderr, "Requested %d bytes, but wrote %d!\n",
- bytes, ret);
- break;
+ } else if (example == EXAMPLE_SELECT) {
+ fd_set fds;
+
+ for (;;) {
+ printf("Select processing\n");
+ FD_ZERO(&fds);
+ FD_SET(config.fd, &fds);
+ ret = select(config.fd + 1, &fds, NULL, NULL, NULL);
+ if (FD_ISSET(config.fd, &fds))
+ if (process_audio(&config, ibuf, obuf, channels, bytes) != 0)
+ break;
}
- }
+ } else if (example == EXAMPLE_POLL) {
+ struct pollfd pfds[1];
+
+ for (;;) {
+ printf("Poll processing\n");
+ pfds[0].fd = config.fd;
+ pfds[0].events = POLLIN;
+ ret = poll(pfds, sizeof(pfds) / sizeof(struct pollfd), -1);
+ if (pfds[0].revents != 0)
+ if (process_audio(&config, ibuf, obuf, channels, bytes) != 0)
+ break;
+ }
+ } else if (example == EXAMPLE_KQUEUE) {
+ int kq;
+ struct kevent event = {};
+
+ kq = kqueue();
+ if (kq == -1)
+ errx(1, "Failed to allocate kqueue");
+ EV_SET(&event, fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0, 0);
+ ret = kevent(kq, &event, 1, 0, 0, 0);
+ if (ret == -1)
+ errx(1, "Failed to register kevent");
+ for (;;) {
+ printf("Kqueue processing\n");
+ ret = kevent(kq, 0, 0, &event, 1, 0);
+ if (ret == -1 || event.data == 0)
+ break;
+ if (event.flags & EV_ERROR)
+ errx(1, "Event error: %s", strerror(event.data));
+ if (process_audio(&config, ibuf, obuf, channels, bytes) != 0)
+ break;
+ }
+ close(kq);
+ } else
+ errx(1, "Unknown example id: %d", example);
/* Cleanup */
free(channels);
diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c
--- a/sys/dev/sound/pcm/channel.c
+++ b/sys/dev/sound/pcm/channel.c
@@ -313,8 +313,10 @@
bs = c->bufsoft;
if (CHN_EMPTY(c, children.busy)) {
- if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c))
+ if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c)) {
selwakeuppri(sndbuf_getsel(bs), PRIBIO);
+ KNOTE_LOCKED(&bs->sel.si_note, 0);
+ }
CHN_BROADCAST(&c->intr_cv);
} else {
CHN_FOREACH(ch, c, children.busy) {
diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -81,6 +81,7 @@
static d_poll_t dsp_poll;
static d_mmap_t dsp_mmap;
static d_mmap_single_t dsp_mmap_single;
+static d_kqfilter_t dsp_kqfilter;
struct cdevsw dsp_cdevsw = {
.d_version = D_VERSION,
@@ -89,6 +90,7 @@
.d_write = dsp_write,
.d_ioctl = dsp_ioctl,
.d_poll = dsp_poll,
+ .d_kqfilter = dsp_kqfilter,
.d_mmap = dsp_mmap,
.d_mmap_single = dsp_mmap_single,
.d_name = "dsp",
@@ -235,6 +237,7 @@
chn_vpc_reset(*ch, SND_VOL_C_PCM, 0);
CHN_UNLOCK(*ch);
+ knlist_init_mtx(&(*ch)->bufsoft->sel.si_note, (*ch)->lock);
return (0);
}
@@ -264,10 +267,16 @@
rdch = priv->rdch;
wrch = priv->wrch;
- if (rdch != NULL)
+ if (rdch != NULL) {
+ knlist_clear(&rdch->bufsoft->sel.si_note, 0);
+ knlist_destroy(&rdch->bufsoft->sel.si_note);
CHN_REMOVE(d, rdch, channels.pcm.opened);
- if (wrch != NULL)
+ }
+ if (wrch != NULL) {
+ knlist_clear(&wrch->bufsoft->sel.si_note, 0);
+ knlist_destroy(&wrch->bufsoft->sel.si_note);
CHN_REMOVE(d, wrch, channels.pcm.opened);
+ }
if (rdch != NULL || wrch != NULL) {
PCM_UNLOCK(d);
@@ -2962,6 +2971,141 @@
return (ret);
}
+static void
+dsp_kqdetach(struct knote *kn)
+{
+ struct dsp_cdevpriv *priv;
+ struct snddev_info *d;
+ struct pcm_channel *ch = kn->kn_hook;
+ struct snd_dbuf *bs;
+
+ if (devfs_get_cdevpriv((void **)&priv) != 0)
+ return;
+ d = priv->sc;
+ if (!DSP_REGISTERED(d))
+ return;
+ PCM_GIANT_ENTER(d);
+ dsp_lock_chans(priv, FREAD | FWRITE);
+ if (ch != NULL && !(ch->flags & CHN_F_DEAD)) {
+ bs = ch->bufsoft;
+ knlist_remove(&bs->sel.si_note, kn, 1);
+ }
+ dsp_unlock_chans(priv, FREAD | FWRITE);
+ PCM_GIANT_LEAVE(d);
+}
+
+static int
+dsp_read_filter(struct knote *kn, long hint)
+{
+ struct dsp_cdevpriv *priv;
+ struct snddev_info *d;
+ struct pcm_channel *ch = kn->kn_hook;
+ int err;
+
+ if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
+ return (err);
+ d = priv->sc;
+ if (!DSP_REGISTERED(d)) {
+ kn->kn_data = EBADF;
+ kn->kn_flags |= EV_ERROR;
+ return (1);
+ }
+ PCM_GIANT_ENTER(d);
+ dsp_lock_chans(priv, FREAD);
+ if (ch != NULL && !(ch->flags & CHN_F_DEAD))
+ kn->kn_data = sndbuf_getready(bs);
+ else
+ kn->kn_data = 0;
+ dsp_unlock_chans(priv, FREAD);
+ PCM_GIANT_LEAVE(d);
+ return (kn->kn_data > 0);
+}
+
+static int
+dsp_write_filter(struct knote *kn, long hint)
+{
+ struct dsp_cdevpriv *priv;
+ struct snddev_info *d;
+ struct pcm_channel *ch = kn->kn_hook;
+ int err;
+
+ if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
+ return (err);
+ d = priv->sc;
+ if (!DSP_REGISTERED(d)) {
+ kn->kn_data = EBADF;
+ kn->kn_flags |= EV_ERROR;
+ return (1);
+ }
+ PCM_GIANT_ENTER(d);
+ dsp_lock_chans(priv, FWRITE);
+ if (ch != NULL && !(ch->flags & CHN_F_DEAD))
+ kn->kn_data = sndbuf_getfree(ch->bufsoft);
+
+ else
+ kn->kn_data = 0;
+ dsp_unlock_chans(priv, FWRITE);
+ PCM_GIANT_LEAVE(d);
+ return (kn->kn_data > 0);
+}
+
+static const struct filterops dsp_read_filtops = {
+ .f_isfd = 1,
+ .f_detach = dsp_kqdetach,
+ .f_event = dsp_read_filter,
+};
+
+static const struct filterops dsp_write_filtops = {
+ .f_isfd = 1,
+ .f_detach = dsp_kqdetach,
+ .f_event = dsp_write_filter,
+};
+
+static int
+dsp_kqfilter(struct cdev *dev, struct knote *kn)
+{
+ int err;
+ struct dsp_cdevpriv *priv;
+ struct snddev_info *d;
+
+ if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
+ return (err);
+ d = priv->sc;
+ if (!DSP_REGISTERED(d))
+ return (EBADF);
+ PCM_GIANT_ENTER(d);
+ switch (kn->kn_filter) {
+ case EVFILT_READ:
+ dsp_lock_chans(priv, FREAD);
+ if (priv->rdch != NULL) {
+ kn->kn_hook = priv->rdch;
+ kn->kn_fop = &dsp_read_filtops;
+ knlist_add(&priv->rdch->bufsoft->sel.si_note, kn, 1);
+ err = 0;
+ } else
+ err = EINVAL;
+ dsp_unlock_chans(priv, FREAD);
+ break;
+ case EVFILT_WRITE:
+ dsp_lock_chans(priv, FWRITE);
+ if (priv->rdch != NULL) {
+ kn->kn_hook = priv->wrch;
+ kn->kn_fop = &dsp_write_filtops;
+ knlist_add(&priv->wrch->bufsoft->sel.si_note, kn, 1);
+ err = 0;
+ } else
+ err = EINVAL;
+ dsp_unlock_chans(priv, FWRITE);
+ break;
+ default:
+ err = EINVAL;
+ break;
+ }
+ PCM_GIANT_LEAVE(d);
+ return(err);
+}
+
+
#ifdef OSSV4_EXPERIMENT
/**
* @brief Retrieve an audio device's label

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 18, 11:54 AM (12 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31717651
Default Alt Text
D53029.id164047.diff (9 KB)

Event Timeline