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