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/types.h>
18 #include <sys/queue.h>
19 #include <sys/uio.h>
21 #include <err.h>
22 #include <event.h>
23 #include <inttypes.h>
24 #include <limits.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdint.h>
28 #include <string.h>
29 #include <imsg.h>
31 #include <FLAC/stream_decoder.h>
33 #include "amused.h"
34 #include "log.h"
36 struct write_args {
37 FLAC__StreamDecoder *decoder;
38 int seek_failed;
39 };
41 static int
42 sample_seek(struct write_args *wa, int64_t seek)
43 {
44 int ok;
46 ok = FLAC__stream_decoder_seek_absolute(wa->decoder, seek);
47 if (ok)
48 player_setpos(seek);
49 else
50 wa->seek_failed = 1;
51 return ok;
52 }
54 static FLAC__StreamDecoderWriteStatus
55 writecb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame,
56 const int32_t * const *src, void *data)
57 {
58 struct write_args *wa = data;
59 static uint8_t buf[BUFSIZ];
60 int64_t seek;
61 int c, i, bps, chans;
62 size_t len;
64 bps = frame->header.bits_per_sample;
65 chans = frame->header.channels;
67 for (i = 0, len = 0; i < frame->header.blocksize; ++i) {
68 if (len + 4*chans >= sizeof(buf)) {
69 if (!play(buf, len, &seek))
70 goto quit;
71 if (seek != -1) {
72 if (sample_seek(wa, seek))
73 break;
74 else
75 goto quit;
76 }
77 len = 0;
78 }
80 for (c = 0; c < chans; ++c) {
81 switch (bps) {
82 case 8:
83 buf[len++] = src[c][i] & 0xff;
84 break;
85 case 16:
86 buf[len++] = src[c][i] & 0xff;
87 buf[len++] = (src[c][i] >> 8) & 0xff;
88 break;
89 case 24:
90 case 32:
91 buf[len++] = src[c][i] & 0xff;
92 buf[len++] = (src[c][i] >> 8) & 0xff;
93 buf[len++] = (src[c][i] >> 16) & 0xff;
94 buf[len++] = (src[c][i] >> 24) & 0xff;
95 break;
96 default:
97 log_warnx("unsupported flac bps=%d", bps);
98 goto quit;
99 }
103 if (len != 0 && !play(buf, len, &seek))
104 goto quit;
106 if (seek != -1 && !sample_seek(wa, seek))
107 goto quit;
109 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
110 quit:
111 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
114 static void
115 metacb(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *meta,
116 void *d)
118 uint32_t sample_rate;
119 int channels, bits;
121 if (meta->type == FLAC__METADATA_TYPE_STREAMINFO) {
122 bits = meta->data.stream_info.bits_per_sample;
123 sample_rate = meta->data.stream_info.sample_rate;
124 channels = meta->data.stream_info.channels;
126 if (player_setup(bits, sample_rate, channels) == -1)
127 err(1, "player_setup");
129 player_setduration(meta->data.stream_info.total_samples);
133 static void
134 errcb(const FLAC__StreamDecoder *decoder,
135 FLAC__StreamDecoderErrorStatus status, void *data)
137 log_warnx("flac error: %s",
138 FLAC__StreamDecoderErrorStatusString[status]);
141 int
142 play_flac(int fd, const char **errstr)
144 FILE *f;
145 struct write_args wa;
146 int s, ok = 1;
147 FLAC__StreamDecoder *decoder = NULL;
148 FLAC__StreamDecoderInitStatus init_status;
150 if ((f = fdopen(fd, "r")) == NULL)
151 err(1, "fdopen");
153 decoder = FLAC__stream_decoder_new();
154 if (decoder == NULL)
155 err(1, "flac stream decoder");
157 FLAC__stream_decoder_set_md5_checking(decoder, 1);
159 memset(&wa, 0, sizeof(wa));
160 wa.decoder = decoder;
162 init_status = FLAC__stream_decoder_init_FILE(decoder, f, writecb,
163 metacb, errcb, &wa);
164 if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
165 errx(1, "flac decoder: %s",
166 FLAC__StreamDecoderInitStatusString[init_status]);
168 ok = FLAC__stream_decoder_process_until_end_of_stream(decoder);
170 s = FLAC__stream_decoder_get_state(decoder);
171 FLAC__stream_decoder_delete(decoder);
172 fclose(f);
174 if (s == FLAC__STREAM_DECODER_ABORTED && !wa.seek_failed)
175 return 1;
176 else if (!ok && !wa.seek_failed) {
177 *errstr = "flac decoding error";
178 return -1;
179 } else
180 return 0;