Blob


1 /*
2 * Copyright (c) 2023 Omar Polo <op@omarpolo.com>
3 *
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.
7 *
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.
15 */
17 #include "config.h"
19 #include <alsa/asoundlib.h>
21 #include <limits.h>
23 #include "amused.h"
24 #include "log.h"
26 static snd_pcm_t *pcm;
28 int
29 audio_open(void (*onmove_cb)(void *, int))
30 {
31 const char *device = "default";
32 int err;
34 err = snd_pcm_open(&pcm, device, SND_PCM_STREAM_PLAYBACK,
35 SND_PCM_NONBLOCK);
36 if (err < 0) {
37 log_warnx("playback open error: %s", snd_strerror(err));
38 return -1;
39 }
41 /* TODO: set up onmove callback? */
42 return 0;
43 }
45 int
46 audio_setup(unsigned int bits, unsigned int rate, unsigned int channels,
47 struct pollfd *pfds)
48 {
49 int err;
50 snd_pcm_format_t fmt;
52 if (bits == 8)
53 fmt = SND_PCM_FORMAT_S8;
54 else if (bits == 16)
55 fmt = SND_PCM_FORMAT_S16;
56 else if (bits == 24)
57 fmt = SND_PCM_FORMAT_S24;
58 else if (bits == 32)
59 fmt = SND_PCM_FORMAT_S32;
60 else {
61 log_warnx("can't handle %d bits", bits);
62 return -1;
63 }
65 err = snd_pcm_set_params(pcm, fmt, SND_PCM_ACCESS_RW_INTERLEAVED,
66 channels, rate, 1, 500000 /* 0.5s */);
67 if (err < 0) {
68 log_warnx("invalid params: %s", snd_strerror(err));
69 return -1;
70 }
72 err = snd_pcm_prepare(pcm);
73 if (err < 0) {
74 log_warnx("snd_pcm_prepare failed: %s", snd_strerror(err));
75 return -1;
76 }
78 return 0;
79 }
81 int
82 audio_nfds(void)
83 {
84 return snd_pcm_poll_descriptors_count(pcm);
85 }
87 int
88 audio_pollfd(struct pollfd *pfds, int events)
89 {
90 return snd_pcm_poll_descriptors(pcm, pfds, audio_nfds());
91 }
93 int
94 audio_revents(struct pollfd *pfds)
95 {
96 int err;
97 unsigned short revents;
99 err = snd_pcm_poll_descriptors_revents(pcm, pfds, audio_nfds(),
100 &revents);
101 if (err < 0) {
102 log_warnx("snd revents failure: %s", snd_strerror(err));
103 return 0;
106 return revents;
109 size_t
110 audio_write(const void *buf, size_t len)
112 snd_pcm_sframes_t ret;
114 ret = snd_pcm_writei(pcm, buf, len);
115 if (ret < 0) {
116 log_warnx("snd_pcm_writei failed: %s", snd_strerror(ret));
117 return 0;
119 return ret;
122 int
123 audio_flush(void)
125 int err;
127 err = snd_pcm_drop(pcm);
128 if (err < 0) {
129 log_warnx("snd_pcm_drop: %s", snd_strerror(err));
130 return -1;
133 return 0;
136 int
137 audio_stop(void)
139 int err;
141 err = snd_pcm_drain(pcm);
142 if (err < 0) {
143 log_warnx("snd_pcm_drain: %s", snd_strerror(err));
144 return -1;
147 return 0;