comparison src/cue/cuesheet.c @ 848:2452835bbfcf trunk

[svn] - make "stop after current song" work. - now cuesheet plugin handles the end of file nicely. - improve reliability.
author yaz
date Tue, 13 Mar 2007 09:37:27 -0700
parents 29ae10725c4c
children def1af87ae1f
comparison
equal deleted inserted replaced
847:11278fe4764b 848:2452835bbfcf
1 /* Audacious: An advanced media player. 1 /* Audacious: An advanced media player.
2 * cuesheet.c: Support cuesheets as a media container. 2 * cuesheet.c: Support cuesheets as a media container.
3 * 3 *
4 * Copyright (C) 2006 William Pitcock <nenolod -at- nenolod.net>. 4 * Copyright (C) 2006 William Pitcock <nenolod -at- nenolod.net>.
5 * Jonathan Schleifer <js@h3c.de> (only small fixes) 5 * Jonathan Schleifer <js@h3c.de> (only small fixes)
6 *
7 * Copyright (C) 2007 Yoshiki Yazawa <yaz@cc.rim.or.jp> (millisecond
8 * seek and multithreading)
6 * 9 *
7 * This file was hacked out of of xmms-cueinfo, 10 * This file was hacked out of of xmms-cueinfo,
8 * Copyright (C) 2003 Oskar Liljeblad 11 * Copyright (C) 2003 Oskar Liljeblad
9 * 12 *
10 * This software is copyrighted work licensed under the terms of the 13 * This software is copyrighted work licensed under the terms of the
13 */ 16 */
14 #ifdef HAVE_CONFIG_H 17 #ifdef HAVE_CONFIG_H
15 #include "config.h" 18 #include "config.h"
16 #endif 19 #endif
17 20
18 #define DEBUG 1 21 /* #define DEBUG 1 */
19 22
20 #include <string.h> 23 #include <string.h>
21 #include <stdlib.h> 24 #include <stdlib.h>
22 #include <stdio.h> 25 #include <stdio.h>
23 #include <ctype.h> 26 #include <ctype.h>
56 static enum { 59 static enum {
57 STOP, 60 STOP,
58 RUN, 61 RUN,
59 EXIT, 62 EXIT,
60 } watchdog_state; 63 } watchdog_state;
64
65 static InputPlayback *caller_ip = NULL;
66 GThread *exec_thread;
61 67
62 static gchar *cue_file = NULL; 68 static gchar *cue_file = NULL;
63 static gchar *cue_title = NULL; 69 static gchar *cue_title = NULL;
64 static gchar *cue_performer = NULL; 70 static gchar *cue_performer = NULL;
65 static gchar *cue_genre = NULL; 71 static gchar *cue_genre = NULL;
126 132
127 static void cue_cleanup(void) 133 static void cue_cleanup(void)
128 { 134 {
129 g_mutex_lock(cue_mutex); 135 g_mutex_lock(cue_mutex);
130 watchdog_state = EXIT; 136 watchdog_state = EXIT;
131 g_cond_signal(cue_cond);
132 g_mutex_unlock(cue_mutex); 137 g_mutex_unlock(cue_mutex);
138 g_cond_broadcast(cue_cond);
133 139
134 g_thread_join(watchdog_thread); 140 g_thread_join(watchdog_thread);
135 141
136 g_cond_free(cue_cond); 142 g_cond_free(cue_cond);
137 g_mutex_free(cue_mutex); 143 g_mutex_free(cue_mutex);
179 } 185 }
180 186
181 static void play(InputPlayback *data) 187 static void play(InputPlayback *data)
182 { 188 {
183 gchar *uri = data->filename; 189 gchar *uri = data->filename;
190
191 #ifdef DEBUG
192 g_print("play: playback = %p\n", data);
193 #endif
194
195 caller_ip = data;
184 /* this isn't a cue:// uri? */ 196 /* this isn't a cue:// uri? */
185 if (strncasecmp("cue://", uri, 6)) 197 if (strncasecmp("cue://", uri, 6))
186 { 198 {
187 gchar *tmp = g_strdup_printf("cue://%s?0", uri); 199 gchar *tmp = g_strdup_printf("cue://%s?0", uri);
188 play_cue_uri(data, tmp); 200 play_cue_uri(data, tmp);
282 bmp_title_input_free(tuple); 294 bmp_title_input_free(tuple);
283 } 295 }
284 296
285 static void seek(InputPlayback * data, gint time) 297 static void seek(InputPlayback * data, gint time)
286 { 298 {
299 #ifdef DEBUG
300 g_print("seek: playback = %p\n", data);
301 #endif
302
287 if (real_ip != NULL) 303 if (real_ip != NULL)
288 real_ip->plugin->seek(real_ip, time); 304 real_ip->plugin->seek(real_ip, time);
289 } 305 }
290 306
291 static void stop(InputPlayback * data) 307 static void stop(InputPlayback * data)
292 { 308 {
309 #ifdef DEBUG
310 g_print("f: stop: playback = %p\n", data);
311 #endif
293 if (real_ip != NULL) 312 if (real_ip != NULL)
294 real_ip->plugin->stop(real_ip); 313 real_ip->plugin->stop(real_ip);
295 314
296 if (data != NULL) 315 if (data != NULL)
297 data->playing = 0; 316 data->playing = 0;
317 if (caller_ip != NULL)
318 caller_ip->playing = 0;
298 319
299 g_mutex_lock(cue_mutex); 320 g_mutex_lock(cue_mutex);
300 watchdog_state = STOP; 321 watchdog_state = STOP;
322 g_mutex_unlock(cue_mutex);
301 g_cond_signal(cue_cond); 323 g_cond_signal(cue_cond);
302 g_mutex_unlock(cue_mutex);
303 324
304 free_cue_info(); 325 free_cue_info();
305 326
306 if (real_ip != NULL) { 327 if (real_ip != NULL) {
307 real_ip->plugin->set_info = cue_ip.set_info; 328 real_ip->plugin->set_info = cue_ip.set_info;
308 real_ip->plugin->output = NULL; 329 real_ip->plugin->output = NULL;
309 g_free(real_ip); 330 g_free(real_ip);
310 real_ip = NULL; 331 real_ip = NULL;
311 } 332 }
312 } 333 #ifdef DEBUG
334 g_print("e: stop\n");
335 #endif
336 }
337
338 static gpointer do_stop(gpointer data)
339 {
340 InputPlayback *playback = (InputPlayback *)data;
341 #ifdef DEBUG
342 g_print("f: do_stop\n");
343 #endif
344 ip_data.stop = TRUE;
345 playback_stop();
346 ip_data.stop = FALSE;
347
348 gdk_threads_enter();
349 mainwin_clear_song_info();
350 gdk_threads_leave();
351
352 #ifdef DEBUG
353 g_print("e: do_stop\n");
354 #endif
355 g_thread_exit(NULL);
356 }
357
358 static gpointer do_prev(gpointer data)
359 {
360 Playlist *playlist = playlist_get_active();
361
362 #ifdef DEBUG
363 g_print("do_prev\n");
364 #endif
365 playlist_prev(playlist);
366 g_thread_exit(NULL);
367 }
368
369 static gpointer do_next(gpointer data)
370 {
371 Playlist *playlist = playlist_get_active();
372
373 #ifdef DEBUG
374 g_print("do_next\n");
375 #endif
376 playlist_next(playlist);
377 g_thread_exit(NULL);
378 }
379
313 380
314 static void cue_pause(InputPlayback * data, short p) 381 static void cue_pause(InputPlayback * data, short p)
315 { 382 {
316 if (real_ip != NULL) 383 if (real_ip != NULL)
317 real_ip->plugin->pause(real_ip, p); 384 real_ip->plugin->pause(real_ip, p);
345 gchar *dummy = NULL; 412 gchar *dummy = NULL;
346 InputPlugin *real_ip_plugin; 413 InputPlugin *real_ip_plugin;
347 414
348 #ifdef DEBUG 415 #ifdef DEBUG
349 g_print("f: play_cue_uri\n"); 416 g_print("f: play_cue_uri\n");
350 #endif 417 g_print("play_cue_uri: playback = %p\n", data);
418 #endif
419
351 /* stop watchdog thread */ 420 /* stop watchdog thread */
352 g_mutex_lock(cue_mutex); 421 g_mutex_lock(cue_mutex);
353 watchdog_state = STOP; 422 watchdog_state = STOP;
423 g_mutex_unlock(cue_mutex);
354 g_cond_signal(cue_cond); 424 g_cond_signal(cue_cond);
355 g_mutex_unlock(cue_mutex);
356 425
357 if (_path != NULL && *_path == '?') 426 if (_path != NULL && *_path == '?')
358 { 427 {
359 *_path = '\0'; 428 *_path = '\0';
360 _path++; 429 _path++;
394 real_ip->plugin->seek(real_ip, finetune_seek ? finetune_seek / 1000 : cue_tracks[track].index / 1000 + 1); 463 real_ip->plugin->seek(real_ip, finetune_seek ? finetune_seek / 1000 : cue_tracks[track].index / 1000 + 1);
395 464
396 /* kick watchdog thread */ 465 /* kick watchdog thread */
397 g_mutex_lock(cue_mutex); 466 g_mutex_lock(cue_mutex);
398 watchdog_state = RUN; 467 watchdog_state = RUN;
468 g_mutex_unlock(cue_mutex);
399 g_cond_signal(cue_cond); 469 g_cond_signal(cue_cond);
400 g_mutex_unlock(cue_mutex); 470 g_print("watchdog activated\n");
401 471
402 // in some plugins, NULL as 2nd arg causes crash. 472 // in some plugins, NULL as 2nd arg causes crash.
403 real_ip->plugin->get_song_info(cue_file, &dummy, &file_length); 473 real_ip->plugin->get_song_info(cue_file, &dummy, &file_length);
404 g_free(dummy); 474 g_free(dummy);
405 cue_tracks[last_cue_track].index = file_length; 475 cue_tracks[last_cue_track].index = file_length;
444 #ifdef DEBUG 514 #ifdef DEBUG
445 g_print("f: watchdog\n"); 515 g_print("f: watchdog\n");
446 #endif 516 #endif
447 517
448 while(1) { 518 while(1) {
449 #if 0 519 #if 1
450 #if DEBUG 520 #if DEBUG
451 g_print("time = %d cur = %d cidx = %d nidx = %d\n", time, cur_cue_track, 521 g_print("time = %d cur = %d cidx = %d nidx = %d last = %d\n",
522 time, cur_cue_track,
452 cue_tracks[cur_cue_track].index, 523 cue_tracks[cur_cue_track].index,
453 cue_tracks[cur_cue_track+1].index); 524 cue_tracks[cur_cue_track+1].index, last_cue_track);
454 #endif 525 #endif
455 #endif 526 #endif
456 g_get_current_time(&sleep_time); 527 g_get_current_time(&sleep_time);
457 g_time_val_add(&sleep_time, 10000); // 10msec 528 g_time_val_add(&sleep_time, 10000); // 10msec
458 529
480 break; 551 break;
481 } 552 }
482 g_mutex_unlock(cue_mutex); 553 g_mutex_unlock(cue_mutex);
483 554
484 time = get_output_time(); 555 time = get_output_time();
485 556 if(time == 0)
486 if(time == 0 || (real_ip && real_ip->playing == 0))
487 continue; 557 continue;
558
559 #ifdef DEBUG
560 if(real_ip) {
561 g_print("real_ip->playing = %d\n", real_ip->playing);
562 if(real_ip->playing == 0)
563 g_print("not playing\n");
564 if(!real_ip->output->buffer_playing())
565 g_print("not buffer_playing\n");
566 }
567 #endif
488 568
489 // prev track 569 // prev track
490 if (time < cue_tracks[cur_cue_track].index) 570 if (time < cue_tracks[cur_cue_track].index)
491 { 571 {
492 #ifdef DEBUG 572 #ifdef DEBUG
496 cue_tracks[cur_cue_track+1].index); 576 cue_tracks[cur_cue_track+1].index);
497 #endif 577 #endif
498 cur_cue_track--; 578 cur_cue_track--;
499 if (time >= cue_tracks[cur_cue_track].index) 579 if (time >= cue_tracks[cur_cue_track].index)
500 finetune_seek = time; 580 finetune_seek = time;
501 playlist_prev(playlist); 581 exec_thread = g_thread_create(do_prev, NULL, FALSE, NULL);
502 } 582 }
503 583
504 // next track 584 // next track
505 if (cur_cue_track != last_cue_track && (time > cue_tracks[cur_cue_track + 1].index)) 585 if (cur_cue_track != last_cue_track && (time > cue_tracks[cur_cue_track + 1].index))
506 { 586 {
512 #endif 592 #endif
513 cur_cue_track++; 593 cur_cue_track++;
514 if (time <= cue_tracks[cur_cue_track].index) 594 if (time <= cue_tracks[cur_cue_track].index)
515 finetune_seek = time; 595 finetune_seek = time;
516 596
517 if(cfg.stopaftersong) 597 if(cfg.stopaftersong) {
518 stop(real_ip); 598 exec_thread = g_thread_create(do_stop, (void *)real_ip, FALSE, NULL);
599 }
519 else 600 else
520 playlist_next(playlist); 601 exec_thread = g_thread_create(do_next, NULL, FALSE, NULL);
521 } 602 }
603
604 // end of file
605 if (cur_cue_track + 1 == last_cue_track &&
606 cue_tracks[cur_cue_track + 1].index - time < 500) { // difference < 500ms
607 #ifdef DEBUG
608 g_print("eof reached\n");
609 #endif
610 exec_thread = g_thread_create(do_stop, (void *)real_ip, FALSE, NULL);
611 }
612
522 } 613 }
523 614
524 #ifdef DEBUG 615 #ifdef DEBUG
525 g_print("e: watchdog\n"); 616 g_print("e: watchdog\n");
526 #endif 617 #endif