2 * This file is part of DisOrder
3 * Copyright (C) 2007-2011 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-flac.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
);