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 |
