Mercurial > audlegacy-plugins
comparison src/tta/aud-tta.c @ 851:712df386597e trunk
[svn] - add support for mseek.
- fix inaccurate seek position calculation. this bug prevented tta working with cuesheet.
- move to GThread API and make use of GCond signaling.
author | yaz |
---|---|
date | Wed, 14 Mar 2007 03:16:45 -0700 |
parents | 7b65072e2efb |
children | 421d5587b761 |
comparison
equal
deleted
inserted
replaced
850:e9d2de5aa638 | 851:712df386597e |
---|---|
38 #include <string.h> | 38 #include <string.h> |
39 #include <time.h> | 39 #include <time.h> |
40 #include <sys/types.h> | 40 #include <sys/types.h> |
41 #include <sys/stat.h> | 41 #include <sys/stat.h> |
42 #include <glib.h> | 42 #include <glib.h> |
43 #include <pthread.h> | |
44 #include <string.h> | 43 #include <string.h> |
45 | 44 |
46 #include <audacious/util.h> | 45 #include <audacious/util.h> |
47 #include <audacious/plugin.h> | 46 #include <audacious/plugin.h> |
48 #include <audacious/titlestring.h> | 47 #include <audacious/titlestring.h> |
52 #include <audacious/strings.h> | 51 #include <audacious/strings.h> |
53 #include <audacious/i18n.h> | 52 #include <audacious/i18n.h> |
54 | 53 |
55 #include <audacious/id3tag.h> | 54 #include <audacious/id3tag.h> |
56 | 55 |
57 | 56 /* #define DEBUG 1 */ |
58 | 57 |
59 #define PLUGIN_VERSION "1.2" | 58 #define PLUGIN_VERSION "1.2" |
60 #define PROJECT_URL "<http://www.true-audio.com>" | 59 #define PROJECT_URL "<http://www.true-audio.com>" |
61 | 60 |
62 #pragma pack (1) | 61 #pragma pack (1) |
77 static void get_song_info (char *filename, char **title, int *length); | 76 static void get_song_info (char *filename, char **title, int *length); |
78 static void file_info (char *filename); | 77 static void file_info (char *filename); |
79 static void about (); | 78 static void about (); |
80 static TitleInput *get_song_tuple(char *filename); | 79 static TitleInput *get_song_tuple(char *filename); |
81 static gchar *extname(const char *filename); | 80 static gchar *extname(const char *filename); |
81 static void mseek (InputPlayback *data, gulong millisecond); | |
82 | |
82 | 83 |
83 gchar *tta_fmts[] = { "tta", NULL }; | 84 gchar *tta_fmts[] = { "tta", NULL }; |
84 | 85 |
85 InputPlugin tta_ip = | 86 InputPlugin tta_ip = |
86 { | 87 { |
111 get_song_tuple, // get_song_tuple | 112 get_song_tuple, // get_song_tuple |
112 NULL, // set_song_tuple | 113 NULL, // set_song_tuple |
113 NULL, // buffer | 114 NULL, // buffer |
114 NULL, // vfs | 115 NULL, // vfs |
115 tta_fmts, | 116 tta_fmts, |
117 mseek, | |
116 }; | 118 }; |
117 | 119 |
118 InputPlugin * | 120 InputPlugin * |
119 get_iplugin_info (void) | 121 get_iplugin_info (void) |
120 { | 122 { |
121 tta_ip.description = g_strdup_printf ("True Audio Plugin %s", PLUGIN_VERSION); | 123 tta_ip.description = g_strdup_printf ("True Audio Plugin %s", PLUGIN_VERSION); |
122 return &tta_ip; | 124 return &tta_ip; |
123 } | 125 } |
124 | 126 |
125 static pthread_t decode_thread; | 127 static GThread *decode_thread; |
126 static char sample_buffer[PCM_BUFFER_LENGTH * MAX_BSIZE * MAX_NCH]; | 128 static char sample_buffer[PCM_BUFFER_LENGTH * MAX_BSIZE * MAX_NCH]; |
127 static tta_info info; // currently playing file info | 129 static tta_info info; // currently playing file info |
128 static long seek_position = -1; | 130 static long seek_position = -1; |
129 static int playing = FALSE; | 131 static int playing = FALSE; |
130 static int read_samples = -1; | 132 static int read_samples = -1; |
133 | |
134 static GMutex *play_mutex; | |
135 static GCond *play_cond; | |
131 | 136 |
132 static void | 137 static void |
133 tta_error (int error) | 138 tta_error (int error) |
134 { | 139 { |
135 char *message; | 140 char *message; |
198 g_free (name); | 203 g_free (name); |
199 return p; | 204 return p; |
200 } | 205 } |
201 | 206 |
202 static void * | 207 static void * |
203 play_loop (void *arg) | 208 play_loop (gpointer arg) |
204 { | 209 { |
205 InputPlayback *playback = arg; | 210 InputPlayback *playback = (InputPlayback *)arg; |
206 int bufsize = PCM_BUFFER_LENGTH * info.BSIZE * info.NCH; | 211 int bufsize = PCM_BUFFER_LENGTH * info.BSIZE * info.NCH; |
212 GTimeVal sleep_time; | |
207 | 213 |
208 //////////////////////////////////////// | 214 //////////////////////////////////////// |
209 // decode PCM_BUFFER_LENGTH samples | 215 // decode PCM_BUFFER_LENGTH samples |
210 // into the current PCM buffer position | 216 // into the current PCM buffer position |
211 | 217 |
212 while (playing) | 218 while (playing) { |
213 { | 219 while ((read_samples = get_samples (sample_buffer)) > 0) { |
214 while ((read_samples = get_samples (sample_buffer)) > 0) | 220 // wait for buffer becomes available |
215 { | 221 while ((playback->output->buffer_free () < bufsize) && seek_position == -1) { |
216 | 222 g_get_current_time(&sleep_time); |
217 while ((playback->output->buffer_free () < bufsize) | 223 g_time_val_add(&sleep_time, 10000); |
218 && seek_position == -1) | 224 g_mutex_lock(play_mutex); |
219 { | 225 g_cond_timed_wait(play_cond, play_mutex, &sleep_time); |
220 if (!playing) | 226 g_mutex_unlock(play_mutex); |
221 goto DONE; | 227 if (!playing) |
222 xmms_usleep (10000); | 228 goto DONE; |
223 } | 229 } |
224 if (seek_position == -1) | 230 |
225 { | 231 if (seek_position == -1) { |
226 produce_audio(playback->output->written_time(), | 232 produce_audio(playback->output->written_time(), |
227 ((info.BPS == 8) ? FMT_U8 : FMT_S16_LE), | 233 ((info.BPS == 8) ? FMT_U8 : FMT_S16_LE), |
228 info.NCH, | 234 info.NCH, |
229 read_samples * info.NCH * info.BSIZE, | 235 read_samples * info.NCH * info.BSIZE, |
230 sample_buffer, | 236 sample_buffer, |
231 NULL); | 237 NULL); |
232 } | 238 } |
233 else | 239 else { |
234 { | 240 set_position (seek_position / SEEK_STEP); //now seek_postion is in millisecond. |
235 set_position (seek_position); | 241 playback->output->flush (seek_position); |
236 playback->output->flush (seek_position * SEEK_STEP); | 242 seek_position = -1; |
237 seek_position = -1; | 243 } |
238 } | 244 |
239 } | 245 // sleep for a while |
240 playback->output->buffer_free (); | 246 g_get_current_time(&sleep_time); |
241 playback->output->buffer_free (); | 247 g_time_val_add(&sleep_time, 10000); |
242 xmms_usleep(10000); | 248 g_mutex_lock(play_mutex); |
243 } | 249 g_cond_timed_wait(play_cond, play_mutex, &sleep_time); |
244 DONE: | 250 g_mutex_unlock(play_mutex); |
245 | 251 if (!playing) |
246 //////////////////////// | 252 goto DONE; |
247 // destroy memory pools | 253 } |
248 player_stop (); | 254 |
249 | 255 // process remaining data |
250 /////////////////////////////// | 256 playback->output->buffer_free (); |
251 // close currently playing file | 257 playback->output->buffer_free (); |
252 close_tta_file (&info); | 258 |
253 | 259 while(playback->output->buffer_playing()) { |
254 pthread_exit (NULL); | 260 g_get_current_time(&sleep_time); |
261 g_time_val_add(&sleep_time, 10000); | |
262 g_mutex_lock(play_mutex); | |
263 g_cond_timed_wait(play_cond, play_mutex, &sleep_time); | |
264 g_mutex_unlock(play_mutex); | |
265 if(!playing) | |
266 goto DONE; | |
267 } | |
268 } | |
269 | |
270 DONE: | |
271 g_thread_exit(NULL); | |
255 } | 272 } |
256 | 273 |
257 static void | 274 static void |
258 init () | 275 init () |
259 { | 276 { |
260 memset (&info, 0, sizeof (tta_info)); | 277 memset (&info, 0, sizeof (tta_info)); |
278 play_mutex = g_mutex_new(); | |
279 play_cond = g_cond_new(); | |
261 } | 280 } |
262 | 281 |
263 static void | 282 static void |
264 cleanup () | 283 cleanup () |
265 { | 284 { |
285 g_cond_free(play_cond); | |
286 g_mutex_free(play_mutex); | |
266 } | 287 } |
267 | 288 |
268 static void | 289 static void |
269 about () | 290 about () |
270 { | 291 { |
489 { | 510 { |
490 char *filename = playback->filename; | 511 char *filename = playback->filename; |
491 char *title; | 512 char *title; |
492 long datasize, origsize, bitrate; | 513 long datasize, origsize, bitrate; |
493 | 514 |
515 g_mutex_lock(play_mutex); | |
494 playing = FALSE; | 516 playing = FALSE; |
517 g_mutex_unlock(play_mutex); | |
518 g_cond_signal(play_cond); | |
495 | 519 |
496 //////////////////////////////////////// | 520 //////////////////////////////////////// |
497 // open TTA file | 521 // open TTA file |
498 if (open_tta_file (filename, &info, 0) < 0) | 522 if (open_tta_file (filename, &info, 0) < 0) |
499 { | 523 { |
500 tta_error (info.STATE); | 524 tta_error (info.STATE); |
501 close_tta_file (&info); | 525 close_tta_file (&info); |
502 return; | 526 return; |
503 } | 527 } |
504 | 528 |
505 //////////////////////////////////////// | 529 //////////////////////////////////////// |
506 // initialize TTA player | 530 // initialize TTA player |
507 if (player_init (&info) < 0) | 531 if (player_init (&info) < 0) |
508 { | 532 { |
509 tta_error (info.STATE); | 533 tta_error (info.STATE); |
510 close_tta_file (&info); | 534 close_tta_file (&info); |
511 return; | 535 return; |
512 } | 536 } |
513 | 537 |
514 | 538 |
515 if (playback->output->open_audio ((info.BPS == 8) ? FMT_U8 : FMT_S16_LE, | 539 if (playback->output->open_audio ((info.BPS == 8) ? FMT_U8 : FMT_S16_LE, |
516 info.SAMPLERATE, info.NCH) == 0) | 540 info.SAMPLERATE, info.NCH) == 0) |
517 { | 541 { |
518 tta_error (OUTPUT_ERROR); | 542 tta_error (OUTPUT_ERROR); |
519 close_tta_file (&info); | 543 close_tta_file (&info); |
520 return; | 544 return; |
521 } | 545 } |
522 title = get_title (filename, &info); | 546 title = get_title (filename, &info); |
547 #ifdef DEBUG | |
523 printf("title @1 = %s\n", title); | 548 printf("title @1 = %s\n", title); |
549 #endif | |
524 { | 550 { |
525 TitleInput *tuple; | 551 TitleInput *tuple; |
526 | 552 |
527 tuple = get_song_tuple(filename); | 553 tuple = get_song_tuple(filename); |
528 if(tuple->track_name) { | 554 if(tuple->track_name) { |
529 g_free(title); | 555 g_free(title); |
530 title = g_strdup(tuple->track_name); | 556 title = g_strdup(tuple->track_name); |
557 #ifdef DEBUG | |
531 printf("title @2 = %s\n", title); | 558 printf("title @2 = %s\n", title); |
559 #endif | |
532 } | 560 } |
533 | 561 |
534 bmp_title_input_free(tuple); | 562 bmp_title_input_free(tuple); |
535 } | 563 } |
536 | 564 |
537 datasize = file_size(filename) - info.DATAPOS; | 565 datasize = file_size(filename) - info.DATAPOS; |
538 origsize = info.DATALENGTH * info.BSIZE * info.NCH; | 566 origsize = info.DATALENGTH * info.BSIZE * info.NCH; |
539 | 567 |
540 bitrate = (long) ((float) datasize / origsize * | 568 bitrate = (long) ((float) datasize / origsize * |
541 (info.SAMPLERATE * info.NCH * info.BPS)); | 569 (info.SAMPLERATE * info.NCH * info.BPS)); |
542 | 570 |
543 tta_ip.set_info (title, 1000 * info.LENGTH, bitrate, info.SAMPLERATE, info.NCH); | 571 tta_ip.set_info (title, 1000 * info.LENGTH, bitrate, info.SAMPLERATE, info.NCH); |
544 | 572 |
545 if (title) | 573 if (title) |
546 g_free (title); | 574 g_free (title); |
547 | 575 |
576 g_mutex_lock(play_mutex); | |
548 playing = TRUE; | 577 playing = TRUE; |
549 seek_position = -1; | 578 seek_position = -1; |
550 read_samples = -1; | 579 read_samples = -1; |
551 | 580 g_mutex_unlock(play_mutex); |
552 pthread_create (&decode_thread, NULL, play_loop, playback); | 581 g_cond_signal(play_cond); |
582 | |
583 decode_thread = g_thread_create(play_loop, (gpointer)playback, TRUE, NULL); | |
584 printf("decode_thread = %p\n", decode_thread); | |
553 } | 585 } |
554 | 586 |
555 static void | 587 static void |
556 tta_pause (InputPlayback *playback, short paused) | 588 tta_pause (InputPlayback *playback, short paused) |
557 { | 589 { |
558 playback->output->pause (paused); | 590 playback->output->pause (paused); |
559 } | 591 } |
592 | |
560 static void | 593 static void |
561 stop (InputPlayback *playback) | 594 stop (InputPlayback *playback) |
562 { | 595 { |
563 if (playing) | 596 printf("tta: f: stop:\n"); |
564 { | 597 |
565 playing = FALSE; | 598 g_mutex_lock(play_mutex); |
566 pthread_join (decode_thread, NULL); | 599 playing = FALSE; |
567 playback->output->close_audio (); | 600 g_mutex_unlock(play_mutex); |
568 close_tta_file (&info); | 601 g_cond_signal(play_cond); |
569 read_samples = 0; | 602 printf("tta: i: stop: stop signaled\n"); |
603 | |
604 if (decode_thread) { | |
605 g_thread_join(decode_thread); | |
606 } | |
607 | |
608 #ifdef DEBUG | |
609 printf("tta: stop: decode_thread joined\n"); | |
610 #endif | |
611 playback->output->close_audio (); | |
612 player_stop(); | |
613 close_tta_file (&info); | |
614 read_samples = 0; | |
615 } | |
616 | |
617 static void | |
618 mseek (InputPlayback *data, gulong millisecond) | |
619 { | |
620 if (playing) { | |
621 seek_position = millisecond; | |
570 } | 622 } |
571 } | 623 } |
572 | 624 |
573 static void | 625 static void |
574 seek (InputPlayback *data, int time) | 626 seek (InputPlayback *data, int time) |
575 { | 627 { |
576 if (playing) | 628 mseek(data, 1000 * time); |
577 { | |
578 seek_position = 1000 * time / SEEK_STEP; | |
579 | |
580 while (seek_position != -1) | |
581 xmms_usleep (10000); | |
582 } | |
583 } | 629 } |
584 | 630 |
585 static int | 631 static int |
586 get_time (InputPlayback *playback) | 632 get_time (InputPlayback *playback) |
587 { | 633 { |