2 d1705aab 2023-10-07 op * Copyright (c) 2023 Omar Polo <op@omarpolo.com>
4 d1705aab 2023-10-07 op * Permission to use, copy, modify, and distribute this software for any
5 d1705aab 2023-10-07 op * purpose with or without fee is hereby granted, provided that the above
6 d1705aab 2023-10-07 op * copyright notice and this permission notice appear in all copies.
8 d1705aab 2023-10-07 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 d1705aab 2023-10-07 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 d1705aab 2023-10-07 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 d1705aab 2023-10-07 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 d1705aab 2023-10-07 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 d1705aab 2023-10-07 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 d1705aab 2023-10-07 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 d1705aab 2023-10-07 op #include "config.h"
19 d1705aab 2023-10-07 op #include <sys/socket.h>
21 d1705aab 2023-10-07 op #include <ao/ao.h>
22 d1705aab 2023-10-07 op #include <limits.h>
23 d1705aab 2023-10-07 op #include <poll.h>
24 d1705aab 2023-10-07 op #include <pthread.h>
25 d1705aab 2023-10-07 op #include <string.h>
27 d1705aab 2023-10-07 op #include "amused.h"
28 d1705aab 2023-10-07 op #include "log.h"
30 d1705aab 2023-10-07 op static void (*onmove_cb)(void *, int);
31 d1705aab 2023-10-07 op static int sp[2]; /* main, audio thread */
32 d1705aab 2023-10-07 op static pthread_t at;
34 d1705aab 2023-10-07 op static int bpf;
35 d1705aab 2023-10-07 op static ao_sample_format fmt;
36 d1705aab 2023-10-07 op static char buf[BUFSIZ];
37 d1705aab 2023-10-07 op static size_t buflen;
40 d1705aab 2023-10-07 op aworker(void *d)
42 d1705aab 2023-10-07 op ao_sample_format f;
43 d1705aab 2023-10-07 op ao_device *device = NULL;
45 d1705aab 2023-10-07 op int sock = sp[1];
48 d1705aab 2023-10-07 op memset(&f, 0, sizeof(f));
50 d1705aab 2023-10-07 op log_info("%s: starting", __func__);
54 d1705aab 2023-10-07 op if ((r = write(sock, &ch, 1)) == -1)
55 d1705aab 2023-10-07 op fatal("write");
59 d1705aab 2023-10-07 op if ((r = read(sock, &ch, 1)) == -1)
60 d1705aab 2023-10-07 op fatal("read");
64 d1705aab 2023-10-07 op if (memcmp(&fmt, &f, sizeof(f)) != 0) {
65 d1705aab 2023-10-07 op if (device != NULL)
66 d1705aab 2023-10-07 op ao_close(device);
67 d1705aab 2023-10-07 op device = ao_open_live(ao_default_driver_id(),
69 d1705aab 2023-10-07 op if (device == NULL) {
70 d1705aab 2023-10-07 op switch (errno) {
71 d1705aab 2023-10-07 op case AO_ENODRIVER:
72 d1705aab 2023-10-07 op log_warnx("ao: no driver found");
74 d1705aab 2023-10-07 op case AO_ENOTLIVE:
75 d1705aab 2023-10-07 op log_warnx("ao: not a live device");
77 d1705aab 2023-10-07 op case AO_EBADOPTION:
78 d1705aab 2023-10-07 op log_warnx("ao: bad option(s)");
80 d1705aab 2023-10-07 op case AO_EOPENDEVICE:
81 d1705aab 2023-10-07 op log_warnx("ao: failed to open device");
83 d1705aab 2023-10-07 op case AO_EFAIL:
85 d1705aab 2023-10-07 op log_warnx("ao: failed opening driver");
88 d1705aab 2023-10-07 op errno = EINVAL;
91 d1705aab 2023-10-07 op log_info("%s: device (re)opened", __func__);
92 d1705aab 2023-10-07 op memcpy(&f, &fmt, sizeof(f));
95 d1705aab 2023-10-07 op if (ao_play(device, buf, buflen) == 0) {
96 d1705aab 2023-10-07 op log_warnx("ao_play failed");
101 d1705aab 2023-10-07 op log_info("quitting audio thread");
107 d1705aab 2023-10-07 op audio_open(void (*cb)(void *, int))
109 d1705aab 2023-10-07 op ao_initialize();
110 d1705aab 2023-10-07 op onmove_cb = cb;
112 d1705aab 2023-10-07 op if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == -1) {
113 d1705aab 2023-10-07 op log_warn("socketpair");
117 d1705aab 2023-10-07 op if (pthread_create(&at, NULL, aworker, NULL) == -1) {
118 d1705aab 2023-10-07 op log_warn("pthread_create");
126 d1705aab 2023-10-07 op audio_setup(unsigned int bits, unsigned int rate, unsigned int channels,
127 d1705aab 2023-10-07 op struct pollfd *pfds, int nfds)
129 d1705aab 2023-10-07 op fmt.bits = bits;
130 d1705aab 2023-10-07 op fmt.rate = rate;
131 d1705aab 2023-10-07 op fmt.channels = channels;
132 d1705aab 2023-10-07 op fmt.byte_format = AO_FMT_NATIVE;
133 d1705aab 2023-10-07 op fmt.matrix = NULL;
135 d1705aab 2023-10-07 op if (bits == 8)
137 d1705aab 2023-10-07 op else if (bits == 16)
139 d1705aab 2023-10-07 op else if (bits == 24 || bits == 32)
142 d1705aab 2023-10-07 op log_warnx("can't handle %d bits", bits);
150 d1705aab 2023-10-07 op audio_nfds(void)
156 d1705aab 2023-10-07 op audio_pollfd(struct pollfd *pfds, int nfds, int events)
158 d1705aab 2023-10-07 op if (nfds != 1) {
159 d1705aab 2023-10-07 op errno = EINVAL;
163 d1705aab 2023-10-07 op pfds[0].fd = sp[0];
164 d1705aab 2023-10-07 op pfds[0].events = POLLIN;
169 d1705aab 2023-10-07 op audio_revents(struct pollfd *pfds, int nfds)
171 d1705aab 2023-10-07 op if (nfds != 1) {
172 d1705aab 2023-10-07 op log_warnx("%s: called with nfds=%d", __func__, nfds);
176 d1705aab 2023-10-07 op /* don't need to check; if we're here the audio thread is ready */
177 d1705aab 2023-10-07 op return POLLOUT;
181 d1705aab 2023-10-07 op audio_write(const void *data, size_t len)
186 d1705aab 2023-10-07 op if ((r = read(sp[0], &ch, 1)) == -1) {
187 d1705aab 2023-10-07 op log_warn("ao/%s: read failed", __func__);
193 d1705aab 2023-10-07 op if (len > sizeof(buf))
194 d1705aab 2023-10-07 op len = sizeof(buf);
196 d1705aab 2023-10-07 op memcpy(buf, data, len);
197 d1705aab 2023-10-07 op buflen = len;
200 d1705aab 2023-10-07 op if ((r = write(sp[0], &ch, 1)) == -1) {
201 d1705aab 2023-10-07 op log_warn("ao/%s: write failed", __func__);
204 d1705aab 2023-10-07 op if (r == 0) {
205 d1705aab 2023-10-07 op log_warnx("ao/%s: write got EOF", __func__);
209 d1705aab 2023-10-07 op if (onmove_cb)
210 d1705aab 2023-10-07 op onmove_cb(NULL, len / bpf);
216 d1705aab 2023-10-07 op audio_flush(void)
222 d1705aab 2023-10-07 op audio_stop(void)