2 * Copyright (c) 2023 Omar Polo <op@omarpolo.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include <sys/socket.h>
28 #include <oboe/Oboe.h>
35 #define ext extern "C"
37 static void (*onmove_cb)(void *, int);
38 static int sp[2]; /* main, audio thread */
42 static unsigned int bits, rate, chan;
43 static oboe::AudioFormat fmt;
44 static char buf[BUFSIZ];
47 static std::shared_ptr<oboe::AudioStream> stream;
52 unsigned int last_bits, last_rate, last_chan;
58 last_bits = last_rate = last_chan = 0;
60 log_info("%s: starting", __func__);
63 if ((r = write(sock, &ch, 1)) == -1)
68 if ((r = read(sock, &ch, 1)) == -1)
73 if (bits != last_bits ||
85 log_debug("setting bits=%d rate=%d chan=%d bpf=%d",
86 bits, rate, chan, bpf);
88 oboe::AudioStreamBuilder streamBuilder;
89 streamBuilder.setFormat(fmt);
90 streamBuilder.setSampleRate(rate);
91 streamBuilder.setChannelCount(chan);
92 oboe::Result result = streamBuilder.openStream(stream);
93 if (result != oboe::Result::OK)
94 fatalx("Error opening stream %s",
95 oboe::convertToText(result));
97 stream->requestStart();
100 // oboe works in terms of FRAMES not BYTES!
101 unsigned int len = buflen / bpf;
103 // XXX should be the timeout in nanoseconds...
104 auto ret = stream->write(buf, len, 1000000000);
106 fatalx("write failed: %s",
107 oboe::convertToText(ret.error()));
115 audio_open(void (*cb)(void *, int))
119 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == -1) {
120 log_warn("socketpair");
124 if (pthread_create(&at, NULL, aworker, NULL) == -1) {
125 log_warn("pthread_create");
133 audio_setup(unsigned int p_bits, unsigned int p_rate, unsigned int p_chan,
134 struct pollfd *pfds, int nfds)
141 log_warnx("would require a conversion layer...");
143 } else if (bits == 16) {
145 fmt = oboe::AudioFormat::I16;
146 } else if (bits == 24) {
148 fmt = oboe::AudioFormat::I24;
149 } else if (bits == 32) {
150 // XXX not so sure...
152 fmt = oboe::AudioFormat::I24;
154 log_warnx("can't handle %d bits", bits);
170 audio_pollfd(struct pollfd *pfds, int nfds, int events)
178 pfds[0].events = POLLIN;
183 audio_revents(struct pollfd *pfds, int nfds)
186 log_warnx("%s: called with %d nfds", __func__, nfds);
190 /* don't need to check; if we're here the audio thread is ready */
195 audio_write(const void *data, size_t len)
200 if ((r = read(sp[0], &ch, 1)) == -1) {
201 log_warn("oboe/%s: read failed", __func__);
207 if (len > sizeof(buf))
210 memcpy(buf, data, len);
214 if ((r = write(sp[0], &ch, 1)) == -1) {
215 log_warn("oboe/%s: write failed", __func__);
219 log_warnx("oboe/%s: write got EOF", __func__);
224 onmove_cb(NULL, len / bpf);
232 return 0; // XXX request flush
238 return 0; // XXX request stop