Blame


1 d1705aab 2023-10-07 op /*
2 d1705aab 2023-10-07 op * Copyright (c) 2023 Omar Polo <op@omarpolo.com>
3 d1705aab 2023-10-07 op *
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.
7 d1705aab 2023-10-07 op *
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.
15 d1705aab 2023-10-07 op */
16 d1705aab 2023-10-07 op
17 d1705aab 2023-10-07 op #include "config.h"
18 d1705aab 2023-10-07 op
19 d1705aab 2023-10-07 op #include <sys/socket.h>
20 d1705aab 2023-10-07 op
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>
26 d1705aab 2023-10-07 op
27 d1705aab 2023-10-07 op #include "amused.h"
28 d1705aab 2023-10-07 op #include "log.h"
29 d1705aab 2023-10-07 op
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;
33 d1705aab 2023-10-07 op
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;
38 d1705aab 2023-10-07 op
39 d1705aab 2023-10-07 op static void *
40 d1705aab 2023-10-07 op aworker(void *d)
41 d1705aab 2023-10-07 op {
42 d1705aab 2023-10-07 op ao_sample_format f;
43 d1705aab 2023-10-07 op ao_device *device = NULL;
44 d1705aab 2023-10-07 op ssize_t r;
45 d1705aab 2023-10-07 op int sock = sp[1];
46 d1705aab 2023-10-07 op char ch;
47 d1705aab 2023-10-07 op
48 d1705aab 2023-10-07 op memset(&f, 0, sizeof(f));
49 d1705aab 2023-10-07 op
50 d1705aab 2023-10-07 op log_info("%s: starting", __func__);
51 d1705aab 2023-10-07 op
52 d1705aab 2023-10-07 op for (;;) {
53 d1705aab 2023-10-07 op ch = 1;
54 d1705aab 2023-10-07 op if ((r = write(sock, &ch, 1)) == -1)
55 d1705aab 2023-10-07 op fatal("write");
56 d1705aab 2023-10-07 op if (r == 0)
57 d1705aab 2023-10-07 op break;
58 d1705aab 2023-10-07 op
59 d1705aab 2023-10-07 op if ((r = read(sock, &ch, 1)) == -1)
60 d1705aab 2023-10-07 op fatal("read");
61 d1705aab 2023-10-07 op if (r == 0)
62 d1705aab 2023-10-07 op break;
63 d1705aab 2023-10-07 op
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(),
68 d1705aab 2023-10-07 op &fmt, NULL);
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");
73 d1705aab 2023-10-07 op break;
74 d1705aab 2023-10-07 op case AO_ENOTLIVE:
75 d1705aab 2023-10-07 op log_warnx("ao: not a live device");
76 d1705aab 2023-10-07 op break;
77 d1705aab 2023-10-07 op case AO_EBADOPTION:
78 d1705aab 2023-10-07 op log_warnx("ao: bad option(s)");
79 d1705aab 2023-10-07 op break;
80 d1705aab 2023-10-07 op case AO_EOPENDEVICE:
81 d1705aab 2023-10-07 op log_warnx("ao: failed to open device");
82 d1705aab 2023-10-07 op break;
83 d1705aab 2023-10-07 op case AO_EFAIL:
84 d1705aab 2023-10-07 op default:
85 d1705aab 2023-10-07 op log_warnx("ao: failed opening driver");
86 d1705aab 2023-10-07 op break;
87 d1705aab 2023-10-07 op }
88 d1705aab 2023-10-07 op errno = EINVAL;
89 d1705aab 2023-10-07 op break;
90 d1705aab 2023-10-07 op }
91 d1705aab 2023-10-07 op log_info("%s: device (re)opened", __func__);
92 d1705aab 2023-10-07 op memcpy(&f, &fmt, sizeof(f));
93 d1705aab 2023-10-07 op }
94 d1705aab 2023-10-07 op
95 d1705aab 2023-10-07 op if (ao_play(device, buf, buflen) == 0) {
96 d1705aab 2023-10-07 op log_warnx("ao_play failed");
97 d1705aab 2023-10-07 op break;
98 d1705aab 2023-10-07 op }
99 d1705aab 2023-10-07 op }
100 d1705aab 2023-10-07 op
101 d1705aab 2023-10-07 op log_info("quitting audio thread");
102 d1705aab 2023-10-07 op close(sock);
103 d1705aab 2023-10-07 op return NULL;
104 d1705aab 2023-10-07 op }
105 d1705aab 2023-10-07 op
106 d1705aab 2023-10-07 op int
107 d1705aab 2023-10-07 op audio_open(void (*cb)(void *, int))
108 d1705aab 2023-10-07 op {
109 d1705aab 2023-10-07 op ao_initialize();
110 d1705aab 2023-10-07 op onmove_cb = cb;
111 d1705aab 2023-10-07 op
112 d1705aab 2023-10-07 op if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == -1) {
113 d1705aab 2023-10-07 op log_warn("socketpair");
114 d1705aab 2023-10-07 op return (-1);
115 d1705aab 2023-10-07 op }
116 d1705aab 2023-10-07 op
117 d1705aab 2023-10-07 op if (pthread_create(&at, NULL, aworker, NULL) == -1) {
118 d1705aab 2023-10-07 op log_warn("pthread_create");
119 d1705aab 2023-10-07 op return (-1);
120 d1705aab 2023-10-07 op }
121 d1705aab 2023-10-07 op
122 d1705aab 2023-10-07 op return 0;
123 d1705aab 2023-10-07 op }
124 d1705aab 2023-10-07 op
125 d1705aab 2023-10-07 op int
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)
128 d1705aab 2023-10-07 op {
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;
134 d1705aab 2023-10-07 op
135 d1705aab 2023-10-07 op if (bits == 8)
136 d1705aab 2023-10-07 op bpf = 1;
137 d1705aab 2023-10-07 op else if (bits == 16)
138 d1705aab 2023-10-07 op bpf = 2;
139 d1705aab 2023-10-07 op else if (bits == 24 || bits == 32)
140 d1705aab 2023-10-07 op bpf = 4;
141 d1705aab 2023-10-07 op else {
142 d1705aab 2023-10-07 op log_warnx("can't handle %d bits", bits);
143 d1705aab 2023-10-07 op return -1;
144 d1705aab 2023-10-07 op }
145 d1705aab 2023-10-07 op
146 d1705aab 2023-10-07 op return 0;
147 d1705aab 2023-10-07 op }
148 d1705aab 2023-10-07 op
149 d1705aab 2023-10-07 op int
150 d1705aab 2023-10-07 op audio_nfds(void)
151 d1705aab 2023-10-07 op {
152 d1705aab 2023-10-07 op return 1;
153 d1705aab 2023-10-07 op }
154 d1705aab 2023-10-07 op
155 d1705aab 2023-10-07 op int
156 d1705aab 2023-10-07 op audio_pollfd(struct pollfd *pfds, int nfds, int events)
157 d1705aab 2023-10-07 op {
158 d1705aab 2023-10-07 op if (nfds != 1) {
159 d1705aab 2023-10-07 op errno = EINVAL;
160 d1705aab 2023-10-07 op return -1;
161 d1705aab 2023-10-07 op }
162 d1705aab 2023-10-07 op
163 d1705aab 2023-10-07 op pfds[0].fd = sp[0];
164 d1705aab 2023-10-07 op pfds[0].events = POLLIN;
165 d1705aab 2023-10-07 op return 0;
166 d1705aab 2023-10-07 op }
167 d1705aab 2023-10-07 op
168 d1705aab 2023-10-07 op int
169 d1705aab 2023-10-07 op audio_revents(struct pollfd *pfds, int nfds)
170 d1705aab 2023-10-07 op {
171 d1705aab 2023-10-07 op if (nfds != 1) {
172 d1705aab 2023-10-07 op log_warnx("%s: called with nfds=%d", __func__, nfds);
173 d1705aab 2023-10-07 op return 0;
174 d1705aab 2023-10-07 op }
175 d1705aab 2023-10-07 op
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;
178 d1705aab 2023-10-07 op }
179 d1705aab 2023-10-07 op
180 d1705aab 2023-10-07 op size_t
181 d1705aab 2023-10-07 op audio_write(const void *data, size_t len)
182 d1705aab 2023-10-07 op {
183 d1705aab 2023-10-07 op char ch;
184 d1705aab 2023-10-07 op ssize_t r;
185 d1705aab 2023-10-07 op
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__);
188 d1705aab 2023-10-07 op return 0;
189 d1705aab 2023-10-07 op }
190 d1705aab 2023-10-07 op if (r == 0)
191 d1705aab 2023-10-07 op return 0;
192 d1705aab 2023-10-07 op
193 d1705aab 2023-10-07 op if (len > sizeof(buf))
194 d1705aab 2023-10-07 op len = sizeof(buf);
195 d1705aab 2023-10-07 op
196 d1705aab 2023-10-07 op memcpy(buf, data, len);
197 d1705aab 2023-10-07 op buflen = len;
198 d1705aab 2023-10-07 op
199 d1705aab 2023-10-07 op ch = 1;
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__);
202 d1705aab 2023-10-07 op return 0;
203 d1705aab 2023-10-07 op }
204 d1705aab 2023-10-07 op if (r == 0) {
205 d1705aab 2023-10-07 op log_warnx("ao/%s: write got EOF", __func__);
206 d1705aab 2023-10-07 op return 0;
207 d1705aab 2023-10-07 op }
208 d1705aab 2023-10-07 op
209 d1705aab 2023-10-07 op if (onmove_cb)
210 d1705aab 2023-10-07 op onmove_cb(NULL, len / bpf);
211 d1705aab 2023-10-07 op
212 d1705aab 2023-10-07 op return len;
213 d1705aab 2023-10-07 op }
214 d1705aab 2023-10-07 op
215 d1705aab 2023-10-07 op int
216 d1705aab 2023-10-07 op audio_flush(void)
217 d1705aab 2023-10-07 op {
218 d1705aab 2023-10-07 op return 0;
219 d1705aab 2023-10-07 op }
220 d1705aab 2023-10-07 op
221 d1705aab 2023-10-07 op int
222 d1705aab 2023-10-07 op audio_stop(void)
223 d1705aab 2023-10-07 op {
224 d1705aab 2023-10-07 op return 0;
225 d1705aab 2023-10-07 op }