summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorSteve Bavin <pondlife@pondlife.me>2006-09-01 07:59:31 +0000
committerSteve Bavin <pondlife@pondlife.me>2006-09-01 07:59:31 +0000
commit3cc46e762065c1d7f6bceebaa39572e30ca78b2b (patch)
tree80fd48076d09c5c3f61eb59f2afe8e692a786acf /apps
parent1bb8657a8f1a3145ae0d66068f142008012da1cb (diff)
downloadrockbox-3cc46e762065c1d7f6bceebaa39572e30ca78b2b.tar.gz
rockbox-3cc46e762065c1d7f6bceebaa39572e30ca78b2b.zip
Rearrangement of playback.c to group routines by thread
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10838 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/playback.c3453
1 files changed, 1737 insertions, 1716 deletions
diff --git a/apps/playback.c b/apps/playback.c
index ed8bb10caa..352c99b390 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -165,27 +165,6 @@ extern bool audio_is_initialized;
165static bool audio_is_initialized = false; 165static bool audio_is_initialized = false;
166#endif 166#endif
167 167
168/* Buffer control thread. */
169static struct event_queue audio_queue;
170static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
171static const char audio_thread_name[] = "audio";
172
173/* Codec thread. */
174static struct event_queue codec_queue;
175static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
176IBSS_ATTR;
177static const char codec_thread_name[] = "codec";
178
179/* Voice codec thread. */
180static struct event_queue voice_codec_queue;
181static long voice_codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
182IBSS_ATTR;
183static const char voice_codec_thread_name[] = "voice codec";
184struct voice_info {
185 void (*callback)(unsigned char **start, int *size);
186 int size;
187 char *buf;
188};
189 168
190 169
191static struct mutex mutex_codecthread; 170static struct mutex mutex_codecthread;
@@ -262,24 +241,452 @@ void (*track_changed_callback)(struct mp3entry *id3);
262void (*track_buffer_callback)(struct mp3entry *id3, bool last_track); 241void (*track_buffer_callback)(struct mp3entry *id3, bool last_track);
263void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track); 242void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track);
264 243
265static void playback_init(void);
266
267/* Configuration */ 244/* Configuration */
268static size_t conf_watermark; 245static size_t conf_watermark;
269static size_t conf_filechunk; 246static size_t conf_filechunk;
270static size_t conf_preseek; 247static size_t conf_preseek;
271static size_t buffer_margin; 248static size_t buffer_margin;
272
273static bool v1first = false; 249static bool v1first = false;
274 250
275static void mp3_set_elapsed(struct mp3entry* id3); 251/* Multiple threads */
276static int mp3_get_file_pos(void); 252static const char * get_codec_filename(int enc_spec);
277 253
278static void audio_clear_track_entries( 254/* Audio thread */
279 bool clear_buffered, bool clear_unbuffered, bool may_yield); 255static struct event_queue audio_queue;
280static bool audio_initialize_buffer_fill(bool clear_tracks); 256static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
281static void audio_fill_file_buffer( 257static const char audio_thread_name[] = "audio";
282 bool start_play, bool rebuffer, size_t offset); 258
259static void audio_thread(void);
260static void set_filebuf_watermark(int seconds);
261static void audio_initiate_track_change(long direction);
262static bool audio_have_tracks(void);
263static void audio_reset_buffer(void);
264
265/* Codec thread */
266static struct event_queue codec_queue;
267static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
268IBSS_ATTR;
269static const char codec_thread_name[] = "codec";
270
271/* Voice thread */
272static struct event_queue voice_queue;
273static long voice_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
274IBSS_ATTR;
275static const char voice_thread_name[] = "voice codec";
276struct voice_info {
277 void (*callback)(unsigned char **start, int *size);
278 int size;
279 char *buf;
280};
281
282#ifdef HAVE_ADJUSTABLE_CPU_FREQ
283static void voice_boost_cpu(bool state);
284#else
285#define voice_boost_cpu(state) do { } while(0)
286#endif
287
288static void voice_thread(void);
289
290/* --- External interfaces --- */
291
292void mp3_play_data(const unsigned char* start, int size,
293 void (*get_more)(unsigned char** start, int* size))
294{
295 static struct voice_info voice_clip;
296 voice_clip.callback = get_more;
297 voice_clip.buf = (char *)start;
298 voice_clip.size = size;
299 logf("mp3 > voice Q_VOICE_STOP");
300 queue_post(&voice_queue, Q_VOICE_STOP, 0);
301 logf("mp3 > voice Q_VOICE_PLAY");
302 queue_post(&voice_queue, Q_VOICE_PLAY, &voice_clip);
303 voice_is_playing = true;
304 voice_boost_cpu(true);
305}
306
307void mp3_play_stop(void)
308{
309 logf("mp3 > voice Q_VOICE_STOP");
310 queue_post(&voice_queue, Q_VOICE_STOP, 0);
311}
312
313bool mp3_pause_done(void)
314{
315 return pcm_is_paused();
316}
317
318void mpeg_id3_options(bool _v1first)
319{
320 v1first = _v1first;
321}
322
323void audio_load_encoder(int enc_id)
324{
325#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
326 const char *enc_fn = get_codec_filename(enc_id | CODEC_TYPE_ENCODER);
327 if (!enc_fn)
328 return;
329
330 audio_remove_encoder();
331
332 LOGFQUEUE("audio > codec Q_ENCODER_LOAD_DISK");
333 queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (void *)enc_fn);
334
335 while (!ci.enc_codec_loaded)
336 yield();
337#endif
338 return;
339 (void)enc_id;
340} /* audio_load_encoder */
341
342void audio_remove_encoder(void)
343{
344#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
345 /* force encoder codec unload (if previously loaded) */
346 if (!ci.enc_codec_loaded)
347 return;
348
349 ci.stop_codec = true;
350 while (ci.enc_codec_loaded)
351 yield();
352#endif
353} /* audio_remove_encoder */
354
355struct mp3entry* audio_current_track(void)
356{
357 const char *filename;
358 const char *p;
359 static struct mp3entry temp_id3;
360 int cur_idx;
361
362 cur_idx = track_ridx + ci.new_track;
363 cur_idx &= MAX_TRACK_MASK;
364
365 if (tracks[cur_idx].taginfo_ready)
366 return &tracks[cur_idx].id3;
367
368 memset(&temp_id3, 0, sizeof(struct mp3entry));
369
370 filename = playlist_peek(ci.new_track);
371 if (!filename)
372 filename = "No file!";
373
374#ifdef HAVE_TC_RAMCACHE
375 if (tagcache_fill_tags(&temp_id3, filename))
376 return &temp_id3;
377#endif
378
379 p = strrchr(filename, '/');
380 if (!p)
381 p = filename;
382 else
383 p++;
384
385 strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1);
386 temp_id3.title = &temp_id3.path[0];
387
388 return &temp_id3;
389}
390
391struct mp3entry* audio_next_track(void)
392{
393 int next_idx = track_ridx;
394
395 if (!audio_have_tracks())
396 return NULL;
397
398 next_idx++;
399 next_idx &= MAX_TRACK_MASK;
400
401 if (!tracks[next_idx].taginfo_ready)
402 return NULL;
403
404 return &tracks[next_idx].id3;
405}
406
407bool audio_has_changed_track(void)
408{
409 if (track_changed)
410 {
411 track_changed = false;
412 return true;
413 }
414
415 return false;
416}
417
418void audio_play(long offset)
419{
420 logf("audio_play");
421 if (playing && offset <= 0)
422 {
423 LOGFQUEUE("audio > audio Q_AUDIO_NEW_PLAYLIST");
424 queue_post(&audio_queue, Q_AUDIO_NEW_PLAYLIST, 0);
425 }
426 else
427 {
428 if (playing)
429 audio_stop();
430
431 playing = true;
432 LOGFQUEUE("audio > audio Q_AUDIO_PLAY");
433 queue_post(&audio_queue, Q_AUDIO_PLAY, (void *)offset);
434 }
435}
436
437void audio_stop(void)
438{
439 LOGFQUEUE("audio > audio Q_AUDIO_STOP");
440 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
441 while (playing || audio_codec_loaded)
442 yield();
443}
444
445void audio_pause(void)
446{
447 LOGFQUEUE("audio > audio Q_AUDIO_PAUSE");
448 queue_post(&audio_queue, Q_AUDIO_PAUSE, (void *)true);
449}
450
451void audio_resume(void)
452{
453 LOGFQUEUE("audio > audio Q_AUDIO_PAUSE resume");
454 queue_post(&audio_queue, Q_AUDIO_PAUSE, (void *)false);
455}
456
457void audio_next(void)
458{
459 if (global_settings.beep)
460 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
461
462 /* Should be safe to do outside of thread, that way we get
463 * the instant wps response at least. */
464 audio_initiate_track_change(1);
465 // queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)1);
466}
467
468void audio_prev(void)
469{
470 if (global_settings.beep)
471 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
472
473 audio_initiate_track_change(-1);
474 // queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)-1);
475}
476
477void audio_next_dir(void)
478{
479 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
480 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, (void *)1);
481}
482
483void audio_prev_dir(void)
484{
485 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
486 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, (void *)-1);
487}
488
489void audio_pre_ff_rewind(void)
490{
491 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
492 queue_post(&audio_queue, Q_AUDIO_PRE_FF_REWIND, 0);
493}
494
495void audio_ff_rewind(long newpos)
496{
497 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
498 queue_post(&audio_queue, Q_AUDIO_FF_REWIND, (int *)newpos);
499}
500
501void audio_flush_and_reload_tracks(void)
502{
503 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
504 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0);
505}
506
507void audio_error_clear(void)
508{
509}
510
511int audio_status(void)
512{
513 int ret = 0;
514
515 if (playing)
516 ret |= AUDIO_STATUS_PLAY;
517
518 if (paused)
519 ret |= AUDIO_STATUS_PAUSE;
520
521#ifdef HAVE_RECORDING
522 /* Do this here for constitency with mpeg.c version */
523 ret |= pcm_rec_status();
524#endif
525
526 return ret;
527}
528
529bool audio_query_poweroff(void)
530{
531 return !(playing && paused);
532}
533
534int audio_get_file_pos(void)
535{
536 return 0;
537}
538
539void audio_set_buffer_margin(int setting)
540{
541 static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
542 buffer_margin = lookup[setting];
543 logf("buffer margin: %ds", buffer_margin);
544 set_filebuf_watermark(buffer_margin);
545}
546
547/* Set crossfade & PCM buffer length. */
548void audio_set_crossfade(int enable)
549{
550 size_t size;
551 bool was_playing = (playing && audio_is_initialized);
552 size_t offset = 0;
553#if MEM > 1
554 int seconds = 1;
555#endif
556
557 if (!filebuf)
558 return; /* Audio buffers not yet set up */
559
560#if MEM > 1
561 if (enable)
562 seconds = global_settings.crossfade_fade_out_delay
563 + global_settings.crossfade_fade_out_duration;
564
565 /* Buffer has to be at least 2s long. */
566 seconds += 2;
567 logf("buf len: %d", seconds);
568 size = seconds * (NATIVE_FREQUENCY*4);
569#else
570 enable = 0;
571 size = NATIVE_FREQUENCY*2;
572#endif
573 if (pcmbuf_get_bufsize() == size)
574 return ;
575
576 if (was_playing)
577 {
578 /* Store the track resume position */
579 offset = cur_ti->id3.offset;
580 /* Playback has to be stopped before changing the buffer size. */
581 LOGFQUEUE("audio > audio Q_AUDIO_STOP");
582 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
583 while (audio_codec_loaded)
584 yield();
585 gui_syncsplash(0, true, (char *)str(LANG_RESTARTING_PLAYBACK));
586 }
587
588 /* Re-initialize audio system. */
589 pcmbuf_init(size);
590 pcmbuf_crossfade_enable(enable);
591 audio_reset_buffer();
592 logf("abuf:%dB", pcmbuf_get_bufsize());
593 logf("fbuf:%dB", filebuflen);
594
595 voice_init();
596
597 /* Restart playback. */
598 if (was_playing) {
599 playing = true;
600 LOGFQUEUE("audio > audio Q_AUDIO_PLAY");
601 queue_post(&audio_queue, Q_AUDIO_PLAY, (void *)offset);
602
603 /* Wait for the playback to start again (and display the splash
604 screen during that period. */
605 while (playing && !audio_codec_loaded)
606 yield();
607 }
608}
609
610void audio_preinit(void)
611{
612 logf("playback system pre-init");
613
614 filebufused = 0;
615 filling = false;
616 current_codec = CODEC_IDX_AUDIO;
617 playing = false;
618 paused = false;
619 audio_codec_loaded = false;
620 voice_is_playing = false;
621 track_changed = false;
622 current_fd = -1;
623 track_buffer_callback = NULL;
624 track_unbuffer_callback = NULL;
625 track_changed_callback = NULL;
626 /* Just to prevent cur_ti never be anything random. */
627 cur_ti = &tracks[0];
628
629 mutex_init(&mutex_codecthread);
630
631 queue_init(&audio_queue);
632 queue_init(&codec_queue);
633 /* clear, not init to create a private queue */
634 queue_clear(&codec_callback_queue);
635
636 create_thread(audio_thread, audio_stack, sizeof(audio_stack),
637 audio_thread_name);
638}
639
640void audio_init(void)
641{
642 LOGFQUEUE("audio > audio Q_AUDIO_POSTINIT");
643 queue_post(&audio_queue, Q_AUDIO_POSTINIT, 0);
644}
645
646void voice_init(void)
647{
648 if (!filebuf)
649 return; /* Audio buffers not yet set up */
650
651 if (voice_thread_num >= 0)
652 {
653 logf("Terminating voice codec");
654 remove_thread(voice_thread_num);
655 if (current_codec == CODEC_IDX_VOICE)
656 mutex_unlock(&mutex_codecthread);
657 queue_delete(&voice_queue);
658 voice_thread_num = -1;
659 voice_codec_loaded = false;
660 }
661
662 if (!talk_voice_required())
663 return;
664
665 logf("Starting voice codec");
666 queue_init(&voice_queue);
667 voice_thread_num = create_thread(voice_thread, voice_stack,
668 sizeof(voice_stack), voice_thread_name);
669
670 while (!voice_codec_loaded)
671 yield();
672} /* voice_init */
673
674void voice_stop(void)
675{
676 /* Messages should not be posted to voice codec queue unless it is the
677 current codec or deadlocks happen. This will be addressed globally soon.
678 -- jhMikeS */
679 if (current_codec != CODEC_IDX_VOICE)
680 return;
681
682 mp3_play_stop();
683 while (voice_is_playing && !queue_empty(&voice_queue))
684 yield();
685} /* voice_stop */
686
687
688
689/* --- Routines called from multiple threads --- */
283 690
284static void swap_codec(void) 691static void swap_codec(void)
285{ 692{
@@ -314,6 +721,43 @@ static void swap_codec(void)
314 logf("resuming codec:%d", my_codec); 721 logf("resuming codec:%d", my_codec);
315} 722}
316 723
724static void set_filebuf_watermark(int seconds)
725{
726 size_t bytes;
727
728 if (current_codec == CODEC_IDX_VOICE)
729 return;
730
731 if (!filebuf)
732 return; /* Audio buffers not yet set up */
733
734 bytes = MAX(cur_ti->id3.bitrate * seconds * (1000/8), conf_watermark);
735 bytes = MIN(bytes, filebuflen / 2);
736 conf_watermark = bytes;
737}
738
739static const char * get_codec_filename(int enc_spec)
740{
741 const char *fname;
742 int type = enc_spec & CODEC_TYPE_MASK;
743 int afmt = enc_spec & CODEC_AFMT_MASK;
744
745 if ((unsigned)afmt >= AFMT_NUM_CODECS)
746 type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
747
748 fname = (type == CODEC_TYPE_DECODER) ?
749 audio_formats[afmt].codec_fn : audio_formats[afmt].codec_enc_fn;
750
751 logf("%s: %d - %s",
752 (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
753 afmt, fname ? fname : "<unknown>");
754
755 return fname;
756} /* get_codec_filename */
757
758
759/* --- Voice thread --- */
760
317#ifdef HAVE_ADJUSTABLE_CPU_FREQ 761#ifdef HAVE_ADJUSTABLE_CPU_FREQ
318static void voice_boost_cpu(bool state) 762static void voice_boost_cpu(bool state)
319{ 763{
@@ -325,8 +769,6 @@ static void voice_boost_cpu(bool state)
325 voice_cpu_boosted = state; 769 voice_cpu_boosted = state;
326 } 770 }
327} 771}
328#else
329#define voice_boost_cpu(state) do { } while(0)
330#endif 772#endif
331 773
332static bool voice_pcmbuf_insert_split_callback( 774static bool voice_pcmbuf_insert_split_callback(
@@ -390,6 +832,218 @@ static bool voice_pcmbuf_insert_split_callback(
390 return true; 832 return true;
391} /* voice_pcmbuf_insert_split_callback */ 833} /* voice_pcmbuf_insert_split_callback */
392 834
835static bool voice_pcmbuf_insert_callback(const char *buf, size_t length)
836{
837 /* TODO: The audiobuffer API should probably be updated, and be based on
838 * pcmbuf_insert_split(). */
839 long real_length = length;
840
841 if (dsp_stereo_mode() == STEREO_NONINTERLEAVED)
842 length /= 2; /* Length is per channel */
843
844 /* Second channel is only used for non-interleaved stereo. */
845 return voice_pcmbuf_insert_split_callback(buf, buf + (real_length / 2),
846 length);
847}
848
849static void* voice_get_memory_callback(size_t *size)
850{
851 *size = 0;
852 return NULL;
853}
854
855static void voice_set_elapsed_callback(unsigned int value)
856{
857 (void)value;
858}
859
860static void voice_set_offset_callback(size_t value)
861{
862 (void)value;
863}
864
865static size_t voice_filebuf_callback(void *ptr, size_t size)
866{
867 (void)ptr;
868 (void)size;
869
870 return 0;
871}
872
873static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
874{
875 struct event ev;
876
877 if (ci_voice.new_track)
878 {
879 *realsize = 0;
880 return NULL;
881 }
882
883 while (1)
884 {
885 if (voice_is_playing)
886 {
887 queue_wait_w_tmo(&voice_queue, &ev, 0);
888 }
889 else if (playing)
890 {
891 queue_wait_w_tmo(&voice_queue, &ev, 0);
892 if (ev.id == SYS_TIMEOUT)
893 ev.id = Q_AUDIO_PLAY;
894 }
895 else
896 queue_wait(&voice_queue, &ev);
897
898 switch (ev.id) {
899 case Q_AUDIO_PLAY:
900 LOGFQUEUE("voice < Q_AUDIO_PLAY");
901 if (playing)
902 swap_codec();
903 break;
904
905#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
906 case Q_ENCODER_RECORD:
907 LOGFQUEUE("voice < Q_ENCODER_RECORD");
908 swap_codec();
909 break;
910#endif
911
912 case Q_VOICE_STOP:
913 LOGFQUEUE("voice < Q_VOICE_STOP");
914 if (voice_is_playing)
915 {
916 /* Clear the current buffer */
917 voice_is_playing = false;
918 voice_getmore = NULL;
919 voice_remaining = 0;
920 voicebuf = NULL;
921 voice_boost_cpu(false);
922 ci_voice.new_track = 1;
923 /* Force the codec to think it's changing tracks */
924 *realsize = 0;
925 return NULL;
926 }
927 else
928 break;
929
930 case SYS_USB_CONNECTED:
931 LOGFQUEUE("voice < SYS_USB_CONNECTED");
932 usb_acknowledge(SYS_USB_CONNECTED_ACK);
933 if (audio_codec_loaded)
934 swap_codec();
935 usb_wait_for_disconnect(&voice_queue);
936 break;
937
938 case Q_VOICE_PLAY:
939 LOGFQUEUE("voice < Q_VOICE_PLAY");
940 {
941 struct voice_info *voice_data;
942 voice_is_playing = true;
943 voice_boost_cpu(true);
944 voice_data = ev.data;
945 voice_remaining = voice_data->size;
946 voicebuf = voice_data->buf;
947 voice_getmore = voice_data->callback;
948 }
949
950 case SYS_TIMEOUT:
951 LOGFQUEUE("voice < SYS_TIMEOUT");
952 goto voice_play_clip;
953
954 default:
955 LOGFQUEUE("voice < default");
956 }
957 }
958
959voice_play_clip:
960
961 if (voice_remaining == 0 || voicebuf == NULL)
962 {
963 if (voice_getmore)
964 voice_getmore((unsigned char **)&voicebuf, (int *)&voice_remaining);
965
966 /* If this clip is done */
967 if (!voice_remaining)
968 {
969 LOGFQUEUE("voice > voice Q_VOICE_STOP");
970 queue_post(&voice_queue, Q_VOICE_STOP, 0);
971 /* Force pcm playback. */
972 if (!pcm_is_playing())
973 pcmbuf_play_start();
974 }
975 }
976
977 *realsize = MIN(voice_remaining, reqsize);
978
979 if (*realsize == 0)
980 return NULL;
981
982 return voicebuf;
983} /* voice_request_buffer_callback */
984
985static void voice_advance_buffer_callback(size_t amount)
986{
987 amount = MIN(amount, voice_remaining);
988 voicebuf += amount;
989 voice_remaining -= amount;
990}
991
992static void voice_advance_buffer_loc_callback(void *ptr)
993{
994 size_t amount = (size_t)ptr - (size_t)voicebuf;
995
996 voice_advance_buffer_callback(amount);
997}
998
999static off_t voice_mp3_get_filepos_callback(int newtime)
1000{
1001 (void)newtime;
1002
1003 return 0;
1004}
1005
1006static void voice_do_nothing(void)
1007{
1008 return;
1009}
1010
1011static bool voice_seek_buffer_callback(size_t newpos)
1012{
1013 (void)newpos;
1014
1015 return false;
1016}
1017
1018static bool voice_request_next_track_callback(void)
1019{
1020 ci_voice.new_track = 0;
1021 return true;
1022}
1023
1024static void voice_thread(void)
1025{
1026 while (1)
1027 {
1028 logf("Loading voice codec");
1029 voice_codec_loaded = true;
1030 mutex_lock(&mutex_codecthread);
1031 current_codec = CODEC_IDX_VOICE;
1032 dsp_configure(DSP_RESET, 0);
1033 voice_remaining = 0;
1034 voice_getmore = NULL;
1035
1036 codec_load_file(get_codec_filename(AFMT_MPA_L3), &ci_voice);
1037
1038 logf("Voice codec finished");
1039 voice_codec_loaded = false;
1040 mutex_unlock(&mutex_codecthread);
1041 }
1042} /* voice_thread */
1043
1044
1045/* --- Codec thread --- */
1046
393static bool codec_pcmbuf_insert_split_callback( 1047static bool codec_pcmbuf_insert_split_callback(
394 const void *ch1, const void *ch2, size_t length) 1048 const void *ch1, const void *ch2, size_t length)
395{ 1049{
@@ -452,20 +1106,6 @@ static bool codec_pcmbuf_insert_split_callback(
452 return true; 1106 return true;
453} /* codec_pcmbuf_insert_split_callback */ 1107} /* codec_pcmbuf_insert_split_callback */
454 1108
455static bool voice_pcmbuf_insert_callback(const char *buf, size_t length)
456{
457 /* TODO: The audiobuffer API should probably be updated, and be based on
458 * pcmbuf_insert_split(). */
459 long real_length = length;
460
461 if (dsp_stereo_mode() == STEREO_NONINTERLEAVED)
462 length /= 2; /* Length is per channel */
463
464 /* Second channel is only used for non-interleaved stereo. */
465 return voice_pcmbuf_insert_split_callback(buf, buf + (real_length / 2),
466 length);
467}
468
469static bool codec_pcmbuf_insert_callback(const char *buf, size_t length) 1109static bool codec_pcmbuf_insert_callback(const char *buf, size_t length)
470{ 1110{
471 /* TODO: The audiobuffer API should probably be updated, and be based on 1111 /* TODO: The audiobuffer API should probably be updated, and be based on
@@ -480,20 +1120,14 @@ static bool codec_pcmbuf_insert_callback(const char *buf, size_t length)
480 length); 1120 length);
481} 1121}
482 1122
483static void* get_voice_memory_callback(size_t *size) 1123static void* codec_get_memory_callback(size_t *size)
484{
485 *size = 0;
486 return NULL;
487}
488
489static void* get_codec_memory_callback(size_t *size)
490{ 1124{
491 *size = MALLOC_BUFSIZE; 1125 *size = MALLOC_BUFSIZE;
492 return &audiobuf[talk_get_bufsize()]; 1126 return &audiobuf[talk_get_bufsize()];
493} 1127}
494 1128
495static void pcmbuf_position_callback(size_t size) ICODE_ATTR; 1129static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
496static void pcmbuf_position_callback(size_t size) 1130static void codec_pcmbuf_position_callback(size_t size)
497{ 1131{
498 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY + 1132 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
499 prev_ti->id3.elapsed; 1133 prev_ti->id3.elapsed;
@@ -507,11 +1141,6 @@ static void pcmbuf_position_callback(size_t size)
507 prev_ti->id3.elapsed = time; 1141 prev_ti->id3.elapsed = time;
508} 1142}
509 1143
510static void voice_set_elapsed_callback(unsigned int value)
511{
512 (void)value;
513}
514
515static void codec_set_elapsed_callback(unsigned int value) 1144static void codec_set_elapsed_callback(unsigned int value)
516{ 1145{
517 unsigned int latency; 1146 unsigned int latency;
@@ -532,11 +1161,6 @@ static void codec_set_elapsed_callback(unsigned int value)
532 } 1161 }
533} 1162}
534 1163
535static void voice_set_offset_callback(size_t value)
536{
537 (void)value;
538}
539
540static void codec_set_offset_callback(size_t value) 1164static void codec_set_offset_callback(size_t value)
541{ 1165{
542 unsigned int latency; 1166 unsigned int latency;
@@ -551,41 +1175,6 @@ static void codec_set_offset_callback(size_t value)
551 cur_ti->id3.offset = value - latency; 1175 cur_ti->id3.offset = value - latency;
552} 1176}
553 1177
554static bool filebuf_is_lowdata(void)
555{
556 return filebufused < AUDIO_FILEBUF_CRITICAL;
557}
558
559static bool have_tracks(void)
560{
561 return track_ridx != track_widx || cur_ti->filesize;
562}
563
564static bool have_free_tracks(void)
565{
566 if (track_widx < track_ridx)
567 return track_widx + 1 < track_ridx;
568 else if (track_ridx == 0)
569 return track_widx < MAX_TRACK - 1;
570
571 return true;
572}
573
574int audio_track_count(void)
575{
576 if (have_tracks())
577 {
578 int relative_track_widx = track_widx;
579
580 if (track_ridx > track_widx)
581 relative_track_widx += MAX_TRACK;
582
583 return relative_track_widx - track_ridx + 1;
584 }
585
586 return 0;
587}
588
589static void codec_advance_buffer_counters(size_t amount) 1178static void codec_advance_buffer_counters(size_t amount)
590{ 1179{
591 buf_ridx += amount; 1180 buf_ridx += amount;
@@ -608,14 +1197,6 @@ static void codec_advance_buffer_counters(size_t amount)
608 } 1197 }
609} 1198}
610 1199
611static size_t voice_filebuf_callback(void *ptr, size_t size)
612{
613 (void)ptr;
614 (void)size;
615
616 return 0;
617}
618
619/* copy up-to size bytes into ptr and return the actual size copied */ 1200/* copy up-to size bytes into ptr and return the actual size copied */
620static size_t codec_filebuf_callback(void *ptr, size_t size) 1201static size_t codec_filebuf_callback(void *ptr, size_t size)
621{ 1202{
@@ -663,118 +1244,6 @@ static size_t codec_filebuf_callback(void *ptr, size_t size)
663 return copy_n; 1244 return copy_n;
664} /* codec_filebuf_callback */ 1245} /* codec_filebuf_callback */
665 1246
666static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
667{
668 struct event ev;
669
670 if (ci_voice.new_track)
671 {
672 *realsize = 0;
673 return NULL;
674 }
675
676 while (1)
677 {
678 if (voice_is_playing)
679 {
680 queue_wait_w_tmo(&voice_codec_queue, &ev, 0);
681 }
682 else if (playing)
683 {
684 queue_wait_w_tmo(&voice_codec_queue, &ev, 0);
685 if (ev.id == SYS_TIMEOUT)
686 ev.id = Q_AUDIO_PLAY;
687 }
688 else
689 queue_wait(&voice_codec_queue, &ev);
690
691 switch (ev.id) {
692 case Q_AUDIO_PLAY:
693 LOGFQUEUE("voice < Q_AUDIO_PLAY");
694 if (playing)
695 swap_codec();
696 break;
697
698#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
699 case Q_ENCODER_RECORD:
700 LOGFQUEUE("voice < Q_ENCODER_RECORD");
701 swap_codec();
702 break;
703#endif
704
705 case Q_VOICE_STOP:
706 LOGFQUEUE("voice < Q_VOICE_STOP");
707 if (voice_is_playing)
708 {
709 /* Clear the current buffer */
710 voice_is_playing = false;
711 voice_getmore = NULL;
712 voice_remaining = 0;
713 voicebuf = NULL;
714 voice_boost_cpu(false);
715 ci_voice.new_track = 1;
716 /* Force the codec to think it's changing tracks */
717 *realsize = 0;
718 return NULL;
719 }
720 else
721 break;
722
723 case SYS_USB_CONNECTED:
724 LOGFQUEUE("voice < SYS_USB_CONNECTED");
725 usb_acknowledge(SYS_USB_CONNECTED_ACK);
726 if (audio_codec_loaded)
727 swap_codec();
728 usb_wait_for_disconnect(&voice_codec_queue);
729 break;
730
731 case Q_VOICE_PLAY:
732 LOGFQUEUE("voice < Q_VOICE_PLAY");
733 {
734 struct voice_info *voice_data;
735 voice_is_playing = true;
736 voice_boost_cpu(true);
737 voice_data = ev.data;
738 voice_remaining = voice_data->size;
739 voicebuf = voice_data->buf;
740 voice_getmore = voice_data->callback;
741 }
742
743 case SYS_TIMEOUT:
744 LOGFQUEUE("voice < SYS_TIMEOUT");
745 goto voice_play_clip;
746
747 default:
748 LOGFQUEUE("voice < default");
749 }
750 }
751
752voice_play_clip:
753
754 if (voice_remaining == 0 || voicebuf == NULL)
755 {
756 if (voice_getmore)
757 voice_getmore((unsigned char **)&voicebuf, (int *)&voice_remaining);
758
759 /* If this clip is done */
760 if (!voice_remaining)
761 {
762 LOGFQUEUE("voice > voice Q_VOICE_STOP");
763 queue_post(&voice_codec_queue, Q_VOICE_STOP, 0);
764 /* Force pcm playback. */
765 if (!pcm_is_playing())
766 pcmbuf_play_start();
767 }
768 }
769
770 *realsize = MIN(voice_remaining, reqsize);
771
772 if (*realsize == 0)
773 return NULL;
774
775 return voicebuf;
776} /* voice_request_buffer_callback */
777
778static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize) 1247static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
779{ 1248{
780 size_t short_n, copy_n, buf_rem; 1249 size_t short_n, copy_n, buf_rem;
@@ -841,370 +1310,6 @@ static int get_codec_base_type(int type)
841 return type; 1310 return type;
842} 1311}
843 1312
844/* Count the data BETWEEN the selected tracks */
845static size_t buffer_count_tracks(int from_track, int to_track)
846{
847 size_t amount = 0;
848 bool need_wrap = to_track < from_track;
849
850 while (1)
851 {
852 if (++from_track >= MAX_TRACK)
853 {
854 from_track -= MAX_TRACK;
855 need_wrap = false;
856 }
857
858 if (from_track >= to_track && !need_wrap)
859 break;
860
861 amount += tracks[from_track].codecsize + tracks[from_track].filesize;
862 }
863 return amount;
864}
865
866static bool buffer_wind_forward(int new_track_ridx, int old_track_ridx)
867{
868 size_t amount;
869
870 /* Start with the remainder of the previously playing track */
871 amount = tracks[old_track_ridx].filesize - ci.curpos;
872 /* Then collect all data from tracks in between them */
873 amount += buffer_count_tracks(old_track_ridx, new_track_ridx);
874
875 if (amount > filebufused)
876 return false;
877
878 logf("bwf:%ldB",amount);
879
880 /* Wind the buffer to the beginning of the target track or its codec */
881 buf_ridx += amount;
882 filebufused -= amount;
883
884 /* Check and handle buffer wrapping */
885 if (buf_ridx >= filebuflen)
886 buf_ridx -= filebuflen;
887
888 return true;
889}
890
891static bool buffer_wind_backward(int new_track_ridx, int old_track_ridx)
892{
893 /* Available buffer data */
894 size_t buf_back;
895 /* Start with the previously playing track's data and our data */
896 size_t amount;
897
898 buf_back = buf_ridx;
899 amount = ci.curpos;
900 if (buf_ridx < buf_widx)
901 buf_back += filebuflen;
902 buf_back -= buf_widx;
903
904 /* If we're not just resetting the current track */
905 if (new_track_ridx != old_track_ridx)
906 {
907 /* Need to wind to before the old track's codec and our filesize */
908 amount += tracks[old_track_ridx].codecsize;
909 amount += tracks[new_track_ridx].filesize;
910
911 /* Rewind the old track to its beginning */
912 tracks[old_track_ridx].available =
913 tracks[old_track_ridx].filesize - tracks[old_track_ridx].filerem;
914 }
915
916 /* If the codec was ever buffered */
917 if (tracks[new_track_ridx].codecsize)
918 {
919 /* Add the codec to the needed size */
920 amount += tracks[new_track_ridx].codecsize;
921 tracks[new_track_ridx].has_codec = true;
922 }
923
924 /* Then collect all data from tracks between new and old */
925 amount += buffer_count_tracks(new_track_ridx, old_track_ridx);
926
927 /* Do we have space to make this skip? */
928 if (amount > buf_back)
929 return false;
930
931 logf("bwb:%ldB",amount);
932
933 /* Check and handle buffer wrapping */
934 if (amount > buf_ridx)
935 buf_ridx += filebuflen;
936 /* Rewind the buffer to the beginning of the target track or its codec */
937 buf_ridx -= amount;
938 filebufused += amount;
939
940 /* Reset to the beginning of the new track */
941 tracks[new_track_ridx].available = tracks[new_track_ridx].filesize;
942
943 return true;
944}
945
946static void audio_update_trackinfo(void)
947{
948 ci.filesize = cur_ti->filesize;
949 cur_ti->id3.elapsed = 0;
950 cur_ti->id3.offset = 0;
951 ci.id3 = &cur_ti->id3;
952 ci.curpos = 0;
953 ci.taginfo_ready = &cur_ti->taginfo_ready;
954}
955
956static void audio_rebuffer(void)
957{
958 logf("Forcing rebuffer");
959
960 /* Notify the codec that this will take a while */
961 /* Currently this can cause some problems (logf in reverse order):
962 * Codec load error:-1
963 * Codec load disk
964 * Codec: Unsupported
965 * Codec finished
966 * New codec:0/3
967 * Clearing tracks:7/7, 1
968 * Forcing rebuffer
969 * Check new track buffer
970 * Request new track
971 * Clearing tracks:5/5, 0
972 * Starting buffer fill
973 * Clearing tracks:5/5, 1
974 * Re-buffering song w/seek
975 */
976 //if (!filling)
977 // queue_post(&codec_callback_queue, Q_CODEC_REQUEST_PENDING, 0);
978
979 /* Stop in progress fill, and clear open file descriptor */
980 if (current_fd >= 0)
981 {
982 close(current_fd);
983 current_fd = -1;
984 }
985 filling = false;
986
987 /* Reset buffer and track pointers */
988 tracks[track_ridx].buf_idx = buf_ridx = buf_widx = 0;
989 track_widx = track_ridx;
990 cur_ti = &tracks[track_ridx];
991 audio_clear_track_entries(true, true, false);
992 filebufused = 0;
993 cur_ti->available = 0;
994
995 /* Fill the buffer */
996 last_peek_offset = -1;
997 cur_ti->filesize = 0;
998 cur_ti->start_pos = 0;
999 ci.curpos = 0;
1000
1001 if (!cur_ti->taginfo_ready)
1002 memset(&cur_ti->id3, 0, sizeof(struct mp3entry));
1003
1004 audio_fill_file_buffer(false, true, 0);
1005}
1006
1007static void audio_check_new_track(void)
1008{
1009 int track_count = audio_track_count();
1010 int old_track_ridx = track_ridx;
1011 bool forward;
1012
1013 if (dir_skip)
1014 {
1015 dir_skip = false;
1016 if (playlist_next_dir(ci.new_track))
1017 {
1018 ci.new_track = 0;
1019 cur_ti->taginfo_ready = false;
1020 audio_rebuffer();
1021 goto skip_done;
1022 }
1023 else
1024 {
1025 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
1026 queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0);
1027 return;
1028 }
1029 }
1030
1031 if (new_playlist)
1032 ci.new_track = 0;
1033
1034 /* If the playlist isn't that big */
1035 if (!playlist_check(ci.new_track))
1036 {
1037 if (ci.new_track >= 0)
1038 {
1039 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
1040 queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0);
1041 return;
1042 }
1043 /* Find the beginning backward if the user over-skips it */
1044 while (!playlist_check(++ci.new_track))
1045 if (ci.new_track >= 0)
1046 {
1047 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
1048 queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0);
1049 return;
1050 }
1051 }
1052 /* Update the playlist */
1053 last_peek_offset -= ci.new_track;
1054
1055 if (playlist_next(ci.new_track) < 0)
1056 {
1057 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
1058 queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0);
1059 return;
1060 }
1061
1062 if (new_playlist)
1063 {
1064 ci.new_track = 1;
1065 new_playlist = false;
1066 }
1067
1068 track_ridx += ci.new_track;
1069 track_ridx &= MAX_TRACK_MASK;
1070
1071 /* Save the old track */
1072 prev_ti = cur_ti;
1073 /* Move to the new track */
1074 cur_ti = &tracks[track_ridx];
1075
1076 if (automatic_skip)
1077 playlist_end = false;
1078
1079 track_changed = !automatic_skip;
1080
1081 /* If it is not safe to even skip this many track entries */
1082 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
1083 {
1084 ci.new_track = 0;
1085 cur_ti->taginfo_ready = false;
1086 audio_rebuffer();
1087 goto skip_done;
1088 }
1089
1090 forward = ci.new_track > 0;
1091 ci.new_track = 0;
1092
1093 /* If the target track is clearly not in memory */
1094 if (cur_ti->filesize == 0 || !cur_ti->taginfo_ready)
1095 {
1096 audio_rebuffer();
1097 goto skip_done;
1098 }
1099
1100 /* The track may be in memory, see if it really is */
1101 if (forward)
1102 {
1103 if (!buffer_wind_forward(track_ridx, old_track_ridx))
1104 audio_rebuffer();
1105 }
1106 else
1107 {
1108 int cur_idx = track_ridx;
1109 bool taginfo_ready = true;
1110 bool wrap = track_ridx > old_track_ridx;
1111
1112 while (1)
1113 {
1114 cur_idx++;
1115 cur_idx &= MAX_TRACK_MASK;
1116 if (!(wrap || cur_idx < old_track_ridx))
1117 break;
1118
1119 /* If we hit a track in between without valid tag info, bail */
1120 if (!tracks[cur_idx].taginfo_ready)
1121 {
1122 taginfo_ready = false;
1123 break;
1124 }
1125
1126 tracks[cur_idx].available = tracks[cur_idx].filesize;
1127 if (tracks[cur_idx].codecsize)
1128 tracks[cur_idx].has_codec = true;
1129 }
1130 if (taginfo_ready)
1131 {
1132 if (!buffer_wind_backward(track_ridx, old_track_ridx))
1133 audio_rebuffer();
1134 }
1135 else
1136 {
1137 cur_ti->taginfo_ready = false;
1138 audio_rebuffer();
1139 }
1140 }
1141
1142skip_done:
1143 audio_update_trackinfo();
1144 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_COMPLETE");
1145 queue_post(&codec_callback_queue, Q_CODEC_REQUEST_COMPLETE, 0);
1146}
1147
1148static void audio_rebuffer_and_seek(size_t newpos)
1149{
1150 int fd;
1151 char *trackname;
1152
1153 trackname = playlist_peek(0);
1154 /* (Re-)open current track's file handle. */
1155
1156 fd = open(trackname, O_RDONLY);
1157 if (fd < 0)
1158 {
1159 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
1160 queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0);
1161 return;
1162 }
1163
1164 if (current_fd >= 0)
1165 close(current_fd);
1166 current_fd = fd;
1167
1168 playlist_end = false;
1169
1170 ci.curpos = newpos;
1171
1172 /* Clear codec buffer. */
1173 track_widx = track_ridx;
1174 filebufused = 0;
1175 tracks[track_widx].buf_idx = buf_widx = buf_ridx = 0;
1176
1177 last_peek_offset = 0;
1178 filling = false;
1179 audio_initialize_buffer_fill(true);
1180 filling = true;
1181
1182 if (newpos > conf_preseek) {
1183 buf_ridx += conf_preseek;
1184 cur_ti->start_pos = newpos - conf_preseek;
1185 }
1186 else
1187 {
1188 buf_ridx += newpos;
1189 cur_ti->start_pos = 0;
1190 }
1191
1192 cur_ti->filerem = cur_ti->filesize - cur_ti->start_pos;
1193 cur_ti->available = 0;
1194
1195 lseek(current_fd, cur_ti->start_pos, SEEK_SET);
1196
1197 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_COMPLETE");
1198 queue_post(&codec_callback_queue, Q_CODEC_REQUEST_COMPLETE, 0);
1199}
1200
1201static void voice_advance_buffer_callback(size_t amount)
1202{
1203 amount = MIN(amount, voice_remaining);
1204 voicebuf += amount;
1205 voice_remaining -= amount;
1206}
1207
1208static void codec_advance_buffer_callback(size_t amount) 1313static void codec_advance_buffer_callback(size_t amount)
1209{ 1314{
1210 if (amount > cur_ti->available + cur_ti->filerem) 1315 if (amount > cur_ti->available + cur_ti->filerem)
@@ -1245,13 +1350,6 @@ static void codec_advance_buffer_callback(size_t amount)
1245 codec_set_offset_callback(ci.curpos); 1350 codec_set_offset_callback(ci.curpos);
1246} 1351}
1247 1352
1248static void voice_advance_buffer_loc_callback(void *ptr)
1249{
1250 size_t amount = (size_t)ptr - (size_t)voicebuf;
1251
1252 voice_advance_buffer_callback(amount);
1253}
1254
1255static void codec_advance_buffer_loc_callback(void *ptr) 1353static void codec_advance_buffer_loc_callback(void *ptr)
1256{ 1354{
1257 size_t amount = (size_t)ptr - (size_t)&filebuf[buf_ridx]; 1355 size_t amount = (size_t)ptr - (size_t)&filebuf[buf_ridx];
@@ -1259,11 +1357,60 @@ static void codec_advance_buffer_loc_callback(void *ptr)
1259 codec_advance_buffer_callback(amount); 1357 codec_advance_buffer_callback(amount);
1260} 1358}
1261 1359
1262static off_t voice_mp3_get_filepos_callback(int newtime) 1360/* Copied from mpeg.c. Should be moved somewhere else. */
1361static int codec_get_file_pos(void)
1263{ 1362{
1264 (void)newtime; 1363 int pos = -1;
1265 1364 struct mp3entry *id3 = audio_current_track();
1266 return 0; 1365
1366 if (id3->vbr)
1367 {
1368 if (id3->has_toc)
1369 {
1370 /* Use the TOC to find the new position */
1371 unsigned int percent, remainder;
1372 int curtoc, nexttoc, plen;
1373
1374 percent = (id3->elapsed*100)/id3->length;
1375 if (percent > 99)
1376 percent = 99;
1377
1378 curtoc = id3->toc[percent];
1379
1380 if (percent < 99)
1381 nexttoc = id3->toc[percent+1];
1382 else
1383 nexttoc = 256;
1384
1385 pos = (id3->filesize/256)*curtoc;
1386
1387 /* Use the remainder to get a more accurate position */
1388 remainder = (id3->elapsed*100)%id3->length;
1389 remainder = (remainder*100)/id3->length;
1390 plen = (nexttoc - curtoc)*(id3->filesize/256);
1391 pos += (plen/100)*remainder;
1392 }
1393 else
1394 {
1395 /* No TOC exists, estimate the new position */
1396 pos = (id3->filesize / (id3->length / 1000)) *
1397 (id3->elapsed / 1000);
1398 }
1399 }
1400 else if (id3->bitrate)
1401 pos = id3->elapsed * (id3->bitrate / 8);
1402 else
1403 return -1;
1404
1405 /* Don't seek right to the end of the file so that we can
1406 transition properly to the next song */
1407 if (pos >= (int)(id3->filesize - id3->id3v1len))
1408 pos = id3->filesize - id3->id3v1len - 1;
1409 /* skip past id3v2 tag and other leading garbage */
1410 else if (pos < (int)id3->first_frame_offset)
1411 pos = id3->first_frame_offset;
1412
1413 return pos;
1267} 1414}
1268 1415
1269static off_t codec_mp3_get_filepos_callback(int newtime) 1416static off_t codec_mp3_get_filepos_callback(int newtime)
@@ -1271,16 +1418,11 @@ static off_t codec_mp3_get_filepos_callback(int newtime)
1271 off_t newpos; 1418 off_t newpos;
1272 1419
1273 cur_ti->id3.elapsed = newtime; 1420 cur_ti->id3.elapsed = newtime;
1274 newpos = mp3_get_file_pos(); 1421 newpos = codec_get_file_pos();
1275 1422
1276 return newpos; 1423 return newpos;
1277} 1424}
1278 1425
1279static void voice_do_nothing(void)
1280{
1281 return;
1282}
1283
1284static void codec_seek_complete_callback(void) 1426static void codec_seek_complete_callback(void)
1285{ 1427{
1286 logf("seek_complete"); 1428 logf("seek_complete");
@@ -1296,13 +1438,6 @@ static void codec_seek_complete_callback(void)
1296 ci.seek_time = 0; 1438 ci.seek_time = 0;
1297} 1439}
1298 1440
1299static bool voice_seek_buffer_callback(size_t newpos)
1300{
1301 (void)newpos;
1302
1303 return false;
1304}
1305
1306static bool codec_seek_buffer_callback(size_t newpos) 1441static bool codec_seek_buffer_callback(size_t newpos)
1307{ 1442{
1308 int difference; 1443 int difference;
@@ -1364,21 +1499,6 @@ static bool codec_seek_buffer_callback(size_t newpos)
1364 return true; 1499 return true;
1365} 1500}
1366 1501
1367static void set_filebuf_watermark(int seconds)
1368{
1369 size_t bytes;
1370
1371 if (current_codec == CODEC_IDX_VOICE)
1372 return;
1373
1374 if (!filebuf)
1375 return; /* Audio buffers not yet set up */
1376
1377 bytes = MAX(cur_ti->id3.bitrate * seconds * (1000/8), conf_watermark);
1378 bytes = MIN(bytes, filebuflen / 2);
1379 conf_watermark = bytes;
1380}
1381
1382static void codec_configure_callback(int setting, void *value) 1502static void codec_configure_callback(int setting, void *value)
1383{ 1503{
1384 switch (setting) { 1504 switch (setting) {
@@ -1400,35 +1520,459 @@ static void codec_configure_callback(int setting, void *value)
1400 } 1520 }
1401} 1521}
1402 1522
1403void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3, 1523static void codec_track_changed(void)
1404 bool last_track))
1405{ 1524{
1406 track_buffer_callback = handler; 1525 automatic_skip = false;
1526 track_changed = true;
1527 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1528 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1407} 1529}
1408 1530
1409void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3, 1531static void codec_pcmbuf_track_changed_callback(void)
1410 bool last_track))
1411{ 1532{
1412 track_unbuffer_callback = handler; 1533 pcmbuf_set_position_callback(NULL);
1534 codec_track_changed();
1413} 1535}
1414 1536
1415void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3)) 1537static void codec_discard_codec_callback(void)
1416{ 1538{
1417 track_changed_callback = handler; 1539 if (cur_ti->has_codec)
1540 {
1541 cur_ti->has_codec = false;
1542 filebufused -= cur_ti->codecsize;
1543 buf_ridx += cur_ti->codecsize;
1544 if (buf_ridx >= filebuflen)
1545 buf_ridx -= filebuflen;
1546 }
1547
1548#if 0
1549 /* Check if a buffer desync has happened, log it and stop playback. */
1550 if (buf_ridx != cur_ti->buf_idx)
1551 {
1552 int offset = cur_ti->buf_idx - buf_ridx;
1553 size_t new_used = filebufused - offset;
1554
1555 logf("Buf off :%d=%d-%d", offset, cur_ti->buf_idx, buf_ridx);
1556 logf("Used off:%d",filebufused - new_used);
1557
1558 /* This is a fatal internal error and it's not safe to
1559 * continue playback. */
1560 ci.stop_codec = true;
1561 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1562 }
1563#endif
1418} 1564}
1419 1565
1420static void codec_track_changed(void) 1566static void codec_track_skip_done(bool was_manual)
1421{ 1567{
1422 automatic_skip = false; 1568 /* Manual track change (always crossfade or flush audio). */
1423 track_changed = true; 1569 if (was_manual)
1424 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED"); 1570 {
1425 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0); 1571 pcmbuf_crossfade_init(true);
1572 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1573 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1574 }
1575 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1576 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1577 && global_settings.crossfade != 2)
1578 {
1579 pcmbuf_crossfade_init(false);
1580 codec_track_changed();
1581 }
1582 /* Gapless playback. */
1583 else
1584 {
1585 pcmbuf_set_position_callback(codec_pcmbuf_position_callback);
1586 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
1587 }
1426} 1588}
1427 1589
1428static void pcmbuf_track_changed_callback(void) 1590static bool codec_load_next_track(void)
1429{ 1591{
1430 pcmbuf_set_position_callback(NULL); 1592 struct event ev;
1431 codec_track_changed(); 1593
1594 if (ci.seek_time)
1595 codec_seek_complete_callback();
1596
1597#ifdef AB_REPEAT_ENABLE
1598 ab_end_of_track_report();
1599#endif
1600
1601 logf("Request new track");
1602
1603 if (ci.new_track == 0)
1604 {
1605 ci.new_track++;
1606 automatic_skip = true;
1607 }
1608
1609 cpu_boost(true);
1610 LOGFQUEUE("codec > audio Q_AUDIO_CHECK_NEW_TRACK");
1611 queue_post(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
1612 while (1)
1613 {
1614 queue_wait(&codec_callback_queue, &ev);
1615 if (ev.id == Q_CODEC_REQUEST_PENDING)
1616 {
1617 if (!automatic_skip)
1618 pcmbuf_play_stop();
1619 }
1620 else
1621 break;
1622 }
1623 cpu_boost(false);
1624 switch (ev.id)
1625 {
1626 case Q_CODEC_REQUEST_COMPLETE:
1627 LOGFQUEUE("codec < Q_CODEC_REQUEST_COMPLETE");
1628 codec_track_skip_done(!automatic_skip);
1629 return true;
1630
1631 case Q_CODEC_REQUEST_FAILED:
1632 LOGFQUEUE("codec < Q_CODEC_REQUEST_FAILED");
1633 ci.new_track = 0;
1634 ci.stop_codec = true;
1635 return false;
1636
1637 default:
1638 LOGFQUEUE("codec < default");
1639 ci.stop_codec = true;
1640 return false;
1641 }
1642}
1643
1644static bool codec_request_next_track_callback(void)
1645{
1646 int prev_codectype;
1647
1648 if (ci.stop_codec || !playing)
1649 return false;
1650
1651 prev_codectype = get_codec_base_type(cur_ti->id3.codectype);
1652
1653 if (!codec_load_next_track())
1654 return false;
1655
1656 /* Check if the next codec is the same file. */
1657 if (prev_codectype == get_codec_base_type(cur_ti->id3.codectype))
1658 {
1659 logf("New track loaded");
1660 codec_discard_codec_callback();
1661 return true;
1662 }
1663 else
1664 {
1665 logf("New codec:%d/%d", cur_ti->id3.codectype, prev_codectype);
1666 return false;
1667 }
1668}
1669
1670static void codec_thread(void)
1671{
1672 struct event ev;
1673 int status;
1674 size_t wrap;
1675
1676 while (1) {
1677 status = 0;
1678 queue_wait(&codec_queue, &ev);
1679
1680 switch (ev.id) {
1681 case Q_CODEC_LOAD_DISK:
1682 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1683 audio_codec_loaded = true;
1684 if (voice_codec_loaded)
1685 {
1686 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1687 queue_post(&voice_queue, Q_AUDIO_PLAY, 0);
1688 }
1689 mutex_lock(&mutex_codecthread);
1690 current_codec = CODEC_IDX_AUDIO;
1691 ci.stop_codec = false;
1692 status = codec_load_file((const char *)ev.data, &ci);
1693 mutex_unlock(&mutex_codecthread);
1694 break ;
1695
1696 case Q_CODEC_LOAD:
1697 LOGFQUEUE("codec < Q_CODEC_LOAD");
1698 if (!cur_ti->has_codec) {
1699 logf("Codec slot is empty!");
1700 /* Wait for the pcm buffer to go empty */
1701 while (pcm_is_playing())
1702 yield();
1703 /* This must be set to prevent an infinite loop */
1704 ci.stop_codec = true;
1705 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1706 queue_post(&codec_queue, Q_AUDIO_PLAY, 0);
1707 break ;
1708 }
1709
1710 audio_codec_loaded = true;
1711 if (voice_codec_loaded)
1712 {
1713 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1714 queue_post(&voice_queue, Q_AUDIO_PLAY, 0);
1715 }
1716 mutex_lock(&mutex_codecthread);
1717 current_codec = CODEC_IDX_AUDIO;
1718 ci.stop_codec = false;
1719 wrap = (size_t)&filebuf[filebuflen] - (size_t)cur_ti->codecbuf;
1720 status = codec_load_ram(cur_ti->codecbuf, cur_ti->codecsize,
1721 &filebuf[0], wrap, &ci);
1722 mutex_unlock(&mutex_codecthread);
1723 break ;
1724
1725#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
1726 case Q_ENCODER_LOAD_DISK:
1727 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1728 audio_codec_loaded = false;
1729 if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE)
1730 {
1731 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
1732 queue_post(&voice_queue, Q_ENCODER_RECORD, NULL);
1733 }
1734 mutex_lock(&mutex_codecthread);
1735 current_codec = CODEC_IDX_AUDIO;
1736 ci.stop_codec = false;
1737 status = codec_load_file((const char *)ev.data, &ci);
1738 mutex_unlock(&mutex_codecthread);
1739 break;
1740#endif
1741
1742#ifndef SIMULATOR
1743 case SYS_USB_CONNECTED:
1744 LOGFQUEUE("codec < SYS_USB_CONNECTED");
1745 queue_clear(&codec_queue);
1746 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1747 if (voice_codec_loaded)
1748 swap_codec();
1749 usb_wait_for_disconnect(&codec_queue);
1750 break;
1751#endif
1752
1753 default:
1754 LOGFQUEUE("codec < default");
1755 }
1756
1757 if (audio_codec_loaded)
1758 {
1759 if (ci.stop_codec)
1760 {
1761 status = CODEC_OK;
1762 if (!playing)
1763 pcmbuf_play_stop();
1764 }
1765 audio_codec_loaded = false;
1766 }
1767
1768 switch (ev.id) {
1769 case Q_CODEC_LOAD_DISK:
1770 case Q_CODEC_LOAD:
1771 LOGFQUEUE("codec < Q_CODEC_LOAD");
1772 if (playing)
1773 {
1774 if (ci.new_track || status != CODEC_OK)
1775 {
1776 if (!ci.new_track)
1777 {
1778 logf("Codec failure");
1779 gui_syncsplash(HZ*2, true, "Codec failure");
1780 }
1781
1782 if (!codec_load_next_track())
1783 {
1784 // queue_post(&codec_queue, Q_AUDIO_STOP, 0);
1785 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1786 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1787 break;
1788 }
1789 }
1790 else
1791 {
1792 logf("Codec finished");
1793 if (ci.stop_codec)
1794 {
1795 /* Wait for the audio to stop playing before
1796 * triggering the WPS exit */
1797 while(pcm_is_playing())
1798 sleep(1);
1799 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1800 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1801 break;
1802 }
1803 }
1804
1805 if (cur_ti->has_codec)
1806 {
1807 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1808 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
1809 }
1810 else
1811 {
1812 const char *codec_fn = get_codec_filename(cur_ti->id3.codectype);
1813 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1814 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
1815 (void *)codec_fn);
1816 }
1817 }
1818 break;
1819
1820 default:
1821 LOGFQUEUE("codec < default");
1822
1823 } /* end switch */
1824 }
1825}
1826
1827
1828/* --- Audio thread --- */
1829
1830static bool audio_filebuf_is_lowdata(void)
1831{
1832 return filebufused < AUDIO_FILEBUF_CRITICAL;
1833}
1834
1835static bool audio_have_tracks(void)
1836{
1837 return track_ridx != track_widx || cur_ti->filesize;
1838}
1839
1840static bool audio_have_free_tracks(void)
1841{
1842 if (track_widx < track_ridx)
1843 return track_widx + 1 < track_ridx;
1844 else if (track_ridx == 0)
1845 return track_widx < MAX_TRACK - 1;
1846
1847 return true;
1848}
1849
1850int audio_track_count(void)
1851{
1852 if (audio_have_tracks())
1853 {
1854 int relative_track_widx = track_widx;
1855
1856 if (track_ridx > track_widx)
1857 relative_track_widx += MAX_TRACK;
1858
1859 return relative_track_widx - track_ridx + 1;
1860 }
1861
1862 return 0;
1863}
1864
1865
1866/* Count the data BETWEEN the selected tracks */
1867static size_t audio_buffer_count_tracks(int from_track, int to_track)
1868{
1869 size_t amount = 0;
1870 bool need_wrap = to_track < from_track;
1871
1872 while (1)
1873 {
1874 if (++from_track >= MAX_TRACK)
1875 {
1876 from_track -= MAX_TRACK;
1877 need_wrap = false;
1878 }
1879
1880 if (from_track >= to_track && !need_wrap)
1881 break;
1882
1883 amount += tracks[from_track].codecsize + tracks[from_track].filesize;
1884 }
1885 return amount;
1886}
1887
1888static bool audio_buffer_wind_forward(int new_track_ridx, int old_track_ridx)
1889{
1890 size_t amount;
1891
1892 /* Start with the remainder of the previously playing track */
1893 amount = tracks[old_track_ridx].filesize - ci.curpos;
1894 /* Then collect all data from tracks in between them */
1895 amount += audio_buffer_count_tracks(old_track_ridx, new_track_ridx);
1896
1897 if (amount > filebufused)
1898 return false;
1899
1900 logf("bwf:%ldB",amount);
1901
1902 /* Wind the buffer to the beginning of the target track or its codec */
1903 buf_ridx += amount;
1904 filebufused -= amount;
1905
1906 /* Check and handle buffer wrapping */
1907 if (buf_ridx >= filebuflen)
1908 buf_ridx -= filebuflen;
1909
1910 return true;
1911}
1912
1913static bool audio_buffer_wind_backward(int new_track_ridx, int old_track_ridx)
1914{
1915 /* Available buffer data */
1916 size_t buf_back;
1917 /* Start with the previously playing track's data and our data */
1918 size_t amount;
1919
1920 buf_back = buf_ridx;
1921 amount = ci.curpos;
1922 if (buf_ridx < buf_widx)
1923 buf_back += filebuflen;
1924 buf_back -= buf_widx;
1925
1926 /* If we're not just resetting the current track */
1927 if (new_track_ridx != old_track_ridx)
1928 {
1929 /* Need to wind to before the old track's codec and our filesize */
1930 amount += tracks[old_track_ridx].codecsize;
1931 amount += tracks[new_track_ridx].filesize;
1932
1933 /* Rewind the old track to its beginning */
1934 tracks[old_track_ridx].available =
1935 tracks[old_track_ridx].filesize - tracks[old_track_ridx].filerem;
1936 }
1937
1938 /* If the codec was ever buffered */
1939 if (tracks[new_track_ridx].codecsize)
1940 {
1941 /* Add the codec to the needed size */
1942 amount += tracks[new_track_ridx].codecsize;
1943 tracks[new_track_ridx].has_codec = true;
1944 }
1945
1946 /* Then collect all data from tracks between new and old */
1947 amount += audio_buffer_count_tracks(new_track_ridx, old_track_ridx);
1948
1949 /* Do we have space to make this skip? */
1950 if (amount > buf_back)
1951 return false;
1952
1953 logf("bwb:%ldB",amount);
1954
1955 /* Check and handle buffer wrapping */
1956 if (amount > buf_ridx)
1957 buf_ridx += filebuflen;
1958 /* Rewind the buffer to the beginning of the target track or its codec */
1959 buf_ridx -= amount;
1960 filebufused += amount;
1961
1962 /* Reset to the beginning of the new track */
1963 tracks[new_track_ridx].available = tracks[new_track_ridx].filesize;
1964
1965 return true;
1966}
1967
1968static void audio_update_trackinfo(void)
1969{
1970 ci.filesize = cur_ti->filesize;
1971 cur_ti->id3.elapsed = 0;
1972 cur_ti->id3.offset = 0;
1973 ci.id3 = &cur_ti->id3;
1974 ci.curpos = 0;
1975 ci.taginfo_ready = &cur_ti->taginfo_ready;
1432} 1976}
1433 1977
1434/* Yield to codecs for as long as possible if they are in need of data 1978/* Yield to codecs for as long as possible if they are in need of data
@@ -1441,7 +1985,7 @@ static bool audio_yield_codecs(void)
1441 if (!queue_empty(&audio_queue)) return true; 1985 if (!queue_empty(&audio_queue)) return true;
1442 1986
1443 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata()) 1987 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
1444 && !ci.stop_codec && playing && !filebuf_is_lowdata()) 1988 && !ci.stop_codec && playing && !audio_filebuf_is_lowdata())
1445 { 1989 {
1446 sleep(1); 1990 sleep(1);
1447 if (!queue_empty(&audio_queue)) return true; 1991 if (!queue_empty(&audio_queue)) return true;
@@ -1450,8 +1994,64 @@ static bool audio_yield_codecs(void)
1450 return false; 1994 return false;
1451} 1995}
1452 1996
1997/* Note that this function might yield(). */
1998static void audio_clear_track_entries(
1999 bool clear_buffered, bool clear_unbuffered,
2000 bool may_yield)
2001{
2002 int cur_idx = track_widx;
2003 int last_idx = -1;
2004
2005 logf("Clearing tracks:%d/%d, %d", track_ridx, track_widx, clear_unbuffered);
2006
2007 /* Loop over all tracks from write-to-read */
2008 while (1)
2009 {
2010 cur_idx++;
2011 cur_idx &= MAX_TRACK_MASK;
2012
2013 if (cur_idx == track_ridx)
2014 break;
2015
2016 /* If the track is buffered, conditionally clear/notify,
2017 * otherwise clear the track if that option is selected */
2018 if (tracks[cur_idx].event_sent)
2019 {
2020 if (clear_buffered)
2021 {
2022 if (last_idx >= 0)
2023 {
2024 /* If there is an unbuffer callback, call it, otherwise,
2025 * just clear the track */
2026 if (track_unbuffer_callback)
2027 {
2028 if (may_yield)
2029 audio_yield_codecs();
2030 track_unbuffer_callback(&tracks[last_idx].id3, false);
2031 }
2032
2033 memset(&tracks[last_idx], 0, sizeof(struct track_info));
2034 }
2035 last_idx = cur_idx;
2036 }
2037 }
2038 else if (clear_unbuffered)
2039 memset(&tracks[cur_idx], 0, sizeof(struct track_info));
2040 }
2041
2042 /* We clear the previous instance of a buffered track throughout
2043 * the above loop to facilitate 'last' detection. Clear/notify
2044 * the last track here */
2045 if (last_idx >= 0)
2046 {
2047 if (track_unbuffer_callback)
2048 track_unbuffer_callback(&tracks[last_idx].id3, true);
2049 memset(&tracks[last_idx], 0, sizeof(struct track_info));
2050 }
2051}
2052
1453/* FIXME: This code should be made more generic and move to metadata.c */ 2053/* FIXME: This code should be made more generic and move to metadata.c */
1454static void strip_id3v1_tag(void) 2054static void audio_strip_id3v1_tag(void)
1455{ 2055{
1456 int i; 2056 int i;
1457 static const unsigned char tag[] = "TAG"; 2057 static const unsigned char tag[] = "TAG";
@@ -1555,7 +2155,7 @@ static void audio_read_file(bool quick)
1555 logf("Finished buf:%dB", tracks[track_widx].filesize); 2155 logf("Finished buf:%dB", tracks[track_widx].filesize);
1556 close(current_fd); 2156 close(current_fd);
1557 current_fd = -1; 2157 current_fd = -1;
1558 strip_id3v1_tag(); 2158 audio_strip_id3v1_tag();
1559 2159
1560 track_widx++; 2160 track_widx++;
1561 track_widx &= MAX_TRACK_MASK; 2161 track_widx &= MAX_TRACK_MASK;
@@ -1569,54 +2169,6 @@ static void audio_read_file(bool quick)
1569 } 2169 }
1570} 2170}
1571 2171
1572static void codec_discard_codec_callback(void)
1573{
1574 if (cur_ti->has_codec)
1575 {
1576 cur_ti->has_codec = false;
1577 filebufused -= cur_ti->codecsize;
1578 buf_ridx += cur_ti->codecsize;
1579 if (buf_ridx >= filebuflen)
1580 buf_ridx -= filebuflen;
1581 }
1582
1583#if 0
1584 /* Check if a buffer desync has happened, log it and stop playback. */
1585 if (buf_ridx != cur_ti->buf_idx)
1586 {
1587 int offset = cur_ti->buf_idx - buf_ridx;
1588 size_t new_used = filebufused - offset;
1589
1590 logf("Buf off :%d=%d-%d", offset, cur_ti->buf_idx, buf_ridx);
1591 logf("Used off:%d",filebufused - new_used);
1592
1593 /* This is a fatal internal error and it's not safe to
1594 * continue playback. */
1595 ci.stop_codec = true;
1596 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1597 }
1598#endif
1599}
1600
1601static const char * get_codec_filename(int enc_spec)
1602{
1603 const char *fname;
1604 int type = enc_spec & CODEC_TYPE_MASK;
1605 int afmt = enc_spec & CODEC_AFMT_MASK;
1606
1607 if ((unsigned)afmt >= AFMT_NUM_CODECS)
1608 type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
1609
1610 fname = (type == CODEC_TYPE_DECODER) ?
1611 audio_formats[afmt].codec_fn : audio_formats[afmt].codec_enc_fn;
1612
1613 logf("%s: %d - %s",
1614 (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
1615 afmt, fname ? fname : "<unknown>");
1616
1617 return fname;
1618} /* get_codec_filename */
1619
1620static bool audio_loadcodec(bool start_play) 2172static bool audio_loadcodec(bool start_play)
1621{ 2173{
1622 size_t size; 2174 size_t size;
@@ -1716,45 +2268,55 @@ static bool audio_loadcodec(bool start_play)
1716 return true; 2268 return true;
1717} 2269}
1718 2270
1719static bool read_next_metadata(void) 2271/* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2272static void audio_set_elapsed(struct mp3entry* id3)
1720{ 2273{
1721 int fd; 2274 if ( id3->vbr ) {
1722 char *trackname; 2275 if ( id3->has_toc ) {
1723 int next_idx; 2276 /* calculate elapsed time using TOC */
1724 int status; 2277 int i;
2278 unsigned int remainder, plen, relpos, nextpos;
1725 2279
1726 next_idx = track_widx; 2280 /* find wich percent we're at */
1727 if (tracks[next_idx].taginfo_ready) 2281 for (i=0; i<100; i++ )
1728 { 2282 if ( id3->offset < id3->toc[i] * (id3->filesize / 256) )
1729 next_idx++; 2283 break;
1730 next_idx &= MAX_TRACK_MASK;
1731 2284
1732 if (tracks[next_idx].taginfo_ready) 2285 i--;
1733 return true; 2286 if (i < 0)
1734 } 2287 i = 0;
1735 2288
1736 trackname = playlist_peek(last_peek_offset + 1); 2289 relpos = id3->toc[i];
1737 if (!trackname)
1738 return false;
1739 2290
1740 fd = open(trackname, O_RDONLY); 2291 if (i < 99)
1741 if (fd < 0) 2292 nextpos = id3->toc[i+1];
1742 return false; 2293 else
2294 nextpos = 256;
1743 2295
1744 status = get_metadata(&tracks[next_idx],fd,trackname,v1first); 2296 remainder = id3->offset - (relpos * (id3->filesize / 256));
1745 /* Preload the glyphs in the tags */ 2297
1746 if (status) 2298 /* set time for this percent (divide before multiply to prevent
2299 overflow on long files. loss of precision is negligible on
2300 short files) */
2301 id3->elapsed = i * (id3->length / 100);
2302
2303 /* calculate remainder time */
2304 plen = (nextpos - relpos) * (id3->filesize / 256);
2305 id3->elapsed += (((remainder * 100) / plen) *
2306 (id3->length / 10000));
2307 }
2308 else {
2309 /* no TOC exists. set a rough estimate using average bitrate */
2310 int tpk = id3->length / (id3->filesize / 1024);
2311 id3->elapsed = id3->offset / 1024 * tpk;
2312 }
2313 }
2314 else
1747 { 2315 {
1748 if (tracks[next_idx].id3.title) 2316 /* constant bitrate, use exact calculation */
1749 lcd_getstringsize(tracks[next_idx].id3.title, NULL, NULL); 2317 if (id3->bitrate != 0)
1750 if (tracks[next_idx].id3.artist) 2318 id3->elapsed = id3->offset / (id3->bitrate / 8);
1751 lcd_getstringsize(tracks[next_idx].id3.artist, NULL, NULL);
1752 if (tracks[next_idx].id3.album)
1753 lcd_getstringsize(tracks[next_idx].id3.album, NULL, NULL);
1754 } 2319 }
1755 close(fd);
1756
1757 return status;
1758} 2320}
1759 2321
1760static bool audio_load_track(int offset, bool start_play, bool rebuffer) 2322static bool audio_load_track(int offset, bool start_play, bool rebuffer)
@@ -1766,7 +2328,7 @@ static bool audio_load_track(int offset, bool start_play, bool rebuffer)
1766 /* Stop buffer filling if there is no free track entries. 2328 /* Stop buffer filling if there is no free track entries.
1767 Don't fill up the last track entry (we wan't to store next track 2329 Don't fill up the last track entry (we wan't to store next track
1768 metadata there). */ 2330 metadata there). */
1769 if (!have_free_tracks()) 2331 if (!audio_have_free_tracks())
1770 { 2332 {
1771 logf("No free tracks"); 2333 logf("No free tracks");
1772 return false; 2334 return false;
@@ -1902,7 +2464,7 @@ static bool audio_load_track(int offset, bool start_play, bool rebuffer)
1902 case AFMT_MPA_L3: 2464 case AFMT_MPA_L3:
1903 lseek(current_fd, offset, SEEK_SET); 2465 lseek(current_fd, offset, SEEK_SET);
1904 tracks[track_widx].id3.offset = offset; 2466 tracks[track_widx].id3.offset = offset;
1905 mp3_set_elapsed(&tracks[track_widx].id3); 2467 audio_set_elapsed(&tracks[track_widx].id3);
1906 tracks[track_widx].filerem = size - offset; 2468 tracks[track_widx].filerem = size - offset;
1907 ci.curpos = offset; 2469 ci.curpos = offset;
1908 tracks[track_widx].start_pos = offset; 2470 tracks[track_widx].start_pos = offset;
@@ -1937,140 +2499,45 @@ static bool audio_load_track(int offset, bool start_play, bool rebuffer)
1937 return true; 2499 return true;
1938} 2500}
1939 2501
1940/* Note that this function might yield(). */ 2502static bool audio_read_next_metadata(void)
1941static void audio_clear_track_entries(
1942 bool clear_buffered, bool clear_unbuffered,
1943 bool may_yield)
1944{
1945 int cur_idx = track_widx;
1946 int last_idx = -1;
1947
1948 logf("Clearing tracks:%d/%d, %d", track_ridx, track_widx, clear_unbuffered);
1949
1950 /* Loop over all tracks from write-to-read */
1951 while (1)
1952 {
1953 cur_idx++;
1954 cur_idx &= MAX_TRACK_MASK;
1955
1956 if (cur_idx == track_ridx)
1957 break;
1958
1959 /* If the track is buffered, conditionally clear/notify,
1960 * otherwise clear the track if that option is selected */
1961 if (tracks[cur_idx].event_sent)
1962 {
1963 if (clear_buffered)
1964 {
1965 if (last_idx >= 0)
1966 {
1967 /* If there is an unbuffer callback, call it, otherwise,
1968 * just clear the track */
1969 if (track_unbuffer_callback)
1970 {
1971 if (may_yield)
1972 audio_yield_codecs();
1973 track_unbuffer_callback(&tracks[last_idx].id3, false);
1974 }
1975
1976 memset(&tracks[last_idx], 0, sizeof(struct track_info));
1977 }
1978 last_idx = cur_idx;
1979 }
1980 }
1981 else if (clear_unbuffered)
1982 memset(&tracks[cur_idx], 0, sizeof(struct track_info));
1983 }
1984
1985 /* We clear the previous instance of a buffered track throughout
1986 * the above loop to facilitate 'last' detection. Clear/notify
1987 * the last track here */
1988 if (last_idx >= 0)
1989 {
1990 if (track_unbuffer_callback)
1991 track_unbuffer_callback(&tracks[last_idx].id3, true);
1992 memset(&tracks[last_idx], 0, sizeof(struct track_info));
1993 }
1994}
1995
1996static void audio_stop_codec_flush(void)
1997{ 2503{
1998 ci.stop_codec = true; 2504 int fd;
1999 pcmbuf_pause(true); 2505 char *trackname;
2000 while (audio_codec_loaded) 2506 int next_idx;
2001 yield(); 2507 int status;
2002 /* If the audio codec is not loaded any more, and the audio is still
2003 * playing, it is now and _only_ now safe to call this function from the
2004 * audio thread */
2005 if (pcm_is_playing())
2006 pcmbuf_play_stop();
2007 pcmbuf_pause(paused);
2008}
2009 2508
2010static void audio_stop_playback(void) 2509 next_idx = track_widx;
2011{ 2510 if (tracks[next_idx].taginfo_ready)
2012 /* If we were playing, save resume information */
2013 if (playing)
2014 { 2511 {
2015 /* Save the current playing spot, or NULL if the playlist has ended */ 2512 next_idx++;
2016 playlist_update_resume_info( 2513 next_idx &= MAX_TRACK_MASK;
2017 (playlist_end && ci.stop_codec)?NULL:audio_current_track());
2018 }
2019 2514
2020 while (voice_is_playing && !queue_empty(&voice_codec_queue)) 2515 if (tracks[next_idx].taginfo_ready)
2021 yield(); 2516 return true;
2022
2023 filebufused = 0;
2024 playing = false;
2025 filling = false;
2026 paused = false;
2027 audio_stop_codec_flush();
2028
2029 if (current_fd >= 0)
2030 {
2031 close(current_fd);
2032 current_fd = -1;
2033 } 2517 }
2034 2518
2035 /* Mark all entries null. */ 2519 trackname = playlist_peek(last_peek_offset + 1);
2036 audio_clear_track_entries(true, false, false); 2520 if (!trackname)
2037 memset(tracks, 0, sizeof(struct track_info) * MAX_TRACK); 2521 return false;
2038}
2039
2040static void audio_play_start(size_t offset)
2041{
2042#if defined(HAVE_RECORDING) || defined(CONFIG_TUNER)
2043 rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2044#endif
2045
2046 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2047 while (audio_codec_loaded)
2048 audio_stop_codec_flush();
2049
2050 track_changed = true;
2051 playlist_end = false;
2052 2522
2053 playing = true; 2523 fd = open(trackname, O_RDONLY);
2054 ci.new_track = 0; 2524 if (fd < 0)
2055 ci.seek_time = 0; 2525 return false;
2056 2526
2057 if (current_fd >= 0) 2527 status = get_metadata(&tracks[next_idx],fd,trackname,v1first);
2528 /* Preload the glyphs in the tags */
2529 if (status)
2058 { 2530 {
2059 close(current_fd); 2531 if (tracks[next_idx].id3.title)
2060 current_fd = -1; 2532 lcd_getstringsize(tracks[next_idx].id3.title, NULL, NULL);
2533 if (tracks[next_idx].id3.artist)
2534 lcd_getstringsize(tracks[next_idx].id3.artist, NULL, NULL);
2535 if (tracks[next_idx].id3.album)
2536 lcd_getstringsize(tracks[next_idx].id3.album, NULL, NULL);
2061 } 2537 }
2538 close(fd);
2062 2539
2063 sound_set_volume(global_settings.volume); 2540 return status;
2064 track_widx = track_ridx = 0;
2065 buf_ridx = buf_widx = 0;
2066 filebufused = 0;
2067
2068 /* Mark all entries null. */
2069 memset(tracks, 0, sizeof(struct track_info) * MAX_TRACK);
2070
2071 last_peek_offset = -1;
2072
2073 audio_fill_file_buffer(true, false, offset);
2074} 2541}
2075 2542
2076/* Send callback events to notify about new tracks. */ 2543/* Send callback events to notify about new tracks. */
@@ -2081,7 +2548,7 @@ static void audio_generate_postbuffer_events(void)
2081 2548
2082 logf("Postbuffer:%d/%d",track_ridx,track_widx); 2549 logf("Postbuffer:%d/%d",track_ridx,track_widx);
2083 2550
2084 if (have_tracks()) 2551 if (audio_have_tracks())
2085 { 2552 {
2086 cur_idx = track_ridx; 2553 cur_idx = track_ridx;
2087 2554
@@ -2171,7 +2638,7 @@ static void audio_fill_file_buffer(
2171 /* If we're done buffering */ 2638 /* If we're done buffering */
2172 if (fill_bytesleft == 0) 2639 if (fill_bytesleft == 0)
2173 { 2640 {
2174 read_next_metadata(); 2641 audio_read_next_metadata();
2175 2642
2176 audio_generate_postbuffer_events(); 2643 audio_generate_postbuffer_events();
2177 filling = false; 2644 filling = false;
@@ -2183,120 +2650,353 @@ static void audio_fill_file_buffer(
2183 } 2650 }
2184} 2651}
2185 2652
2186static void codec_track_skip_done(bool was_manual) 2653static void audio_rebuffer(void)
2187{ 2654{
2188 /* Manual track change (always crossfade or flush audio). */ 2655 logf("Forcing rebuffer");
2189 if (was_manual) 2656
2657 /* Notify the codec that this will take a while */
2658 /* Currently this can cause some problems (logf in reverse order):
2659 * Codec load error:-1
2660 * Codec load disk
2661 * Codec: Unsupported
2662 * Codec finished
2663 * New codec:0/3
2664 * Clearing tracks:7/7, 1
2665 * Forcing rebuffer
2666 * Check new track buffer
2667 * Request new track
2668 * Clearing tracks:5/5, 0
2669 * Starting buffer fill
2670 * Clearing tracks:5/5, 1
2671 * Re-buffering song w/seek
2672 */
2673 //if (!filling)
2674 // queue_post(&codec_callback_queue, Q_CODEC_REQUEST_PENDING, 0);
2675
2676 /* Stop in progress fill, and clear open file descriptor */
2677 if (current_fd >= 0)
2190 { 2678 {
2191 pcmbuf_crossfade_init(true); 2679 close(current_fd);
2192 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED"); 2680 current_fd = -1;
2193 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
2194 } 2681 }
2195 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */ 2682 filling = false;
2196 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active() 2683
2197 && global_settings.crossfade != 2) 2684 /* Reset buffer and track pointers */
2685 tracks[track_ridx].buf_idx = buf_ridx = buf_widx = 0;
2686 track_widx = track_ridx;
2687 cur_ti = &tracks[track_ridx];
2688 audio_clear_track_entries(true, true, false);
2689 filebufused = 0;
2690 cur_ti->available = 0;
2691
2692 /* Fill the buffer */
2693 last_peek_offset = -1;
2694 cur_ti->filesize = 0;
2695 cur_ti->start_pos = 0;
2696 ci.curpos = 0;
2697
2698 if (!cur_ti->taginfo_ready)
2699 memset(&cur_ti->id3, 0, sizeof(struct mp3entry));
2700
2701 audio_fill_file_buffer(false, true, 0);
2702}
2703
2704static void audio_check_new_track(void)
2705{
2706 int track_count = audio_track_count();
2707 int old_track_ridx = track_ridx;
2708 bool forward;
2709
2710 if (dir_skip)
2198 { 2711 {
2199 pcmbuf_crossfade_init(false); 2712 dir_skip = false;
2200 codec_track_changed(); 2713 if (playlist_next_dir(ci.new_track))
2714 {
2715 ci.new_track = 0;
2716 cur_ti->taginfo_ready = false;
2717 audio_rebuffer();
2718 goto skip_done;
2719 }
2720 else
2721 {
2722 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
2723 queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0);
2724 return;
2725 }
2201 } 2726 }
2202 /* Gapless playback. */ 2727
2203 else 2728 if (new_playlist)
2729 ci.new_track = 0;
2730
2731 /* If the playlist isn't that big */
2732 if (!playlist_check(ci.new_track))
2204 { 2733 {
2205 pcmbuf_set_position_callback(pcmbuf_position_callback); 2734 if (ci.new_track >= 0)
2206 pcmbuf_set_event_handler(pcmbuf_track_changed_callback); 2735 {
2736 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
2737 queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0);
2738 return;
2739 }
2740 /* Find the beginning backward if the user over-skips it */
2741 while (!playlist_check(++ci.new_track))
2742 if (ci.new_track >= 0)
2743 {
2744 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
2745 queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0);
2746 return;
2747 }
2207 } 2748 }
2208} 2749 /* Update the playlist */
2750 last_peek_offset -= ci.new_track;
2209 2751
2210static bool codec_load_next_track(void) 2752 if (playlist_next(ci.new_track) < 0)
2211{ 2753 {
2212 struct event ev; 2754 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
2755 queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0);
2756 return;
2757 }
2213 2758
2214 if (ci.seek_time) 2759 if (new_playlist)
2215 codec_seek_complete_callback(); 2760 {
2761 ci.new_track = 1;
2762 new_playlist = false;
2763 }
2216 2764
2217#ifdef AB_REPEAT_ENABLE 2765 track_ridx += ci.new_track;
2218 ab_end_of_track_report(); 2766 track_ridx &= MAX_TRACK_MASK;
2219#endif
2220 2767
2221 logf("Request new track"); 2768 /* Save the old track */
2769 prev_ti = cur_ti;
2770 /* Move to the new track */
2771 cur_ti = &tracks[track_ridx];
2222 2772
2223 if (ci.new_track == 0) 2773 if (automatic_skip)
2774 playlist_end = false;
2775
2776 track_changed = !automatic_skip;
2777
2778 /* If it is not safe to even skip this many track entries */
2779 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
2224 { 2780 {
2225 ci.new_track++; 2781 ci.new_track = 0;
2226 automatic_skip = true; 2782 cur_ti->taginfo_ready = false;
2783 audio_rebuffer();
2784 goto skip_done;
2227 } 2785 }
2228 2786
2229 cpu_boost(true); 2787 forward = ci.new_track > 0;
2230 LOGFQUEUE("codec > audio Q_AUDIO_CHECK_NEW_TRACK"); 2788 ci.new_track = 0;
2231 queue_post(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0); 2789
2232 while (1) 2790 /* If the target track is clearly not in memory */
2791 if (cur_ti->filesize == 0 || !cur_ti->taginfo_ready)
2233 { 2792 {
2234 queue_wait(&codec_callback_queue, &ev); 2793 audio_rebuffer();
2235 if (ev.id == Q_CODEC_REQUEST_PENDING) 2794 goto skip_done;
2795 }
2796
2797 /* The track may be in memory, see if it really is */
2798 if (forward)
2799 {
2800 if (!audio_buffer_wind_forward(track_ridx, old_track_ridx))
2801 audio_rebuffer();
2802 }
2803 else
2804 {
2805 int cur_idx = track_ridx;
2806 bool taginfo_ready = true;
2807 bool wrap = track_ridx > old_track_ridx;
2808
2809 while (1)
2236 { 2810 {
2237 if (!automatic_skip) 2811 cur_idx++;
2238 pcmbuf_play_stop(); 2812 cur_idx &= MAX_TRACK_MASK;
2813 if (!(wrap || cur_idx < old_track_ridx))
2814 break;
2815
2816 /* If we hit a track in between without valid tag info, bail */
2817 if (!tracks[cur_idx].taginfo_ready)
2818 {
2819 taginfo_ready = false;
2820 break;
2821 }
2822
2823 tracks[cur_idx].available = tracks[cur_idx].filesize;
2824 if (tracks[cur_idx].codecsize)
2825 tracks[cur_idx].has_codec = true;
2826 }
2827 if (taginfo_ready)
2828 {
2829 if (!audio_buffer_wind_backward(track_ridx, old_track_ridx))
2830 audio_rebuffer();
2239 } 2831 }
2240 else 2832 else
2241 break; 2833 {
2834 cur_ti->taginfo_ready = false;
2835 audio_rebuffer();
2836 }
2242 } 2837 }
2243 cpu_boost(false); 2838
2244 switch (ev.id) 2839skip_done:
2840 audio_update_trackinfo();
2841 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_COMPLETE");
2842 queue_post(&codec_callback_queue, Q_CODEC_REQUEST_COMPLETE, 0);
2843}
2844
2845static void audio_rebuffer_and_seek(size_t newpos)
2846{
2847 int fd;
2848 char *trackname;
2849
2850 trackname = playlist_peek(0);
2851 /* (Re-)open current track's file handle. */
2852
2853 fd = open(trackname, O_RDONLY);
2854 if (fd < 0)
2245 { 2855 {
2246 case Q_CODEC_REQUEST_COMPLETE: 2856 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
2247 LOGFQUEUE("codec < Q_CODEC_REQUEST_COMPLETE"); 2857 queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0);
2248 codec_track_skip_done(!automatic_skip); 2858 return;
2249 return true; 2859 }
2860
2861 if (current_fd >= 0)
2862 close(current_fd);
2863 current_fd = fd;
2250 2864
2251 case Q_CODEC_REQUEST_FAILED: 2865 playlist_end = false;
2252 LOGFQUEUE("codec < Q_CODEC_REQUEST_FAILED");
2253 ci.new_track = 0;
2254 ci.stop_codec = true;
2255 return false;
2256 2866
2257 default: 2867 ci.curpos = newpos;
2258 LOGFQUEUE("codec < default"); 2868
2259 ci.stop_codec = true; 2869 /* Clear codec buffer. */
2260 return false; 2870 track_widx = track_ridx;
2871 filebufused = 0;
2872 tracks[track_widx].buf_idx = buf_widx = buf_ridx = 0;
2873
2874 last_peek_offset = 0;
2875 filling = false;
2876 audio_initialize_buffer_fill(true);
2877 filling = true;
2878
2879 if (newpos > conf_preseek) {
2880 buf_ridx += conf_preseek;
2881 cur_ti->start_pos = newpos - conf_preseek;
2882 }
2883 else
2884 {
2885 buf_ridx += newpos;
2886 cur_ti->start_pos = 0;
2261 } 2887 }
2888
2889 cur_ti->filerem = cur_ti->filesize - cur_ti->start_pos;
2890 cur_ti->available = 0;
2891
2892 lseek(current_fd, cur_ti->start_pos, SEEK_SET);
2893
2894 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_COMPLETE");
2895 queue_post(&codec_callback_queue, Q_CODEC_REQUEST_COMPLETE, 0);
2262} 2896}
2263 2897
2264static bool voice_request_next_track_callback(void) 2898void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3,
2899 bool last_track))
2265{ 2900{
2266 ci_voice.new_track = 0; 2901 track_buffer_callback = handler;
2267 return true;
2268} 2902}
2269 2903
2270static bool codec_request_next_track_callback(void) 2904void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3,
2905 bool last_track))
2271{ 2906{
2272 int prev_codectype; 2907 track_unbuffer_callback = handler;
2908}
2273 2909
2274 if (ci.stop_codec || !playing) 2910void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3))
2275 return false; 2911{
2912 track_changed_callback = handler;
2913}
2276 2914
2277 prev_codectype = get_codec_base_type(cur_ti->id3.codectype); 2915static void audio_stop_codec_flush(void)
2916{
2917 ci.stop_codec = true;
2918 pcmbuf_pause(true);
2919 while (audio_codec_loaded)
2920 yield();
2921 /* If the audio codec is not loaded any more, and the audio is still
2922 * playing, it is now and _only_ now safe to call this function from the
2923 * audio thread */
2924 if (pcm_is_playing())
2925 pcmbuf_play_stop();
2926 pcmbuf_pause(paused);
2927}
2278 2928
2279 if (!codec_load_next_track()) 2929static void audio_stop_playback(void)
2280 return false; 2930{
2931 /* If we were playing, save resume information */
2932 if (playing)
2933 {
2934 /* Save the current playing spot, or NULL if the playlist has ended */
2935 playlist_update_resume_info(
2936 (playlist_end && ci.stop_codec)?NULL:audio_current_track());
2937 }
2281 2938
2282 /* Check if the next codec is the same file. */ 2939 while (voice_is_playing && !queue_empty(&voice_queue))
2283 if (prev_codectype == get_codec_base_type(cur_ti->id3.codectype)) 2940 yield();
2941
2942 filebufused = 0;
2943 playing = false;
2944 filling = false;
2945 paused = false;
2946 audio_stop_codec_flush();
2947
2948 if (current_fd >= 0)
2284 { 2949 {
2285 logf("New track loaded"); 2950 close(current_fd);
2286 codec_discard_codec_callback(); 2951 current_fd = -1;
2287 return true;
2288 } 2952 }
2289 else 2953
2954 /* Mark all entries null. */
2955 audio_clear_track_entries(true, false, false);
2956 memset(tracks, 0, sizeof(struct track_info) * MAX_TRACK);
2957}
2958
2959static void audio_play_start(size_t offset)
2960{
2961#if defined(HAVE_RECORDING) || defined(CONFIG_TUNER)
2962 rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2963#endif
2964
2965 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2966 while (audio_codec_loaded)
2967 audio_stop_codec_flush();
2968
2969 track_changed = true;
2970 playlist_end = false;
2971
2972 playing = true;
2973 ci.new_track = 0;
2974 ci.seek_time = 0;
2975
2976 if (current_fd >= 0)
2290 { 2977 {
2291 logf("New codec:%d/%d", cur_ti->id3.codectype, prev_codectype); 2978 close(current_fd);
2292 return false; 2979 current_fd = -1;
2293 } 2980 }
2981
2982 sound_set_volume(global_settings.volume);
2983 track_widx = track_ridx = 0;
2984 buf_ridx = buf_widx = 0;
2985 filebufused = 0;
2986
2987 /* Mark all entries null. */
2988 memset(tracks, 0, sizeof(struct track_info) * MAX_TRACK);
2989
2990 last_peek_offset = -1;
2991
2992 audio_fill_file_buffer(true, false, offset);
2294} 2993}
2295 2994
2995
2296/* Invalidates all but currently playing track. */ 2996/* Invalidates all but currently playing track. */
2297void audio_invalidate_tracks(void) 2997void audio_invalidate_tracks(void)
2298{ 2998{
2299 if (have_tracks()) { 2999 if (audio_have_tracks()) {
2300 last_peek_offset = 0; 3000 last_peek_offset = 0;
2301 3001
2302 playlist_end = false; 3002 playlist_end = false;
@@ -2313,7 +3013,7 @@ void audio_invalidate_tracks(void)
2313 if (buf_widx >= filebuflen) 3013 if (buf_widx >= filebuflen)
2314 buf_widx -= filebuflen; 3014 buf_widx -= filebuflen;
2315 3015
2316 read_next_metadata(); 3016 audio_read_next_metadata();
2317 } 3017 }
2318} 3018}
2319 3019
@@ -2321,7 +3021,7 @@ static void audio_new_playlist(void)
2321{ 3021{
2322 /* Prepare to start a new fill from the beginning of the playlist */ 3022 /* Prepare to start a new fill from the beginning of the playlist */
2323 last_peek_offset = -1; 3023 last_peek_offset = -1;
2324 if (have_tracks()) { 3024 if (audio_have_tracks()) {
2325 playlist_end = false; 3025 playlist_end = false;
2326 track_widx = track_ridx; 3026 track_widx = track_ridx;
2327 audio_clear_track_entries(true, true, true); 3027 audio_clear_track_entries(true, true, true);
@@ -2370,280 +3070,6 @@ static void audio_initiate_dir_change(long direction)
2370 ci.new_track = direction; 3070 ci.new_track = direction;
2371} 3071}
2372 3072
2373void audio_thread(void)
2374{
2375 struct event ev;
2376
2377 /* At first initialize audio system in background. */
2378 playback_init();
2379
2380 while (1) {
2381 if (filling)
2382 {
2383 queue_wait_w_tmo(&audio_queue, &ev, 0);
2384 if (ev.id == SYS_TIMEOUT)
2385 ev.id = Q_AUDIO_FILL_BUFFER;
2386 }
2387 else
2388 queue_wait_w_tmo(&audio_queue, &ev, HZ);
2389
2390 switch (ev.id) {
2391 case Q_AUDIO_FILL_BUFFER:
2392 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
2393 if (!filling)
2394 if (!playing || playlist_end || ci.stop_codec)
2395 break;
2396 audio_fill_file_buffer(false, false, 0);
2397 break;
2398
2399 case Q_AUDIO_PLAY:
2400 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2401 audio_clear_track_entries(true, false, true);
2402 audio_play_start((size_t)ev.data);
2403 break ;
2404
2405 case Q_AUDIO_STOP:
2406 LOGFQUEUE("audio < Q_AUDIO_STOP");
2407 audio_stop_playback();
2408 break ;
2409
2410 case Q_AUDIO_PAUSE:
2411 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
2412 pcmbuf_pause((bool)ev.data);
2413 paused = (bool)ev.data;
2414 break ;
2415
2416 case Q_AUDIO_SKIP:
2417 LOGFQUEUE("audio < Q_AUDIO_SKIP");
2418 audio_initiate_track_change((long)ev.data);
2419 break;
2420
2421 case Q_AUDIO_PRE_FF_REWIND:
2422 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
2423 if (!playing)
2424 break;
2425 pcmbuf_pause(true);
2426 break;
2427
2428 case Q_AUDIO_FF_REWIND:
2429 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
2430 if (!playing)
2431 break ;
2432 ci.seek_time = (long)ev.data+1;
2433 break ;
2434
2435 case Q_AUDIO_REBUFFER_SEEK:
2436 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
2437 audio_rebuffer_and_seek((size_t)ev.data);
2438 break;
2439
2440 case Q_AUDIO_CHECK_NEW_TRACK:
2441 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
2442 audio_check_new_track();
2443 break;
2444
2445 case Q_AUDIO_DIR_SKIP:
2446 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2447 playlist_end = false;
2448 if (global_settings.beep)
2449 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
2450 audio_initiate_dir_change((long)ev.data);
2451 break;
2452
2453 case Q_AUDIO_NEW_PLAYLIST:
2454 LOGFQUEUE("audio < Q_AUDIO_NEW_PLAYLIST");
2455 audio_new_playlist();
2456 break;
2457
2458 case Q_AUDIO_FLUSH:
2459 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
2460 audio_invalidate_tracks();
2461 break ;
2462
2463 case Q_AUDIO_TRACK_CHANGED:
2464 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2465 if (track_changed_callback)
2466 track_changed_callback(&cur_ti->id3);
2467 track_changed = true;
2468 playlist_update_resume_info(audio_current_track());
2469 break ;
2470
2471#ifndef SIMULATOR
2472 case SYS_USB_CONNECTED:
2473 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2474 audio_stop_playback();
2475 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2476 usb_wait_for_disconnect(&audio_queue);
2477 break ;
2478#endif
2479
2480 case SYS_TIMEOUT:
2481 LOGFQUEUE("audio < SYS_TIMEOUT");
2482 break;
2483
2484 default:
2485 LOGFQUEUE("audio < default");
2486 }
2487 }
2488}
2489
2490static void codec_thread(void)
2491{
2492 struct event ev;
2493 int status;
2494 size_t wrap;
2495
2496 while (1) {
2497 status = 0;
2498 queue_wait(&codec_queue, &ev);
2499
2500 switch (ev.id) {
2501 case Q_CODEC_LOAD_DISK:
2502 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
2503 audio_codec_loaded = true;
2504 if (voice_codec_loaded)
2505 {
2506 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
2507 queue_post(&voice_codec_queue, Q_AUDIO_PLAY, 0);
2508 }
2509 mutex_lock(&mutex_codecthread);
2510 current_codec = CODEC_IDX_AUDIO;
2511 ci.stop_codec = false;
2512 status = codec_load_file((const char *)ev.data, &ci);
2513 mutex_unlock(&mutex_codecthread);
2514 break ;
2515
2516 case Q_CODEC_LOAD:
2517 LOGFQUEUE("codec < Q_CODEC_LOAD");
2518 if (!cur_ti->has_codec) {
2519 logf("Codec slot is empty!");
2520 /* Wait for the pcm buffer to go empty */
2521 while (pcm_is_playing())
2522 yield();
2523 /* This must be set to prevent an infinite loop */
2524 ci.stop_codec = true;
2525 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
2526 queue_post(&codec_queue, Q_AUDIO_PLAY, 0);
2527 break ;
2528 }
2529
2530 audio_codec_loaded = true;
2531 if (voice_codec_loaded)
2532 {
2533 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
2534 queue_post(&voice_codec_queue, Q_AUDIO_PLAY, 0);
2535 }
2536 mutex_lock(&mutex_codecthread);
2537 current_codec = CODEC_IDX_AUDIO;
2538 ci.stop_codec = false;
2539 wrap = (size_t)&filebuf[filebuflen] - (size_t)cur_ti->codecbuf;
2540 status = codec_load_ram(cur_ti->codecbuf, cur_ti->codecsize,
2541 &filebuf[0], wrap, &ci);
2542 mutex_unlock(&mutex_codecthread);
2543 break ;
2544
2545#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
2546 case Q_ENCODER_LOAD_DISK:
2547 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2548 audio_codec_loaded = false;
2549 if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE)
2550 {
2551 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
2552 queue_post(&voice_codec_queue, Q_ENCODER_RECORD, NULL);
2553 }
2554 mutex_lock(&mutex_codecthread);
2555 current_codec = CODEC_IDX_AUDIO;
2556 ci.stop_codec = false;
2557 status = codec_load_file((const char *)ev.data, &ci);
2558 mutex_unlock(&mutex_codecthread);
2559 break;
2560#endif
2561
2562#ifndef SIMULATOR
2563 case SYS_USB_CONNECTED:
2564 LOGFQUEUE("codec < SYS_USB_CONNECTED");
2565 queue_clear(&codec_queue);
2566 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2567 if (voice_codec_loaded)
2568 swap_codec();
2569 usb_wait_for_disconnect(&codec_queue);
2570 break;
2571#endif
2572
2573 default:
2574 LOGFQUEUE("codec < default");
2575 }
2576
2577 if (audio_codec_loaded)
2578 {
2579 if (ci.stop_codec)
2580 {
2581 status = CODEC_OK;
2582 if (!playing)
2583 pcmbuf_play_stop();
2584 }
2585 audio_codec_loaded = false;
2586 }
2587
2588 switch (ev.id) {
2589 case Q_CODEC_LOAD_DISK:
2590 case Q_CODEC_LOAD:
2591 LOGFQUEUE("codec < Q_CODEC_LOAD");
2592 if (playing)
2593 {
2594 if (ci.new_track || status != CODEC_OK)
2595 {
2596 if (!ci.new_track)
2597 {
2598 logf("Codec failure");
2599 gui_syncsplash(HZ*2, true, "Codec failure");
2600 }
2601
2602 if (!codec_load_next_track())
2603 {
2604 // queue_post(&codec_queue, Q_AUDIO_STOP, 0);
2605 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2606 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
2607 break;
2608 }
2609 }
2610 else
2611 {
2612 logf("Codec finished");
2613 if (ci.stop_codec)
2614 {
2615 /* Wait for the audio to stop playing before
2616 * triggering the WPS exit */
2617 while(pcm_is_playing())
2618 sleep(1);
2619 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2620 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
2621 break;
2622 }
2623 }
2624
2625 if (cur_ti->has_codec)
2626 {
2627 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2628 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
2629 }
2630 else
2631 {
2632 const char *codec_fn = get_codec_filename(cur_ti->id3.codectype);
2633 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2634 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
2635 (void *)codec_fn);
2636 }
2637 }
2638 break;
2639
2640 default:
2641 LOGFQUEUE("codec < default");
2642
2643 } /* end switch */
2644 }
2645}
2646
2647static void audio_reset_buffer(void) 3073static void audio_reset_buffer(void)
2648{ 3074{
2649 size_t offset; 3075 size_t offset;
@@ -2686,495 +3112,9 @@ static void audio_reset_buffer(void)
2686 filebuflen &= ~3; 3112 filebuflen &= ~3;
2687} 3113}
2688 3114
2689void audio_load_encoder(int enc_id)
2690{
2691#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
2692 const char *enc_fn = get_codec_filename(enc_id | CODEC_TYPE_ENCODER);
2693 if (!enc_fn)
2694 return;
2695
2696 audio_remove_encoder();
2697
2698 LOGFQUEUE("audio > codec Q_ENCODER_LOAD_DISK");
2699 queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (void *)enc_fn);
2700
2701 while (!ci.enc_codec_loaded)
2702 yield();
2703#endif
2704 return;
2705 (void)enc_id;
2706} /* audio_load_encoder */
2707
2708void audio_remove_encoder(void)
2709{
2710#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
2711 /* force encoder codec unload (if previously loaded) */
2712 if (!ci.enc_codec_loaded)
2713 return;
2714
2715 ci.stop_codec = true;
2716 while (ci.enc_codec_loaded)
2717 yield();
2718#endif
2719} /* audio_remove_encoder */
2720
2721static void voice_codec_thread(void)
2722{
2723 while (1)
2724 {
2725 logf("Loading voice codec");
2726 voice_codec_loaded = true;
2727 mutex_lock(&mutex_codecthread);
2728 current_codec = CODEC_IDX_VOICE;
2729 dsp_configure(DSP_RESET, 0);
2730 voice_remaining = 0;
2731 voice_getmore = NULL;
2732
2733 codec_load_file(get_codec_filename(AFMT_MPA_L3), &ci_voice);
2734
2735 logf("Voice codec finished");
2736 voice_codec_loaded = false;
2737 mutex_unlock(&mutex_codecthread);
2738 }
2739} /* voice_codec_thread */
2740
2741void voice_init(void)
2742{
2743 if (!filebuf)
2744 return; /* Audio buffers not yet set up */
2745
2746 if (voice_thread_num >= 0)
2747 {
2748 logf("Terminating voice codec");
2749 remove_thread(voice_thread_num);
2750 if (current_codec == CODEC_IDX_VOICE)
2751 mutex_unlock(&mutex_codecthread);
2752 queue_delete(&voice_codec_queue);
2753 voice_thread_num = -1;
2754 voice_codec_loaded = false;
2755 }
2756
2757 if (!talk_voice_required())
2758 return;
2759
2760 logf("Starting voice codec");
2761 queue_init(&voice_codec_queue);
2762 voice_thread_num = create_thread(voice_codec_thread, voice_codec_stack,
2763 sizeof(voice_codec_stack), voice_codec_thread_name);
2764
2765 while (!voice_codec_loaded)
2766 yield();
2767} /* voice_init */
2768
2769void voice_stop(void)
2770{
2771 /* Messages should not be posted to voice codec queue unless it is the
2772 current codec or deadlocks happen. This will be addressed globally soon.
2773 -- jhMikeS */
2774 if (current_codec != CODEC_IDX_VOICE)
2775 return;
2776
2777 mp3_play_stop();
2778 while (voice_is_playing && !queue_empty(&voice_codec_queue))
2779 yield();
2780} /* voice_stop */
2781
2782struct mp3entry* audio_current_track(void)
2783{
2784 const char *filename;
2785 const char *p;
2786 static struct mp3entry temp_id3;
2787 int cur_idx;
2788
2789 cur_idx = track_ridx + ci.new_track;
2790 cur_idx &= MAX_TRACK_MASK;
2791
2792 if (tracks[cur_idx].taginfo_ready)
2793 return &tracks[cur_idx].id3;
2794
2795 memset(&temp_id3, 0, sizeof(struct mp3entry));
2796
2797 filename = playlist_peek(ci.new_track);
2798 if (!filename)
2799 filename = "No file!";
2800
2801#ifdef HAVE_TC_RAMCACHE
2802 if (tagcache_fill_tags(&temp_id3, filename))
2803 return &temp_id3;
2804#endif
2805
2806 p = strrchr(filename, '/');
2807 if (!p)
2808 p = filename;
2809 else
2810 p++;
2811
2812 strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1);
2813 temp_id3.title = &temp_id3.path[0];
2814
2815 return &temp_id3;
2816}
2817
2818struct mp3entry* audio_next_track(void)
2819{
2820 int next_idx = track_ridx;
2821
2822 if (!have_tracks())
2823 return NULL;
2824
2825 next_idx++;
2826 next_idx &= MAX_TRACK_MASK;
2827
2828 if (!tracks[next_idx].taginfo_ready)
2829 return NULL;
2830
2831 return &tracks[next_idx].id3;
2832}
2833
2834bool audio_has_changed_track(void)
2835{
2836 if (track_changed)
2837 {
2838 track_changed = false;
2839 return true;
2840 }
2841
2842 return false;
2843}
2844
2845void audio_play(long offset)
2846{
2847 logf("audio_play");
2848 if (playing && offset <= 0)
2849 {
2850 LOGFQUEUE("audio > audio Q_AUDIO_NEW_PLAYLIST");
2851 queue_post(&audio_queue, Q_AUDIO_NEW_PLAYLIST, 0);
2852 }
2853 else
2854 {
2855 if (playing)
2856 audio_stop();
2857
2858 playing = true;
2859 LOGFQUEUE("audio > audio Q_AUDIO_PLAY");
2860 queue_post(&audio_queue, Q_AUDIO_PLAY, (void *)offset);
2861 }
2862}
2863
2864void audio_stop(void)
2865{
2866 LOGFQUEUE("audio > audio Q_AUDIO_STOP");
2867 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
2868 while (playing || audio_codec_loaded)
2869 yield();
2870}
2871
2872bool mp3_pause_done(void)
2873{
2874 return pcm_is_paused();
2875}
2876
2877void audio_pause(void)
2878{
2879 LOGFQUEUE("audio > audio Q_AUDIO_PAUSE");
2880 queue_post(&audio_queue, Q_AUDIO_PAUSE, (void *)true);
2881}
2882
2883void audio_resume(void)
2884{
2885 LOGFQUEUE("audio > audio Q_AUDIO_PAUSE resume");
2886 queue_post(&audio_queue, Q_AUDIO_PAUSE, (void *)false);
2887}
2888
2889void audio_next(void)
2890{
2891 if (global_settings.beep)
2892 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
2893
2894 /* Should be safe to do outside of thread, that way we get
2895 * the instant wps response at least. */
2896 audio_initiate_track_change(1);
2897 // queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)1);
2898}
2899
2900void audio_prev(void)
2901{
2902 if (global_settings.beep)
2903 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
2904
2905 audio_initiate_track_change(-1);
2906 // queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)-1);
2907}
2908
2909void audio_next_dir(void)
2910{
2911 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
2912 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, (void *)1);
2913}
2914
2915void audio_prev_dir(void)
2916{
2917 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
2918 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, (void *)-1);
2919}
2920
2921void audio_pre_ff_rewind(void)
2922{
2923 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
2924 queue_post(&audio_queue, Q_AUDIO_PRE_FF_REWIND, 0);
2925}
2926
2927void audio_ff_rewind(long newpos)
2928{
2929 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
2930 queue_post(&audio_queue, Q_AUDIO_FF_REWIND, (int *)newpos);
2931}
2932
2933void audio_flush_and_reload_tracks(void)
2934{
2935 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
2936 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0);
2937}
2938
2939void audio_error_clear(void)
2940{
2941}
2942
2943int audio_status(void)
2944{
2945 int ret = 0;
2946
2947 if (playing)
2948 ret |= AUDIO_STATUS_PLAY;
2949
2950 if (paused)
2951 ret |= AUDIO_STATUS_PAUSE;
2952
2953#ifdef HAVE_RECORDING
2954 /* Do this here for constitency with mpeg.c version */
2955 ret |= pcm_rec_status();
2956#endif
2957
2958 return ret;
2959}
2960
2961bool audio_query_poweroff(void)
2962{
2963 return !(playing && paused);
2964}
2965
2966int audio_get_file_pos(void)
2967{
2968 return 0;
2969}
2970
2971
2972/* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2973static void mp3_set_elapsed(struct mp3entry* id3)
2974{
2975 if ( id3->vbr ) {
2976 if ( id3->has_toc ) {
2977 /* calculate elapsed time using TOC */
2978 int i;
2979 unsigned int remainder, plen, relpos, nextpos;
2980
2981 /* find wich percent we're at */
2982 for (i=0; i<100; i++ )
2983 if ( id3->offset < id3->toc[i] * (id3->filesize / 256) )
2984 break;
2985
2986 i--;
2987 if (i < 0)
2988 i = 0;
2989
2990 relpos = id3->toc[i];
2991
2992 if (i < 99)
2993 nextpos = id3->toc[i+1];
2994 else
2995 nextpos = 256;
2996
2997 remainder = id3->offset - (relpos * (id3->filesize / 256));
2998
2999 /* set time for this percent (divide before multiply to prevent
3000 overflow on long files. loss of precision is negligible on
3001 short files) */
3002 id3->elapsed = i * (id3->length / 100);
3003
3004 /* calculate remainder time */
3005 plen = (nextpos - relpos) * (id3->filesize / 256);
3006 id3->elapsed += (((remainder * 100) / plen) *
3007 (id3->length / 10000));
3008 }
3009 else {
3010 /* no TOC exists. set a rough estimate using average bitrate */
3011 int tpk = id3->length / (id3->filesize / 1024);
3012 id3->elapsed = id3->offset / 1024 * tpk;
3013 }
3014 }
3015 else
3016 {
3017 /* constant bitrate, use exact calculation */
3018 if (id3->bitrate != 0)
3019 id3->elapsed = id3->offset / (id3->bitrate / 8);
3020 }
3021}
3022
3023/* Copied from mpeg.c. Should be moved somewhere else. */
3024static int mp3_get_file_pos(void)
3025{
3026 int pos = -1;
3027 struct mp3entry *id3 = audio_current_track();
3028
3029 if (id3->vbr)
3030 {
3031 if (id3->has_toc)
3032 {
3033 /* Use the TOC to find the new position */
3034 unsigned int percent, remainder;
3035 int curtoc, nexttoc, plen;
3036
3037 percent = (id3->elapsed*100)/id3->length;
3038 if (percent > 99)
3039 percent = 99;
3040
3041 curtoc = id3->toc[percent];
3042
3043 if (percent < 99)
3044 nexttoc = id3->toc[percent+1];
3045 else
3046 nexttoc = 256;
3047
3048 pos = (id3->filesize/256)*curtoc;
3049
3050 /* Use the remainder to get a more accurate position */
3051 remainder = (id3->elapsed*100)%id3->length;
3052 remainder = (remainder*100)/id3->length;
3053 plen = (nexttoc - curtoc)*(id3->filesize/256);
3054 pos += (plen/100)*remainder;
3055 }
3056 else
3057 {
3058 /* No TOC exists, estimate the new position */
3059 pos = (id3->filesize / (id3->length / 1000)) *
3060 (id3->elapsed / 1000);
3061 }
3062 }
3063 else if (id3->bitrate)
3064 pos = id3->elapsed * (id3->bitrate / 8);
3065 else
3066 return -1;
3067
3068 /* Don't seek right to the end of the file so that we can
3069 transition properly to the next song */
3070 if (pos >= (int)(id3->filesize - id3->id3v1len))
3071 pos = id3->filesize - id3->id3v1len - 1;
3072 /* skip past id3v2 tag and other leading garbage */
3073 else if (pos < (int)id3->first_frame_offset)
3074 pos = id3->first_frame_offset;
3075
3076 return pos;
3077}
3078
3079void mp3_play_data(const unsigned char* start, int size,
3080 void (*get_more)(unsigned char** start, int* size))
3081{
3082 static struct voice_info voice_clip;
3083 voice_clip.callback = get_more;
3084 voice_clip.buf = (char *)start;
3085 voice_clip.size = size;
3086 logf("mp3 > voice Q_VOICE_STOP");
3087 queue_post(&voice_codec_queue, Q_VOICE_STOP, 0);
3088 logf("mp3 > voice Q_VOICE_PLAY");
3089 queue_post(&voice_codec_queue, Q_VOICE_PLAY, &voice_clip);
3090 voice_is_playing = true;
3091 voice_boost_cpu(true);
3092}
3093
3094void mp3_play_stop(void)
3095{
3096 logf("mp3 > voice Q_VOICE_STOP");
3097 queue_post(&voice_codec_queue, Q_VOICE_STOP, 0);
3098}
3099
3100void audio_set_buffer_margin(int setting)
3101{
3102 static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
3103 buffer_margin = lookup[setting];
3104 logf("buffer margin: %ds", buffer_margin);
3105 set_filebuf_watermark(buffer_margin);
3106}
3107
3108/* Set crossfade & PCM buffer length. */
3109void audio_set_crossfade(int enable)
3110{
3111 size_t size;
3112 bool was_playing = (playing && audio_is_initialized);
3113 size_t offset = 0;
3114#if MEM > 1
3115 int seconds = 1;
3116#endif
3117
3118 if (!filebuf)
3119 return; /* Audio buffers not yet set up */
3120
3121#if MEM > 1
3122 if (enable)
3123 seconds = global_settings.crossfade_fade_out_delay
3124 + global_settings.crossfade_fade_out_duration;
3125
3126 /* Buffer has to be at least 2s long. */
3127 seconds += 2;
3128 logf("buf len: %d", seconds);
3129 size = seconds * (NATIVE_FREQUENCY*4);
3130#else
3131 enable = 0;
3132 size = NATIVE_FREQUENCY*2;
3133#endif
3134 if (pcmbuf_get_bufsize() == size)
3135 return ;
3136
3137 if (was_playing)
3138 {
3139 /* Store the track resume position */
3140 offset = cur_ti->id3.offset;
3141 /* Playback has to be stopped before changing the buffer size. */
3142 LOGFQUEUE("audio > audio Q_AUDIO_STOP");
3143 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
3144 while (audio_codec_loaded)
3145 yield();
3146 gui_syncsplash(0, true, (char *)str(LANG_RESTARTING_PLAYBACK));
3147 }
3148
3149 /* Re-initialize audio system. */
3150 pcmbuf_init(size);
3151 pcmbuf_crossfade_enable(enable);
3152 audio_reset_buffer();
3153 logf("abuf:%dB", pcmbuf_get_bufsize());
3154 logf("fbuf:%dB", filebuflen);
3155
3156 voice_init();
3157
3158 /* Restart playback. */
3159 if (was_playing) {
3160 playing = true;
3161 LOGFQUEUE("audio > audio Q_AUDIO_PLAY");
3162 queue_post(&audio_queue, Q_AUDIO_PLAY, (void *)offset);
3163
3164 /* Wait for the playback to start again (and display the splash
3165 screen during that period. */
3166 while (playing && !audio_codec_loaded)
3167 yield();
3168 }
3169}
3170
3171void mpeg_id3_options(bool _v1first)
3172{
3173 v1first = _v1first;
3174}
3175 3115
3176#ifdef ROCKBOX_HAS_LOGF 3116#ifdef ROCKBOX_HAS_LOGF
3177void test_track_changed_event(struct mp3entry *id3) 3117static void audio_test_track_changed_event(struct mp3entry *id3)
3178{ 3118{
3179 (void)id3; 3119 (void)id3;
3180 3120
@@ -3182,7 +3122,7 @@ void test_track_changed_event(struct mp3entry *id3)
3182} 3122}
3183#endif 3123#endif
3184 3124
3185static void playback_init(void) 3125static void audio_playback_init(void)
3186{ 3126{
3187 static bool voicetagtrue = true; 3127 static bool voicetagtrue = true;
3188 struct event ev; 3128 struct event ev;
@@ -3196,14 +3136,14 @@ static void playback_init(void)
3196#endif 3136#endif
3197 3137
3198#ifdef ROCKBOX_HAS_LOGF 3138#ifdef ROCKBOX_HAS_LOGF
3199 audio_set_track_changed_event(test_track_changed_event); 3139 audio_set_track_changed_event(audio_test_track_changed_event);
3200#endif 3140#endif
3201 3141
3202 /* Initialize codec api. */ 3142 /* Initialize codec api. */
3203 ci.read_filebuf = codec_filebuf_callback; 3143 ci.read_filebuf = codec_filebuf_callback;
3204 ci.pcmbuf_insert = codec_pcmbuf_insert_callback; 3144 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
3205 ci.pcmbuf_insert_split = codec_pcmbuf_insert_split_callback; 3145 ci.pcmbuf_insert_split = codec_pcmbuf_insert_split_callback;
3206 ci.get_codec_memory = get_codec_memory_callback; 3146 ci.get_codec_memory = codec_get_memory_callback;
3207 ci.request_buffer = codec_request_buffer_callback; 3147 ci.request_buffer = codec_request_buffer_callback;
3208 ci.advance_buffer = codec_advance_buffer_callback; 3148 ci.advance_buffer = codec_advance_buffer_callback;
3209 ci.advance_buffer_loc = codec_advance_buffer_loc_callback; 3149 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
@@ -3222,7 +3162,7 @@ static void playback_init(void)
3222 ci_voice.read_filebuf = voice_filebuf_callback; 3162 ci_voice.read_filebuf = voice_filebuf_callback;
3223 ci_voice.pcmbuf_insert = voice_pcmbuf_insert_callback; 3163 ci_voice.pcmbuf_insert = voice_pcmbuf_insert_callback;
3224 ci_voice.pcmbuf_insert_split = voice_pcmbuf_insert_split_callback; 3164 ci_voice.pcmbuf_insert_split = voice_pcmbuf_insert_split_callback;
3225 ci_voice.get_codec_memory = get_voice_memory_callback; 3165 ci_voice.get_codec_memory = voice_get_memory_callback;
3226 ci_voice.request_buffer = voice_request_buffer_callback; 3166 ci_voice.request_buffer = voice_request_buffer_callback;
3227 ci_voice.advance_buffer = voice_advance_buffer_callback; 3167 ci_voice.advance_buffer = voice_advance_buffer_callback;
3228 ci_voice.advance_buffer_loc = voice_advance_buffer_loc_callback; 3168 ci_voice.advance_buffer_loc = voice_advance_buffer_loc_callback;
@@ -3266,39 +3206,120 @@ static void playback_init(void)
3266 sound_settings_apply(); 3206 sound_settings_apply();
3267} 3207}
3268 3208
3269void audio_preinit(void) 3209static void audio_thread(void)
3270{ 3210{
3271 logf("playback system pre-init"); 3211 struct event ev;
3272 3212
3273 filebufused = 0; 3213 /* At first initialize audio system in background. */
3274 filling = false; 3214 audio_playback_init();
3275 current_codec = CODEC_IDX_AUDIO;
3276 playing = false;
3277 paused = false;
3278 audio_codec_loaded = false;
3279 voice_is_playing = false;
3280 track_changed = false;
3281 current_fd = -1;
3282 track_buffer_callback = NULL;
3283 track_unbuffer_callback = NULL;
3284 track_changed_callback = NULL;
3285 /* Just to prevent cur_ti never be anything random. */
3286 cur_ti = &tracks[0];
3287 3215
3288 mutex_init(&mutex_codecthread); 3216 while (1) {
3217 if (filling)
3218 {
3219 queue_wait_w_tmo(&audio_queue, &ev, 0);
3220 if (ev.id == SYS_TIMEOUT)
3221 ev.id = Q_AUDIO_FILL_BUFFER;
3222 }
3223 else
3224 queue_wait_w_tmo(&audio_queue, &ev, HZ);
3289 3225
3290 queue_init(&audio_queue); 3226 switch (ev.id) {
3291 queue_init(&codec_queue); 3227 case Q_AUDIO_FILL_BUFFER:
3292 /* clear, not init to create a private queue */ 3228 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3293 queue_clear(&codec_callback_queue); 3229 if (!filling)
3230 if (!playing || playlist_end || ci.stop_codec)
3231 break;
3232 audio_fill_file_buffer(false, false, 0);
3233 break;
3294 3234
3295 create_thread(audio_thread, audio_stack, sizeof(audio_stack), 3235 case Q_AUDIO_PLAY:
3296 audio_thread_name); 3236 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3297} 3237 audio_clear_track_entries(true, false, true);
3238 audio_play_start((size_t)ev.data);
3239 break ;
3298 3240
3299void audio_init(void) 3241 case Q_AUDIO_STOP:
3300{ 3242 LOGFQUEUE("audio < Q_AUDIO_STOP");
3301 LOGFQUEUE("audio > audio Q_AUDIO_POSTINIT"); 3243 audio_stop_playback();
3302 queue_post(&audio_queue, Q_AUDIO_POSTINIT, 0); 3244 break ;
3245
3246 case Q_AUDIO_PAUSE:
3247 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3248 pcmbuf_pause((bool)ev.data);
3249 paused = (bool)ev.data;
3250 break ;
3251
3252 case Q_AUDIO_SKIP:
3253 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3254 audio_initiate_track_change((long)ev.data);
3255 break;
3256
3257 case Q_AUDIO_PRE_FF_REWIND:
3258 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3259 if (!playing)
3260 break;
3261 pcmbuf_pause(true);
3262 break;
3263
3264 case Q_AUDIO_FF_REWIND:
3265 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3266 if (!playing)
3267 break ;
3268 ci.seek_time = (long)ev.data+1;
3269 break ;
3270
3271 case Q_AUDIO_REBUFFER_SEEK:
3272 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
3273 audio_rebuffer_and_seek((size_t)ev.data);
3274 break;
3275
3276 case Q_AUDIO_CHECK_NEW_TRACK:
3277 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3278 audio_check_new_track();
3279 break;
3280
3281 case Q_AUDIO_DIR_SKIP:
3282 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3283 playlist_end = false;
3284 if (global_settings.beep)
3285 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
3286 audio_initiate_dir_change((long)ev.data);
3287 break;
3288
3289 case Q_AUDIO_NEW_PLAYLIST:
3290 LOGFQUEUE("audio < Q_AUDIO_NEW_PLAYLIST");
3291 audio_new_playlist();
3292 break;
3293
3294 case Q_AUDIO_FLUSH:
3295 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3296 audio_invalidate_tracks();
3297 break ;
3298
3299 case Q_AUDIO_TRACK_CHANGED:
3300 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3301 if (track_changed_callback)
3302 track_changed_callback(&cur_ti->id3);
3303 track_changed = true;
3304 playlist_update_resume_info(audio_current_track());
3305 break ;
3306
3307#ifndef SIMULATOR
3308 case SYS_USB_CONNECTED:
3309 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3310 audio_stop_playback();
3311 usb_acknowledge(SYS_USB_CONNECTED_ACK);
3312 usb_wait_for_disconnect(&audio_queue);
3313 break ;
3314#endif
3315
3316 case SYS_TIMEOUT:
3317 LOGFQUEUE("audio < SYS_TIMEOUT");
3318 break;
3319
3320 default:
3321 LOGFQUEUE("audio < default");
3322 }
3323 }
3303} 3324}
3304 3325