commit 06ceb3767eb7e480de05cd50f4fbaf75fb3322a2 from: Omar Polo date: Thu Mar 23 14:10:28 2023 UTC split out sndio-specific parts to audio_sndio.c This hides the libsndio bits behind a small audio_* API for which in the future we may provide multiple implementations. commit - 069e653bc1e64578b0a97465a2016b7dc0bf3f56 commit + 06ceb3767eb7e480de05cd50f4fbaf75fb3322a2 blob - 7b9eb922ca793410bf8c7c3ef53d5387f0cf41dd blob + ed6eac93eeae2b298b126764266afb1ebaf7ca0e --- Makefile +++ Makefile @@ -5,6 +5,7 @@ PROG = amused DISTNAME = ${PROG}-${VERSION} SOURCES = amused.c \ + audio_sndio.c \ compats.c \ control.c \ ctl.c \ @@ -93,6 +94,7 @@ ${DISTNAME}.tar.gz: ${DISTFILES} # supports it. -include amused.d +-include audio_sndio.d -include compats.d -include control.d -include ctl.d blob - fc49a771a10bbb1a9f2e3fa8767085c0d51fe99b blob + 8e43ca26a080662b1a3be57c37217cdb5ac8953d --- amused.h +++ amused.h @@ -138,6 +138,7 @@ struct ctl_command { }; struct playlist; +struct pollfd; /* amused.c */ void spawn_daemon(void); @@ -156,6 +157,17 @@ void main_send_playlist(struct imsgev *); void main_send_status(struct imsgev *); void main_seek(struct player_seek *); +/* audio_*.c */ +int audio_open(void (*)(void *, int)); +int audio_setup(unsigned int, unsigned int, unsigned int, + struct pollfd *); +int audio_nfds(void); +int audio_pollfd(struct pollfd *, int); +int audio_revents(struct pollfd *); +size_t audio_write(const void *, size_t); +int audio_flush(void); +int audio_stop(void); + /* ctl.c */ __dead void usage(void); __dead void ctl(int, char **); blob - /dev/null blob + 3a44d164a81a7d7317f6284e0b8c84aad10e3e30 (mode 644) --- /dev/null +++ audio_sndio.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2023 Omar Polo + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "amused.h" +#include "log.h" + +static struct sio_hdl *hdl; +static struct sio_par par; +static int stopped = 1; + +int +audio_open(void (*onmove_cb)(void *, int)) +{ + if ((hdl = sio_open(SIO_DEVANY, SIO_PLAY, 1)) == NULL) + return -1; + + sio_onmove(hdl, onmove_cb, NULL); + return 0; +} + +int +audio_setup(unsigned int bits, unsigned int rate, unsigned int channels, + struct pollfd *pfds) +{ + int nfds, fpct; + + fpct = (rate * 5) / 100; + + /* don't stop if the parameters are the same */ + if (bits == par.bits && channels == par.pchan && + par.rate - fpct <= rate && rate <= par.rate + fpct) { + if (stopped) + goto start; + return 0; + } + + again: + if (!stopped) { + sio_stop(hdl); + stopped = 1; + } + + sio_initpar(&par); + par.bits = bits; + par.rate = rate; + par.pchan = channels; + if (!sio_setpar(hdl, &par)) { + if (errno == EAGAIN) { + nfds = sio_pollfd(hdl, pfds, POLLOUT); + if (poll(pfds, nfds, INFTIM) == -1) + fatal("poll"); + goto again; + } + log_warnx("invalid params (bits=%u, rate=%u, channels=%u)", + bits, rate, channels); + return -1; + } + if (!sio_getpar(hdl, &par)) { + log_warnx("can't get params"); + return -1; + } + + if (par.bits != bits || par.pchan != channels) { + log_warnx("failed to set params"); + return -1; + } + + /* TODO: check sample rate? */ + + start: + if (!sio_start(hdl)) { + log_warn("sio_start"); + return -1; + } + stopped = 0; + return 0; +} + +int +audio_nfds(void) +{ + return sio_nfds(hdl); +} + +int +audio_pollfd(struct pollfd *pfds, int events) +{ + return sio_pollfd(hdl, pfds, events); +} + +int +audio_revents(struct pollfd *pfds) +{ + return sio_revents(hdl, pfds); +} + +size_t +audio_write(const void *buf, size_t len) +{ + return sio_write(hdl, buf, len); +} + +int +audio_flush(void) +{ + stopped = 1; + return sio_flush(hdl); +} + +int +audio_stop(void) +{ + stopped = 1; + return sio_stop(hdl); +} blob - a20334041994cda28a95a0e42e2bc12e2877b478 blob + 1bdef9ba7768c972ef5db3b2676830406134982e --- player.c +++ player.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -34,15 +33,13 @@ #include "log.h" #include "xmalloc.h" -struct sio_hdl *hdl; -struct sio_par par; struct pollfd *player_pfds; static struct imsgbuf *ibuf; -static int stopped = 1; static int nextfd = -1; static int64_t samples; static int64_t duration; +static unsigned int current_rate; volatile sig_atomic_t halted; @@ -55,61 +52,11 @@ player_signal_handler(int signo) int player_setup(unsigned int bits, unsigned int rate, unsigned int channels) { - int nfds, fpct; - log_debug("%s: bits=%u, rate=%u, channels=%u", __func__, bits, rate, channels); - fpct = (rate*5)/100; - - /* don't stop if the parameters are the same */ - if (bits == par.bits && channels == par.pchan && - par.rate - fpct <= rate && rate <= par.rate + fpct) { - if (stopped) - goto start; - return 0; - } - -again: - if (!stopped) { - sio_stop(hdl); - stopped = 1; - } - - sio_initpar(&par); - par.bits = bits; - par.rate = rate; - par.pchan = channels; - if (!sio_setpar(hdl, &par)) { - if (errno == EAGAIN) { - nfds = sio_pollfd(hdl, player_pfds + 1, POLLOUT); - if (poll(player_pfds + 1, nfds, INFTIM) == -1) - fatal("poll"); - goto again; - } - log_warnx("invalid params (bits=%d, rate=%d, channels=%d", - bits, rate, channels); - return -1; - } - if (!sio_getpar(hdl, &par)) { - log_warnx("can't get params"); - return -1; - } - - if (par.bits != bits || par.pchan != channels) { - log_warnx("failed to set params"); - return -1; - } - - /* TODO: check the sample rate? */ - -start: - if (!sio_start(hdl)) { - log_warn("sio_start"); - return -1; - } - stopped = 0; - return 0; + current_rate = rate; + return audio_setup(bits, rate, channels, player_pfds + 1); } void @@ -118,7 +65,7 @@ player_setduration(int64_t d) int64_t seconds; duration = d; - seconds = duration / par.rate; + seconds = duration / current_rate; imsg_compose(ibuf, IMSG_LEN, 0, 0, -1, &seconds, sizeof(seconds)); imsg_flush(ibuf); } @@ -130,9 +77,9 @@ player_onmove(void *arg, int delta) int64_t sec; samples += delta; - if (llabs(samples - reported) >= par.rate) { + if (llabs(samples - reported) >= current_rate) { reported = samples; - sec = samples / par.rate; + sec = samples / current_rate; imsg_compose(ibuf, IMSG_POS, 0, 0, -1, &sec, sizeof(sec)); imsg_flush(ibuf); @@ -200,7 +147,7 @@ again: if (seek.percent) { *s = (double)seek.offset * (double)duration / 100.0; } else { - *s = seek.offset * par.rate; + *s = seek.offset * current_rate; if (seek.relative) *s += samples; } @@ -310,26 +257,25 @@ play(const void *buf, size_t len, int64_t *s) *s = -1; while (len != 0) { - nfds = sio_pollfd(hdl, player_pfds + 1, POLLOUT); + nfds = audio_pollfd(player_pfds + 1, POLLOUT); r = poll(player_pfds, nfds + 1, INFTIM); if (r == -1) fatal("poll"); wait = player_pfds[0].revents & (POLLHUP|POLLIN); if (player_shouldstop(s, wait)) { - sio_flush(hdl); - stopped = 1; + audio_flush(); return 0; } - revents = sio_revents(hdl, player_pfds + 1); + revents = audio_revents(player_pfds + 1); if (revents & POLLHUP) { if (errno == EAGAIN) continue; - fatal("sndio hang-up"); + fatal("audio hang-up"); } if (revents & POLLOUT) { - w = sio_write(hdl, buf, len); + w = audio_write(buf, len); len -= w; buf += w; } @@ -358,13 +304,11 @@ player(int debug, int verbose) } #endif - if ((hdl = sio_open(SIO_DEVANY, SIO_PLAY, 1)) == NULL) - fatal("sio_open"); + if (audio_open(player_onmove) == -1) + fatal("audio_open"); - sio_onmove(hdl, player_onmove, NULL); - /* allocate one extra for imsg */ - player_pfds = calloc(sio_nfds(hdl) + 1, sizeof(*player_pfds)); + player_pfds = calloc(audio_nfds() + 1, sizeof(*player_pfds)); if (player_pfds == NULL) fatal("calloc");