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>
26 #include <FLAC/stream_decoder.h>
28 #include "amused.h"
29 #include "log.h"
31 struct write_args {
32 FLAC__StreamDecoder *decoder;
33 int seek_failed;
34 };
36 static int
37 sample_seek(struct write_args *wa, int64_t seek)
38 {
39 int ok;
41 ok = FLAC__stream_decoder_seek_absolute(wa->decoder, seek);
42 if (ok)
43 player_setpos(seek);
44 else
45 wa->seek_failed = 1;
46 return ok;
47 }
49 static FLAC__StreamDecoderWriteStatus
50 writecb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame,
51 const int32_t * const *src, void *data)
52 {
53 struct write_args *wa = data;
54 static uint8_t buf[BUFSIZ];
55 int64_t seek;
56 int c, i, bps, chans;
57 size_t len;
59 bps = frame->header.bits_per_sample;
60 chans = frame->header.channels;
62 for (i = 0, len = 0; i < frame->header.blocksize; ++i) {
63 if (len + 4*chans >= sizeof(buf)) {
64 if (!play(buf, len, &seek))
65 goto quit;
66 if (seek != -1) {
67 if (sample_seek(wa, seek))
68 break;
69 else
70 goto quit;
71 }
72 len = 0;
73 }
75 for (c = 0; c < chans; ++c) {
76 switch (bps) {
77 case 8:
78 buf[len++] = src[c][i] & 0xff;
79 break;
80 case 16:
81 buf[len++] = src[c][i] & 0xff;
82 buf[len++] = (src[c][i] >> 8) & 0xff;
83 break;
84 case 24:
85 case 32:
86 buf[len++] = src[c][i] & 0xff;
87 buf[len++] = (src[c][i] >> 8) & 0xff;
88 buf[len++] = (src[c][i] >> 16) & 0xff;
89 buf[len++] = (src[c][i] >> 24) & 0xff;
90 break;
91 default:
92 log_warnx("unsupported flac bps=%d", bps);
93 goto quit;
94 }
95 }
96 }
98 if (len != 0 && !play(buf, len, &seek))
99 goto quit;
101 if (seek != -1 && !sample_seek(wa, seek))
102 goto quit;
104 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
105 quit:
106 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
109 static void
110 metacb(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *meta,
111 void *d)
113 uint32_t sample_rate;
114 int channels, bits;
116 if (meta->type == FLAC__METADATA_TYPE_STREAMINFO) {
117 bits = meta->data.stream_info.bits_per_sample;
118 sample_rate = meta->data.stream_info.sample_rate;
119 channels = meta->data.stream_info.channels;
121 if (player_setup(bits, sample_rate, channels) == -1)
122 err(1, "player_setup");
124 player_setduration(meta->data.stream_info.total_samples);
128 static void
129 errcb(const FLAC__StreamDecoder *decoder,
130 FLAC__StreamDecoderErrorStatus status, void *data)
132 log_warnx("flac error: %s",
133 FLAC__StreamDecoderErrorStatusString[status]);
136 int
137 play_flac(int fd, const char **errstr)
139 FILE *f;
140 struct write_args wa;
141 int s, ok = 1;
142 FLAC__StreamDecoder *decoder = NULL;
143 FLAC__StreamDecoderInitStatus init_status;
145 if ((f = fdopen(fd, "r")) == NULL)
146 err(1, "fdopen");
148 decoder = FLAC__stream_decoder_new();
149 if (decoder == NULL)
150 err(1, "flac stream decoder");
152 FLAC__stream_decoder_set_md5_checking(decoder, 1);
154 memset(&wa, 0, sizeof(wa));
155 wa.decoder = decoder;
157 init_status = FLAC__stream_decoder_init_FILE(decoder, f, writecb,
158 metacb, errcb, &wa);
159 if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
160 errx(1, "flac decoder: %s",
161 FLAC__StreamDecoderInitStatusString[init_status]);
163 ok = FLAC__stream_decoder_process_until_end_of_stream(decoder);
165 s = FLAC__stream_decoder_get_state(decoder);
166 FLAC__stream_decoder_delete(decoder);
167 fclose(f);
169 if (s == FLAC__STREAM_DECODER_ABORTED && !wa.seek_failed)
170 return 1;
171 else if (!ok && !wa.seek_failed) {
172 *errstr = "flac decoding error";
173 return -1;
174 } else
175 return 0;