Blob


1 /*
2 * Copyright (c) 2022 Omar Polo <op@openbsd.org>
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 <sys/mman.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <sys/uio.h>
23 #include <err.h>
24 #include <event.h>
25 #include <fcntl.h>
26 #include <limits.h>
27 #include <sndio.h>
28 #include <stdio.h>
29 #include <stdint.h>
30 #include <imsg.h>
31 #include <unistd.h>
33 #include <string.h>
35 #include <mad.h>
37 #include "amused.h"
38 #include "log.h"
40 struct mad_stream mad_stream;
41 struct mad_frame mad_frame;
42 struct mad_synth mad_synth;
44 struct buffer {
45 const void *start;
46 size_t length;
47 int sample_rate;
48 int channels;
49 };
51 static enum mad_flow
52 input(void *d, struct mad_stream *stream)
53 {
54 struct buffer *buffer = d;
56 if (buffer->length == 0)
57 return MAD_FLOW_STOP;
59 mad_stream_buffer(stream, buffer->start, buffer->length);
60 buffer->length = 0;
61 buffer->sample_rate = 0;
62 buffer->channels = 0;
63 return MAD_FLOW_CONTINUE;
64 }
66 static enum mad_flow
67 output(void *data, const struct mad_header *header, struct mad_pcm *pcm)
68 {
69 static uint32_t buf[BUFSIZ];
70 size_t len;
71 struct buffer *buffer = data;
72 int nsamples, i;
73 uint32_t sample;
74 const mad_fixed_t *leftch, *rightch;
76 if (player_shouldstop())
77 return MAD_FLOW_STOP;
79 nsamples = pcm->length;
80 leftch = pcm->samples[0];
81 rightch = pcm->samples[1];
83 if (buffer->sample_rate != pcm->samplerate ||
84 buffer->channels != pcm->channels) {
85 buffer->sample_rate = pcm->samplerate;
86 buffer->channels = pcm->channels;
87 if (player_setup(32, pcm->samplerate, pcm->channels) == -1)
88 err(1, "player_setrate");
89 }
91 for (i = 0, len = 0; i < nsamples; ++i) {
92 if (len+2 >= sizeof(buf)) {
93 sio_write(hdl, buf, len * sizeof(sample));
94 len = 0;
95 }
97 sample = *leftch++;
98 buf[len++] = sample;
100 if (pcm->channels == 2) {
101 sample = *rightch++;
102 buf[len++] = sample;
106 if (len != 0)
107 sio_write(hdl, buf, len * sizeof(sample));
109 return MAD_FLOW_CONTINUE;
112 static enum mad_flow
113 error(void *d, struct mad_stream *stream, struct mad_frame *frame)
115 struct buffer *buffer = d;
117 /*
118 * most of the decoding errors are actually ID3 tags. Since
119 * they're common, this has a lower priority to avoid spamming
120 * syslog.
121 */
122 log_debug("decoding error 0x%04x (%s) at byte offset %zu",
123 stream->error, mad_stream_errorstr(stream),
124 stream->this_frame - (const unsigned char *)buffer->start);
126 return MAD_FLOW_CONTINUE;
129 static int
130 decode(void *m, size_t len)
132 struct buffer buffer;
133 struct mad_decoder decoder;
134 int result;
136 /* initialize our private message structure; */
137 buffer.start = m;
138 buffer.length = len;
140 /* configure input, output and error functions */
141 mad_decoder_init(&decoder, &buffer, input, 0 /* header */,
142 0 /* filter */, output, error, 0 /* message */);
144 /* start decoding */
145 result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
147 /* release the decoder */
148 mad_decoder_finish(&decoder);
150 return result;
153 void
154 play_mp3(int fd)
156 struct stat stat;
157 void *m;
159 if (fstat(fd, &stat) == -1) {
160 log_warn("fstat");
161 goto end;
164 m = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
165 if (m == MAP_FAILED) {
166 log_warn("map failed");
167 goto end;
170 decode(m, stat.st_size);
171 munmap(m, stat.st_size);
173 end:
174 close(fd);