2 * This file is part of DisOrder
3 * Copyright (C) 2007-2010 Richard Kettlewell
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 /** @file server/decode.c
19 * @brief General-purpose decoder for use by speaker process
22 #include <FLAC/stream_decoder.h>
24 /** @brief Metadata callback for FLAC decoder
26 * This is a no-op here.
28 static void flac_metadata(const FLAC__StreamDecoder attribute((unused)) *decoder,
29 const FLAC__StreamMetadata attribute((unused)) *metadata,
30 void attribute((unused)) *client_data) {
33 /** @brief Error callback for FLAC decoder */
34 static void flac_error(const FLAC__StreamDecoder attribute((unused)) *decoder,
35 FLAC__StreamDecoderErrorStatus status,
36 void attribute((unused)) *client_data) {
37 disorder_fatal(0, "error decoding %s: %s", path,
38 FLAC__StreamDecoderErrorStatusString[status]);
41 /** @brief Write callback for FLAC decoder */
42 static FLAC__StreamDecoderWriteStatus flac_write
43 (const FLAC__StreamDecoder attribute((unused)) *decoder,
44 const FLAC__Frame *frame,
45 const FLAC__int32 *const buffer[],
46 void attribute((unused)) *client_data) {
49 output_header(frame->header.sample_rate,
50 frame->header.channels,
51 frame->header.bits_per_sample,
52 (frame->header.channels * frame->header.blocksize
53 * frame->header.bits_per_sample) / 8,
55 for(n = 0; n < frame->header.blocksize; ++n) {
56 for(c = 0; c < frame->header.channels; ++c) {
57 switch(frame->header.bits_per_sample) {
58 case 8: output_8(buffer[c][n]); break;
59 case 16: output_16(buffer[c][n]); break;
60 case 24: output_24(buffer[c][n]); break;
61 case 32: output_32(buffer[c][n]); break;
65 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
68 static FLAC__StreamDecoderReadStatus flac_read(const FLAC__StreamDecoder attribute((unused)) *decoder,
72 struct hreader *flacinput = client_data;
73 int n = hreader_read(flacinput, buffer, *bytes);
76 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
80 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
83 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
86 static FLAC__StreamDecoderSeekStatus flac_seek(const FLAC__StreamDecoder attribute((unused)) *decoder,
87 FLAC__uint64 absolute_byte_offset,
89 struct hreader *flacinput = client_data;
90 if(hreader_seek(flacinput, absolute_byte_offset, SEEK_SET) < 0)
91 return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
93 return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
96 static FLAC__StreamDecoderTellStatus flac_tell(const FLAC__StreamDecoder attribute((unused)) *decoder,
97 FLAC__uint64 *absolute_byte_offset,
99 struct hreader *flacinput = client_data;
100 off_t offset = hreader_seek(flacinput, 0, SEEK_CUR);
102 return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
103 *absolute_byte_offset = offset;
104 return FLAC__STREAM_DECODER_TELL_STATUS_OK;
107 static FLAC__StreamDecoderLengthStatus flac_length(const FLAC__StreamDecoder attribute((unused)) *decoder,
108 FLAC__uint64 *stream_length,
110 struct hreader *flacinput = client_data;
111 *stream_length = hreader_size(flacinput);
112 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
115 static FLAC__bool flac_eof(const FLAC__StreamDecoder attribute((unused)) *decoder,
117 struct hreader *flacinput = client_data;
118 return hreader_eof(flacinput);
121 /** @brief FLAC file decoder */
122 void decode_flac(void) {
123 FLAC__StreamDecoder *sd = FLAC__stream_decoder_new();
124 FLAC__StreamDecoderInitStatus is;
125 struct hreader flacinput[1];
128 disorder_fatal(0, "FLAC__stream_decoder_new failed");
129 if(hreader_init(path, flacinput))
130 disorder_fatal(errno, "error opening %s", path);
132 if((is = FLAC__stream_decoder_init_stream(sd,
138 flac_write, flac_metadata,
141 disorder_fatal(0, "FLAC__stream_decoder_init_stream %s: %s",
142 path, FLAC__StreamDecoderInitStatusString[is]);
144 FLAC__stream_decoder_process_until_end_of_stream(sd);
145 FLAC__stream_decoder_finish(sd);
146 FLAC__stream_decoder_delete(sd);