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 {