Fix not being able to skip to the last track in a playlist.
[Rockbox.git] / apps / playback.c
blob6715db5d6cea3883614f3c384c56e21fcb188e1e
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 Miika Pekkarinen
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 /* TODO: Pause should be handled in here, rather than PCMBUF so that voice can
21 * play whilst audio is paused */
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <ctype.h>
28 #include "system.h"
29 #include "thread.h"
30 #include "file.h"
31 #include "panic.h"
32 #include "memory.h"
33 #include "lcd.h"
34 #include "font.h"
35 #include "button.h"
36 #include "kernel.h"
37 #include "tree.h"
38 #include "debug.h"
39 #include "sprintf.h"
40 #include "settings.h"
41 #include "codecs.h"
42 #include "audio.h"
43 #include "buffering.h"
44 #include "voice_thread.h"
45 #include "mp3_playback.h"
46 #include "usb.h"
47 #include "status.h"
48 #include "ata.h"
49 #include "screens.h"
50 #include "playlist.h"
51 #include "playback.h"
52 #include "pcmbuf.h"
53 #include "buffer.h"
54 #include "dsp.h"
55 #include "abrepeat.h"
56 #include "cuesheet.h"
57 #ifdef HAVE_TAGCACHE
58 #include "tagcache.h"
59 #endif
60 #ifdef HAVE_LCD_BITMAP
61 #include "icons.h"
62 #include "peakmeter.h"
63 #include "action.h"
64 #include "albumart.h"
65 #endif
66 #include "lang.h"
67 #include "bookmark.h"
68 #include "misc.h"
69 #include "sound.h"
70 #include "metadata.h"
71 #include "splash.h"
72 #include "talk.h"
73 #include "ata_idle_notify.h"
75 #ifdef HAVE_RECORDING
76 #include "recording.h"
77 #include "talk.h"
78 #endif
80 #define PLAYBACK_VOICE
82 /* default point to start buffer refill */
83 #define AUDIO_DEFAULT_WATERMARK (1024*512)
84 /* amount of guess-space to allow for codecs that must hunt and peck
85 * for their correct seeek target, 32k seems a good size */
86 #define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
88 /* Define LOGF_ENABLE to enable logf output in this file */
89 /*#define LOGF_ENABLE*/
90 #include "logf.h"
92 /* macros to enable logf for queues
93 logging on SYS_TIMEOUT can be disabled */
94 #ifdef SIMULATOR
95 /* Define this for logf output of all queuing except SYS_TIMEOUT */
96 #define PLAYBACK_LOGQUEUES
97 /* Define this to logf SYS_TIMEOUT messages */
98 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
99 #endif
101 #ifdef PLAYBACK_LOGQUEUES
102 #define LOGFQUEUE logf
103 #else
104 #define LOGFQUEUE(...)
105 #endif
107 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
108 #define LOGFQUEUE_SYS_TIMEOUT logf
109 #else
110 #define LOGFQUEUE_SYS_TIMEOUT(...)
111 #endif
114 /* Define one constant that includes recording related functionality */
115 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
116 #define AUDIO_HAVE_RECORDING
117 #endif
119 enum {
120 Q_NULL = 0,
121 Q_AUDIO_PLAY = 1,
122 Q_AUDIO_STOP,
123 Q_AUDIO_PAUSE,
124 Q_AUDIO_SKIP,
125 Q_AUDIO_PRE_FF_REWIND,
126 Q_AUDIO_FF_REWIND,
127 Q_AUDIO_CHECK_NEW_TRACK,
128 Q_AUDIO_FLUSH,
129 Q_AUDIO_TRACK_CHANGED,
130 Q_AUDIO_DIR_SKIP,
131 Q_AUDIO_POSTINIT,
132 Q_AUDIO_FILL_BUFFER,
133 Q_CODEC_REQUEST_COMPLETE,
134 Q_CODEC_REQUEST_FAILED,
136 Q_CODEC_LOAD,
137 Q_CODEC_LOAD_DISK,
139 #ifdef AUDIO_HAVE_RECORDING
140 Q_ENCODER_LOAD_DISK,
141 Q_ENCODER_RECORD,
142 #endif
145 /* As defined in plugins/lib/xxx2wav.h */
146 #if MEM > 1
147 #define MALLOC_BUFSIZE (512*1024)
148 #define GUARD_BUFSIZE (32*1024)
149 #else
150 #define MALLOC_BUFSIZE (100*1024)
151 #define GUARD_BUFSIZE (8*1024)
152 #endif
154 /* As defined in plugin.lds */
155 #if defined(CPU_PP)
156 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
157 #define CODEC_IRAM_SIZE ((size_t)0xc000)
158 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
159 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
160 #define CODEC_IRAM_SIZE ((size_t)0x10000)
161 #else
162 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
163 #define CODEC_IRAM_SIZE ((size_t)0xc000)
164 #endif
166 bool audio_is_initialized = false;
167 static bool audio_thread_ready NOCACHEBSS_ATTR = false;
169 /* Variables are commented with the threads that use them: *
170 * A=audio, C=codec, V=voice. A suffix of - indicates that *
171 * the variable is read but not updated on that thread. */
172 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
174 /* Main state control */
175 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR = false; /* Codec loaded? (C/A-) */
176 static volatile bool playing NOCACHEBSS_ATTR = false; /* Is audio playing? (A) */
177 static volatile bool paused NOCACHEBSS_ATTR = false; /* Is audio paused? (A/C-) */
179 /* Ring buffer where compressed audio and codecs are loaded */
180 static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */
181 static unsigned char *malloc_buf = NULL; /* Start of malloc buffer (A/C-) */
182 /* FIXME: make filebuflen static */
183 size_t filebuflen = 0; /* Size of buffer (A/C-) */
184 /* FIXME: make buf_ridx (C/A-) */
186 /* Possible arrangements of the buffer */
187 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
188 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
189 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
190 static int buffer_state = BUFFER_STATE_TRASHED; /* Buffer state */
192 /* Used to keep the WPS up-to-date during track transtition */
193 static struct mp3entry prevtrack_id3;
195 /* Used to provide the codec with a pointer */
196 static struct mp3entry curtrack_id3;
198 /* Used to make next track info available while playing last track on buffer */
199 static struct mp3entry lasttrack_id3;
201 /* Track info structure about songs in the file buffer (A/C-) */
202 struct track_info {
203 int audio_hid; /* The ID for the track's buffer handle */
204 int id3_hid; /* The ID for the track's metadata handle */
205 int codec_hid; /* The ID for the track's codec handle */
206 #ifdef HAVE_ALBUMART
207 int aa_hid; /* The ID for the track's album art handle */
208 #endif
210 size_t filesize; /* File total length */
212 bool taginfo_ready; /* Is metadata read */
214 bool event_sent; /* Was this track's buffered event sent */
217 static struct track_info tracks[MAX_TRACK];
218 static volatile int track_ridx = 0; /* Track being decoded (A/C-) */
219 static int track_widx = 0; /* Track being buffered (A) */
221 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
222 static struct track_info *prev_ti = NULL; /* Pointer to the previously played
223 track */
225 /* Set by buffering_audio_callback when the low buffer event is received, to
226 avoid flodding the audio queue with fill_file_buffer messages. */
227 static bool lowbuffer_event_sent = false;
229 /* Set by the audio thread when the current track information has updated
230 * and the WPS may need to update its cached information */
231 static bool track_changed = false;
233 /* Information used only for filling the buffer */
234 /* Playlist steps from playing track to next track to be buffered (A) */
235 static int last_peek_offset = 0;
237 /* Scrobbler support */
238 static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/
240 /* Track change controls */
241 static bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */
242 static bool playlist_end = false; /* Has the current playlist ended? (A) */
243 static bool auto_dir_skip = false; /* Have we changed dirs automatically? */
244 static bool dir_skip = false; /* Is a directory skip pending? (A) */
245 static bool new_playlist = false; /* Are we starting a new playlist? (A) */
246 static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */
247 static bool skipped_during_pause = false; /* Do we need to clear the PCM buffer when playback resumes (A) */
249 /* Callbacks which applications or plugins may set */
250 /* When the playing track has changed from the user's perspective */
251 void (*track_changed_callback)(struct mp3entry *id3) = NULL;
252 /* When a track has been buffered */
253 void (*track_buffer_callback)(struct mp3entry *id3) = NULL;
254 /* When a track's buffer has been overwritten or cleared */
255 void (*track_unbuffer_callback)(struct mp3entry *id3) = NULL;
257 static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */
259 /* Multiple threads */
260 /* Set the watermark to trigger buffer fill (A/C) FIXME */
261 static void set_filebuf_watermark(int seconds, size_t max);
263 /* Audio thread */
264 static struct event_queue audio_queue NOCACHEBSS_ATTR;
265 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR;
266 static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
267 static const char audio_thread_name[] = "audio";
269 static void audio_thread(void);
270 static void audio_initiate_track_change(long direction);
271 static bool audio_have_tracks(void);
272 static void audio_reset_buffer(void);
274 /* Codec thread */
275 extern struct codec_api ci;
276 static struct event_queue codec_queue NOCACHEBSS_ATTR;
277 static struct queue_sender_list codec_queue_sender_list;
278 static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
279 IBSS_ATTR;
280 static const char codec_thread_name[] = "codec";
281 struct thread_entry *codec_thread_p; /* For modifying thread priority later. */
283 /* --- Helper functions --- */
285 static struct mp3entry *bufgetid3(int handle_id)
287 if (handle_id < 0)
288 return NULL;
290 struct mp3entry *id3;
291 ssize_t ret = bufgetdata(handle_id, 0, (void *)&id3);
293 if (ret < 0 || ret != sizeof(struct mp3entry))
294 return NULL;
296 return id3;
299 static bool clear_track_info(struct track_info *track)
301 /* bufclose returns true if the handle is not found, or if it is closed
302 * successfully, so these checks are safe on non-existant handles */
303 if (!track)
304 return false;
306 if (track->codec_hid >= 0) {
307 if (bufclose(track->codec_hid))
308 track->codec_hid = -1;
309 else
310 return false;
313 if (track->id3_hid >= 0) {
314 if (track->event_sent && track_unbuffer_callback) {
315 /* If there is an unbuffer callback, call it */
316 track_unbuffer_callback(bufgetid3(track->id3_hid));
319 if (bufclose(track->id3_hid))
320 track->id3_hid = -1;
321 else
322 return false;
325 if (track->audio_hid >= 0) {
326 if (bufclose(track->audio_hid))
327 track->audio_hid = -1;
328 else
329 return false;
332 #ifdef HAVE_ALBUMART
333 if (track->aa_hid >= 0) {
334 if (bufclose(track->aa_hid))
335 track->aa_hid = -1;
336 else
337 return false;
339 #endif
341 track->filesize = 0;
342 track->taginfo_ready = false;
343 track->event_sent = false;
345 return true;
348 /* --- External interfaces --- */
350 /* This sends a stop message and the audio thread will dump all it's
351 subsequenct messages */
352 void audio_hard_stop(void)
354 /* Stop playback */
355 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
356 queue_send(&audio_queue, Q_AUDIO_STOP, 1);
357 #ifdef PLAYBACK_VOICE
358 voice_stop();
359 #endif
362 bool audio_restore_playback(int type)
364 switch (type)
366 case AUDIO_WANT_PLAYBACK:
367 if (buffer_state != BUFFER_STATE_INITIALIZED)
368 audio_reset_buffer();
369 return true;
370 case AUDIO_WANT_VOICE:
371 if (buffer_state == BUFFER_STATE_TRASHED)
372 audio_reset_buffer();
373 return true;
374 default:
375 return false;
379 unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
381 unsigned char *buf, *end;
383 if (audio_is_initialized)
385 audio_hard_stop();
387 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
389 if (buffer_size == NULL)
391 /* Special case for talk_init to use since it already knows it's
392 trashed */
393 buffer_state = BUFFER_STATE_TRASHED;
394 return NULL;
397 if (talk_buf || buffer_state == BUFFER_STATE_TRASHED
398 || !talk_voice_required())
400 logf("get buffer: talk, audio");
401 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
402 the talk buffer is not needed because voice isn't being used, or
403 could be BUFFER_STATE_TRASHED already. If state is
404 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
405 without the caller knowing what's going on. Changing certain settings
406 may move it to a worse condition but the memory in use by something
407 else will remain undisturbed.
409 if (buffer_state != BUFFER_STATE_TRASHED)
411 talk_buffer_steal();
412 buffer_state = BUFFER_STATE_TRASHED;
415 buf = audiobuf;
416 end = audiobufend;
418 else
420 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
421 still BUFFER_STATE_INITIALIZED */
422 /* Skip talk buffer and move pcm buffer to end to maximize available
423 contiguous memory - no audio running means voice will not need the
424 swap space */
425 logf("get buffer: audio");
426 buf = audiobuf + talk_get_bufsize();
427 end = audiobufend - pcmbuf_init(audiobufend);
428 buffer_state = BUFFER_STATE_VOICED_ONLY;
431 *buffer_size = end - buf;
433 return buf;
436 #ifdef HAVE_RECORDING
437 unsigned char *audio_get_recording_buffer(size_t *buffer_size)
439 /* Stop audio, voice and obtain all available buffer space */
440 audio_hard_stop();
441 talk_buffer_steal();
443 unsigned char *end = audiobufend;
444 buffer_state = BUFFER_STATE_TRASHED;
445 *buffer_size = end - audiobuf;
447 return (unsigned char *)audiobuf;
450 bool audio_load_encoder(int afmt)
452 #ifndef SIMULATOR
453 const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER);
454 if (!enc_fn)
455 return false;
457 audio_remove_encoder();
458 ci.enc_codec_loaded = 0; /* clear any previous error condition */
460 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
461 queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (intptr_t)enc_fn);
463 while (ci.enc_codec_loaded == 0)
464 yield();
466 logf("codec loaded: %d", ci.enc_codec_loaded);
468 return ci.enc_codec_loaded > 0;
469 #else
470 (void)afmt;
471 return true;
472 #endif
473 } /* audio_load_encoder */
475 void audio_remove_encoder(void)
477 #ifndef SIMULATOR
478 /* force encoder codec unload (if currently loaded) */
479 if (ci.enc_codec_loaded <= 0)
480 return;
482 ci.stop_encoder = true;
483 while (ci.enc_codec_loaded > 0)
484 yield();
485 #endif
486 } /* audio_remove_encoder */
488 #endif /* HAVE_RECORDING */
490 #ifdef HAVE_ALBUMART
491 int audio_current_aa_hid(void)
493 int cur_idx;
494 int offset = ci.new_track + wps_offset;
496 cur_idx = track_ridx + offset;
497 cur_idx &= MAX_TRACK_MASK;
499 return tracks[cur_idx].aa_hid;
501 #endif
503 struct mp3entry* audio_current_track(void)
505 const char *filename;
506 const char *p;
507 static struct mp3entry temp_id3;
508 int cur_idx;
509 int offset = ci.new_track + wps_offset;
511 cur_idx = (track_ridx + offset) & MAX_TRACK_MASK;
513 if (cur_idx == track_ridx && *curtrack_id3.path)
515 /* The usual case */
516 return &curtrack_id3;
518 else if (offset == -1 && *prevtrack_id3.path)
520 /* We're in a track transition. The codec has moved on to the nex track,
521 but the audio being played is still the same (now previous) track.
522 prevtrack_id3.elapsed is being updated in an ISR by
523 codec_pcmbuf_position_callback */
524 return &prevtrack_id3;
526 else if (tracks[cur_idx].id3_hid >= 0)
528 /* Get the ID3 metadata from the main buffer */
529 return bufgetid3(tracks[cur_idx].id3_hid);
532 /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info
533 we have and return that. */
535 memset(&temp_id3, 0, sizeof(struct mp3entry));
537 filename = playlist_peek(0);
538 if (!filename)
539 filename = "No file!";
541 #ifdef HAVE_TC_RAMCACHE
542 if (tagcache_fill_tags(&temp_id3, filename))
543 return &temp_id3;
544 #endif
546 p = strrchr(filename, '/');
547 if (!p)
548 p = filename;
549 else
550 p++;
552 strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1);
553 temp_id3.title = &temp_id3.path[0];
555 return &temp_id3;
558 struct mp3entry* audio_next_track(void)
560 int next_idx;
561 int offset = ci.new_track + wps_offset;
563 if (!audio_have_tracks())
564 return NULL;
566 if (wps_offset == -1 && *prevtrack_id3.path)
568 /* We're in a track transition. The next track for the WPS is the one
569 currently being decoded. */
570 return &curtrack_id3;
573 next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK;
575 if (next_idx == track_widx)
577 /* The next track hasn't been buffered yet, so we return the static
578 version of its metadata. */
579 return &lasttrack_id3;
582 if (tracks[next_idx].id3_hid < 0)
583 return NULL;
584 else
585 return bufgetid3(tracks[next_idx].id3_hid);
588 bool audio_has_changed_track(void)
590 if (track_changed)
592 track_changed = false;
593 return true;
596 return false;
599 void audio_play(long offset)
601 logf("audio_play");
603 #ifdef PLAYBACK_VOICE
604 /* Truncate any existing voice output so we don't have spelling
605 * etc. over the first part of the played track */
606 talk_force_shutup();
607 #endif
609 /* Start playback */
610 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset);
611 /* Don't return until playback has actually started */
612 queue_send(&audio_queue, Q_AUDIO_PLAY, offset);
615 void audio_stop(void)
617 /* Stop playback */
618 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
619 /* Don't return until playback has actually stopped */
620 queue_send(&audio_queue, Q_AUDIO_STOP, 0);
623 void audio_pause(void)
625 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
626 /* Don't return until playback has actually paused */
627 queue_send(&audio_queue, Q_AUDIO_PAUSE, true);
630 void audio_resume(void)
632 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
633 /* Don't return until playback has actually resumed */
634 queue_send(&audio_queue, Q_AUDIO_PAUSE, false);
637 static void audio_skip(int direction)
639 if (playlist_check(ci.new_track + wps_offset + direction))
641 if (global_settings.beep)
642 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
644 LOGFQUEUE("audio > audio Q_AUDIO_SKIP %d", direction);
645 queue_post(&audio_queue, Q_AUDIO_SKIP, direction);
646 /* Update wps while our message travels inside deep playback queues. */
647 wps_offset += direction;
648 /* Immediately update the playlist index */
649 playlist_next(direction);
650 last_peek_offset -= direction;
651 track_changed = true;
653 else
655 /* No more tracks. */
656 if (global_settings.beep)
657 pcmbuf_beep(1000, 100, 1000*global_settings.beep);
661 void audio_next(void)
663 audio_skip(1);
666 void audio_prev(void)
668 audio_skip(-1);
671 void audio_next_dir(void)
673 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
674 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, 1);
677 void audio_prev_dir(void)
679 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
680 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, -1);
683 void audio_pre_ff_rewind(void)
685 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
686 queue_post(&audio_queue, Q_AUDIO_PRE_FF_REWIND, 0);
689 void audio_ff_rewind(long newpos)
691 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
692 queue_post(&audio_queue, Q_AUDIO_FF_REWIND, newpos);
695 void audio_flush_and_reload_tracks(void)
697 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
698 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0);
701 void audio_error_clear(void)
703 #ifdef AUDIO_HAVE_RECORDING
704 pcm_rec_error_clear();
705 #endif
708 int audio_status(void)
710 int ret = 0;
712 if (playing)
713 ret |= AUDIO_STATUS_PLAY;
715 if (paused)
716 ret |= AUDIO_STATUS_PAUSE;
718 #ifdef HAVE_RECORDING
719 /* Do this here for constitency with mpeg.c version */
720 ret |= pcm_rec_status();
721 #endif
723 return ret;
726 int audio_get_file_pos(void)
728 return 0;
731 #ifndef HAVE_FLASH_STORAGE
732 void audio_set_buffer_margin(int setting)
734 static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
735 buffer_margin = lookup[setting];
736 logf("buffer margin: %ld", (long)buffer_margin);
737 set_filebuf_watermark(buffer_margin, 0);
739 #endif
741 /* Take nescessary steps to enable or disable the crossfade setting */
742 void audio_set_crossfade(int enable)
744 size_t offset;
745 bool was_playing;
746 size_t size;
748 /* Tell it the next setting to use */
749 pcmbuf_crossfade_enable(enable);
751 /* Return if size hasn't changed or this is too early to determine
752 which in the second case there's no way we could be playing
753 anything at all */
754 if (pcmbuf_is_same_size())
756 /* This function is a copout and just syncs some variables -
757 to be removed at a later date */
758 pcmbuf_crossfade_enable_finished();
759 return;
762 offset = 0;
763 was_playing = playing;
765 /* Playback has to be stopped before changing the buffer size */
766 if (was_playing)
768 /* Store the track resume position */
769 offset = curtrack_id3.offset;
770 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK));
773 /* Blast it - audio buffer will have to be setup again next time
774 something plays */
775 audio_get_buffer(true, &size);
777 /* Restart playback if audio was running previously */
778 if (was_playing)
779 audio_play(offset);
782 /* --- Routines called from multiple threads --- */
784 static void set_filebuf_watermark(int seconds, size_t max)
786 size_t bytes;
788 if (!filebuf)
789 return; /* Audio buffers not yet set up */
791 bytes = seconds?MAX(curtrack_id3.bitrate * seconds * (1000/8), max):max;
792 bytes = MIN(bytes, filebuflen / 2);
793 buf_set_watermark(bytes);
796 const char * get_codec_filename(int cod_spec)
798 const char *fname;
800 #ifdef HAVE_RECORDING
801 /* Can choose decoder or encoder if one available */
802 int type = cod_spec & CODEC_TYPE_MASK;
803 int afmt = cod_spec & CODEC_AFMT_MASK;
805 if ((unsigned)afmt >= AFMT_NUM_CODECS)
806 type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
808 fname = (type == CODEC_TYPE_ENCODER) ?
809 audio_formats[afmt].codec_enc_root_fn :
810 audio_formats[afmt].codec_root_fn;
812 logf("%s: %d - %s",
813 (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
814 afmt, fname ? fname : "<unknown>");
815 #else /* !HAVE_RECORDING */
816 /* Always decoder */
817 if ((unsigned)cod_spec >= AFMT_NUM_CODECS)
818 cod_spec = AFMT_UNKNOWN;
819 fname = audio_formats[cod_spec].codec_root_fn;
820 logf("Codec: %d - %s", cod_spec, fname ? fname : "<unknown>");
821 #endif /* HAVE_RECORDING */
823 return fname;
824 } /* get_codec_filename */
826 /* --- Codec thread --- */
827 static bool codec_pcmbuf_insert_callback(
828 const void *ch1, const void *ch2, int count)
830 const char *src[2] = { ch1, ch2 };
832 while (count > 0)
834 int out_count = dsp_output_count(ci.dsp, count);
835 int inp_count;
836 char *dest;
838 /* Prevent audio from a previous track from playing */
839 if (ci.new_track || ci.stop_codec)
840 return true;
842 while ((dest = pcmbuf_request_buffer(&out_count)) == NULL)
844 cancel_cpu_boost();
845 sleep(1);
846 if (ci.seek_time || ci.new_track || ci.stop_codec)
847 return true;
850 /* Get the real input_size for output_size bytes, guarding
851 * against resampling buffer overflows. */
852 inp_count = dsp_input_count(ci.dsp, out_count);
854 if (inp_count <= 0)
855 return true;
857 /* Input size has grown, no error, just don't write more than length */
858 if (inp_count > count)
859 inp_count = count;
861 out_count = dsp_process(ci.dsp, dest, src, inp_count);
863 if (out_count <= 0)
864 return true;
866 pcmbuf_write_complete(out_count);
868 count -= inp_count;
871 return true;
872 } /* codec_pcmbuf_insert_callback */
874 static void* codec_get_memory_callback(size_t *size)
876 *size = MALLOC_BUFSIZE;
877 return malloc_buf;
880 /* Between the codec and PCM track change, we need to keep updating the
881 "elapsed" value of the previous (to the codec, but current to the
882 user/PCM/WPS) track, so that the progressbar reaches the end.
883 During that transition, the WPS will display prevtrack_id3. */
884 static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
885 static void codec_pcmbuf_position_callback(size_t size)
887 /* This is called from an ISR, so be quick */
888 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
889 prevtrack_id3.elapsed;
891 if (time >= prevtrack_id3.length)
893 pcmbuf_set_position_callback(NULL);
894 prevtrack_id3.elapsed = prevtrack_id3.length;
896 else
897 prevtrack_id3.elapsed = time;
900 static void codec_set_elapsed_callback(unsigned int value)
902 unsigned int latency;
903 if (ci.seek_time)
904 return;
906 #ifdef AB_REPEAT_ENABLE
907 ab_position_report(value);
908 #endif
910 latency = pcmbuf_get_latency();
911 if (value < latency)
912 curtrack_id3.elapsed = 0;
913 else if (value - latency > curtrack_id3.elapsed ||
914 value - latency < curtrack_id3.elapsed - 2)
916 curtrack_id3.elapsed = value - latency;
920 static void codec_set_offset_callback(size_t value)
922 unsigned int latency;
924 if (ci.seek_time)
925 return;
927 latency = pcmbuf_get_latency() * curtrack_id3.bitrate / 8;
928 if (value < latency)
929 curtrack_id3.offset = 0;
930 else
931 curtrack_id3.offset = value - latency;
934 static void codec_advance_buffer_counters(size_t amount)
936 bufadvance(CUR_TI->audio_hid, amount);
937 ci.curpos += amount;
940 /* copy up-to size bytes into ptr and return the actual size copied */
941 static size_t codec_filebuf_callback(void *ptr, size_t size)
943 ssize_t copy_n;
945 if (ci.stop_codec || !playing)
946 return 0;
948 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
950 /* Nothing requested OR nothing left */
951 if (copy_n == 0)
952 return 0;
954 /* Update read and other position pointers */
955 codec_advance_buffer_counters(copy_n);
957 /* Return the actual amount of data copied to the buffer */
958 return copy_n;
959 } /* codec_filebuf_callback */
961 static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
963 size_t copy_n = reqsize;
964 ssize_t ret;
965 void *ptr;
967 if (!playing)
969 *realsize = 0;
970 return NULL;
973 ret = bufgetdata(CUR_TI->audio_hid, reqsize, &ptr);
974 if (ret >= 0)
975 copy_n = MIN((size_t)ret, reqsize);
977 if (copy_n == 0)
979 *realsize = 0;
980 return NULL;
983 *realsize = copy_n;
985 return ptr;
986 } /* codec_request_buffer_callback */
988 static int get_codec_base_type(int type)
990 switch (type) {
991 case AFMT_MPA_L1:
992 case AFMT_MPA_L2:
993 case AFMT_MPA_L3:
994 return AFMT_MPA_L3;
997 return type;
1000 static void codec_advance_buffer_callback(size_t amount)
1002 codec_advance_buffer_counters(amount);
1003 codec_set_offset_callback(ci.curpos);
1006 static void codec_advance_buffer_loc_callback(void *ptr)
1008 size_t amount = buf_get_offset(CUR_TI->audio_hid, ptr);
1009 codec_advance_buffer_callback(amount);
1012 /* Copied from mpeg.c. Should be moved somewhere else. */
1013 static int codec_get_file_pos(void)
1015 int pos = -1;
1016 struct mp3entry *id3 = audio_current_track();
1018 if (id3->vbr)
1020 if (id3->has_toc)
1022 /* Use the TOC to find the new position */
1023 unsigned int percent, remainder;
1024 int curtoc, nexttoc, plen;
1026 percent = (id3->elapsed*100)/id3->length;
1027 if (percent > 99)
1028 percent = 99;
1030 curtoc = id3->toc[percent];
1032 if (percent < 99)
1033 nexttoc = id3->toc[percent+1];
1034 else
1035 nexttoc = 256;
1037 pos = (id3->filesize/256)*curtoc;
1039 /* Use the remainder to get a more accurate position */
1040 remainder = (id3->elapsed*100)%id3->length;
1041 remainder = (remainder*100)/id3->length;
1042 plen = (nexttoc - curtoc)*(id3->filesize/256);
1043 pos += (plen/100)*remainder;
1045 else
1047 /* No TOC exists, estimate the new position */
1048 pos = (id3->filesize / (id3->length / 1000)) *
1049 (id3->elapsed / 1000);
1052 else if (id3->bitrate)
1053 pos = id3->elapsed * (id3->bitrate / 8);
1054 else
1055 return -1;
1057 pos += id3->first_frame_offset;
1059 /* Don't seek right to the end of the file so that we can
1060 transition properly to the next song */
1061 if (pos >= (int)(id3->filesize - id3->id3v1len))
1062 pos = id3->filesize - id3->id3v1len - 1;
1064 return pos;
1067 static off_t codec_mp3_get_filepos_callback(int newtime)
1069 off_t newpos;
1071 curtrack_id3.elapsed = newtime;
1072 newpos = codec_get_file_pos();
1074 return newpos;
1077 static void codec_seek_complete_callback(void)
1079 logf("seek_complete");
1080 if (pcm_is_paused())
1082 /* If this is not a seamless seek, clear the buffer */
1083 pcmbuf_play_stop();
1084 dsp_configure(ci.dsp, DSP_FLUSH, 0);
1086 /* If playback was not 'deliberately' paused, unpause now */
1087 if (!paused)
1088 pcmbuf_pause(false);
1090 ci.seek_time = 0;
1093 static bool codec_seek_buffer_callback(size_t newpos)
1095 logf("codec_seek_buffer_callback");
1097 int ret = bufseek(CUR_TI->audio_hid, newpos);
1098 if (ret == 0) {
1099 ci.curpos = newpos;
1100 return true;
1102 else {
1103 return false;
1107 static void codec_configure_callback(int setting, intptr_t value)
1109 switch (setting) {
1110 case CODEC_SET_FILEBUF_WATERMARK:
1111 set_filebuf_watermark(buffer_margin, value);
1112 break;
1114 default:
1115 if (!dsp_configure(ci.dsp, setting, value))
1116 { logf("Illegal key:%d", setting); }
1120 static void codec_track_changed(void)
1122 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1123 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1126 static void codec_pcmbuf_track_changed_callback(void)
1128 pcmbuf_set_position_callback(NULL);
1129 codec_track_changed();
1132 static void codec_discard_codec_callback(void)
1134 if (CUR_TI->codec_hid >= 0)
1136 bufclose(CUR_TI->codec_hid);
1137 CUR_TI->codec_hid = -1;
1141 static inline void codec_gapless_track_change(void)
1143 /* callback keeps the progress bar moving while the pcmbuf empties */
1144 pcmbuf_set_position_callback(codec_pcmbuf_position_callback);
1145 /* set the pcmbuf callback for when the track really changes */
1146 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
1149 static inline void codec_crossfade_track_change(void)
1151 /* Initiate automatic crossfade mode */
1152 pcmbuf_crossfade_init(false);
1153 /* Notify the wps that the track change starts now */
1154 codec_track_changed();
1157 static void codec_track_skip_done(bool was_manual)
1159 /* Manual track change (always crossfade or flush audio). */
1160 if (was_manual)
1162 pcmbuf_crossfade_init(true);
1163 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1164 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1166 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1167 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1168 && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP)
1170 if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
1172 if (global_settings.playlist_shuffle)
1173 /* shuffle mode is on, so crossfade: */
1174 codec_crossfade_track_change();
1175 else
1176 /* shuffle mode is off, so do a gapless track change */
1177 codec_gapless_track_change();
1179 else
1180 /* normal crossfade: */
1181 codec_crossfade_track_change();
1183 else
1184 /* normal gapless playback. */
1185 codec_gapless_track_change();
1188 static bool codec_load_next_track(void)
1190 intptr_t result = Q_CODEC_REQUEST_FAILED;
1192 prev_track_elapsed = curtrack_id3.elapsed;
1194 #ifdef AB_REPEAT_ENABLE
1195 ab_end_of_track_report();
1196 #endif
1198 logf("Request new track");
1200 if (ci.new_track == 0)
1202 ci.new_track++;
1203 automatic_skip = true;
1206 if (!ci.stop_codec)
1208 trigger_cpu_boost();
1209 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1210 result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
1213 switch (result)
1215 case Q_CODEC_REQUEST_COMPLETE:
1216 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1217 codec_track_skip_done(!automatic_skip);
1218 return true;
1220 case Q_CODEC_REQUEST_FAILED:
1221 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1222 ci.new_track = 0;
1223 ci.stop_codec = true;
1224 return false;
1226 default:
1227 LOGFQUEUE("codec |< default");
1228 ci.stop_codec = true;
1229 return false;
1233 static bool codec_request_next_track_callback(void)
1235 int prev_codectype;
1237 if (ci.stop_codec || !playing)
1238 return false;
1240 prev_codectype = get_codec_base_type(curtrack_id3.codectype);
1242 if (!codec_load_next_track())
1243 return false;
1245 /* Check if the next codec is the same file. */
1246 if (prev_codectype == get_codec_base_type(curtrack_id3.codectype))
1248 logf("New track loaded");
1249 codec_discard_codec_callback();
1250 return true;
1252 else
1254 logf("New codec:%d/%d", curtrack_id3.codectype, prev_codectype);
1255 return false;
1259 static void codec_thread(void)
1261 struct queue_event ev;
1262 int status;
1264 while (1) {
1265 status = 0;
1266 cancel_cpu_boost();
1267 queue_wait(&codec_queue, &ev);
1269 switch (ev.id) {
1270 case Q_CODEC_LOAD_DISK:
1271 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1272 queue_reply(&codec_queue, 1);
1273 audio_codec_loaded = true;
1274 ci.stop_codec = false;
1275 status = codec_load_file((const char *)ev.data, &ci);
1276 break;
1278 case Q_CODEC_LOAD:
1279 LOGFQUEUE("codec < Q_CODEC_LOAD");
1280 if (CUR_TI->codec_hid < 0) {
1281 logf("Codec slot is empty!");
1282 /* Wait for the pcm buffer to go empty */
1283 while (pcm_is_playing())
1284 yield();
1285 /* This must be set to prevent an infinite loop */
1286 ci.stop_codec = true;
1287 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1288 queue_post(&codec_queue, Q_AUDIO_PLAY, 0);
1289 break;
1292 audio_codec_loaded = true;
1293 ci.stop_codec = false;
1294 status = codec_load_buf(CUR_TI->codec_hid, &ci);
1295 break;
1297 #ifdef AUDIO_HAVE_RECORDING
1298 case Q_ENCODER_LOAD_DISK:
1299 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1300 audio_codec_loaded = false; /* Not audio codec! */
1301 logf("loading encoder");
1302 ci.stop_encoder = false;
1303 status = codec_load_file((const char *)ev.data, &ci);
1304 logf("encoder stopped");
1305 break;
1306 #endif /* AUDIO_HAVE_RECORDING */
1308 default:
1309 LOGFQUEUE("codec < default");
1312 if (audio_codec_loaded)
1314 if (ci.stop_codec)
1316 status = CODEC_OK;
1317 if (!playing)
1318 pcmbuf_play_stop();
1321 audio_codec_loaded = false;
1324 switch (ev.id) {
1325 case Q_CODEC_LOAD_DISK:
1326 case Q_CODEC_LOAD:
1327 LOGFQUEUE("codec < Q_CODEC_LOAD");
1328 if (playing)
1330 if (ci.new_track || status != CODEC_OK)
1332 if (!ci.new_track)
1334 logf("Codec failure");
1335 gui_syncsplash(HZ*2, "Codec failure");
1338 if (!codec_load_next_track())
1340 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1341 /* End of playlist */
1342 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1343 break;
1346 else
1348 logf("Codec finished");
1349 if (ci.stop_codec)
1351 /* Wait for the audio to stop playing before
1352 * triggering the WPS exit */
1353 while(pcm_is_playing())
1355 curtrack_id3.elapsed =
1356 curtrack_id3.length - pcmbuf_get_latency();
1357 sleep(1);
1359 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1360 /* End of playlist */
1361 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1362 break;
1366 if (CUR_TI->codec_hid >= 0)
1368 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1369 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
1371 else
1373 const char *codec_fn =
1374 get_codec_filename(curtrack_id3.codectype);
1375 if (codec_fn)
1377 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1378 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
1379 (intptr_t)codec_fn);
1383 break;
1385 #ifdef AUDIO_HAVE_RECORDING
1386 case Q_ENCODER_LOAD_DISK:
1387 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1389 if (status == CODEC_OK)
1390 break;
1392 logf("Encoder failure");
1393 gui_syncsplash(HZ*2, "Encoder failure");
1395 if (ci.enc_codec_loaded < 0)
1396 break;
1398 logf("Encoder failed to load");
1399 ci.enc_codec_loaded = -1;
1400 break;
1401 #endif /* AUDIO_HAVE_RECORDING */
1403 default:
1404 LOGFQUEUE("codec < default");
1406 } /* end switch */
1411 /* --- Audio thread --- */
1413 static bool audio_have_tracks(void)
1415 return (audio_track_count() != 0);
1418 static int audio_free_track_count(void)
1420 /* Used tracks + free tracks adds up to MAX_TRACK - 1 */
1421 return MAX_TRACK - 1 - audio_track_count();
1424 int audio_track_count(void)
1426 /* Calculate difference from track_ridx to track_widx
1427 * taking into account a possible wrap-around. */
1428 return (MAX_TRACK + track_widx - track_ridx) & MAX_TRACK_MASK;
1431 long audio_filebufused(void)
1433 return (long) buf_used();
1436 /* Update track info after successful a codec track change */
1437 static void audio_update_trackinfo(void)
1439 /* Load the curent track's metadata into curtrack_id3 */
1440 CUR_TI->taginfo_ready = (CUR_TI->id3_hid >= 0);
1441 if (CUR_TI->id3_hid >= 0)
1442 copy_mp3entry(&curtrack_id3, bufgetid3(CUR_TI->id3_hid));
1444 int next_idx = (track_ridx + 1) & MAX_TRACK_MASK;
1445 tracks[next_idx].taginfo_ready = (tracks[next_idx].id3_hid >= 0);
1447 /* Reset current position */
1448 curtrack_id3.elapsed = 0;
1449 curtrack_id3.offset = 0;
1451 /* Update the codec API */
1452 ci.filesize = CUR_TI->filesize;
1453 ci.id3 = &curtrack_id3;
1454 ci.curpos = 0;
1455 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1458 static void buffering_audio_callback(enum callback_event ev, int value)
1460 (void)value;
1461 logf("buffering_audio_callback");
1463 switch (ev)
1465 case EVENT_BUFFER_LOW:
1466 if (!lowbuffer_event_sent) {
1467 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1468 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1469 lowbuffer_event_sent = true;
1471 break;
1473 case EVENT_HANDLE_REBUFFER:
1474 LOGFQUEUE("audio >| audio Q_AUDIO_FLUSH");
1475 queue_send(&audio_queue, Q_AUDIO_FLUSH, 0);
1476 break;
1478 case EVENT_HANDLE_FINISHED:
1479 logf("handle %d finished buffering", value);
1480 strip_tags(value);
1481 break;
1483 default:
1484 break;
1488 /* Clear tracks between write and read, non inclusive */
1489 static void audio_clear_track_entries(bool clear_unbuffered)
1491 int cur_idx = track_widx;
1493 logf("Clearing tracks:%d/%d, %d", track_ridx, track_widx, clear_unbuffered);
1495 /* Loop over all tracks from write-to-read */
1496 while (1)
1498 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
1500 if (cur_idx == track_ridx)
1501 break;
1503 /* If the track is buffered, conditionally clear/notify,
1504 * otherwise clear the track if that option is selected */
1505 if (tracks[cur_idx].event_sent || clear_unbuffered)
1506 clear_track_info(&tracks[cur_idx]);
1510 /* Clear all tracks */
1511 static bool audio_release_tracks(void)
1513 int i, cur_idx;
1515 logf("releasing all tracks");
1517 for(i = 0; i < MAX_TRACK; i++)
1519 cur_idx = (track_ridx + i) & MAX_TRACK_MASK;
1520 if (!clear_track_info(&tracks[cur_idx]))
1521 return false;
1524 return true;
1527 static bool audio_loadcodec(bool start_play)
1529 int prev_track;
1530 char codec_path[MAX_PATH]; /* Full path to codec */
1532 if (tracks[track_widx].id3_hid < 0) {
1533 return false;
1536 const char * codec_fn =
1537 get_codec_filename(bufgetid3(tracks[track_widx].id3_hid)->codectype);
1538 if (codec_fn == NULL)
1539 return false;
1541 tracks[track_widx].codec_hid = -1;
1543 if (start_play)
1545 /* Load the codec directly from disk and save some memory. */
1546 track_ridx = track_widx;
1547 ci.filesize = CUR_TI->filesize;
1548 ci.id3 = &curtrack_id3;
1549 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1550 ci.curpos = 0;
1551 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1552 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (intptr_t)codec_fn);
1553 return true;
1555 else
1557 /* If we already have another track than this one buffered */
1558 if (track_widx != track_ridx)
1560 prev_track = (track_widx - 1) & MAX_TRACK_MASK;
1562 /* If the previous codec is the same as this one, there is no need
1563 * to put another copy of it on the file buffer */
1564 if (get_codec_base_type(
1565 bufgetid3(tracks[track_widx].id3_hid)->codectype) ==
1566 get_codec_base_type(
1567 bufgetid3(tracks[prev_track].id3_hid)->codectype)
1568 && audio_codec_loaded)
1570 logf("Reusing prev. codec");
1571 return true;
1576 codec_get_full_path(codec_path, codec_fn);
1578 tracks[track_widx].codec_hid = bufopen(codec_path, 0, TYPE_CODEC);
1579 if (tracks[track_widx].codec_hid < 0)
1580 return false;
1582 logf("Loaded codec");
1584 return true;
1587 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
1588 static void audio_set_elapsed(struct mp3entry* id3)
1590 unsigned long offset = id3->offset > id3->first_frame_offset ?
1591 id3->offset - id3->first_frame_offset : 0;
1593 if ( id3->vbr ) {
1594 if ( id3->has_toc ) {
1595 /* calculate elapsed time using TOC */
1596 int i;
1597 unsigned int remainder, plen, relpos, nextpos;
1599 /* find wich percent we're at */
1600 for (i=0; i<100; i++ )
1601 if ( offset < id3->toc[i] * (id3->filesize / 256) )
1602 break;
1604 i--;
1605 if (i < 0)
1606 i = 0;
1608 relpos = id3->toc[i];
1610 if (i < 99)
1611 nextpos = id3->toc[i+1];
1612 else
1613 nextpos = 256;
1615 remainder = offset - (relpos * (id3->filesize / 256));
1617 /* set time for this percent (divide before multiply to prevent
1618 overflow on long files. loss of precision is negligible on
1619 short files) */
1620 id3->elapsed = i * (id3->length / 100);
1622 /* calculate remainder time */
1623 plen = (nextpos - relpos) * (id3->filesize / 256);
1624 id3->elapsed += (((remainder * 100) / plen) *
1625 (id3->length / 10000));
1627 else {
1628 /* no TOC exists. set a rough estimate using average bitrate */
1629 int tpk = id3->length /
1630 ((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
1631 1024);
1632 id3->elapsed = offset / 1024 * tpk;
1635 else
1637 /* constant bitrate, use exact calculation */
1638 if (id3->bitrate != 0)
1639 id3->elapsed = offset / (id3->bitrate / 8);
1643 /* Load one track by making the appropriate bufopen calls. Return true if
1644 everything required was loaded correctly, false if not. */
1645 static bool audio_load_track(int offset, bool start_play)
1647 char *trackname;
1648 char msgbuf[80];
1649 int fd = -1;
1650 int file_offset = 0;
1651 struct mp3entry id3;
1653 /* Stop buffer filling if there is no free track entries.
1654 Don't fill up the last track entry (we wan't to store next track
1655 metadata there). */
1656 if (!audio_free_track_count())
1658 logf("No free tracks");
1659 return false;
1662 last_peek_offset++;
1663 tracks[track_widx].taginfo_ready = false;
1665 peek_again:
1666 logf("Buffering track:%d/%d", track_widx, track_ridx);
1667 /* Get track name from current playlist read position. */
1668 while ((trackname = playlist_peek(last_peek_offset)) != NULL)
1670 /* Handle broken playlists. */
1671 fd = open(trackname, O_RDONLY);
1672 if (fd < 0)
1674 logf("Open failed");
1675 /* Skip invalid entry from playlist. */
1676 playlist_skip_entry(NULL, last_peek_offset);
1678 else
1679 break;
1682 if (!trackname)
1684 logf("End-of-playlist");
1685 playlist_end = true;
1686 memset(&lasttrack_id3, 0, sizeof(struct mp3entry));
1687 return false;
1690 tracks[track_widx].filesize = filesize(fd);
1692 if ((unsigned)offset > tracks[track_widx].filesize)
1693 offset = 0;
1695 /* Set default values */
1696 if (start_play)
1698 buf_set_watermark(AUDIO_DEFAULT_WATERMARK);
1699 dsp_configure(ci.dsp, DSP_RESET, 0);
1700 track_changed = true;
1701 playlist_update_resume_info(audio_current_track());
1704 /* Get track metadata if we don't already have it. */
1705 if (tracks[track_widx].id3_hid < 0)
1707 if (get_metadata(&id3, fd, trackname))
1709 if (track_buffer_callback)
1710 track_buffer_callback(&id3);
1712 tracks[track_widx].id3_hid =
1713 bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3);
1715 if (tracks[track_widx].id3_hid < 0)
1717 last_peek_offset--;
1718 close(fd);
1719 copy_mp3entry(&lasttrack_id3, &id3);
1720 return false;
1723 if (track_widx == track_ridx)
1724 copy_mp3entry(&curtrack_id3, &id3);
1726 if (start_play)
1728 track_changed = true;
1729 playlist_update_resume_info(audio_current_track());
1732 else
1734 logf("mde:%s!",trackname);
1736 /* Skip invalid entry from playlist. */
1737 playlist_skip_entry(NULL, last_peek_offset);
1738 close(fd);
1739 goto peek_again;
1744 close(fd);
1746 #if 0
1747 if (cuesheet_is_enabled() && tracks[track_widx].id3.cuesheet_type == 1)
1749 char cuepath[MAX_PATH];
1751 struct cuesheet *cue = start_play ? curr_cue : temp_cue;
1753 if (look_for_cuesheet_file(trackname, cuepath) &&
1754 parse_cuesheet(cuepath, cue))
1756 strcpy((cue)->audio_filename, trackname);
1757 if (start_play)
1758 cue_spoof_id3(curr_cue, &tracks[track_widx].id3);
1761 #endif
1763 struct mp3entry *track_id3;
1765 if (track_widx == track_ridx)
1766 track_id3 = &curtrack_id3;
1767 else
1768 track_id3 = bufgetid3(tracks[track_widx].id3_hid);
1770 #ifdef HAVE_ALBUMART
1771 if (tracks[track_widx].aa_hid < 0 && gui_sync_wps_uses_albumart())
1773 char aa_path[MAX_PATH];
1774 if (find_albumart(track_id3, aa_path, sizeof(aa_path)))
1775 tracks[track_widx].aa_hid = bufopen(aa_path, 0, TYPE_BITMAP);
1777 #endif
1779 /* Load the codec. */
1780 if (!audio_loadcodec(start_play))
1782 if (tracks[track_widx].codec_hid == ERR_BUFFER_FULL)
1784 /* No space for codec on buffer, not an error */
1785 return false;
1788 /* This is an error condition, either no codec was found, or reading
1789 * the codec file failed part way through, either way, skip the track */
1790 snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname);
1791 /* We should not use gui_syncplash from audio thread! */
1792 gui_syncsplash(HZ*2, msgbuf);
1793 /* Skip invalid entry from playlist. */
1794 playlist_skip_entry(NULL, last_peek_offset);
1795 goto peek_again;
1798 track_id3->elapsed = 0;
1800 enum data_type type = TYPE_PACKET_AUDIO;
1802 switch (track_id3->codectype) {
1803 case AFMT_MPA_L1:
1804 case AFMT_MPA_L2:
1805 case AFMT_MPA_L3:
1806 if (offset > 0) {
1807 file_offset = offset;
1808 track_id3->offset = offset;
1809 audio_set_elapsed(track_id3);
1811 break;
1813 case AFMT_WAVPACK:
1814 if (offset > 0) {
1815 file_offset = offset;
1816 track_id3->offset = offset;
1817 track_id3->elapsed = track_id3->length / 2;
1819 break;
1821 case AFMT_OGG_VORBIS:
1822 case AFMT_SPEEX:
1823 case AFMT_FLAC:
1824 case AFMT_PCM_WAV:
1825 case AFMT_A52:
1826 case AFMT_AAC:
1827 case AFMT_MPC:
1828 case AFMT_APE:
1829 if (offset > 0)
1830 track_id3->offset = offset;
1831 break;
1833 case AFMT_NSF:
1834 case AFMT_SPC:
1835 case AFMT_SID:
1836 logf("Loading atomic %d",track_id3->codectype);
1837 type = TYPE_ATOMIC_AUDIO;
1838 break;
1841 logf("alt:%s", trackname);
1843 if (file_offset > AUDIO_REBUFFER_GUESS_SIZE)
1844 file_offset -= AUDIO_REBUFFER_GUESS_SIZE;
1845 else if (track_id3->first_frame_offset)
1846 file_offset = track_id3->first_frame_offset;
1847 else
1848 file_offset = 0;
1850 tracks[track_widx].audio_hid = bufopen(trackname, file_offset, type);
1852 if (tracks[track_widx].audio_hid < 0)
1853 return false;
1855 /* All required data is now available for the codec. */
1856 tracks[track_widx].taginfo_ready = true;
1858 if (start_play)
1860 ci.curpos=file_offset;
1861 buf_request_buffer_handle(tracks[track_widx].audio_hid);
1864 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
1866 return true;
1869 /* Send callback events to notify about new tracks. */
1870 static void audio_generate_postbuffer_events(void)
1872 int cur_idx;
1874 logf("Postbuffer:%d/%d",track_ridx,track_widx);
1876 if (audio_have_tracks())
1878 cur_idx = track_ridx;
1880 while (1) {
1881 if (!tracks[cur_idx].event_sent)
1883 /* Mark the event 'sent' even if we don't really send one */
1884 tracks[cur_idx].event_sent = true;
1886 if (cur_idx == track_widx)
1887 break;
1888 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
1893 static void audio_fill_file_buffer(bool start_play, size_t offset)
1895 struct queue_event ev;
1896 bool had_next_track = audio_next_track() != NULL;
1897 bool continue_buffering;
1899 /* No need to rebuffer if there are track skips pending. */
1900 if (ci.new_track != 0)
1901 return;
1903 /* Must reset the buffer before use if trashed or voice only - voice
1904 file size shouldn't have changed so we can go straight from
1905 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
1906 if (buffer_state != BUFFER_STATE_INITIALIZED)
1907 audio_reset_buffer();
1909 logf("Starting buffer fill");
1911 if (!start_play)
1912 audio_clear_track_entries(false);
1914 /* Save the current resume position once. */
1915 playlist_update_resume_info(audio_current_track());
1917 do {
1918 continue_buffering = audio_load_track(offset, start_play);
1919 start_play = false;
1920 offset = 0;
1921 sleep(1);
1922 if (queue_peek(&audio_queue, &ev)) {
1923 if (ev.id != Q_AUDIO_FILL_BUFFER)
1925 /* There's a message in the queue. break the loop to treat it,
1926 and go back to filling after that. */
1927 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1928 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1930 break;
1932 } while (continue_buffering);
1934 if (!had_next_track && audio_next_track())
1935 track_changed = true;
1937 audio_generate_postbuffer_events();
1938 lowbuffer_event_sent = false;
1941 static void audio_rebuffer(void)
1943 logf("Forcing rebuffer");
1945 clear_track_info(CUR_TI);
1947 /* Reset track pointers */
1948 track_widx = track_ridx;
1949 audio_clear_track_entries(true);
1951 /* Fill the buffer */
1952 last_peek_offset = -1;
1953 ci.curpos = 0;
1955 if (!CUR_TI->taginfo_ready)
1956 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
1958 audio_fill_file_buffer(false, 0);
1961 /* Called on request from the codec to get a new track. This is the codec part
1962 of the track transition. */
1963 static int audio_check_new_track(void)
1965 int track_count = audio_track_count();
1966 int old_track_ridx = track_ridx;
1967 int i, idx;
1968 int next_playlist_index;
1969 bool forward;
1970 bool end_of_playlist; /* Temporary flag, not the same as playlist_end */
1972 if (dir_skip)
1974 dir_skip = false;
1975 if (playlist_next_dir(ci.new_track))
1977 ci.new_track = 0;
1978 audio_rebuffer();
1979 goto skip_done;
1981 else
1983 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1984 return Q_CODEC_REQUEST_FAILED;
1988 if (new_playlist)
1989 ci.new_track = 0;
1991 end_of_playlist = playlist_peek(ci.new_track) == NULL;
1992 auto_dir_skip = end_of_playlist && global_settings.next_folder;
1994 /* If the playlist isn't that big */
1995 if (automatic_skip && !playlist_check(ci.new_track))
1997 if (ci.new_track >= 0)
1999 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2000 return Q_CODEC_REQUEST_FAILED;
2002 /* Find the beginning backward if the user over-skips it */
2003 while (!playlist_check(++ci.new_track))
2004 if (ci.new_track >= 0)
2006 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2007 return Q_CODEC_REQUEST_FAILED;
2011 if (auto_dir_skip)
2013 /* Update the playlist */
2014 last_peek_offset -= ci.new_track;
2016 /* If the track change was the result of an auto dir skip,
2017 we need to update the playlist now */
2018 next_playlist_index = playlist_next(ci.new_track);
2020 if (next_playlist_index < 0)
2022 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2023 return Q_CODEC_REQUEST_FAILED;
2027 if (new_playlist)
2029 ci.new_track = 1;
2030 new_playlist = false;
2033 /* Save the track metadata to allow the WPS to display it
2034 while PCM finishes playing that track */
2035 copy_mp3entry(&prevtrack_id3, &curtrack_id3);
2037 /* Update the main buffer copy of the track metadata with the one
2038 the codec has been using (for the unbuffer callbacks) */
2039 if (CUR_TI->id3_hid >= 0)
2040 copy_mp3entry(bufgetid3(CUR_TI->id3_hid), &curtrack_id3);
2042 /* Save a pointer to the old track to allow later clearing */
2043 prev_ti = CUR_TI;
2045 for (i = 0; i < ci.new_track; i++)
2047 idx = (track_ridx + i) & MAX_TRACK_MASK;
2048 struct mp3entry *id3 = bufgetid3(tracks[idx].id3_hid);
2049 ssize_t offset = buf_handle_offset(tracks[idx].audio_hid);
2050 if (!id3 || offset < 0 || (unsigned)offset > id3->first_frame_offset)
2052 /* We don't have all the audio data for that track, so clear it,
2053 but keep the metadata. */
2054 if (tracks[idx].audio_hid >= 0 && bufclose(tracks[idx].audio_hid))
2056 tracks[idx].audio_hid = -1;
2057 tracks[idx].filesize = 0;
2062 /* Move to the new track */
2063 track_ridx = (track_ridx + ci.new_track) & MAX_TRACK_MASK;
2065 buf_set_base_handle(CUR_TI->audio_hid);
2067 if (automatic_skip)
2069 playlist_end = false;
2070 wps_offset = -ci.new_track;
2071 track_changed = true;
2074 /* If it is not safe to even skip this many track entries */
2075 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
2077 ci.new_track = 0;
2078 audio_rebuffer();
2079 goto skip_done;
2082 forward = ci.new_track > 0;
2083 ci.new_track = 0;
2085 /* If the target track is clearly not in memory */
2086 if (CUR_TI->filesize == 0 || !CUR_TI->taginfo_ready)
2088 audio_rebuffer();
2089 goto skip_done;
2092 /* When skipping backwards, it is possible that we've found a track that's
2093 * buffered, but which is around the track-wrap and therefor not the track
2094 * we are looking for */
2095 if (!forward)
2097 int cur_idx = track_ridx;
2098 bool taginfo_ready = true;
2099 /* We've wrapped the buffer backwards if new > old */
2100 bool wrap = track_ridx > old_track_ridx;
2102 while (1)
2104 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
2106 /* if we've advanced past the wrap when cur_idx is zeroed */
2107 if (!cur_idx)
2108 wrap = false;
2110 /* if we aren't still on the wrap and we've caught the old track */
2111 if (!(wrap || cur_idx < old_track_ridx))
2112 break;
2114 /* If we hit a track in between without valid tag info, bail */
2115 if (!tracks[cur_idx].taginfo_ready)
2117 taginfo_ready = false;
2118 break;
2121 if (!taginfo_ready)
2123 audio_rebuffer();
2127 skip_done:
2128 audio_update_trackinfo();
2129 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2130 return Q_CODEC_REQUEST_COMPLETE;
2133 void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3))
2135 track_buffer_callback = handler;
2138 void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3))
2140 track_unbuffer_callback = handler;
2143 void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3))
2145 track_changed_callback = handler;
2148 unsigned long audio_prev_elapsed(void)
2150 return prev_track_elapsed;
2153 static void audio_stop_codec_flush(void)
2155 ci.stop_codec = true;
2156 pcmbuf_pause(true);
2158 while (audio_codec_loaded)
2159 yield();
2161 /* If the audio codec is not loaded any more, and the audio is still
2162 * playing, it is now and _only_ now safe to call this function from the
2163 * audio thread */
2164 if (pcm_is_playing())
2165 pcmbuf_play_stop();
2166 pcmbuf_pause(paused);
2169 static void audio_stop_playback(void)
2171 /* If we were playing, save resume information */
2172 if (playing)
2174 struct mp3entry *id3 = NULL;
2176 if (!playlist_end || !ci.stop_codec)
2178 /* Set this early, the outside code yields and may allow the codec
2179 to try to wait for a reply on a buffer wait */
2180 ci.stop_codec = true;
2181 id3 = audio_current_track();
2184 /* Save the current playing spot, or NULL if the playlist has ended */
2185 playlist_update_resume_info(id3);
2187 prev_track_elapsed = curtrack_id3.elapsed;
2189 /* At end of playlist save current id3 (id3.elapsed!) to buffer and
2190 * Increment index so runtime info is saved in audio_clear_track_entries().
2192 if ((playlist_end) && (tracks[track_ridx].id3_hid >= 0)) {
2193 copy_mp3entry(bufgetid3(tracks[track_ridx].id3_hid), &curtrack_id3);
2194 track_ridx = (track_ridx + 1) & MAX_TRACK_MASK;
2198 paused = false;
2199 audio_stop_codec_flush();
2200 playing = false;
2202 /* Mark all entries null. */
2203 audio_clear_track_entries(false);
2205 /* Close all tracks */
2206 audio_release_tracks();
2208 unregister_buffering_callback(buffering_audio_callback);
2210 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
2213 static void audio_play_start(size_t offset)
2215 int i;
2217 #if INPUT_SRC_CAPS != 0
2218 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2219 audio_set_output_source(AUDIO_SRC_PLAYBACK);
2220 #endif
2222 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2223 paused = false;
2224 audio_stop_codec_flush();
2226 track_changed = true;
2227 playlist_end = false;
2229 playing = true;
2231 ci.new_track = 0;
2232 ci.seek_time = 0;
2233 wps_offset = 0;
2235 sound_set_volume(global_settings.volume);
2236 track_widx = track_ridx = 0;
2238 /* Clear all track entries. */
2239 for (i = 0; i < MAX_TRACK; i++) {
2240 clear_track_info(&tracks[i]);
2243 last_peek_offset = -1;
2245 /* Officially playing */
2246 queue_reply(&audio_queue, 1);
2248 #ifndef HAVE_FLASH_STORAGE
2249 set_filebuf_watermark(buffer_margin, 0);
2250 #endif
2251 audio_fill_file_buffer(true, offset);
2252 register_buffering_callback(buffering_audio_callback);
2254 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2255 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
2259 /* Invalidates all but currently playing track. */
2260 static void audio_invalidate_tracks(void)
2262 if (audio_have_tracks())
2264 last_peek_offset = 0;
2265 playlist_end = false;
2266 track_widx = track_ridx;
2268 /* Mark all other entries null (also buffered wrong metadata). */
2269 audio_clear_track_entries(true);
2271 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2273 audio_fill_file_buffer(false, 0);
2277 static void audio_new_playlist(void)
2279 /* Prepare to start a new fill from the beginning of the playlist */
2280 last_peek_offset = -1;
2281 if (audio_have_tracks())
2283 if (paused)
2284 skipped_during_pause = true;
2285 playlist_end = false;
2286 track_widx = track_ridx;
2287 audio_clear_track_entries(true);
2289 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2291 /* Mark the current track as invalid to prevent skipping back to it */
2292 CUR_TI->taginfo_ready = false;
2295 /* Signal the codec to initiate a track change forward */
2296 new_playlist = true;
2297 ci.new_track = 1;
2299 /* Officially playing */
2300 queue_reply(&audio_queue, 1);
2302 audio_fill_file_buffer(false, 0);
2305 /* Called on manual track skip */
2306 static void audio_initiate_track_change(long direction)
2308 logf("audio_initiate_track_change(%ld)", direction);
2310 playlist_end = false;
2311 ci.new_track += direction;
2312 wps_offset -= direction;
2313 if (paused)
2314 skipped_during_pause = true;
2317 /* Called on manual dir skip */
2318 static void audio_initiate_dir_change(long direction)
2320 playlist_end = false;
2321 dir_skip = true;
2322 ci.new_track = direction;
2323 if (paused)
2324 skipped_during_pause = true;
2327 /* Called when PCM track change is complete */
2328 static void audio_finalise_track_change(void)
2330 logf("audio_finalise_track_change");
2332 if (automatic_skip)
2334 if (!auto_dir_skip)
2335 playlist_next(-wps_offset);
2337 wps_offset = 0;
2338 automatic_skip = false;
2341 auto_dir_skip = false;
2343 /* Invalidate prevtrack_id3 */
2344 prevtrack_id3.path[0] = 0;
2346 if (prev_ti && prev_ti->audio_hid < 0)
2348 /* No audio left so we clear all the track info. */
2349 clear_track_info(prev_ti);
2352 if (prev_ti && prev_ti->id3_hid >= 0)
2354 /* Reset the elapsed time to force the progressbar to be empty if
2355 the user skips back to this track */
2356 bufgetid3(prev_ti->id3_hid)->elapsed = 0;
2359 if (track_changed_callback)
2360 track_changed_callback(&curtrack_id3);
2362 track_changed = true;
2363 playlist_update_resume_info(audio_current_track());
2367 * Layout audio buffer as follows - iram buffer depends on target:
2368 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
2370 static void audio_reset_buffer(void)
2372 /* see audio_get_recording_buffer if this is modified */
2373 logf("audio_reset_buffer");
2375 /* If the setup of anything allocated before the file buffer is
2376 changed, do check the adjustments after the buffer_alloc call
2377 as it will likely be affected and need sliding over */
2379 /* Initially set up file buffer as all space available */
2380 malloc_buf = audiobuf + talk_get_bufsize();
2381 /* Align the malloc buf to line size. Especially important to cf
2382 targets that do line reads/writes. */
2383 malloc_buf = (unsigned char *)(((uintptr_t)malloc_buf + 15) & ~15);
2384 filebuf = malloc_buf + MALLOC_BUFSIZE; /* filebuf line align implied */
2385 filebuflen = audiobufend - filebuf;
2387 filebuflen &= ~15;
2389 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
2390 filebuflen -= pcmbuf_init(filebuf + filebuflen) + GUARD_BUFSIZE;
2392 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
2393 will already be line aligned */
2394 filebuflen &= ~3;
2396 buffering_reset(filebuf, filebuflen);
2398 /* Clear any references to the file buffer */
2399 buffer_state = BUFFER_STATE_INITIALIZED;
2401 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
2402 /* Make sure everything adds up - yes, some info is a bit redundant but
2403 aids viewing and the sumation of certain variables should add up to
2404 the location of others. */
2406 size_t pcmbufsize;
2407 unsigned char * pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
2408 logf("mabuf: %08X", (unsigned)malloc_buf);
2409 logf("mabufe: %08X", (unsigned)(malloc_buf + MALLOC_BUFSIZE));
2410 logf("fbuf: %08X", (unsigned)filebuf);
2411 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
2412 logf("gbuf: %08X", (unsigned)(filebuf + filebuflen));
2413 logf("gbufe: %08X", (unsigned)(filebuf + filebuflen + GUARD_BUFSIZE));
2414 logf("pcmb: %08X", (unsigned)pcmbuf);
2415 logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
2417 #endif
2420 static void audio_thread(void)
2422 struct queue_event ev;
2424 pcm_postinit();
2426 audio_thread_ready = true;
2428 while (1)
2430 cancel_cpu_boost();
2431 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
2433 switch (ev.id) {
2434 case Q_AUDIO_FILL_BUFFER:
2435 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
2436 if (!playing || playlist_end || ci.stop_codec)
2437 break;
2438 audio_fill_file_buffer(false, 0);
2439 break;
2441 case Q_AUDIO_PLAY:
2442 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2443 if (playing && ev.data <= 0)
2444 audio_new_playlist();
2445 else
2447 audio_stop_playback();
2448 audio_play_start((size_t)ev.data);
2450 break;
2452 case Q_AUDIO_STOP:
2453 LOGFQUEUE("audio < Q_AUDIO_STOP");
2454 if (playing)
2455 audio_stop_playback();
2456 if (ev.data != 0)
2457 queue_clear(&audio_queue);
2458 break;
2460 case Q_AUDIO_PAUSE:
2461 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
2462 if (!(bool) ev.data && skipped_during_pause && !pcmbuf_is_crossfade_active())
2463 pcmbuf_play_stop(); /* Flush old track on resume after skip */
2464 skipped_during_pause = false;
2465 if (!playing)
2466 break;
2467 pcmbuf_pause((bool)ev.data);
2468 paused = (bool)ev.data;
2469 break;
2471 case Q_AUDIO_SKIP:
2472 LOGFQUEUE("audio < Q_AUDIO_SKIP");
2473 audio_initiate_track_change((long)ev.data);
2474 break;
2476 case Q_AUDIO_PRE_FF_REWIND:
2477 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
2478 if (!playing)
2479 break;
2480 pcmbuf_pause(true);
2481 break;
2483 case Q_AUDIO_FF_REWIND:
2484 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
2485 if (!playing)
2486 break;
2487 if (automatic_skip)
2489 /* An automatic track skip is in progress. Finalize it,
2490 then go back to the previous track */
2491 audio_finalise_track_change();
2492 ci.new_track = -1;
2494 ci.seek_time = (long)ev.data+1;
2495 break;
2497 case Q_AUDIO_CHECK_NEW_TRACK:
2498 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
2499 queue_reply(&audio_queue, audio_check_new_track());
2500 break;
2502 case Q_AUDIO_DIR_SKIP:
2503 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2504 playlist_end = false;
2505 audio_initiate_dir_change(ev.data);
2506 break;
2508 case Q_AUDIO_FLUSH:
2509 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
2510 audio_invalidate_tracks();
2511 break;
2513 case Q_AUDIO_TRACK_CHANGED:
2514 /* PCM track change done */
2515 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2516 audio_finalise_track_change();
2517 break;
2519 #ifndef SIMULATOR
2520 case SYS_USB_CONNECTED:
2521 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2522 if (playing)
2523 audio_stop_playback();
2524 #ifdef PLAYBACK_VOICE
2525 voice_stop();
2526 #endif
2527 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2528 usb_wait_for_disconnect(&audio_queue);
2530 /* Mark all entries null. */
2531 audio_clear_track_entries(false);
2533 /* release tracks to make sure all handles are closed */
2534 audio_release_tracks();
2535 break;
2536 #endif
2538 case SYS_TIMEOUT:
2539 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
2540 break;
2542 default:
2543 LOGFQUEUE("audio < default");
2544 break;
2545 } /* end switch */
2546 } /* end while */
2549 #ifdef ROCKBOX_HAS_LOGF
2550 static void audio_test_track_changed_event(struct mp3entry *id3)
2552 (void)id3;
2554 logf("tce:%s", id3->path);
2556 #endif
2558 /* Initialize the audio system - called from init() in main.c.
2559 * Last function because of all the references to internal symbols
2561 void audio_init(void)
2563 struct thread_entry *audio_thread_p;
2565 /* Can never do this twice */
2566 if (audio_is_initialized)
2568 logf("audio: already initialized");
2569 return;
2572 logf("audio: initializing");
2574 /* Initialize queues before giving control elsewhere in case it likes
2575 to send messages. Thread creation will be delayed however so nothing
2576 starts running until ready if something yields such as talk_init. */
2577 queue_init(&audio_queue, true);
2578 queue_enable_queue_send(&audio_queue, &audio_queue_sender_list);
2579 queue_init(&codec_queue, false);
2580 queue_enable_queue_send(&codec_queue, &codec_queue_sender_list);
2582 pcm_init();
2584 #ifdef ROCKBOX_HAS_LOGF
2585 audio_set_track_changed_event(audio_test_track_changed_event);
2586 #endif
2588 /* Initialize codec api. */
2589 ci.read_filebuf = codec_filebuf_callback;
2590 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
2591 ci.get_codec_memory = codec_get_memory_callback;
2592 ci.request_buffer = codec_request_buffer_callback;
2593 ci.advance_buffer = codec_advance_buffer_callback;
2594 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
2595 ci.request_next_track = codec_request_next_track_callback;
2596 ci.mp3_get_filepos = codec_mp3_get_filepos_callback;
2597 ci.seek_buffer = codec_seek_buffer_callback;
2598 ci.seek_complete = codec_seek_complete_callback;
2599 ci.set_elapsed = codec_set_elapsed_callback;
2600 ci.set_offset = codec_set_offset_callback;
2601 ci.configure = codec_configure_callback;
2602 ci.discard_codec = codec_discard_codec_callback;
2603 ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP,
2604 CODEC_IDX_AUDIO);
2606 /* initialize the buffer */
2607 filebuf = audiobuf;
2609 /* audio_reset_buffer must to know the size of voice buffer so init
2610 talk first */
2611 talk_init();
2613 codec_thread_p = create_thread(
2614 codec_thread, codec_stack, sizeof(codec_stack),
2615 CREATE_THREAD_FROZEN,
2616 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
2617 IF_COP(, CPU));
2619 audio_thread_p = create_thread(audio_thread, audio_stack,
2620 sizeof(audio_stack), CREATE_THREAD_FROZEN,
2621 audio_thread_name IF_PRIO(, PRIORITY_SYSTEM)
2622 IF_COP(, CPU));
2624 #ifdef PLAYBACK_VOICE
2625 voice_thread_init();
2626 #endif
2628 /* Set crossfade setting for next buffer init which should be about... */
2629 pcmbuf_crossfade_enable(global_settings.crossfade);
2631 /* initialize the buffering system */
2633 buffering_init();
2634 /* ...now! Set up the buffers */
2635 audio_reset_buffer();
2637 int i;
2638 for(i = 0; i < MAX_TRACK; i++)
2640 tracks[i].audio_hid = -1;
2641 tracks[i].id3_hid = -1;
2642 tracks[i].codec_hid = -1;
2643 #ifdef HAVE_ALBUMART
2644 tracks[i].aa_hid = -1;
2645 #endif
2648 /* Probably safe to say */
2649 audio_is_initialized = true;
2651 sound_settings_apply();
2652 #ifndef HAVE_FLASH_STORAGE
2653 audio_set_buffer_margin(global_settings.buffer_margin);
2654 #endif
2656 /* it's safe to let the threads run now */
2657 #ifdef PLAYBACK_VOICE
2658 voice_thread_resume();
2659 #endif
2660 thread_thaw(codec_thread_p);
2661 thread_thaw(audio_thread_p);
2663 } /* audio_init */
2665 void audio_wait_for_init(void)
2667 /* audio thread will only set this once after it finished the final
2668 * audio hardware init so this little construct is safe - even
2669 * cross-core. */
2670 while (!audio_thread_ready)
2672 sleep(0);