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 "config.h"
19 #include <inttypes.h>
20 #include <limits.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <string.h>
25 #include <unistd.h>
27 #include <FLAC/stream_decoder.h>
29 #include "amused.h"
30 #include "log.h"
32 struct write_args {
33 FLAC__StreamDecoder *decoder;
34 int seek_failed;
35 };
37 static int
38 sample_seek(struct write_args *wa, int64_t seek)
39 {
40 int ok;
42 ok = FLAC__stream_decoder_seek_absolute(wa->decoder, seek);
43 if (ok)
44 player_setpos(seek);
45 else
46 wa->seek_failed = 1;
47 return ok;
48 }
50 static FLAC__StreamDecoderWriteStatus
51 writecb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame,
52 const int32_t * const *src, void *data)
53 {
54 struct write_args *wa = data;
55 static uint8_t buf[BUFSIZ];
56 int64_t seek;
57 int c, i, bps, chans;
58 size_t len;
60 bps = frame->header.bits_per_sample;
61 chans = frame->header.channels;
63 for (i = 0, len = 0; i < frame->header.blocksize; ++i) {
64 if (len + 4*chans >= sizeof(buf)) {
65 if (!play(buf, len, &seek))
66 goto quit;
67 if (seek != -1) {
68 if (sample_seek(wa, seek))
69 break;
70 else
71 goto quit;
72 }
73 len = 0;
74 }
76 for (c = 0; c < chans; ++c) {
77 switch (bps) {
78 case 8:
79 buf[len++] = src[c][i] & 0xff;
80 break;
81 case 16:
82 buf[len++] = src[c][i] & 0xff;
83 buf[len++] = (src[c][i] >> 8) & 0xff;
84 break;
85 case 24:
86 case 32:
87 buf[len++] = src[c][i] & 0xff;
88 buf[len++] = (src[c][i] >> 8) & 0xff;
89 buf[len++] = (src[c][i] >> 16) & 0xff;
90 buf[len++] = (src[c][i] >> 24) & 0xff;
91 break;
92 default:
93 log_warnx("unsupported flac bps=%d", bps);
94 goto quit;
95 }
96 }
97 }
99 if (len != 0 && !play(buf, len, &seek))
100 goto quit;
102 if (seek != -1 && !sample_seek(wa, seek))
103 goto quit;
105 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
106 quit:
107 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
110 static void
111 metacb(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *meta,
112 void *d)
114 uint32_t sample_rate;
115 int channels, bits;
117 if (meta->type == FLAC__METADATA_TYPE_STREAMINFO) {
118 bits = meta->data.stream_info.bits_per_sample;
119 sample_rate = meta->data.stream_info.sample_rate;
120 channels = meta->data.stream_info.channels;
122 if (player_setup(bits, sample_rate, channels) == -1)
123 err(1, "player_setup");
125 player_setduration(meta->data.stream_info.total_samples);
129 static void
130 errcb(const FLAC__StreamDecoder *decoder,
131 FLAC__StreamDecoderErrorStatus status, void *data)
133 log_warnx("flac error: %s",
134 FLAC__StreamDecoderErrorStatusString[status]);
137 int
138 play_flac(int fd, const char **errstr)
140 FILE *f;
141 struct write_args wa;
142 int s, ok = 1;
143 FLAC__StreamDecoder *decoder = NULL;
144 FLAC__StreamDecoderInitStatus init_status;
146 if ((f = fdopen(fd, "r")) == NULL) {
147 *errstr = "fdopen failed";
148 close(fd);
149 return -1;
152 decoder = FLAC__stream_decoder_new();
153 if (decoder == NULL) {
154 *errstr = "FLAC__stream_decoder_new() failed";
155 fclose(f);
156 return -1;
159 FLAC__stream_decoder_set_md5_checking(decoder, 1);
161 memset(&wa, 0, sizeof(wa));
162 wa.decoder = decoder;
164 init_status = FLAC__stream_decoder_init_FILE(decoder, f, writecb,
165 metacb, errcb, &wa);
166 if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
167 errx(1, "flac decoder: %s",
168 FLAC__StreamDecoderInitStatusString[init_status]);
170 ok = FLAC__stream_decoder_process_until_end_of_stream(decoder);
172 s = FLAC__stream_decoder_get_state(decoder);
173 FLAC__stream_decoder_delete(decoder);
174 fclose(f);
176 if (s == FLAC__STREAM_DECODER_ABORTED && !wa.seek_failed)
177 return 1;
178 else if (!ok && !wa.seek_failed) {
179 *errstr = "flac decoding error";
180 return -1;
181 } else
182 return 0;