commit - 933d15ce38dbe4081bdc11e05ea094577b3dca72
commit + d1705aabaf2f68036142492a64d2c1ad3ec75b95
blob - 1b2ec6f49b1c89af789fb934acc5f1135d325e6a
blob + a994af5c7645accbb068605407520b0175a008ad
--- Makefile
+++ Makefile
${HEADERS} \
${SOURCES} \
audio_alsa.c \
+ audio_ao.c \
audio_sndio.c
all: ${PROG}
-include amused.d
-include audio_alsa.d
+-include audio_ao.d
-include audio_sndio.d
-include compats.d
-include control.d
blob - /dev/null
blob + 3c2ef4735c191ec4e6363ed6172a8e04bd9671f9 (mode 644)
--- /dev/null
+++ audio_ao.c
+/*
+ * Copyright (c) 2023 Omar Polo <op@omarpolo.com>
+ *
+ * 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 <sys/socket.h>
+
+#include <ao/ao.h>
+#include <limits.h>
+#include <poll.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "amused.h"
+#include "log.h"
+
+static void (*onmove_cb)(void *, int);
+static int sp[2]; /* main, audio thread */
+static pthread_t at;
+
+static int bpf;
+static ao_sample_format fmt;
+static char buf[BUFSIZ];
+static size_t buflen;
+
+static void *
+aworker(void *d)
+{
+ ao_sample_format f;
+ ao_device *device = NULL;
+ ssize_t r;
+ int sock = sp[1];
+ char ch;
+
+ memset(&f, 0, sizeof(f));
+
+ log_info("%s: starting", __func__);
+
+ for (;;) {
+ ch = 1;
+ if ((r = write(sock, &ch, 1)) == -1)
+ fatal("write");
+ if (r == 0)
+ break;
+
+ if ((r = read(sock, &ch, 1)) == -1)
+ fatal("read");
+ if (r == 0)
+ break;
+
+ if (memcmp(&fmt, &f, sizeof(f)) != 0) {
+ if (device != NULL)
+ ao_close(device);
+ device = ao_open_live(ao_default_driver_id(),
+ &fmt, NULL);
+ if (device == NULL) {
+ switch (errno) {
+ case AO_ENODRIVER:
+ log_warnx("ao: no driver found");
+ break;
+ case AO_ENOTLIVE:
+ log_warnx("ao: not a live device");
+ break;
+ case AO_EBADOPTION:
+ log_warnx("ao: bad option(s)");
+ break;
+ case AO_EOPENDEVICE:
+ log_warnx("ao: failed to open device");
+ break;
+ case AO_EFAIL:
+ default:
+ log_warnx("ao: failed opening driver");
+ break;
+ }
+ errno = EINVAL;
+ break;
+ }
+ log_info("%s: device (re)opened", __func__);
+ memcpy(&f, &fmt, sizeof(f));
+ }
+
+ if (ao_play(device, buf, buflen) == 0) {
+ log_warnx("ao_play failed");
+ break;
+ }
+ }
+
+ log_info("quitting audio thread");
+ close(sock);
+ return NULL;
+}
+
+int
+audio_open(void (*cb)(void *, int))
+{
+ ao_initialize();
+ onmove_cb = cb;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == -1) {
+ log_warn("socketpair");
+ return (-1);
+ }
+
+ if (pthread_create(&at, NULL, aworker, NULL) == -1) {
+ log_warn("pthread_create");
+ return (-1);
+ }
+
+ return 0;
+}
+
+int
+audio_setup(unsigned int bits, unsigned int rate, unsigned int channels,
+ struct pollfd *pfds, int nfds)
+{
+ fmt.bits = bits;
+ fmt.rate = rate;
+ fmt.channels = channels;
+ fmt.byte_format = AO_FMT_NATIVE;
+ fmt.matrix = NULL;
+
+ if (bits == 8)
+ bpf = 1;
+ else if (bits == 16)
+ bpf = 2;
+ else if (bits == 24 || bits == 32)
+ bpf = 4;
+ else {
+ log_warnx("can't handle %d bits", bits);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+audio_nfds(void)
+{
+ return 1;
+}
+
+int
+audio_pollfd(struct pollfd *pfds, int nfds, int events)
+{
+ if (nfds != 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ pfds[0].fd = sp[0];
+ pfds[0].events = POLLIN;
+ return 0;
+}
+
+int
+audio_revents(struct pollfd *pfds, int nfds)
+{
+ if (nfds != 1) {
+ log_warnx("%s: called with nfds=%d", __func__, nfds);
+ return 0;
+ }
+
+ /* don't need to check; if we're here the audio thread is ready */
+ return POLLOUT;
+}
+
+size_t
+audio_write(const void *data, size_t len)
+{
+ char ch;
+ ssize_t r;
+
+ if ((r = read(sp[0], &ch, 1)) == -1) {
+ log_warn("ao/%s: read failed", __func__);
+ return 0;
+ }
+ if (r == 0)
+ return 0;
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ memcpy(buf, data, len);
+ buflen = len;
+
+ ch = 1;
+ if ((r = write(sp[0], &ch, 1)) == -1) {
+ log_warn("ao/%s: write failed", __func__);
+ return 0;
+ }
+ if (r == 0) {
+ log_warnx("ao/%s: write got EOF", __func__);
+ return 0;
+ }
+
+ if (onmove_cb)
+ onmove_cb(NULL, len / bpf);
+
+ return len;
+}
+
+int
+audio_flush(void)
+{
+ return 0;
+}
+
+int
+audio_stop(void)
+{
+ return 0;
+}
blob - c9ff87fb3bdcf35acdb6b527cd7cf3940b0542fd
blob + 478ac4b58ff524c05d96c620edcf889183dd58e7
--- configure
+++ configure
Variables available:
- BACKEND audio backend to use; can be "sndio" or "alsa"
+ BACKEND audio backend to use; can be "sndio", "ao" or "alsa"
CC C compiler
CFLAGS generic C compiler flags
CPPFLAGS C preprocessors flags
LDADD generic linker flags
+ LDADD_LIB_AO linker flags for libao
LDADD_LIB_ASOUND linker flags for libasound
LDADD_LIB_FLAC linker flags for libflac
LDADD_LIB_IMSG linker flags for libimsg
LDADD_LIB_MD linker flags for libmd
LDADD_LIB_MPG123 linker flags for libmpg123
+ LDADD_LIB_PTHREAD linker flags for pthread
LDADD_LIB_OPUSFILE linker flags for libopusfile
LDADD_LIB_SNDIO linker flags for libsndio
LDADD_LIB_SOCKET linker flags for libsocket
CFLAGS="${CFLAGS} -Wstrict-prototypes -Wmissing-declarations"
CFLAGS="${CFLAGS} -Wno-unused-parameter -Wno-sign-compare -Wno-pointer-sign"
LDADD=
+LDADD_LIB_AO=
LDADD_LIB_ASOUND=
LDADD_LIB_FLAC=
LDADD_LIB_IMSG=
LDADD_LIB_MD=
LDADD_LIB_MPG123=
+LDADD_LIB_PTHREAD=
LDADD_LIB_OPUSFILE=
LDADD_LIB_SNDIO=
LDADD_LIB_SOCKET=
BACKEND)
case "$val" in
alsa) BACKEND=alsa ;;
+ ao) BACKEND=ao ;;
sndio) BACKEND=sndio ;;
*)
echo "unknown audio backend: $val" 1>&2
CFLAGS="$val" ;;
LDADD)
LDADD="$val" ;;
+ LDADD_LIB_AO)
+ LDADD_LIB_AO="$val"
+ HAVE_LIB_AO=1
+ BACKEND=ao
+ ;;
LDADD_LIB_ASOUND)
LDADD_LIB_ASOUND="$val"
HAVE_LIB_ASOUND=1
LDADD_LIB_MPG123="$val"
HAVE_LIB_MPG123=1
;;
+ LDADD_LIB_PTHREAD)
+ LDADD_LIB_PTHREAD="$val"
+ HAVE_LIB_PTHREAD=1
+ ;;
LDADD_LIB_OPUSFILE)
LDADD_LIB_OPUSFILE="$val"
HAVE_LIB_OPUSFILE=1
runtest unveil UNVEIL || true
runtest __progname __PROGNAME || true
-if [ $BACKEND != alsa ]; then # auto or sndio
+if [ $BACKEND = auto -o $BACKEND = sndio ]; then
runtest lib_sndio LIB_SNDIO "" "" "-lsndio" "sndio" || true
runtest sio_flush SIO_FLUSH "" "" "${LDADD_LIB_SNDIO}" || true
HAVE_SIO_FLUSH=0
fi
-if [ $BACKEND != sndio ]; then # auto or alsa
+if [ $BACKEND = auto -o $BACKEND = alsa ]; then
runtest lib_asound LIB_ASOUND "" "" "-lasound" "alsa" || true
if [ "${HAVE_LIB_ASOUND}" -eq 0 ]; then
if [ $BACKEND = alsa ]; then
echo "Fatal: missing libasound" 1>&2
echo "Fatal: missing libasound" 1>&3
- else
- echo "Fatal: missing libasound or libsndio" 1>&2
- echo "Fatal: missing libasound or libsndio" 1>&3
+ exit 1
fi
- exit 1
fi
BACKEND=alsa
fi
+if [ $BACKEND = auto -o $BACKEND = ao ]; then
+ runtest lib_ao LIB_AO "" "" "-lao" "ao" || true
+ if [ "${HAVE_LIB_AO}" -eq 0 ]; then
+ if [ $BACKEND = ao ]; then
+ echo "Fatal: missing libao" 1>&2
+ echo "Fatal: missing libao" 1>&3
+ else
+ echo "Fatal: missing libasound, libao or libsndio" 1>&2
+ echo "Fatal: missing libasound, libao or libsndio" 1>&3
+ fi
+ exit 1
+ fi
+ BACKEND=ao
+
+ runtest pthread LIB_PTHREAD "" "-pthread" || true
+ if [ "${HAVE_LIB_PTHREAD}" -eq 0 ]; then
+ echo "Fatal: missing pthread" 1>&2
+ echo "Fatal: missing pthread" 1>&3
+ exit 1
+ fi
+ CFLAGS="${CFLAGS} -pthread"
+fi
+
if [ "${HAVE_LIB_FLAC}" -eq 0 -o \
"${HAVE_LIB_MPG123}" -eq 0 -o \
"${HAVE_LIB_OPUSFILE}" -eq 0 -o \
${LDADD_LIB_VORBISFILE}
LDADD_LIB_MD = ${LDADD_LIB_MD}
LDADD_LIB_SOCKET = ${LDADD_LIB_SOCKET}
-LDADD_BACKEND = ${LDADD_LIB_SNDIO} ${LDADD_LIB_ASOUND}
+LDADD_BACKEND = ${LDADD_LIB_SNDIO} ${LDADD_LIB_ASOUND} ${LDADD_LIB_AO} \
+ ${LDADD_LIB_PTHREAD}
LDADD_STATIC = ${LDADD_STATIC}
LDFLAGS = ${LDFLAGS}
STATIC = ${STATIC}
blob - 54ade2b800a80f14edff8c860db21d17cbe84228
blob + 59b7b979f157153849d4d0dcd1db44b73979514d
--- tests.c
+++ tests.c
return 0;
}
#endif/* TEST_LIB_MPG123 */
+#if TEST_LIB_PTHREAD
+#include <stdlib.h>
+#include <pthread.h>
+
+int
+main(void)
+{
+ pthread_mutex_t mutex;
+
+ return (pthread_mutex_init(&mutex, NULL));
+}
+#endif/* TEST_LIB_PTHREAD */
#if TEST_LIB_OPUSFILE
#include <stdio.h>
#include <opusfile.h>
return 0;
}
#endif /* TEST_LIB_VORBISFILE */
+#if TEST_LIB_AO
+#include <stdio.h>
+#include <string.h>
+#include <ao/ao.h>
+
+int
+main(void)
+{
+ ao_initialize();
+ return (0);
+}
+#endif /* TEST_LIB_AO */
#if TEST_LIB_ASOUND
#include <alsa/asoundlib.h>