Mercurial > audlegacy-plugins
comparison src/madplug/plugin.c @ 611:3f7a52adfe0e trunk
[svn] merge recent changes from yaz's branch.
- stable shoutcast playback.
- tag handling improvement.
- view track detail on streaming won't crash. (disabled.)
- filepopup for streaming is partially supported. filepopup displays track name and stream name, but not updated automatically.
author | yaz |
---|---|
date | Tue, 06 Feb 2007 12:11:42 -0800 |
parents | 862190d39e00 |
children | 951b24719ce9 |
comparison
equal
deleted
inserted
replaced
610:862190d39e00 | 611:3f7a52adfe0e |
---|---|
35 | 35 |
36 /* | 36 /* |
37 * Global variables | 37 * Global variables |
38 */ | 38 */ |
39 struct audmad_config_t audmad_config; /**< global configuration */ | 39 struct audmad_config_t audmad_config; /**< global configuration */ |
40 static GStaticMutex mutex; | |
41 InputPlugin *mad_plugin = NULL; | 40 InputPlugin *mad_plugin = NULL; |
41 GMutex *mad_mutex; | |
42 GMutex *pb_mutex; | |
43 GCond *mad_cond; | |
42 | 44 |
43 /* | 45 /* |
44 * static variables | 46 * static variables |
45 */ | 47 */ |
46 static GThread *decode_thread; /**< the single decoder thread */ | 48 static GThread *decode_thread; /**< the single decoder thread */ |
67 ++ext; | 69 ++ext; |
68 | 70 |
69 return ext; | 71 return ext; |
70 } | 72 } |
71 | 73 |
74 | |
72 void audmad_config_compute(struct audmad_config_t *config) | 75 void audmad_config_compute(struct audmad_config_t *config) |
73 { | 76 { |
74 /* set some config parameters by parsing text fields | 77 /* set some config parameters by parsing text fields |
75 (RG default gain, etc..) | 78 (RG default gain, etc..) |
76 */ | 79 */ |
97 ConfigDb *db = NULL; | 100 ConfigDb *db = NULL; |
98 | 101 |
99 audmad_config.fast_play_time_calc = TRUE; | 102 audmad_config.fast_play_time_calc = TRUE; |
100 audmad_config.use_xing = TRUE; | 103 audmad_config.use_xing = TRUE; |
101 audmad_config.dither = TRUE; | 104 audmad_config.dither = TRUE; |
105 audmad_config.sjis = FALSE; | |
102 audmad_config.pregain_db = "+0.00"; | 106 audmad_config.pregain_db = "+0.00"; |
103 audmad_config.replaygain.enable = TRUE; | 107 audmad_config.replaygain.enable = TRUE; |
104 audmad_config.replaygain.track_mode = FALSE; | 108 audmad_config.replaygain.track_mode = FALSE; |
105 audmad_config.hard_limit = FALSE; | 109 audmad_config.hard_limit = FALSE; |
106 audmad_config.replaygain.default_db = "-9.00"; | 110 audmad_config.replaygain.default_db = "-9.00"; |
110 bmp_cfg_db_get_bool(db, "MAD", "fast_play_time_calc", | 114 bmp_cfg_db_get_bool(db, "MAD", "fast_play_time_calc", |
111 &audmad_config.fast_play_time_calc); | 115 &audmad_config.fast_play_time_calc); |
112 bmp_cfg_db_get_bool(db, "MAD", "use_xing", | 116 bmp_cfg_db_get_bool(db, "MAD", "use_xing", |
113 &audmad_config.use_xing); | 117 &audmad_config.use_xing); |
114 bmp_cfg_db_get_bool(db, "MAD", "dither", &audmad_config.dither); | 118 bmp_cfg_db_get_bool(db, "MAD", "dither", &audmad_config.dither); |
119 bmp_cfg_db_get_bool(db, "MAD", "sjis", &audmad_config.sjis); | |
115 bmp_cfg_db_get_bool(db, "MAD", "hard_limit", | 120 bmp_cfg_db_get_bool(db, "MAD", "hard_limit", |
116 &audmad_config.hard_limit); | 121 &audmad_config.hard_limit); |
117 bmp_cfg_db_get_string(db, "MAD", "pregain_db", | 122 bmp_cfg_db_get_string(db, "MAD", "pregain_db", |
118 &audmad_config.pregain_db); | 123 &audmad_config.pregain_db); |
119 bmp_cfg_db_get_bool(db, "MAD", "RG.enable", | 124 bmp_cfg_db_get_bool(db, "MAD", "RG.enable", |
120 &audmad_config.replaygain.enable); | 125 &audmad_config.replaygain.enable); |
121 bmp_cfg_db_get_bool(db, "MAD", "RG.track_mode", | 126 bmp_cfg_db_get_bool(db, "MAD", "RG.track_mode", |
122 &audmad_config.replaygain.track_mode); | 127 &audmad_config.replaygain.track_mode); |
123 bmp_cfg_db_get_string(db, "MAD", "RG.default_db", | 128 bmp_cfg_db_get_string(db, "MAD", "RG.default_db", |
124 &audmad_config.replaygain.default_db); | 129 &audmad_config.replaygain.default_db); |
125 bmp_cfg_db_get_bool(db, "MAD", "title_override", | |
126 &audmad_config.title_override); | |
127 bmp_cfg_db_get_string(db, "MAD", "id3_format", | |
128 &audmad_config.id3_format); | |
129 | 130 |
130 bmp_cfg_db_close(db); | 131 bmp_cfg_db_close(db); |
131 } | 132 } |
132 | 133 |
133 g_static_mutex_init(&mutex); | 134 mad_mutex = g_mutex_new(); |
135 pb_mutex = g_mutex_new(); | |
136 mad_cond = g_cond_new(); | |
134 audmad_config_compute(&audmad_config); | 137 audmad_config_compute(&audmad_config); |
135 | 138 |
136 } | 139 } |
137 | 140 |
138 static void audmad_cleanup() | 141 static void audmad_cleanup() |
181 return ((unsigned long) hbuf[0] << 24) | | 184 return ((unsigned long) hbuf[0] << 24) | |
182 ((unsigned long) hbuf[1] << 16) | | 185 ((unsigned long) hbuf[1] << 16) | |
183 ((unsigned long) hbuf[2] << 8) | (unsigned long) hbuf[3]; | 186 ((unsigned long) hbuf[2] << 8) | (unsigned long) hbuf[3]; |
184 } | 187 } |
185 | 188 |
189 #if 0 | |
190 // XXX: can't add remote stream from add URL dialog. temporally disabled. | |
186 // audacious vfs fast version | 191 // audacious vfs fast version |
187 static int audmad_is_our_fd(char *filename, VFSFile *fin) | 192 static int audmad_is_our_fd(char *filename, VFSFile *fin) |
188 { | 193 { |
189 guint32 check; | 194 guint32 check; |
190 gchar *ext = extname(filename); | 195 gchar *ext = extname(filename); |
236 return 0; | 241 return 0; |
237 } | 242 } |
238 | 243 |
239 return 1; | 244 return 1; |
240 } | 245 } |
246 #endif | |
247 | |
248 // this function will be replaced soon. | |
249 static int audmad_is_our_fd(char *filename, VFSFile *fin) | |
250 { | |
251 int rtn = 0; | |
252 guchar check[4]; | |
253 | |
254 info.remote = FALSE; //awkward... | |
255 | |
256 #ifdef DEBUG | |
257 g_message("audmad: filename = %s\n", filename); | |
258 #endif | |
259 | |
260 // 0. if url is beginning with http://, take it blindly. | |
261 if (!strncasecmp("http://", filename, strlen("http://")) || | |
262 !strncasecmp("https://", filename, strlen("https://"))) { | |
263 g_message("audmad: remote\n"); | |
264 info.remote = TRUE; | |
265 return 1; //ours | |
266 } | |
267 | |
268 // 1. check embeded signature | |
269 if (fin && vfs_fread(check, 1, 4, fin) == 4) { | |
270 /* | |
271 * or three bytes are "ID3" | |
272 */ | |
273 if (mp3_head_check(check)) { | |
274 rtn = 1; | |
275 } | |
276 else if (memcmp(check, "ID3", 3) == 0) { | |
277 rtn = 1; | |
278 } | |
279 else if (memcmp(check, "RIFF", 4) == 0) { | |
280 vfs_fseek(fin, 4, SEEK_CUR); | |
281 vfs_fread(check, 1, 4, fin); | |
282 | |
283 if (memcmp(check, "RMP3", 4) == 0) { | |
284 rtn = 1; | |
285 } | |
286 } | |
287 } | |
288 // 2. exclude files with folloing extensions | |
289 if (strcasecmp("flac", filename + strlen(filename) - 4) == 0 || | |
290 strcasecmp("mpc", filename + strlen(filename) - 3) == 0 || | |
291 strcasecmp("tta", filename + strlen(filename) - 3) == 0) { | |
292 rtn = 0; | |
293 goto tail; | |
294 } | |
295 | |
296 // 3. if we haven't found any signature, take the files with .mp3 extension. | |
297 if (rtn == 0 && strcasecmp("mp3", filename + strlen(filename) - 3) == 0) { | |
298 rtn = 1; | |
299 } | |
300 | |
301 tail: | |
302 return rtn; | |
303 } | |
241 | 304 |
242 // audacious vfs version | 305 // audacious vfs version |
243 static int audmad_is_our_file(char *filename) | 306 static int audmad_is_our_file(char *filename) |
244 { | 307 { |
245 VFSFile *fin = NULL; | 308 VFSFile *fin = NULL; |
259 static void audmad_stop(InputPlayback *playback) | 322 static void audmad_stop(InputPlayback *playback) |
260 { | 323 { |
261 #ifdef DEBUG | 324 #ifdef DEBUG |
262 g_message("f: audmad_stop"); | 325 g_message("f: audmad_stop"); |
263 #endif /* DEBUG */ | 326 #endif /* DEBUG */ |
264 g_static_mutex_lock(&mutex); | 327 g_mutex_lock(mad_mutex); |
328 info.playback = playback; | |
329 g_mutex_unlock(mad_mutex); | |
330 | |
265 if (decode_thread) { | 331 if (decode_thread) { |
332 | |
333 g_mutex_lock(mad_mutex); | |
266 info.playback->playing = 0; | 334 info.playback->playing = 0; |
335 g_mutex_unlock(mad_mutex); | |
336 g_cond_signal(mad_cond); | |
337 | |
267 #ifdef DEBUG | 338 #ifdef DEBUG |
268 g_message("waiting for thread"); | 339 g_message("waiting for thread"); |
269 #endif /* DEBUG */ | 340 #endif /* DEBUG */ |
270 g_thread_join(decode_thread); | 341 g_thread_join(decode_thread); |
271 #ifdef DEBUG | 342 #ifdef DEBUG |
272 g_message("thread done"); | 343 g_message("thread done"); |
273 #endif /* DEBUG */ | 344 #endif /* DEBUG */ |
274 input_term(&info); | 345 input_term(&info); |
275 decode_thread = NULL; | 346 decode_thread = NULL; |
276 } | 347 |
277 g_static_mutex_unlock(&mutex); | 348 } |
278 } | 349 #ifdef DEBUG |
279 | 350 g_message("e: audmad_stop"); |
351 #endif /* DEBUG */ | |
352 } | |
280 | 353 |
281 static void audmad_play_file(InputPlayback *playback) | 354 static void audmad_play_file(InputPlayback *playback) |
282 { | 355 { |
283 gboolean rtn; | 356 gboolean rtn; |
284 gchar *url = playback->filename; | 357 gchar *url = playback->filename; |
305 decode_thread = g_thread_create(decode_loop, (void *) &info, TRUE, NULL); | 378 decode_thread = g_thread_create(decode_loop, (void *) &info, TRUE, NULL); |
306 } | 379 } |
307 | 380 |
308 static void audmad_pause(InputPlayback *playback, short paused) | 381 static void audmad_pause(InputPlayback *playback, short paused) |
309 { | 382 { |
310 mad_plugin->output->pause(paused); | 383 g_mutex_lock(pb_mutex); |
384 info.playback = playback; | |
385 g_mutex_unlock(pb_mutex); | |
386 playback->output->pause(paused); | |
311 } | 387 } |
312 | 388 |
313 static void audmad_seek(InputPlayback *playback, int time) | 389 static void audmad_seek(InputPlayback *playback, int time) |
314 { | 390 { |
391 g_mutex_lock(pb_mutex); | |
392 info.playback = playback; | |
315 /* xmms gives us the desired seek time in seconds */ | 393 /* xmms gives us the desired seek time in seconds */ |
316 info.seek = time; | 394 info.seek = time; |
395 g_mutex_unlock(pb_mutex); | |
396 | |
317 } | 397 } |
318 | 398 |
319 /** | 399 /** |
320 * Scan the given file or URL. | 400 * Scan the given file or URL. |
321 * Fills in the title string and the track length in milliseconds. | 401 * Fills in the title string and the track length in milliseconds. |
322 */ | 402 */ |
323 void audmad_get_song_info(char *url, char **title, int *length) | 403 static void |
404 audmad_get_song_info(char *url, char **title, int *length) | |
324 { | 405 { |
325 struct mad_info_t myinfo; | 406 struct mad_info_t myinfo; |
326 #ifdef DEBUG | 407 #ifdef DEBUG |
327 g_message("f: audmad_get_song_info: %s", url); | 408 g_message("f: audmad_get_song_info: %s", url); |
328 #endif /* DEBUG */ | 409 #endif /* DEBUG */ |
329 | 410 |
330 input_init(&myinfo, url); | 411 input_init(&myinfo, url); |
331 | 412 |
332 if (input_get_info(&myinfo, audmad_config.fast_play_time_calc) == TRUE) | 413 if (input_get_info(&myinfo, info.remote ? TRUE : audmad_config.fast_play_time_calc) == TRUE) { |
333 { | 414 if(myinfo.tuple->track_name) |
334 *title = strdup(myinfo.title); | 415 *title = strdup(myinfo.tuple->track_name); |
416 else | |
417 *title = strdup(url); | |
335 *length = mad_timer_count(myinfo.duration, MAD_UNITS_MILLISECONDS); | 418 *length = mad_timer_count(myinfo.duration, MAD_UNITS_MILLISECONDS); |
336 } | 419 } |
337 else | 420 else { |
338 { | |
339 *title = strdup(url); | 421 *title = strdup(url); |
340 *length = -1; | 422 *length = -1; |
341 } | 423 } |
342 | |
343 input_term(&myinfo); | 424 input_term(&myinfo); |
344 | |
345 #ifdef DEBUG | 425 #ifdef DEBUG |
346 g_message("e: audmad_get_song_info"); | 426 g_message("e: audmad_get_song_info"); |
347 #endif /* DEBUG */ | 427 #endif /* DEBUG */ |
348 } | 428 } |
349 | 429 |
407 } | 487 } |
408 | 488 |
409 extern void audmad_get_file_info(char *filename); | 489 extern void audmad_get_file_info(char *filename); |
410 extern void audmad_configure(); | 490 extern void audmad_configure(); |
411 | 491 |
492 | |
412 // tuple stuff | 493 // tuple stuff |
413 static TitleInput *audmad_get_song_tuple(char *filename) | 494 static TitleInput *audmad_get_song_tuple(char *filename) |
414 { | 495 { |
415 TitleInput *tuple = NULL; | 496 TitleInput *tuple = NULL; |
416 gchar *string = NULL; | 497 gchar *string = NULL; |
426 g_free(string); | 507 g_free(string); |
427 string = NULL; | 508 string = NULL; |
428 } | 509 } |
429 #endif | 510 #endif |
430 | 511 |
512 // can't re-open remote stream | |
513 if(info.remote){ | |
514 tuple = bmp_title_input_new(); | |
515 | |
516 tuple->track_name = vfs_get_metadata(info.infile, "track-name"); | |
517 tuple->album_name = vfs_get_metadata(info.infile, "stream-name"); | |
518 #ifdef DEBUG | |
519 printf("audmad_get_song_tuple: track_name = %s\n", tuple->track_name); | |
520 printf("audmad_get_song_tuple: stream_name = %s\n", tuple->album_name); | |
521 #endif | |
522 tuple->file_name = g_path_get_basename(filename); | |
523 tuple->file_path = g_path_get_dirname(filename); | |
524 tuple->file_ext = extname(filename); | |
525 tuple->length = -1; | |
526 tuple->mtime = 0; // this indicates streaming | |
527 | |
528 return tuple; | |
529 } | |
530 | |
431 if ((file = vfs_fopen(filename, "rb")) != NULL) { | 531 if ((file = vfs_fopen(filename, "rb")) != NULL) { |
532 | |
432 tuple = bmp_title_input_new(); | 533 tuple = bmp_title_input_new(); |
433 | |
434 id3file = id3_file_open(filename, ID3_FILE_MODE_READONLY); | 534 id3file = id3_file_open(filename, ID3_FILE_MODE_READONLY); |
435 | 535 |
436 if (id3file) { | 536 if (id3file) { |
437 tag = id3_file_tag(id3file); | 537 tag = id3_file_tag(id3file); |
438 | 538 |
464 { | 564 { |
465 char *dummy = NULL; | 565 char *dummy = NULL; |
466 int length = 0; | 566 int length = 0; |
467 audmad_get_song_info(filename, &dummy, &length); | 567 audmad_get_song_info(filename, &dummy, &length); |
468 tuple->length = length; | 568 tuple->length = length; |
469 g_free(dummy); | 569 g_free(dummy); |
470 } | 570 } |
471 | 571 |
472 // track number | 572 // track number |
473 string = input_id3_get_string(tag, ID3_FRAME_TRACK); | 573 string = input_id3_get_string(tag, ID3_FRAME_TRACK); |
474 if (string) { | 574 if (string) { |
483 #endif | 583 #endif |
484 // comment | 584 // comment |
485 tuple->comment = | 585 tuple->comment = |
486 input_id3_get_string(tag, ID3_FRAME_COMMENT); | 586 input_id3_get_string(tag, ID3_FRAME_COMMENT); |
487 | 587 |
488 // mtime | |
489 // tuple->mtime = audmad_get_mtime(filename); | |
490 | |
491 } | 588 } |
492 id3_file_close(id3file); | 589 id3_file_close(id3file); |
493 } | 590 } |
591 else { | |
592 tuple->file_name = g_path_get_basename(filename); | |
593 tuple->file_path = g_path_get_dirname(filename); | |
594 tuple->file_ext = extname(filename); | |
595 // length | |
596 { | |
597 char *dummy = NULL; | |
598 int length = 0; | |
599 audmad_get_song_info(filename, &dummy, &length); | |
600 tuple->length = length; | |
601 g_free(dummy); | |
602 } | |
603 } | |
494 vfs_fclose(file); | 604 vfs_fclose(file); |
495 } | 605 } |
496 #ifdef DEBUG | 606 #ifdef DEBUG |
497 g_message("e: mad: audmad_get_song_tuple"); | 607 g_message("e: mad: audmad_get_song_tuple"); |
498 #endif | 608 #endif |
499 tuple->formatter = NULL; //ensure | |
500 return tuple; | 609 return tuple; |
501 | 610 |
502 } | 611 } |
612 | |
503 | 613 |
504 /** | 614 /** |
505 * Retrieve meta-information about URL. | 615 * Retrieve meta-information about URL. |
506 * For local files this means ID3 tag etc. | 616 * For local files this means ID3 tag etc. |
507 */ | 617 */ |
508 gboolean mad_get_info(struct mad_info_t * info, gboolean fast_scan) | 618 gboolean mad_get_info(struct mad_info_t * info, gboolean fast_scan) |
509 { | 619 { |
510 TitleInput *tuple = NULL; | 620 TitleInput *tuple = NULL; |
511 | 621 |
622 #ifdef DEBUG | |
512 g_message("f: mad_get_info: %s", info->filename); | 623 g_message("f: mad_get_info: %s", info->filename); |
513 | 624 #endif |
514 if (info->remote) | 625 if (info->remote) { |
515 return TRUE; | 626 return TRUE; |
627 } | |
516 | 628 |
517 tuple = audmad_get_song_tuple(info->filename); | 629 tuple = audmad_get_song_tuple(info->filename); |
518 info->title = xmms_get_titlestring(audmad_config.title_override == TRUE ? | 630 info->title = xmms_get_titlestring(audmad_config.title_override == TRUE ? |
519 audmad_config.id3_format : xmms_get_gentitle_format(), tuple); | 631 audmad_config.id3_format : xmms_get_gentitle_format(), tuple); |
520 | 632 |
532 char *pos = strrchr(info->filename, '/'); | 644 char *pos = strrchr(info->filename, '/'); |
533 if (pos) | 645 if (pos) |
534 info->title = g_strdup(pos + 1); | 646 info->title = g_strdup(pos + 1); |
535 else | 647 else |
536 info->title = g_strdup(info->filename); | 648 info->title = g_strdup(info->filename); |
537 } | 649 } |
538 | 650 |
651 #ifdef DEBUG | |
539 g_message("e: mad_get_info"); | 652 g_message("e: mad_get_info"); |
653 #endif | |
540 return TRUE; | 654 return TRUE; |
541 } | 655 } |
542 | 656 |
543 static gchar *fmts[] = { "mp3", "mp2", "mpg", NULL }; | 657 static gchar *fmts[] = { "mp3", "mp2", "mpg", NULL }; |
544 | 658 |