Mercurial > audlegacy
annotate Plugins/Input/flac/plugin.c @ 188:6bdc6841b0a9 trunk
[svn] Fix includes to avoid implicit declaration warnings.
author | chainsaw |
---|---|
date | Mon, 14 Nov 2005 15:45:51 -0800 |
parents | 2626212fdad4 |
children | 57d01c5bd39f |
rev | line source |
---|---|
61 | 1 /* libxmms-flac - XMMS FLAC input plugin |
2 * Copyright (C) 2000,2001,2002,2003,2004,2005 Josh Coalson | |
3 * | |
4 * This program is free software; you can redistribute it and/or | |
5 * modify it under the terms of the GNU General Public License | |
6 * as published by the Free Software Foundation; either version 2 | |
7 * of the License, or (at your option) any later version. | |
8 * | |
9 * This program is distributed in the hope that it will be useful, | |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 * GNU General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU General Public License | |
15 * along with this program; if not, write to the Free Software | |
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
17 */ | |
18 | |
19 #include <stdlib.h> | |
20 #include <string.h> | |
21 #include <stdio.h> | |
22 #include <glib.h> | |
23 #include <pwd.h> | |
24 #include <sys/types.h> | |
25 #include <unistd.h> | |
26 | |
27 #include <audacious/plugin.h> | |
188
6bdc6841b0a9
[svn] Fix includes to avoid implicit declaration warnings.
chainsaw
parents:
181
diff
changeset
|
28 #include <libaudacious/util.h> |
61 | 29 #include <libaudacious/configfile.h> |
30 #include <libaudacious/titlestring.h> | |
31 | |
32 #ifdef HAVE_CONFIG_H | |
33 #include <config.h> | |
34 #endif | |
35 | |
36 #ifdef HAVE_LANGINFO_CODESET | |
37 #include <langinfo.h> | |
38 #endif | |
39 | |
40 #include "FLAC/all.h" | |
41 #include "plugin_common/all.h" | |
42 #include "grabbag.h" | |
43 #include "replaygain_synthesis.h" | |
44 #include "configure.h" | |
45 #include "charset.h" | |
46 #include "http.h" | |
47 #include "tag.h" | |
48 | |
49 #ifdef min | |
50 #undef min | |
51 #endif | |
52 #define min(x,y) ((x)<(y)?(x):(y)) | |
53 | |
54 /* adjust for compilers that can't understand using LLU suffix for uint64_t literals */ | |
55 #ifdef _MSC_VER | |
56 #define FLAC__U64L(x) x | |
57 #else | |
58 #define FLAC__U64L(x) x##LLU | |
59 #endif | |
60 | |
61 extern void FLAC_XMMS__file_info_box(char *filename); | |
62 | |
63 typedef struct { | |
64 FLAC__bool abort_flag; | |
65 FLAC__bool is_playing; | |
66 FLAC__bool eof; | |
67 FLAC__bool play_thread_open; /* if true, is_playing must also be true */ | |
68 unsigned total_samples; | |
69 unsigned bits_per_sample; | |
70 unsigned channels; | |
71 unsigned sample_rate; | |
72 unsigned length_in_msec; | |
73 gchar *title; | |
74 AFormat sample_format; | |
75 unsigned sample_format_bytes_per_sample; | |
76 int seek_to_in_sec; | |
77 FLAC__bool has_replaygain; | |
78 double replay_scale; | |
79 DitherContext dither_context; | |
80 } file_info_struct; | |
81 | |
82 typedef FLAC__StreamDecoderWriteStatus (*WriteCallback) (const void *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); | |
83 typedef void (*MetadataCallback) (const void *decoder, const FLAC__StreamMetadata *metadata, void *client_data); | |
84 typedef void (*ErrorCallback) (const void *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); | |
85 | |
86 typedef struct { | |
87 FLAC__bool seekable; | |
88 void* (*new_decoder) (void); | |
89 FLAC__bool (*set_md5_checking) (void *decoder, FLAC__bool value); | |
90 FLAC__bool (*set_source) (void *decoder, const char* source); | |
91 FLAC__bool (*set_metadata_ignore_all) (void *decoder); | |
92 FLAC__bool (*set_metadata_respond) (void *decoder, FLAC__MetadataType type); | |
93 FLAC__bool (*set_write_callback) (void *decoder, WriteCallback value); | |
94 FLAC__bool (*set_metadata_callback) (void *decoder, MetadataCallback value); | |
95 FLAC__bool (*set_error_callback) (void *decoder, ErrorCallback value); | |
96 FLAC__bool (*set_client_data) (void *decoder, void *value); | |
97 FLAC__bool (*decoder_init) (void *decoder); | |
98 void (*safe_decoder_finish) (void *decoder); | |
99 void (*safe_decoder_delete) (void *decoder); | |
100 FLAC__bool (*process_until_end_of_metadata) (void *decoder); | |
101 FLAC__bool (*process_single) (void *decoder); | |
102 FLAC__bool (*is_eof) (void *decoder); | |
103 } decoder_funcs_t; | |
104 | |
105 #define NUM_DECODER_TYPES 2 | |
106 typedef enum { | |
107 DECODER_FILE, | |
108 DECODER_HTTP | |
109 } decoder_t; | |
110 | |
111 static void FLAC_XMMS__init(); | |
112 static int FLAC_XMMS__is_our_file(char *filename); | |
113 static void FLAC_XMMS__play_file(char *filename); | |
114 static void FLAC_XMMS__stop(); | |
115 static void FLAC_XMMS__pause(short p); | |
116 static void FLAC_XMMS__seek(int time); | |
117 static int FLAC_XMMS__get_time(); | |
118 static void FLAC_XMMS__cleanup(); | |
119 static void FLAC_XMMS__get_song_info(char *filename, char **title, int *length); | |
120 | |
121 static void *play_loop_(void *arg); | |
122 | |
123 static FLAC__bool safe_decoder_init_(const char *filename, void **decoderp, decoder_funcs_t const ** fnsp); | |
124 static void file_decoder_safe_decoder_finish_(void *decoder); | |
125 static void file_decoder_safe_decoder_delete_(void *decoder); | |
126 static FLAC__StreamDecoderWriteStatus write_callback_(const void *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); | |
127 static void metadata_callback_(const void *decoder, const FLAC__StreamMetadata *metadata, void *client_data); | |
128 static void error_callback_(const void *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); | |
129 | |
130 static void init_decoder_func_tables(); | |
131 static decoder_t source_to_decoder_type (const char *source); | |
132 | |
133 InputPlugin flac_ip = | |
134 { | |
135 NULL, | |
136 NULL, | |
137 "FLAC Player v" VERSION, | |
138 FLAC_XMMS__init, | |
139 FLAC_XMMS__aboutbox, | |
140 FLAC_XMMS__configure, | |
141 FLAC_XMMS__is_our_file, | |
142 NULL, | |
143 FLAC_XMMS__play_file, | |
144 FLAC_XMMS__stop, | |
145 FLAC_XMMS__pause, | |
146 FLAC_XMMS__seek, | |
147 NULL, | |
148 FLAC_XMMS__get_time, | |
149 NULL, | |
150 NULL, | |
151 FLAC_XMMS__cleanup, | |
152 NULL, | |
153 NULL, | |
154 NULL, | |
155 NULL, | |
156 FLAC_XMMS__get_song_info, | |
157 FLAC_XMMS__file_info_box, | |
158 NULL | |
159 }; | |
160 | |
161 #define SAMPLES_PER_WRITE 512 | |
162 #define SAMPLE_BUFFER_SIZE ((FLAC__MAX_BLOCK_SIZE + SAMPLES_PER_WRITE) * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8)) | |
163 static FLAC__byte sample_buffer_[SAMPLE_BUFFER_SIZE]; | |
164 static unsigned sample_buffer_first_, sample_buffer_last_; | |
165 | |
166 static void *decoder_ = 0; | |
167 static file_info_struct file_info_; | |
181 | 168 static GThread *decode_thread_; |
61 | 169 static FLAC__bool audio_error_ = false; |
170 static FLAC__bool is_big_endian_host_; | |
171 | |
172 #define BITRATE_HIST_SEGMENT_MSEC 500 | |
173 /* 500ms * 50 = 25s should be enough */ | |
174 #define BITRATE_HIST_SIZE 50 | |
175 static unsigned bitrate_history_[BITRATE_HIST_SIZE]; | |
176 | |
177 /* A table of sets of decoder functions, indexed by decoder_t */ | |
178 static const decoder_funcs_t* DECODER_FUNCS[NUM_DECODER_TYPES]; | |
179 | |
180 static decoder_funcs_t const * decoder_func_table_; | |
181 | |
182 | |
183 InputPlugin *get_iplugin_info() | |
184 { | |
185 flac_ip.description = g_strdup_printf("Reference FLAC Player v%s", FLAC__VERSION_STRING); | |
186 return &flac_ip; | |
187 } | |
188 | |
189 void set_track_info(const char* title, int length_in_msec) | |
190 { | |
191 if (file_info_.is_playing) { | |
192 flac_ip.set_info((char*) title, length_in_msec, file_info_.sample_rate * file_info_.channels * file_info_.bits_per_sample, file_info_.sample_rate, file_info_.channels); | |
193 } | |
194 } | |
195 | |
196 static gchar* homedir() | |
197 { | |
198 gchar *result; | |
199 char *env_home = getenv("HOME"); | |
200 if (env_home) { | |
201 result = g_strdup (env_home); | |
202 } else { | |
203 uid_t uid = getuid(); | |
204 struct passwd *pwent; | |
205 do { | |
206 pwent = getpwent(); | |
207 } while (pwent && pwent->pw_uid != uid); | |
208 result = pwent ? g_strdup (pwent->pw_dir) : NULL; | |
209 endpwent(); | |
210 } | |
211 return result; | |
212 } | |
213 | |
214 void FLAC_XMMS__init() | |
215 { | |
216 ConfigFile *cfg; | |
217 FLAC__uint32 test = 1; | |
218 | |
219 is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true; | |
220 | |
221 flac_cfg.title.tag_override = FALSE; | |
222 g_free(flac_cfg.title.tag_format); | |
223 flac_cfg.title.convert_char_set = FALSE; | |
224 | |
225 cfg = xmms_cfg_open_default_file(); | |
226 | |
227 /* title */ | |
228 | |
229 xmms_cfg_read_boolean(cfg, "flac", "title.tag_override", &flac_cfg.title.tag_override); | |
230 | |
231 if(!xmms_cfg_read_string(cfg, "flac", "title.tag_format", &flac_cfg.title.tag_format)) | |
232 flac_cfg.title.tag_format = g_strdup("%p - %t"); | |
233 | |
234 xmms_cfg_read_boolean(cfg, "flac", "title.convert_char_set", &flac_cfg.title.convert_char_set); | |
235 | |
236 if(!xmms_cfg_read_string(cfg, "flac", "title.user_char_set", &flac_cfg.title.user_char_set)) | |
237 flac_cfg.title.user_char_set = FLAC_plugin__charset_get_current(); | |
238 | |
239 /* replaygain */ | |
240 | |
241 xmms_cfg_read_boolean(cfg, "flac", "output.replaygain.enable", &flac_cfg.output.replaygain.enable); | |
242 | |
243 xmms_cfg_read_boolean(cfg, "flac", "output.replaygain.album_mode", &flac_cfg.output.replaygain.album_mode); | |
244 | |
245 if(!xmms_cfg_read_int(cfg, "flac", "output.replaygain.preamp", &flac_cfg.output.replaygain.preamp)) | |
246 flac_cfg.output.replaygain.preamp = 0; | |
247 | |
248 xmms_cfg_read_boolean(cfg, "flac", "output.replaygain.hard_limit", &flac_cfg.output.replaygain.hard_limit); | |
249 | |
250 xmms_cfg_read_boolean(cfg, "flac", "output.resolution.normal.dither_24_to_16", &flac_cfg.output.resolution.normal.dither_24_to_16); | |
251 xmms_cfg_read_boolean(cfg, "flac", "output.resolution.replaygain.dither", &flac_cfg.output.resolution.replaygain.dither); | |
252 | |
253 if(!xmms_cfg_read_int(cfg, "flac", "output.resolution.replaygain.noise_shaping", &flac_cfg.output.resolution.replaygain.noise_shaping)) | |
254 flac_cfg.output.resolution.replaygain.noise_shaping = 1; | |
255 | |
256 if(!xmms_cfg_read_int(cfg, "flac", "output.resolution.replaygain.bps_out", &flac_cfg.output.resolution.replaygain.bps_out)) | |
257 flac_cfg.output.resolution.replaygain.bps_out = 16; | |
258 | |
259 /* stream */ | |
260 | |
261 xmms_cfg_read_int(cfg, "flac", "stream.http_buffer_size", &flac_cfg.stream.http_buffer_size); | |
262 xmms_cfg_read_int(cfg, "flac", "stream.http_prebuffer", &flac_cfg.stream.http_prebuffer); | |
263 xmms_cfg_read_boolean(cfg, "flac", "stream.use_proxy", &flac_cfg.stream.use_proxy); | |
264 xmms_cfg_read_string(cfg, "flac", "stream.proxy_host", &flac_cfg.stream.proxy_host); | |
265 xmms_cfg_read_int(cfg, "flac", "stream.proxy_port", &flac_cfg.stream.proxy_port); | |
266 xmms_cfg_read_boolean(cfg, "flac", "stream.proxy_use_auth", &flac_cfg.stream.proxy_use_auth); | |
267 xmms_cfg_read_string(cfg, "flac", "stream.proxy_user", &flac_cfg.stream.proxy_user); | |
268 xmms_cfg_read_string(cfg, "flac", "stream.proxy_pass", &flac_cfg.stream.proxy_pass); | |
269 xmms_cfg_read_boolean(cfg, "flac", "stream.save_http_stream", &flac_cfg.stream.save_http_stream); | |
270 if (!xmms_cfg_read_string(cfg, "flac", "stream.save_http_path", &flac_cfg.stream.save_http_path) || | |
271 ! *flac_cfg.stream.save_http_path) { | |
272 /* TODO: Is this a memory leak ?? */ | |
273 /* | |
274 if (flac_cfg.stream.save_http_path) | |
275 g_free (flac_cfg.stream.save_http_path); | |
276 */ | |
277 flac_cfg.stream.save_http_path = homedir(); | |
278 } | |
279 xmms_cfg_read_boolean(cfg, "flac", "stream.cast_title_streaming", &flac_cfg.stream.cast_title_streaming); | |
280 xmms_cfg_read_boolean(cfg, "flac", "stream.use_udp_channel", &flac_cfg.stream.use_udp_channel); | |
281 | |
282 init_decoder_func_tables(); | |
283 decoder_func_table_ = DECODER_FUNCS [DECODER_FILE]; | |
284 decoder_ = decoder_func_table_ -> new_decoder(); | |
285 | |
286 xmms_cfg_free(cfg); | |
287 } | |
288 | |
289 int FLAC_XMMS__is_our_file(char *filename) | |
290 { | |
291 char *ext; | |
292 | |
293 ext = strrchr(filename, '.'); | |
294 if(ext) | |
295 if(!strcasecmp(ext, ".flac") || !strcasecmp(ext, ".fla")) | |
296 return 1; | |
297 return 0; | |
298 } | |
299 | |
300 void FLAC_XMMS__play_file(char *filename) | |
301 { | |
302 FILE *f; | |
303 | |
304 sample_buffer_first_ = sample_buffer_last_ = 0; | |
305 audio_error_ = false; | |
306 file_info_.abort_flag = false; | |
307 file_info_.is_playing = false; | |
308 file_info_.eof = false; | |
309 file_info_.play_thread_open = false; | |
310 file_info_.has_replaygain = false; | |
311 | |
312 if (source_to_decoder_type (filename) == DECODER_FILE) { | |
313 if(0 == (f = fopen(filename, "r"))) | |
314 return; | |
315 fclose(f); | |
316 } | |
317 | |
318 if(decoder_ == 0) | |
319 return; | |
320 | |
321 if(!safe_decoder_init_(filename, &decoder_, &decoder_func_table_)) | |
322 return; | |
323 | |
324 if(file_info_.has_replaygain && flac_cfg.output.replaygain.enable) { | |
325 if(flac_cfg.output.resolution.replaygain.bps_out == 8) { | |
326 file_info_.sample_format = FMT_U8; | |
327 file_info_.sample_format_bytes_per_sample = 1; | |
328 } | |
329 else if(flac_cfg.output.resolution.replaygain.bps_out == 16) { | |
330 file_info_.sample_format = (is_big_endian_host_) ? FMT_S16_BE : FMT_S16_LE; | |
331 file_info_.sample_format_bytes_per_sample = 2; | |
332 } | |
333 else { | |
334 /*@@@ need some error here like wa2: MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16-bit samples\n", "ERROR: plugin can only handle 8/16-bit samples", 0); */ | |
335 fprintf(stderr, "libxmms-flac: can't handle %d bit output\n", flac_cfg.output.resolution.replaygain.bps_out); | |
336 decoder_func_table_ -> safe_decoder_finish(decoder_); | |
337 return; | |
338 } | |
339 } | |
340 else { | |
341 if(file_info_.bits_per_sample == 8) { | |
342 file_info_.sample_format = FMT_U8; | |
343 file_info_.sample_format_bytes_per_sample = 1; | |
344 } | |
345 else if(file_info_.bits_per_sample == 16 || (file_info_.bits_per_sample == 24 && flac_cfg.output.resolution.normal.dither_24_to_16)) { | |
346 file_info_.sample_format = (is_big_endian_host_) ? FMT_S16_BE : FMT_S16_LE; | |
347 file_info_.sample_format_bytes_per_sample = 2; | |
348 } | |
349 else { | |
350 /*@@@ need some error here like wa2: MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16-bit samples\n", "ERROR: plugin can only handle 8/16-bit samples", 0); */ | |
351 fprintf(stderr, "libxmms-flac: can't handle %d bit output\n", file_info_.bits_per_sample); | |
352 decoder_func_table_ -> safe_decoder_finish(decoder_); | |
353 return; | |
354 } | |
355 } | |
356 FLAC__replaygain_synthesis__init_dither_context(&file_info_.dither_context, file_info_.sample_format_bytes_per_sample * 8, flac_cfg.output.resolution.replaygain.noise_shaping); | |
357 file_info_.is_playing = true; | |
358 | |
359 if(flac_ip.output->open_audio(file_info_.sample_format, file_info_.sample_rate, file_info_.channels) == 0) { | |
360 audio_error_ = true; | |
361 decoder_func_table_ -> safe_decoder_finish(decoder_); | |
362 return; | |
363 } | |
364 | |
365 file_info_.title = flac_format_song_title(filename); | |
366 flac_ip.set_info(file_info_.title, file_info_.length_in_msec, file_info_.sample_rate * file_info_.channels * file_info_.bits_per_sample, file_info_.sample_rate, file_info_.channels); | |
367 | |
368 file_info_.seek_to_in_sec = -1; | |
369 file_info_.play_thread_open = true; | |
181 | 370 decode_thread_ = g_thread_create((GThreadFunc)play_loop_, NULL, TRUE, NULL); |
61 | 371 } |
372 | |
373 void FLAC_XMMS__stop() | |
374 { | |
375 if(file_info_.is_playing) { | |
376 file_info_.is_playing = false; | |
377 if(file_info_.play_thread_open) { | |
378 file_info_.play_thread_open = false; | |
181 | 379 g_thread_join(decode_thread_); |
61 | 380 } |
381 flac_ip.output->close_audio(); | |
382 decoder_func_table_ -> safe_decoder_finish (decoder_); | |
383 } | |
384 } | |
385 | |
386 void FLAC_XMMS__pause(short p) | |
387 { | |
388 flac_ip.output->pause(p); | |
389 } | |
390 | |
391 void FLAC_XMMS__seek(int time) | |
392 { | |
393 if (decoder_func_table_->seekable) { | |
394 file_info_.seek_to_in_sec = time; | |
395 file_info_.eof = false; | |
396 | |
397 while(file_info_.seek_to_in_sec != -1) | |
398 xmms_usleep(10000); | |
399 } | |
400 } | |
401 | |
402 int FLAC_XMMS__get_time() | |
403 { | |
404 if(audio_error_) | |
405 return -2; | |
406 if(!file_info_.is_playing || (file_info_.eof && !flac_ip.output->buffer_playing())) | |
407 return -1; | |
408 else | |
409 return flac_ip.output->output_time(); | |
410 } | |
411 | |
412 void FLAC_XMMS__cleanup() | |
413 { | |
414 decoder_func_table_ -> safe_decoder_delete(decoder_); | |
415 decoder_ = 0; | |
416 } | |
417 | |
418 void FLAC_XMMS__get_song_info(char *filename, char **title, int *length_in_msec) | |
419 { | |
420 FLAC__StreamMetadata streaminfo; | |
421 | |
422 if(0 == filename) | |
423 filename = ""; | |
424 | |
425 if(!FLAC__metadata_get_streaminfo(filename, &streaminfo)) { | |
426 /* @@@ how to report the error? */ | |
427 if(title) { | |
428 if (source_to_decoder_type (filename) == DECODER_FILE) { | |
429 static const char *errtitle = "Invalid FLAC File: "; | |
430 *title = g_malloc(strlen(errtitle) + 1 + strlen(filename) + 1 + 1); | |
431 sprintf(*title, "%s\"%s\"", errtitle, filename); | |
432 } else { | |
433 *title = NULL; | |
434 } | |
435 } | |
436 if(length_in_msec) | |
437 *length_in_msec = -1; | |
438 return; | |
439 } | |
440 | |
441 if(title) { | |
442 *title = flac_format_song_title(filename); | |
443 } | |
444 if(length_in_msec) | |
445 *length_in_msec = (unsigned)((double)streaminfo.data.stream_info.total_samples / (double)streaminfo.data.stream_info.sample_rate * 1000.0 + 0.5); | |
446 } | |
447 | |
448 /*********************************************************************** | |
449 * local routines | |
450 **********************************************************************/ | |
451 | |
452 void *play_loop_(void *arg) | |
453 { | |
454 unsigned written_time_last = 0, bh_index_last_w = 0, bh_index_last_o = BITRATE_HIST_SIZE, blocksize = 1; | |
455 FLAC__uint64 decode_position_last = 0, decode_position_frame_last = 0, decode_position_frame = 0; | |
456 | |
457 (void)arg; | |
458 | |
459 while(file_info_.is_playing) { | |
460 if(!file_info_.eof) { | |
461 while(sample_buffer_last_ - sample_buffer_first_ < SAMPLES_PER_WRITE) { | |
462 unsigned s; | |
463 | |
464 s = sample_buffer_last_ - sample_buffer_first_; | |
465 if(decoder_func_table_ -> is_eof(decoder_)) { | |
466 file_info_.eof = true; | |
467 break; | |
468 } | |
469 else if (!decoder_func_table_ -> process_single(decoder_)) { | |
470 /*@@@ this should probably be a dialog */ | |
471 fprintf(stderr, "libxmms-flac: READ ERROR processing frame\n"); | |
472 file_info_.eof = true; | |
473 break; | |
474 } | |
475 blocksize = sample_buffer_last_ - sample_buffer_first_ - s; | |
476 decode_position_frame_last = decode_position_frame; | |
477 if(!decoder_func_table_->seekable || !FLAC__file_decoder_get_decode_position(decoder_, &decode_position_frame)) | |
478 decode_position_frame = 0; | |
479 } | |
480 if(sample_buffer_last_ - sample_buffer_first_ > 0) { | |
481 const unsigned n = min(sample_buffer_last_ - sample_buffer_first_, SAMPLES_PER_WRITE); | |
482 int bytes = n * file_info_.channels * file_info_.sample_format_bytes_per_sample; | |
483 FLAC__byte *sample_buffer_start = sample_buffer_ + sample_buffer_first_ * file_info_.channels * file_info_.sample_format_bytes_per_sample; | |
484 unsigned written_time, bh_index_w; | |
485 FLAC__uint64 decode_position; | |
486 | |
487 sample_buffer_first_ += n; | |
488 flac_ip.add_vis_pcm(flac_ip.output->written_time(), file_info_.sample_format, file_info_.channels, bytes, sample_buffer_start); | |
489 while(flac_ip.output->buffer_free() < (int)bytes && file_info_.is_playing && file_info_.seek_to_in_sec == -1) | |
490 xmms_usleep(10000); | |
491 if(file_info_.is_playing && file_info_.seek_to_in_sec == -1) | |
492 flac_ip.output->write_audio(sample_buffer_start, bytes); | |
493 | |
494 /* compute current bitrate */ | |
495 | |
496 written_time = flac_ip.output->written_time(); | |
497 bh_index_w = written_time / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; | |
498 if(bh_index_w != bh_index_last_w) { | |
499 bh_index_last_w = bh_index_w; | |
500 decode_position = decode_position_frame - (double)(sample_buffer_last_ - sample_buffer_first_) * (double)(decode_position_frame - decode_position_frame_last) / (double)blocksize; | |
501 bitrate_history_[(bh_index_w + BITRATE_HIST_SIZE - 1) % BITRATE_HIST_SIZE] = | |
502 decode_position > decode_position_last && written_time > written_time_last ? | |
503 8000 * (decode_position - decode_position_last) / (written_time - written_time_last) : | |
504 file_info_.sample_rate * file_info_.channels * file_info_.bits_per_sample; | |
505 decode_position_last = decode_position; | |
506 written_time_last = written_time; | |
507 } | |
508 } | |
509 else { | |
510 file_info_.eof = true; | |
511 xmms_usleep(10000); | |
512 } | |
513 } | |
514 else | |
515 xmms_usleep(10000); | |
516 if(decoder_func_table_->seekable && file_info_.seek_to_in_sec != -1) { | |
517 const double distance = (double)file_info_.seek_to_in_sec * 1000.0 / (double)file_info_.length_in_msec; | |
518 unsigned target_sample = (unsigned)(distance * (double)file_info_.total_samples); | |
519 if(FLAC__file_decoder_seek_absolute(decoder_, (FLAC__uint64)target_sample)) { | |
520 flac_ip.output->flush(file_info_.seek_to_in_sec * 1000); | |
521 bh_index_last_w = bh_index_last_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; | |
522 if(!FLAC__file_decoder_get_decode_position(decoder_, &decode_position_frame)) | |
523 decode_position_frame = 0; | |
524 file_info_.seek_to_in_sec = -1; | |
525 file_info_.eof = false; | |
526 sample_buffer_first_ = sample_buffer_last_ = 0; | |
527 } | |
528 } | |
529 else { | |
530 /* display the right bitrate from history */ | |
531 unsigned bh_index_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; | |
532 if(bh_index_o != bh_index_last_o && bh_index_o != bh_index_last_w && bh_index_o != (bh_index_last_w + 1) % BITRATE_HIST_SIZE) { | |
533 bh_index_last_o = bh_index_o; | |
534 flac_ip.set_info(file_info_.title, file_info_.length_in_msec, bitrate_history_[bh_index_o], file_info_.sample_rate, file_info_.channels); | |
535 } | |
536 } | |
537 } | |
538 | |
539 decoder_func_table_ -> safe_decoder_finish(decoder_); | |
540 | |
541 /* are these two calls necessary? */ | |
542 flac_ip.output->buffer_free(); | |
543 flac_ip.output->buffer_free(); | |
544 | |
545 g_free(file_info_.title); | |
546 | |
181 | 547 g_thread_exit(NULL); |
61 | 548 return 0; /* to silence the compiler warning about not returning a value */ |
549 } | |
550 | |
551 /*********** File decoder functions */ | |
552 | |
553 static FLAC__bool file_decoder_init (void *decoder) | |
554 { | |
555 return FLAC__file_decoder_init( (FLAC__FileDecoder*) decoder) == FLAC__FILE_DECODER_OK; | |
556 } | |
557 | |
558 static void file_decoder_safe_decoder_finish_(void *decoder) | |
559 { | |
560 if(decoder && FLAC__file_decoder_get_state((FLAC__FileDecoder *) decoder) != FLAC__FILE_DECODER_UNINITIALIZED) | |
561 FLAC__file_decoder_finish((FLAC__FileDecoder *) decoder); | |
562 } | |
563 | |
564 static void file_decoder_safe_decoder_delete_(void *decoder) | |
565 { | |
566 if(decoder) { | |
567 file_decoder_safe_decoder_finish_(decoder); | |
568 FLAC__file_decoder_delete( (FLAC__FileDecoder *) decoder); | |
569 } | |
570 } | |
571 | |
572 static FLAC__bool file_decoder_is_eof(void *decoder) | |
573 { | |
574 return FLAC__file_decoder_get_state((FLAC__FileDecoder *) decoder) == FLAC__FILE_DECODER_END_OF_FILE; | |
575 } | |
576 | |
577 static const decoder_funcs_t FILE_DECODER_FUNCTIONS = { | |
578 true, | |
579 (void* (*) (void)) FLAC__file_decoder_new, | |
580 (FLAC__bool (*) (void *, FLAC__bool)) FLAC__file_decoder_set_md5_checking, | |
581 (FLAC__bool (*) (void *, const char*)) FLAC__file_decoder_set_filename, | |
582 (FLAC__bool (*) (void *)) FLAC__file_decoder_set_metadata_ignore_all, | |
583 (FLAC__bool (*) (void *, FLAC__MetadataType)) FLAC__file_decoder_set_metadata_respond, | |
584 (FLAC__bool (*) (void *, WriteCallback)) FLAC__file_decoder_set_write_callback, | |
585 (FLAC__bool (*) (void *, MetadataCallback)) FLAC__file_decoder_set_metadata_callback, | |
586 (FLAC__bool (*) (void *, ErrorCallback)) FLAC__file_decoder_set_error_callback, | |
587 (FLAC__bool (*) (void *, void *)) FLAC__file_decoder_set_client_data, | |
588 (FLAC__bool (*) (void *)) file_decoder_init, | |
589 (void (*) (void *)) file_decoder_safe_decoder_finish_, | |
590 (void (*) (void *)) file_decoder_safe_decoder_delete_, | |
591 (FLAC__bool (*) (void *)) FLAC__file_decoder_process_until_end_of_metadata, | |
592 (FLAC__bool (*) (void *)) FLAC__file_decoder_process_single, | |
593 file_decoder_is_eof | |
594 }; | |
595 | |
596 /*********** HTTP decoder functions */ | |
597 | |
598 static gchar *url_; | |
599 | |
600 static FLAC__bool http_decoder_set_md5_checking (void *decoder, FLAC__bool value) | |
601 { | |
602 (void) value; | |
603 // operation unsupported | |
604 return FLAC__stream_decoder_get_state ((const FLAC__StreamDecoder *) decoder) == | |
605 FLAC__STREAM_DECODER_UNINITIALIZED; | |
606 } | |
607 | |
608 static FLAC__bool http_decoder_set_url (void *decoder, const char* url) | |
609 { | |
610 (void) decoder; | |
611 url_ = g_strdup (url); | |
612 return true; | |
613 } | |
614 | |
615 static FLAC__StreamDecoderReadStatus http_decoder_read_callback (const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data) | |
616 { | |
617 (void) decoder; | |
618 (void) client_data; | |
619 *bytes = flac_http_read (buffer, *bytes); | |
620 return *bytes ? FLAC__STREAM_DECODER_READ_STATUS_CONTINUE : FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; | |
621 } | |
622 | |
623 static FLAC__bool http_decoder_init (void *decoder) | |
624 { | |
625 flac_http_open (url_, 0); | |
626 g_free (url_); | |
627 FLAC__stream_decoder_set_read_callback (decoder, http_decoder_read_callback); | |
628 return FLAC__stream_decoder_init( (FLAC__StreamDecoder*) decoder) == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA; | |
629 } | |
630 | |
631 static void http_decoder_safe_decoder_finish_(void *decoder) | |
632 { | |
633 if(decoder && FLAC__stream_decoder_get_state((FLAC__StreamDecoder *) decoder) != FLAC__STREAM_DECODER_UNINITIALIZED) { | |
634 FLAC__stream_decoder_finish((FLAC__StreamDecoder *) decoder); | |
635 flac_http_close(); | |
636 } | |
637 } | |
638 | |
639 static void http_decoder_safe_decoder_delete_(void *decoder) | |
640 { | |
641 if(decoder) { | |
642 http_decoder_safe_decoder_finish_(decoder); | |
643 FLAC__stream_decoder_delete( (FLAC__StreamDecoder *) decoder); | |
644 } | |
645 } | |
646 | |
647 static FLAC__bool http_decoder_is_eof(void *decoder) | |
648 { | |
649 return FLAC__stream_decoder_get_state((FLAC__StreamDecoder *) decoder) == FLAC__STREAM_DECODER_END_OF_STREAM; | |
650 } | |
651 | |
652 static const decoder_funcs_t HTTP_DECODER_FUNCTIONS = { | |
653 false, | |
654 (void* (*) (void)) FLAC__stream_decoder_new, | |
655 http_decoder_set_md5_checking, | |
656 (FLAC__bool (*) (void *, const char*)) http_decoder_set_url, | |
657 (FLAC__bool (*) (void *)) FLAC__stream_decoder_set_metadata_ignore_all, | |
658 (FLAC__bool (*) (void *, FLAC__MetadataType)) FLAC__stream_decoder_set_metadata_respond, | |
659 (FLAC__bool (*) (void *, WriteCallback)) FLAC__stream_decoder_set_write_callback, | |
660 (FLAC__bool (*) (void *, MetadataCallback)) FLAC__stream_decoder_set_metadata_callback, | |
661 (FLAC__bool (*) (void *, ErrorCallback)) FLAC__stream_decoder_set_error_callback, | |
662 (FLAC__bool (*) (void *, void *)) FLAC__stream_decoder_set_client_data, | |
663 (FLAC__bool (*) (void *)) http_decoder_init, | |
664 (void (*) (void *)) http_decoder_safe_decoder_finish_, | |
665 (void (*) (void *)) http_decoder_safe_decoder_delete_, | |
666 (FLAC__bool (*) (void *)) FLAC__stream_decoder_process_until_end_of_metadata, | |
667 (FLAC__bool (*) (void *)) FLAC__stream_decoder_process_single, | |
668 http_decoder_is_eof | |
669 }; | |
670 | |
671 static decoder_funcs_t const *decoder_func_table_; | |
672 | |
673 static void init_decoder_func_tables() | |
674 { | |
675 DECODER_FUNCS [DECODER_FILE] = & FILE_DECODER_FUNCTIONS; | |
676 DECODER_FUNCS [DECODER_HTTP] = & HTTP_DECODER_FUNCTIONS; | |
677 } | |
678 | |
679 static decoder_t source_to_decoder_type (const char *source) | |
680 { | |
681 return strncasecmp(source, "http://", 7) ? DECODER_FILE : DECODER_HTTP; | |
682 } | |
683 | |
684 static void change_decoder_if_needed (decoder_t new_decoder_type, void **decoderp, decoder_funcs_t const ** fntabp) | |
685 { | |
686 const decoder_funcs_t *new_fn_table = DECODER_FUNCS [new_decoder_type]; | |
687 if (*fntabp != new_fn_table) { | |
688 (*fntabp)->safe_decoder_delete(*decoderp); | |
689 *fntabp = new_fn_table; | |
690 *decoderp = new_fn_table -> new_decoder(); | |
691 } | |
692 } | |
693 | |
694 FLAC__bool safe_decoder_init_(const char *filename, void **decoderp, decoder_funcs_t const ** fntabp) | |
695 { | |
696 if(decoderp == 0 || *decoderp == 0) | |
697 return false; | |
698 | |
699 (*fntabp)->safe_decoder_finish(*decoderp); | |
700 | |
701 change_decoder_if_needed(source_to_decoder_type(filename), decoderp, fntabp); | |
702 | |
703 { | |
704 decoder_funcs_t const *fntab = *fntabp; | |
705 void *decoder = *decoderp; | |
706 | |
707 decoder = *decoderp; | |
708 fntab = *fntabp; | |
709 | |
710 fntab -> set_md5_checking(decoder, false); | |
711 fntab -> set_source(decoder, filename); | |
712 fntab -> set_metadata_ignore_all(decoder); | |
713 fntab -> set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO); | |
714 fntab -> set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT); | |
715 fntab -> set_write_callback(decoder, write_callback_); | |
716 fntab -> set_metadata_callback(decoder, metadata_callback_); | |
717 fntab -> set_error_callback(decoder, error_callback_); | |
718 fntab -> set_client_data(decoder, &file_info_); | |
719 if(!fntab -> decoder_init(decoder)) | |
720 return false; | |
721 | |
722 if(!fntab -> process_until_end_of_metadata(decoder)) | |
723 return false; | |
724 } | |
725 | |
726 return true; | |
727 } | |
728 | |
729 FLAC__StreamDecoderWriteStatus write_callback_(const void *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) | |
730 { | |
731 file_info_struct *file_info = (file_info_struct *)client_data; | |
732 const unsigned channels = file_info->channels, wide_samples = frame->header.blocksize; | |
733 const unsigned bits_per_sample = file_info->bits_per_sample; | |
734 FLAC__byte *sample_buffer_start; | |
735 | |
736 (void)decoder; | |
737 | |
738 if(file_info->abort_flag) | |
739 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; | |
740 | |
741 if((sample_buffer_last_ + wide_samples) > (SAMPLE_BUFFER_SIZE / (channels * file_info->sample_format_bytes_per_sample))) { | |
742 memmove(sample_buffer_, sample_buffer_ + sample_buffer_first_ * channels * file_info->sample_format_bytes_per_sample, (sample_buffer_last_ - sample_buffer_first_) * channels * file_info->sample_format_bytes_per_sample); | |
743 sample_buffer_last_ -= sample_buffer_first_; | |
744 sample_buffer_first_ = 0; | |
745 } | |
746 sample_buffer_start = sample_buffer_ + sample_buffer_last_ * channels * file_info->sample_format_bytes_per_sample; | |
747 if(file_info->has_replaygain && flac_cfg.output.replaygain.enable) { | |
748 FLAC__replaygain_synthesis__apply_gain( | |
749 sample_buffer_start, | |
750 !is_big_endian_host_, | |
751 file_info->sample_format_bytes_per_sample == 1, /* unsigned_data_out */ | |
752 buffer, | |
753 wide_samples, | |
754 channels, | |
755 bits_per_sample, | |
756 file_info->sample_format_bytes_per_sample * 8, | |
757 file_info->replay_scale, | |
758 flac_cfg.output.replaygain.hard_limit, | |
759 flac_cfg.output.resolution.replaygain.dither, | |
760 &file_info->dither_context | |
761 ); | |
762 } | |
763 else if(is_big_endian_host_) { | |
764 FLAC__plugin_common__pack_pcm_signed_big_endian( | |
765 sample_buffer_start, | |
766 buffer, | |
767 wide_samples, | |
768 channels, | |
769 bits_per_sample, | |
770 file_info->sample_format_bytes_per_sample * 8 | |
771 ); | |
772 } | |
773 else { | |
774 FLAC__plugin_common__pack_pcm_signed_little_endian( | |
775 sample_buffer_start, | |
776 buffer, | |
777 wide_samples, | |
778 channels, | |
779 bits_per_sample, | |
780 file_info->sample_format_bytes_per_sample * 8 | |
781 ); | |
782 } | |
783 | |
784 sample_buffer_last_ += wide_samples; | |
785 | |
786 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; | |
787 } | |
788 | |
789 void metadata_callback_(const void *decoder, const FLAC__StreamMetadata *metadata, void *client_data) | |
790 { | |
791 file_info_struct *file_info = (file_info_struct *)client_data; | |
792 (void)decoder; | |
793 if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { | |
794 FLAC__ASSERT(metadata->data.stream_info.total_samples < FLAC__U64L(0x100000000)); /* this plugin can only handle < 4 gigasamples */ | |
795 file_info->total_samples = (unsigned)(metadata->data.stream_info.total_samples&0xffffffff); | |
796 file_info->bits_per_sample = metadata->data.stream_info.bits_per_sample; | |
797 file_info->channels = metadata->data.stream_info.channels; | |
798 file_info->sample_rate = metadata->data.stream_info.sample_rate; | |
799 file_info->length_in_msec = (unsigned)((double)file_info->total_samples / (double)file_info->sample_rate * 1000.0 + 0.5); | |
800 } | |
801 else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { | |
802 double gain, peak; | |
803 if(grabbag__replaygain_load_from_vorbiscomment(metadata, flac_cfg.output.replaygain.album_mode, &gain, &peak)) { | |
804 file_info->has_replaygain = true; | |
805 file_info->replay_scale = grabbag__replaygain_compute_scale_factor(peak, gain, (double)flac_cfg.output.replaygain.preamp, /*prevent_clipping=*/!flac_cfg.output.replaygain.hard_limit); | |
806 } | |
807 } | |
808 } | |
809 | |
810 void error_callback_(const void *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) | |
811 { | |
812 file_info_struct *file_info = (file_info_struct *)client_data; | |
813 (void)decoder; | |
814 if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) | |
815 file_info->abort_flag = true; | |
816 } |