commit - 4e457e622a3cc784da56111553ff67082014d33b
commit + c2297fa38e218ad8f91175bbb242fb719b1a8435
blob - ad1273c0a22318d0fc4e2061e5313da3d9857ee7
blob + b17bc268d86b86f7a2c753aa6d2766d68141635b
--- Makefile
+++ Makefile
${SOURCES} \
audio_alsa.c \
audio_ao.c \
+ audio_oboe.cpp \
audio_sndio.c
all: ${PROG}
-include amused.d
-include audio_alsa.d
-include audio_ao.d
+-include audio_oboe.d
-include audio_sndio.d
-include compats.d
-include control.d
blob - /dev/null
blob + 3fb5b36cce11850d3ae4b0ecbb84f150c46de9fa (mode 644)
--- /dev/null
+++ audio_oboe.cpp
+/*
+ * 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.
+ */
+
+extern "C" {
+#include "config.h"
+}
+
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdio.h>
+
+#include <oboe/Oboe.h>
+
+extern "C" {
+#include "amused.h"
+#include "log.h"
+}
+
+#define ext extern "C"
+
+static void (*onmove_cb)(void *, int);
+static int sp[2]; /* main, audio thread */
+static pthread_t at;
+
+static int bpf;
+static unsigned int bits, rate, chan;
+static oboe::AudioFormat fmt;
+static char buf[BUFSIZ];
+static size_t buflen;
+
+static std::shared_ptr<oboe::AudioStream> stream;
+
+static void *
+aworker(void *d)
+{
+ unsigned int last_bits, last_rate, last_chan;
+ ssize_t r;
+ int sock = sp[1];
+ char ch;
+
+ stream = nullptr;
+ last_bits = last_rate = last_chan = 0;
+
+ 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 (bits != last_bits ||
+ rate != last_rate ||
+ chan != last_chan) {
+ if (stream) {
+ stream->close();
+ stream = nullptr;
+ }
+
+ last_bits = bits;
+ last_rate = rate;
+ last_chan = chan;
+
+ log_debug("setting bits=%d rate=%d chan=%d bpf=%d",
+ bits, rate, chan, bpf);
+
+ oboe::AudioStreamBuilder streamBuilder;
+ streamBuilder.setFormat(fmt);
+ streamBuilder.setSampleRate(rate);
+ streamBuilder.setChannelCount(chan);
+ oboe::Result result = streamBuilder.openStream(stream);
+ if (result != oboe::Result::OK)
+ fatalx("Error opening stream %s",
+ oboe::convertToText(result));
+
+ stream->requestStart();
+ }
+
+ // oboe works in terms of FRAMES not BYTES!
+ unsigned int len = buflen / bpf;
+
+ // XXX should be the timeout in nanoseconds...
+ auto ret = stream->write(buf, len, 1000000000);
+ if (!ret) {
+ fatalx("write failed: %s",
+ oboe::convertToText(ret.error()));
+ }
+ }
+
+ return nullptr;
+}
+
+ext int
+audio_open(void (*cb)(void *, int))
+{
+ 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);
+}
+
+ext int
+audio_setup(unsigned int p_bits, unsigned int p_rate, unsigned int p_chan,
+ struct pollfd *pfds, int nfds)
+{
+ bits = p_bits;
+ rate = p_rate;
+ chan = p_chan;
+
+ if (bits == 8) {
+ log_warnx("would require a conversion layer...");
+ return (-1);
+ } else if (bits == 16) {
+ bpf = 2;
+ fmt = oboe::AudioFormat::I16;
+ } else if (bits == 24) {
+ bpf = 4;
+ fmt = oboe::AudioFormat::I24;
+ } else if (bits == 32) {
+ // XXX not so sure...
+ bpf = 4;
+ fmt = oboe::AudioFormat::I24;
+ } else {
+ log_warnx("can't handle %d bits", bits);
+ return (-1);
+ }
+
+ bpf *= chan;
+
+ return (0);
+}
+
+ext int
+audio_nfds(void)
+{
+ return 1;
+}
+
+ext 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);
+}
+
+ext int
+audio_revents(struct pollfd *pfds, int nfds)
+{
+ if (nfds != 1) {
+ log_warnx("%s: called with %d nfds", __func__, nfds);
+ return 0;
+ }
+
+ /* don't need to check; if we're here the audio thread is ready */
+ return POLLOUT;
+}
+
+ext 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("oboe/%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("oboe/%s: write failed", __func__);
+ return 0;
+ }
+ if (r == 0) {
+ log_warnx("oboe/%s: write got EOF", __func__);
+ return 0;
+ }
+
+ if (onmove_cb)
+ onmove_cb(NULL, len / bpf);
+
+ return len;
+}
+
+ext int
+audio_flush(void)
+{
+ return 0; // XXX request flush
+}
+
+ext int
+audio_stop(void)
+{
+ return 0; // XXX request stop
+}
blob - 26f15a0acdb7fca63a4345efbd1163deb204f9ba
blob + 83d656a5ddf332bb0cb27a4bf8fc2b8b9d7a0407
--- compats.c
+++ compats.c
* Indirect memset through a volatile pointer to hopefully avoid
* dead-store optimisation eliminating the call.
*/
-static void (* volatile ssh_memset)(void *, int, size_t) = memset;
+static void (* volatile ssh_memset)(void *, int, size_t) =
+ (void (*volatile)(void *, int, size_t))memset;
void
explicit_bzero(void *p, size_t n)
blob - fc890e034e60584ffbbdb798b8235be8ad3af3dc
blob + 497e87b133dfeb21e3bc7097dc37fa81fed4cd58
--- configure
+++ configure
BACKEND=auto
CC=`printf "all:\\n\\t@echo \\\$(CC)\\n" | make ${MAKE_FLAGS} -sf -`
+CXX=`printf "all:\\n\\t@echo \\\$(CXX)\\n" | make ${MAKE_FLAGS} -sf -`
CFLAGS=`printf "all:\\n\\t@echo \\\$(CFLAGS)\\n" | make ${MAKE_FLAGS} -sf -`
CFLAGS="${CFLAGS} -g -W -Wall -Wextra -Wmissing-prototypes"
CFLAGS="${CFLAGS} -Wstrict-prototypes -Wmissing-declarations"
CFLAGS="${CFLAGS} -Wno-unused-parameter -Wno-sign-compare -Wno-pointer-sign"
+CXXFLAGS=`printf "all:\\n\\t@echo \\\$(CXXFLAGS)\\n" | make ${MAKE_FLAGS} -sf -`
+CXXFLAGS="${CXXFLAGS} -g -W -Wall -Wextra -Wno-unused-parameter"
LDADD=
LDADD_LIB_AO=
LDADD_LIB_ASOUND=
case "$val" in
alsa) BACKEND=alsa ;;
ao) BACKEND=ao ;;
+ oboe) BACKEND=oboe ;;
sndio) BACKEND=sndio ;;
*)
echo "unknown audio backend: $val" 1>&2
CC="$val" ;;
CFLAGS)
CFLAGS="$val" ;;
+ CXXFLAGS)
+ CXXFLAGS="$val" ;;
LDADD)
LDADD="$val" ;;
LDADD_LIB_AO)
if runtest -MMD _MMD -MMD; then
CFLAGS="${CFLAGS} -MMD"
- echo "adding -MMD to CFLAGS" 1>&2
- echo "adding -MMD to CFLAGS" 1>&3
+ CXXFLAGS="${CXXFLAGS} -MMD"
+ echo "adding -MMD to CFLAGS and CXXFLAGS" 1>&2
+ echo "adding -MMD to CFLAGS and CXXFLAGS" 1>&3
fi
runtest capsicum CAPSICUM || true
CFLAGS="${CFLAGS} -pthread"
fi
+if [ $BACKEND = auto -o $BACKEND = oboe ]; then
+ 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"
+
+ LDADD="${LDADD} -lstdc++ -lm -llog -lOpenSLES"
+fi
+
if [ "${HAVE_ENDIAN_H}" -eq 0 ]; then
CFLAGS="${CFLAGS} -I."
fi
#ifndef OCONFIGURE_CONFIG_H
#define OCONFIGURE_CONFIG_H
+/* the oboe (android) backend uses c++ */
+#ifndef __ANDROID__
#ifdef __cplusplus
# error "Do not use C++: this is a C application."
#endif
+#endif /* __ANDROID__ */
#if !defined(__GNUC__) || (__GNUC__ < 4)
# define __attribute__(x)
#endif
#if defined(__linux__) || defined(__MINT__)
-# define _GNU_SOURCE /* memmem, memrchr, setresuid... */
+# ifndef __ANDROID__
+# define _GNU_SOURCE /* memmem, memrchr, setresuid... */
+# endif
# define _DEFAULT_SOURCE /* le32toh, crypt, ... */
#endif
#if defined(__NetBSD__)
BACKEND = ${BACKEND}
CC = ${CC}
CFLAGS = ${CFLAGS}
+CXXFLAGS = ${CXXFLAGS}
CPPFLAGS = ${CPPFLAGS}
LDADD = ${LDADD}
LDADD_LIB_IMSG = ${LDADD_LIB_IMSG}