Blame


1 e26da60a 2023-03-23 op /*
2 e26da60a 2023-03-23 op * Copyright (c) 2023 Omar Polo <op@omarpolo.com>
3 e26da60a 2023-03-23 op *
4 e26da60a 2023-03-23 op * Permission to use, copy, modify, and distribute this software for any
5 e26da60a 2023-03-23 op * purpose with or without fee is hereby granted, provided that the above
6 e26da60a 2023-03-23 op * copyright notice and this permission notice appear in all copies.
7 e26da60a 2023-03-23 op *
8 e26da60a 2023-03-23 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 e26da60a 2023-03-23 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 e26da60a 2023-03-23 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 e26da60a 2023-03-23 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 e26da60a 2023-03-23 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 e26da60a 2023-03-23 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 e26da60a 2023-03-23 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 e26da60a 2023-03-23 op */
16 e26da60a 2023-03-23 op
17 e26da60a 2023-03-23 op #include "config.h"
18 e26da60a 2023-03-23 op
19 e26da60a 2023-03-23 op #include <alsa/asoundlib.h>
20 e26da60a 2023-03-23 op
21 e26da60a 2023-03-23 op #include <limits.h>
22 e26da60a 2023-03-23 op
23 e26da60a 2023-03-23 op #include "amused.h"
24 e26da60a 2023-03-23 op #include "log.h"
25 e26da60a 2023-03-23 op
26 e26da60a 2023-03-23 op static snd_pcm_t *pcm;
27 bbd1402d 2023-03-23 op static size_t bpf;
28 8b3efdb3 2023-05-12 op static void (*onmove_cb)(void *, int);
29 e26da60a 2023-03-23 op
30 e26da60a 2023-03-23 op int
31 8b3efdb3 2023-05-12 op audio_open(void (*cb)(void *, int))
32 e26da60a 2023-03-23 op {
33 e26da60a 2023-03-23 op const char *device = "default";
34 e26da60a 2023-03-23 op int err;
35 e26da60a 2023-03-23 op
36 e26da60a 2023-03-23 op err = snd_pcm_open(&pcm, device, SND_PCM_STREAM_PLAYBACK,
37 e26da60a 2023-03-23 op SND_PCM_NONBLOCK);
38 e26da60a 2023-03-23 op if (err < 0) {
39 e26da60a 2023-03-23 op log_warnx("playback open error: %s", snd_strerror(err));
40 e26da60a 2023-03-23 op return -1;
41 e26da60a 2023-03-23 op }
42 e26da60a 2023-03-23 op
43 8b3efdb3 2023-05-12 op onmove_cb = cb;
44 e26da60a 2023-03-23 op return 0;
45 e26da60a 2023-03-23 op }
46 e26da60a 2023-03-23 op
47 e26da60a 2023-03-23 op int
48 e26da60a 2023-03-23 op audio_setup(unsigned int bits, unsigned int rate, unsigned int channels,
49 b02dadd3 2023-05-13 op struct pollfd *pfds, int nfds)
50 e26da60a 2023-03-23 op {
51 e26da60a 2023-03-23 op int err;
52 e26da60a 2023-03-23 op snd_pcm_format_t fmt;
53 e26da60a 2023-03-23 op
54 bbd1402d 2023-03-23 op if (bits == 8) {
55 e26da60a 2023-03-23 op fmt = SND_PCM_FORMAT_S8;
56 bbd1402d 2023-03-23 op bpf = 1;
57 bbd1402d 2023-03-23 op } else if (bits == 16) {
58 e26da60a 2023-03-23 op fmt = SND_PCM_FORMAT_S16;
59 bbd1402d 2023-03-23 op bpf = 2;
60 bbd1402d 2023-03-23 op } else if (bits == 24) {
61 e26da60a 2023-03-23 op fmt = SND_PCM_FORMAT_S24;
62 bbd1402d 2023-03-23 op bpf = 4;
63 bbd1402d 2023-03-23 op } else if (bits == 32) {
64 e26da60a 2023-03-23 op fmt = SND_PCM_FORMAT_S32;
65 bbd1402d 2023-03-23 op bpf = 4;
66 bbd1402d 2023-03-23 op } else {
67 e26da60a 2023-03-23 op log_warnx("can't handle %d bits", bits);
68 e26da60a 2023-03-23 op return -1;
69 e26da60a 2023-03-23 op }
70 bbd1402d 2023-03-23 op
71 bbd1402d 2023-03-23 op bpf *= channels;
72 e26da60a 2023-03-23 op
73 e26da60a 2023-03-23 op err = snd_pcm_set_params(pcm, fmt, SND_PCM_ACCESS_RW_INTERLEAVED,
74 e26da60a 2023-03-23 op channels, rate, 1, 500000 /* 0.5s */);
75 e26da60a 2023-03-23 op if (err < 0) {
76 e26da60a 2023-03-23 op log_warnx("invalid params: %s", snd_strerror(err));
77 e26da60a 2023-03-23 op return -1;
78 e26da60a 2023-03-23 op }
79 e26da60a 2023-03-23 op
80 e26da60a 2023-03-23 op err = snd_pcm_prepare(pcm);
81 e26da60a 2023-03-23 op if (err < 0) {
82 e26da60a 2023-03-23 op log_warnx("snd_pcm_prepare failed: %s", snd_strerror(err));
83 e26da60a 2023-03-23 op return -1;
84 e26da60a 2023-03-23 op }
85 e26da60a 2023-03-23 op
86 e26da60a 2023-03-23 op return 0;
87 e26da60a 2023-03-23 op }
88 e26da60a 2023-03-23 op
89 e26da60a 2023-03-23 op int
90 e26da60a 2023-03-23 op audio_nfds(void)
91 e26da60a 2023-03-23 op {
92 e26da60a 2023-03-23 op return snd_pcm_poll_descriptors_count(pcm);
93 e26da60a 2023-03-23 op }
94 e26da60a 2023-03-23 op
95 e26da60a 2023-03-23 op int
96 b02dadd3 2023-05-13 op audio_pollfd(struct pollfd *pfds, int nfds, int events)
97 e26da60a 2023-03-23 op {
98 b02dadd3 2023-05-13 op return snd_pcm_poll_descriptors(pcm, pfds, nfds);
99 e26da60a 2023-03-23 op }
100 e26da60a 2023-03-23 op
101 e26da60a 2023-03-23 op int
102 b02dadd3 2023-05-13 op audio_revents(struct pollfd *pfds, int nfds)
103 e26da60a 2023-03-23 op {
104 e26da60a 2023-03-23 op int err;
105 e26da60a 2023-03-23 op unsigned short revents;
106 e26da60a 2023-03-23 op
107 b02dadd3 2023-05-13 op err = snd_pcm_poll_descriptors_revents(pcm, pfds, nfds, &revents);
108 e26da60a 2023-03-23 op if (err < 0) {
109 e26da60a 2023-03-23 op log_warnx("snd revents failure: %s", snd_strerror(err));
110 e26da60a 2023-03-23 op return 0;
111 e26da60a 2023-03-23 op }
112 e26da60a 2023-03-23 op
113 e26da60a 2023-03-23 op return revents;
114 e26da60a 2023-03-23 op }
115 e26da60a 2023-03-23 op
116 e26da60a 2023-03-23 op size_t
117 e26da60a 2023-03-23 op audio_write(const void *buf, size_t len)
118 e26da60a 2023-03-23 op {
119 bbd1402d 2023-03-23 op snd_pcm_sframes_t avail, ret;
120 e26da60a 2023-03-23 op
121 bbd1402d 2023-03-23 op /*
122 bbd1402d 2023-03-23 op * snd_pcm_writei works in terms of FRAMES, not BYTES!
123 bbd1402d 2023-03-23 op */
124 bbd1402d 2023-03-23 op len /= bpf;
125 bbd1402d 2023-03-23 op
126 bbd1402d 2023-03-23 op avail = snd_pcm_avail_update(pcm);
127 bbd1402d 2023-03-23 op if (avail < 0) {
128 bbd1402d 2023-03-23 op if (avail == -EPIPE) {
129 440c29a4 2023-05-12 op log_debug("alsa xrun occurred");
130 440c29a4 2023-05-12 op snd_pcm_recover(pcm, -EPIPE, 1);
131 bbd1402d 2023-03-23 op return 0;
132 bbd1402d 2023-03-23 op }
133 bbd1402d 2023-03-23 op log_warnx("snd_pcm_avail_update failure: %s",
134 bbd1402d 2023-03-23 op snd_strerror(avail));
135 bbd1402d 2023-03-23 op return 0;
136 bbd1402d 2023-03-23 op }
137 bbd1402d 2023-03-23 op
138 bbd1402d 2023-03-23 op if (len > avail)
139 bbd1402d 2023-03-23 op len = avail;
140 bbd1402d 2023-03-23 op
141 e26da60a 2023-03-23 op ret = snd_pcm_writei(pcm, buf, len);
142 e26da60a 2023-03-23 op if (ret < 0) {
143 e26da60a 2023-03-23 op log_warnx("snd_pcm_writei failed: %s", snd_strerror(ret));
144 e26da60a 2023-03-23 op return 0;
145 e26da60a 2023-03-23 op }
146 8b3efdb3 2023-05-12 op if (onmove_cb)
147 8b3efdb3 2023-05-12 op onmove_cb(NULL, ret);
148 bbd1402d 2023-03-23 op return ret * bpf;
149 e26da60a 2023-03-23 op }
150 e26da60a 2023-03-23 op
151 e26da60a 2023-03-23 op int
152 e26da60a 2023-03-23 op audio_flush(void)
153 e26da60a 2023-03-23 op {
154 e26da60a 2023-03-23 op int err;
155 e26da60a 2023-03-23 op
156 e26da60a 2023-03-23 op err = snd_pcm_drop(pcm);
157 e26da60a 2023-03-23 op if (err < 0) {
158 e26da60a 2023-03-23 op log_warnx("snd_pcm_drop: %s", snd_strerror(err));
159 e26da60a 2023-03-23 op return -1;
160 e26da60a 2023-03-23 op }
161 e26da60a 2023-03-23 op
162 e26da60a 2023-03-23 op return 0;
163 e26da60a 2023-03-23 op }
164 e26da60a 2023-03-23 op
165 e26da60a 2023-03-23 op int
166 e26da60a 2023-03-23 op audio_stop(void)
167 e26da60a 2023-03-23 op {
168 e26da60a 2023-03-23 op int err;
169 e26da60a 2023-03-23 op
170 e26da60a 2023-03-23 op err = snd_pcm_drain(pcm);
171 e26da60a 2023-03-23 op if (err < 0) {
172 e26da60a 2023-03-23 op log_warnx("snd_pcm_drain: %s", snd_strerror(err));
173 e26da60a 2023-03-23 op return -1;
174 e26da60a 2023-03-23 op }
175 e26da60a 2023-03-23 op
176 e26da60a 2023-03-23 op return 0;
177 e26da60a 2023-03-23 op }