fix the touchpad list code
[Rockbox.git] / apps / playback.c
blobf757f4ae08ef571ad0c0267fd29ff5d497617f5a
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 the audio thread when the current track information has updated
226 * and the WPS may need to update its cached information */
227 static bool track_changed = false;
229 /* Information used only for filling the buffer */
230 /* Playlist steps from playing track to next track to be buffered (A) */
231 static int last_peek_offset = 0;
233 /* Scrobbler support */
234 static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/
236 /* Track change controls */
237 static bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */
238 static bool playlist_end = false; /* Has the current playlist ended? (A) */
239 static bool auto_dir_skip = false; /* Have we changed dirs automatically? */
240 static bool dir_skip = false; /* Is a directory skip pending? (A) */
241 static bool new_playlist = false; /* Are we starting a new playlist? (A) */
242 static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */
243 static bool skipped_during_pause = false; /* Do we need to clear the PCM buffer when playback resumes (A) */
245 /* Set to true if the codec thread should send an audio stop request
246 * (typically because the end of the playlist has been reached).
248 static bool codec_requested_stop = false;
250 /* Callbacks which applications or plugins may set */
251 /* When the playing track has changed from the user's perspective */
252 void (*track_changed_callback)(struct mp3entry *id3) = NULL;
253 /* When a track has been buffered */
254 void (*track_buffer_callback)(struct mp3entry *id3) = NULL;
255 /* When a track's buffer has been overwritten or cleared */
256 void (*track_unbuffer_callback)(struct mp3entry *id3) = NULL;
258 static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */
260 /* Multiple threads */
261 /* Set the watermark to trigger buffer fill (A/C) FIXME */
262 static void set_filebuf_watermark(int seconds, size_t max);
264 /* Audio thread */
265 static struct event_queue audio_queue NOCACHEBSS_ATTR;
266 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR;
267 static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
268 static const char audio_thread_name[] = "audio";
270 static void audio_thread(void);
271 static void audio_initiate_track_change(long direction);
272 static bool audio_have_tracks(void);
273 static void audio_reset_buffer(void);
275 /* Codec thread */
276 extern struct codec_api ci;
277 static struct event_queue codec_queue NOCACHEBSS_ATTR;
278 static struct queue_sender_list codec_queue_sender_list;
279 static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
280 IBSS_ATTR;
281 static const char codec_thread_name[] = "codec";
282 struct thread_entry *codec_thread_p; /* For modifying thread priority later. */
284 /* PCM buffer messaging */
285 static struct event_queue pcmbuf_queue NOCACHEBSS_ATTR;
287 /* Function to be called by pcm buffer callbacks.
288 * Permissible Context(s): Audio interrupt
290 static void pcmbuf_callback_queue_post(long id, intptr_t data)
292 /* No lock since we're already in audio interrupt context */
293 queue_post(&pcmbuf_queue, id, data);
296 /* Scan the pcmbuf queue and return true if a message pulled.
297 * Permissible Context(s): Thread
299 static bool pcmbuf_queue_scan(struct queue_event *ev)
301 if (!queue_empty(&pcmbuf_queue))
303 /* Transfer message to audio queue */
304 pcm_play_lock();
305 /* Pull message - never, ever any blocking call! */
306 queue_wait_w_tmo(&pcmbuf_queue, ev, 0);
307 pcm_play_unlock();
308 return true;
311 return false;
314 /* Clear the pcmbuf queue of messages
315 * Permissible Context(s): Thread
317 static void pcmbuf_queue_clear(void)
319 pcm_play_lock();
320 queue_clear(&pcmbuf_queue);
321 pcm_play_unlock();
324 /* --- Helper functions --- */
326 static struct mp3entry *bufgetid3(int handle_id)
328 if (handle_id < 0)
329 return NULL;
331 struct mp3entry *id3;
332 ssize_t ret = bufgetdata(handle_id, 0, (void *)&id3);
334 if (ret < 0 || ret != sizeof(struct mp3entry))
335 return NULL;
337 return id3;
340 static bool clear_track_info(struct track_info *track)
342 /* bufclose returns true if the handle is not found, or if it is closed
343 * successfully, so these checks are safe on non-existant handles */
344 if (!track)
345 return false;
347 if (track->codec_hid >= 0) {
348 if (bufclose(track->codec_hid))
349 track->codec_hid = -1;
350 else
351 return false;
354 if (track->id3_hid >= 0) {
355 if (track->event_sent && track_unbuffer_callback) {
356 /* If there is an unbuffer callback, call it */
357 track_unbuffer_callback(bufgetid3(track->id3_hid));
360 if (bufclose(track->id3_hid))
361 track->id3_hid = -1;
362 else
363 return false;
366 if (track->audio_hid >= 0) {
367 if (bufclose(track->audio_hid))
368 track->audio_hid = -1;
369 else
370 return false;
373 #ifdef HAVE_ALBUMART
374 if (track->aa_hid >= 0) {
375 if (bufclose(track->aa_hid))
376 track->aa_hid = -1;
377 else
378 return false;
380 #endif
382 track->filesize = 0;
383 track->taginfo_ready = false;
384 track->event_sent = false;
386 return true;
389 /* --- External interfaces --- */
391 /* This sends a stop message and the audio thread will dump all it's
392 subsequenct messages */
393 void audio_hard_stop(void)
395 /* Stop playback */
396 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
397 queue_send(&audio_queue, Q_AUDIO_STOP, 1);
398 #ifdef PLAYBACK_VOICE
399 voice_stop();
400 #endif
403 bool audio_restore_playback(int type)
405 switch (type)
407 case AUDIO_WANT_PLAYBACK:
408 if (buffer_state != BUFFER_STATE_INITIALIZED)
409 audio_reset_buffer();
410 return true;
411 case AUDIO_WANT_VOICE:
412 if (buffer_state == BUFFER_STATE_TRASHED)
413 audio_reset_buffer();
414 return true;
415 default:
416 return false;
420 unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
422 unsigned char *buf, *end;
424 if (audio_is_initialized)
426 audio_hard_stop();
428 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
430 if (buffer_size == NULL)
432 /* Special case for talk_init to use since it already knows it's
433 trashed */
434 buffer_state = BUFFER_STATE_TRASHED;
435 return NULL;
438 if (talk_buf || buffer_state == BUFFER_STATE_TRASHED
439 || !talk_voice_required())
441 logf("get buffer: talk, audio");
442 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
443 the talk buffer is not needed because voice isn't being used, or
444 could be BUFFER_STATE_TRASHED already. If state is
445 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
446 without the caller knowing what's going on. Changing certain settings
447 may move it to a worse condition but the memory in use by something
448 else will remain undisturbed.
450 if (buffer_state != BUFFER_STATE_TRASHED)
452 talk_buffer_steal();
453 buffer_state = BUFFER_STATE_TRASHED;
456 buf = audiobuf;
457 end = audiobufend;
459 else
461 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
462 still BUFFER_STATE_INITIALIZED */
463 /* Skip talk buffer and move pcm buffer to end to maximize available
464 contiguous memory - no audio running means voice will not need the
465 swap space */
466 logf("get buffer: audio");
467 buf = audiobuf + talk_get_bufsize();
468 end = audiobufend - pcmbuf_init(audiobufend);
469 buffer_state = BUFFER_STATE_VOICED_ONLY;
472 *buffer_size = end - buf;
474 return buf;
477 #ifdef HAVE_RECORDING
478 unsigned char *audio_get_recording_buffer(size_t *buffer_size)
480 /* Stop audio, voice and obtain all available buffer space */
481 audio_hard_stop();
482 talk_buffer_steal();
484 unsigned char *end = audiobufend;
485 buffer_state = BUFFER_STATE_TRASHED;
486 *buffer_size = end - audiobuf;
488 return (unsigned char *)audiobuf;
491 bool audio_load_encoder(int afmt)
493 #ifndef SIMULATOR
494 const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER);
495 if (!enc_fn)
496 return false;
498 audio_remove_encoder();
499 ci.enc_codec_loaded = 0; /* clear any previous error condition */
501 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
502 queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (intptr_t)enc_fn);
504 while (ci.enc_codec_loaded == 0)
505 yield();
507 logf("codec loaded: %d", ci.enc_codec_loaded);
509 return ci.enc_codec_loaded > 0;
510 #else
511 (void)afmt;
512 return true;
513 #endif
514 } /* audio_load_encoder */
516 void audio_remove_encoder(void)
518 #ifndef SIMULATOR
519 /* force encoder codec unload (if currently loaded) */
520 if (ci.enc_codec_loaded <= 0)
521 return;
523 ci.stop_encoder = true;
524 while (ci.enc_codec_loaded > 0)
525 yield();
526 #endif
527 } /* audio_remove_encoder */
529 #endif /* HAVE_RECORDING */
531 #ifdef HAVE_ALBUMART
532 int audio_current_aa_hid(void)
534 int cur_idx;
535 int offset = ci.new_track + wps_offset;
537 cur_idx = track_ridx + offset;
538 cur_idx &= MAX_TRACK_MASK;
540 return tracks[cur_idx].aa_hid;
542 #endif
544 struct mp3entry* audio_current_track(void)
546 const char *filename;
547 const char *p;
548 static struct mp3entry temp_id3;
549 int cur_idx;
550 int offset = ci.new_track + wps_offset;
552 cur_idx = (track_ridx + offset) & MAX_TRACK_MASK;
554 if (cur_idx == track_ridx && *curtrack_id3.path)
556 /* The usual case */
557 return &curtrack_id3;
559 else if (offset == -1 && *prevtrack_id3.path)
561 /* We're in a track transition. The codec has moved on to the nex track,
562 but the audio being played is still the same (now previous) track.
563 prevtrack_id3.elapsed is being updated in an ISR by
564 codec_pcmbuf_position_callback */
565 return &prevtrack_id3;
567 else if (tracks[cur_idx].id3_hid >= 0)
569 /* Get the ID3 metadata from the main buffer */
570 return bufgetid3(tracks[cur_idx].id3_hid);
573 /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info
574 we have and return that. */
576 memset(&temp_id3, 0, sizeof(struct mp3entry));
578 filename = playlist_peek(0);
579 if (!filename)
580 filename = "No file!";
582 #ifdef HAVE_TC_RAMCACHE
583 if (tagcache_fill_tags(&temp_id3, filename))
584 return &temp_id3;
585 #endif
587 p = strrchr(filename, '/');
588 if (!p)
589 p = filename;
590 else
591 p++;
593 strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1);
594 temp_id3.title = &temp_id3.path[0];
596 return &temp_id3;
599 struct mp3entry* audio_next_track(void)
601 int next_idx;
602 int offset = ci.new_track + wps_offset;
604 if (!audio_have_tracks())
605 return NULL;
607 if (wps_offset == -1 && *prevtrack_id3.path)
609 /* We're in a track transition. The next track for the WPS is the one
610 currently being decoded. */
611 return &curtrack_id3;
614 next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK;
616 if (next_idx == track_widx)
618 /* The next track hasn't been buffered yet, so we return the static
619 version of its metadata. */
620 return &lasttrack_id3;
623 if (tracks[next_idx].id3_hid < 0)
624 return NULL;
625 else
626 return bufgetid3(tracks[next_idx].id3_hid);
629 bool audio_has_changed_track(void)
631 if (track_changed)
633 track_changed = false;
634 return true;
637 return false;
640 void audio_play(long offset)
642 logf("audio_play");
644 #ifdef PLAYBACK_VOICE
645 /* Truncate any existing voice output so we don't have spelling
646 * etc. over the first part of the played track */
647 talk_force_shutup();
648 #endif
650 /* Start playback */
651 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset);
652 /* Don't return until playback has actually started */
653 queue_send(&audio_queue, Q_AUDIO_PLAY, offset);
656 void audio_stop(void)
658 /* Stop playback */
659 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
660 /* Don't return until playback has actually stopped */
661 queue_send(&audio_queue, Q_AUDIO_STOP, 0);
664 void audio_pause(void)
666 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
667 /* Don't return until playback has actually paused */
668 queue_send(&audio_queue, Q_AUDIO_PAUSE, true);
671 void audio_resume(void)
673 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
674 /* Don't return until playback has actually resumed */
675 queue_send(&audio_queue, Q_AUDIO_PAUSE, false);
678 static void audio_skip(int direction)
680 if (playlist_check(ci.new_track + wps_offset + direction))
682 if (global_settings.beep)
683 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
685 LOGFQUEUE("audio > audio Q_AUDIO_SKIP %d", direction);
686 queue_post(&audio_queue, Q_AUDIO_SKIP, direction);
687 /* Update wps while our message travels inside deep playback queues. */
688 wps_offset += direction;
689 /* Immediately update the playlist index */
690 playlist_next(direction);
691 track_changed = true;
693 else
695 /* No more tracks. */
696 if (global_settings.beep)
697 pcmbuf_beep(1000, 100, 1000*global_settings.beep);
701 void audio_next(void)
703 audio_skip(1);
706 void audio_prev(void)
708 audio_skip(-1);
711 void audio_next_dir(void)
713 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
714 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, 1);
717 void audio_prev_dir(void)
719 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
720 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, -1);
723 void audio_pre_ff_rewind(void)
725 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
726 queue_post(&audio_queue, Q_AUDIO_PRE_FF_REWIND, 0);
729 void audio_ff_rewind(long newpos)
731 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
732 queue_post(&audio_queue, Q_AUDIO_FF_REWIND, newpos);
735 void audio_flush_and_reload_tracks(void)
737 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
738 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0);
741 void audio_error_clear(void)
743 #ifdef AUDIO_HAVE_RECORDING
744 pcm_rec_error_clear();
745 #endif
748 int audio_status(void)
750 int ret = 0;
752 if (playing)
753 ret |= AUDIO_STATUS_PLAY;
755 if (paused)
756 ret |= AUDIO_STATUS_PAUSE;
758 #ifdef HAVE_RECORDING
759 /* Do this here for constitency with mpeg.c version */
760 ret |= pcm_rec_status();
761 #endif
763 return ret;
766 int audio_get_file_pos(void)
768 return 0;
771 #ifndef HAVE_FLASH_STORAGE
772 void audio_set_buffer_margin(int setting)
774 static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
775 buffer_margin = lookup[setting];
776 logf("buffer margin: %ld", (long)buffer_margin);
777 set_filebuf_watermark(buffer_margin, 0);
779 #endif
781 /* Take nescessary steps to enable or disable the crossfade setting */
782 void audio_set_crossfade(int enable)
784 size_t offset;
785 bool was_playing;
786 size_t size;
788 /* Tell it the next setting to use */
789 pcmbuf_crossfade_enable(enable);
791 /* Return if size hasn't changed or this is too early to determine
792 which in the second case there's no way we could be playing
793 anything at all */
794 if (pcmbuf_is_same_size())
796 /* This function is a copout and just syncs some variables -
797 to be removed at a later date */
798 pcmbuf_crossfade_enable_finished();
799 return;
802 offset = 0;
803 was_playing = playing;
805 /* Playback has to be stopped before changing the buffer size */
806 if (was_playing)
808 /* Store the track resume position */
809 offset = curtrack_id3.offset;
810 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK));
813 /* Blast it - audio buffer will have to be setup again next time
814 something plays */
815 audio_get_buffer(true, &size);
817 /* Restart playback if audio was running previously */
818 if (was_playing)
819 audio_play(offset);
822 /* --- Routines called from multiple threads --- */
824 static void set_filebuf_watermark(int seconds, size_t max)
826 size_t bytes;
828 if (!filebuf)
829 return; /* Audio buffers not yet set up */
831 bytes = seconds?MAX(curtrack_id3.bitrate * seconds * (1000/8), max):max;
832 bytes = MIN(bytes, filebuflen / 2);
833 buf_set_watermark(bytes);
836 const char * get_codec_filename(int cod_spec)
838 const char *fname;
840 #ifdef HAVE_RECORDING
841 /* Can choose decoder or encoder if one available */
842 int type = cod_spec & CODEC_TYPE_MASK;
843 int afmt = cod_spec & CODEC_AFMT_MASK;
845 if ((unsigned)afmt >= AFMT_NUM_CODECS)
846 type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
848 fname = (type == CODEC_TYPE_ENCODER) ?
849 audio_formats[afmt].codec_enc_root_fn :
850 audio_formats[afmt].codec_root_fn;
852 logf("%s: %d - %s",
853 (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
854 afmt, fname ? fname : "<unknown>");
855 #else /* !HAVE_RECORDING */
856 /* Always decoder */
857 if ((unsigned)cod_spec >= AFMT_NUM_CODECS)
858 cod_spec = AFMT_UNKNOWN;
859 fname = audio_formats[cod_spec].codec_root_fn;
860 logf("Codec: %d - %s", cod_spec, fname ? fname : "<unknown>");
861 #endif /* HAVE_RECORDING */
863 return fname;
864 } /* get_codec_filename */
866 /* --- Codec thread --- */
867 static bool codec_pcmbuf_insert_callback(
868 const void *ch1, const void *ch2, int count)
870 const char *src[2] = { ch1, ch2 };
872 while (count > 0)
874 int out_count = dsp_output_count(ci.dsp, count);
875 int inp_count;
876 char *dest;
878 /* Prevent audio from a previous track from playing */
879 if (ci.new_track || ci.stop_codec)
880 return true;
882 while ((dest = pcmbuf_request_buffer(&out_count)) == NULL)
884 cancel_cpu_boost();
885 sleep(1);
886 if (ci.seek_time || ci.new_track || ci.stop_codec)
887 return true;
890 /* Get the real input_size for output_size bytes, guarding
891 * against resampling buffer overflows. */
892 inp_count = dsp_input_count(ci.dsp, out_count);
894 if (inp_count <= 0)
895 return true;
897 /* Input size has grown, no error, just don't write more than length */
898 if (inp_count > count)
899 inp_count = count;
901 out_count = dsp_process(ci.dsp, dest, src, inp_count);
903 if (out_count <= 0)
904 return true;
906 pcmbuf_write_complete(out_count);
908 count -= inp_count;
911 return true;
912 } /* codec_pcmbuf_insert_callback */
914 static void* codec_get_memory_callback(size_t *size)
916 *size = MALLOC_BUFSIZE;
917 return malloc_buf;
920 /* Between the codec and PCM track change, we need to keep updating the
921 "elapsed" value of the previous (to the codec, but current to the
922 user/PCM/WPS) track, so that the progressbar reaches the end.
923 During that transition, the WPS will display prevtrack_id3. */
924 static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
925 static void codec_pcmbuf_position_callback(size_t size)
927 /* This is called from an ISR, so be quick */
928 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
929 prevtrack_id3.elapsed;
931 if (time >= prevtrack_id3.length)
933 pcmbuf_set_position_callback(NULL);
934 prevtrack_id3.elapsed = prevtrack_id3.length;
936 else
937 prevtrack_id3.elapsed = time;
940 static void codec_set_elapsed_callback(unsigned int value)
942 unsigned int latency;
943 if (ci.seek_time)
944 return;
946 #ifdef AB_REPEAT_ENABLE
947 ab_position_report(value);
948 #endif
950 latency = pcmbuf_get_latency();
951 if (value < latency)
952 curtrack_id3.elapsed = 0;
953 else if (value - latency > curtrack_id3.elapsed ||
954 value - latency < curtrack_id3.elapsed - 2)
956 curtrack_id3.elapsed = value - latency;
960 static void codec_set_offset_callback(size_t value)
962 unsigned int latency;
964 if (ci.seek_time)
965 return;
967 latency = pcmbuf_get_latency() * curtrack_id3.bitrate / 8;
968 if (value < latency)
969 curtrack_id3.offset = 0;
970 else
971 curtrack_id3.offset = value - latency;
974 static void codec_advance_buffer_counters(size_t amount)
976 bufadvance(CUR_TI->audio_hid, amount);
977 ci.curpos += amount;
980 /* copy up-to size bytes into ptr and return the actual size copied */
981 static size_t codec_filebuf_callback(void *ptr, size_t size)
983 ssize_t copy_n;
985 if (ci.stop_codec || !playing)
986 return 0;
988 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
990 /* Nothing requested OR nothing left */
991 if (copy_n == 0)
992 return 0;
994 /* Update read and other position pointers */
995 codec_advance_buffer_counters(copy_n);
997 /* Return the actual amount of data copied to the buffer */
998 return copy_n;
999 } /* codec_filebuf_callback */
1001 static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
1003 size_t copy_n = reqsize;
1004 ssize_t ret;
1005 void *ptr;
1007 if (!playing)
1009 *realsize = 0;
1010 return NULL;
1013 ret = bufgetdata(CUR_TI->audio_hid, reqsize, &ptr);
1014 if (ret >= 0)
1015 copy_n = MIN((size_t)ret, reqsize);
1017 if (copy_n == 0)
1019 *realsize = 0;
1020 return NULL;
1023 *realsize = copy_n;
1025 return ptr;
1026 } /* codec_request_buffer_callback */
1028 static int get_codec_base_type(int type)
1030 switch (type) {
1031 case AFMT_MPA_L1:
1032 case AFMT_MPA_L2:
1033 case AFMT_MPA_L3:
1034 return AFMT_MPA_L3;
1037 return type;
1040 static void codec_advance_buffer_callback(size_t amount)
1042 codec_advance_buffer_counters(amount);
1043 codec_set_offset_callback(ci.curpos);
1046 static void codec_advance_buffer_loc_callback(void *ptr)
1048 size_t amount = buf_get_offset(CUR_TI->audio_hid, ptr);
1049 codec_advance_buffer_callback(amount);
1052 /* Copied from mpeg.c. Should be moved somewhere else. */
1053 static int codec_get_file_pos(void)
1055 int pos = -1;
1056 struct mp3entry *id3 = audio_current_track();
1058 if (id3->vbr)
1060 if (id3->has_toc)
1062 /* Use the TOC to find the new position */
1063 unsigned int percent, remainder;
1064 int curtoc, nexttoc, plen;
1066 percent = (id3->elapsed*100)/id3->length;
1067 if (percent > 99)
1068 percent = 99;
1070 curtoc = id3->toc[percent];
1072 if (percent < 99)
1073 nexttoc = id3->toc[percent+1];
1074 else
1075 nexttoc = 256;
1077 pos = (id3->filesize/256)*curtoc;
1079 /* Use the remainder to get a more accurate position */
1080 remainder = (id3->elapsed*100)%id3->length;
1081 remainder = (remainder*100)/id3->length;
1082 plen = (nexttoc - curtoc)*(id3->filesize/256);
1083 pos += (plen/100)*remainder;
1085 else
1087 /* No TOC exists, estimate the new position */
1088 pos = (id3->filesize / (id3->length / 1000)) *
1089 (id3->elapsed / 1000);
1092 else if (id3->bitrate)
1093 pos = id3->elapsed * (id3->bitrate / 8);
1094 else
1095 return -1;
1097 pos += id3->first_frame_offset;
1099 /* Don't seek right to the end of the file so that we can
1100 transition properly to the next song */
1101 if (pos >= (int)(id3->filesize - id3->id3v1len))
1102 pos = id3->filesize - id3->id3v1len - 1;
1104 return pos;
1107 static off_t codec_mp3_get_filepos_callback(int newtime)
1109 off_t newpos;
1111 curtrack_id3.elapsed = newtime;
1112 newpos = codec_get_file_pos();
1114 return newpos;
1117 static void codec_seek_complete_callback(void)
1119 logf("seek_complete");
1120 if (pcm_is_paused())
1122 /* If this is not a seamless seek, clear the buffer */
1123 pcmbuf_play_stop();
1124 dsp_configure(ci.dsp, DSP_FLUSH, 0);
1126 /* If playback was not 'deliberately' paused, unpause now */
1127 if (!paused)
1128 pcmbuf_pause(false);
1130 ci.seek_time = 0;
1133 static bool codec_seek_buffer_callback(size_t newpos)
1135 logf("codec_seek_buffer_callback");
1137 int ret = bufseek(CUR_TI->audio_hid, newpos);
1138 if (ret == 0) {
1139 ci.curpos = newpos;
1140 return true;
1142 else {
1143 return false;
1147 static void codec_configure_callback(int setting, intptr_t value)
1149 switch (setting) {
1150 case CODEC_SET_FILEBUF_WATERMARK:
1151 set_filebuf_watermark(buffer_margin, value);
1152 break;
1154 default:
1155 if (!dsp_configure(ci.dsp, setting, value))
1156 { logf("Illegal key:%d", setting); }
1160 static void codec_track_changed(void)
1162 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1163 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1166 static void codec_pcmbuf_track_changed_callback(void)
1168 pcmbuf_set_position_callback(NULL);
1169 pcmbuf_callback_queue_post(Q_AUDIO_TRACK_CHANGED, 0);
1172 static void codec_discard_codec_callback(void)
1174 if (CUR_TI->codec_hid >= 0)
1176 bufclose(CUR_TI->codec_hid);
1177 CUR_TI->codec_hid = -1;
1181 static inline void codec_gapless_track_change(void)
1183 /* callback keeps the progress bar moving while the pcmbuf empties */
1184 pcmbuf_set_position_callback(codec_pcmbuf_position_callback);
1185 /* set the pcmbuf callback for when the track really changes */
1186 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
1189 static inline void codec_crossfade_track_change(void)
1191 /* Initiate automatic crossfade mode */
1192 pcmbuf_crossfade_init(false);
1193 /* Notify the wps that the track change starts now */
1194 codec_track_changed();
1197 static void codec_track_skip_done(bool was_manual)
1199 /* Manual track change (always crossfade or flush audio). */
1200 if (was_manual)
1202 pcmbuf_crossfade_init(true);
1203 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1204 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1206 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1207 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1208 && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP)
1210 if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
1212 if (global_settings.playlist_shuffle)
1213 /* shuffle mode is on, so crossfade: */
1214 codec_crossfade_track_change();
1215 else
1216 /* shuffle mode is off, so do a gapless track change */
1217 codec_gapless_track_change();
1219 else
1220 /* normal crossfade: */
1221 codec_crossfade_track_change();
1223 else
1224 /* normal gapless playback. */
1225 codec_gapless_track_change();
1228 static bool codec_load_next_track(void)
1230 intptr_t result = Q_CODEC_REQUEST_FAILED;
1232 prev_track_elapsed = curtrack_id3.elapsed;
1234 #ifdef AB_REPEAT_ENABLE
1235 ab_end_of_track_report();
1236 #endif
1238 logf("Request new track");
1240 if (ci.new_track == 0)
1242 ci.new_track++;
1243 automatic_skip = true;
1246 if (!ci.stop_codec)
1248 trigger_cpu_boost();
1249 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1250 result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
1253 switch (result)
1255 case Q_CODEC_REQUEST_COMPLETE:
1256 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1257 codec_track_skip_done(!automatic_skip);
1258 return true;
1260 case Q_CODEC_REQUEST_FAILED:
1261 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1262 ci.new_track = 0;
1263 ci.stop_codec = true;
1264 codec_requested_stop = true;
1265 return false;
1267 default:
1268 LOGFQUEUE("codec |< default");
1269 ci.stop_codec = true;
1270 codec_requested_stop = true;
1271 return false;
1275 static bool codec_request_next_track_callback(void)
1277 int prev_codectype;
1279 if (ci.stop_codec || !playing)
1280 return false;
1282 prev_codectype = get_codec_base_type(curtrack_id3.codectype);
1284 if (!codec_load_next_track())
1285 return false;
1287 /* Check if the next codec is the same file. */
1288 if (prev_codectype == get_codec_base_type(curtrack_id3.codectype))
1290 logf("New track loaded");
1291 codec_discard_codec_callback();
1292 return true;
1294 else
1296 logf("New codec:%d/%d", curtrack_id3.codectype, prev_codectype);
1297 return false;
1301 static void codec_thread(void)
1303 struct queue_event ev;
1304 int status;
1306 while (1) {
1307 status = 0;
1308 cancel_cpu_boost();
1309 queue_wait(&codec_queue, &ev);
1310 codec_requested_stop = false;
1312 switch (ev.id) {
1313 case Q_CODEC_LOAD_DISK:
1314 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1315 queue_reply(&codec_queue, 1);
1316 audio_codec_loaded = true;
1317 ci.stop_codec = false;
1318 status = codec_load_file((const char *)ev.data, &ci);
1319 break;
1321 case Q_CODEC_LOAD:
1322 LOGFQUEUE("codec < Q_CODEC_LOAD");
1323 if (CUR_TI->codec_hid < 0) {
1324 logf("Codec slot is empty!");
1325 /* Wait for the pcm buffer to go empty */
1326 while (pcm_is_playing())
1327 yield();
1328 /* This must be set to prevent an infinite loop */
1329 ci.stop_codec = true;
1330 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1331 queue_post(&codec_queue, Q_AUDIO_PLAY, 0);
1332 break;
1335 audio_codec_loaded = true;
1336 ci.stop_codec = false;
1337 status = codec_load_buf(CUR_TI->codec_hid, &ci);
1338 break;
1340 #ifdef AUDIO_HAVE_RECORDING
1341 case Q_ENCODER_LOAD_DISK:
1342 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1343 audio_codec_loaded = false; /* Not audio codec! */
1344 logf("loading encoder");
1345 ci.stop_encoder = false;
1346 status = codec_load_file((const char *)ev.data, &ci);
1347 logf("encoder stopped");
1348 break;
1349 #endif /* AUDIO_HAVE_RECORDING */
1351 default:
1352 LOGFQUEUE("codec < default");
1355 if (audio_codec_loaded)
1357 if (ci.stop_codec)
1359 status = CODEC_OK;
1360 if (!playing)
1361 pcmbuf_play_stop();
1364 audio_codec_loaded = false;
1367 switch (ev.id) {
1368 case Q_CODEC_LOAD_DISK:
1369 case Q_CODEC_LOAD:
1370 LOGFQUEUE("codec < Q_CODEC_LOAD");
1371 if (playing)
1373 if (ci.new_track || status != CODEC_OK)
1375 if (!ci.new_track)
1377 logf("Codec failure");
1378 gui_syncsplash(HZ*2, "Codec failure");
1381 if (!codec_load_next_track())
1383 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1384 /* End of playlist */
1385 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1386 break;
1389 else
1391 logf("Codec finished");
1392 if (ci.stop_codec)
1394 /* Wait for the audio to stop playing before
1395 * triggering the WPS exit */
1396 while(pcm_is_playing())
1398 curtrack_id3.elapsed =
1399 curtrack_id3.length - pcmbuf_get_latency();
1400 sleep(1);
1403 if (codec_requested_stop)
1405 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1406 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1408 break;
1412 if (CUR_TI->codec_hid >= 0)
1414 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1415 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
1417 else
1419 const char *codec_fn =
1420 get_codec_filename(curtrack_id3.codectype);
1421 if (codec_fn)
1423 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1424 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
1425 (intptr_t)codec_fn);
1429 break;
1431 #ifdef AUDIO_HAVE_RECORDING
1432 case Q_ENCODER_LOAD_DISK:
1433 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1435 if (status == CODEC_OK)
1436 break;
1438 logf("Encoder failure");
1439 gui_syncsplash(HZ*2, "Encoder failure");
1441 if (ci.enc_codec_loaded < 0)
1442 break;
1444 logf("Encoder failed to load");
1445 ci.enc_codec_loaded = -1;
1446 break;
1447 #endif /* AUDIO_HAVE_RECORDING */
1449 default:
1450 LOGFQUEUE("codec < default");
1452 } /* end switch */
1457 /* --- Audio thread --- */
1459 static bool audio_have_tracks(void)
1461 return (audio_track_count() != 0);
1464 static int audio_free_track_count(void)
1466 /* Used tracks + free tracks adds up to MAX_TRACK - 1 */
1467 return MAX_TRACK - 1 - audio_track_count();
1470 int audio_track_count(void)
1472 /* Calculate difference from track_ridx to track_widx
1473 * taking into account a possible wrap-around. */
1474 return (MAX_TRACK + track_widx - track_ridx) & MAX_TRACK_MASK;
1477 long audio_filebufused(void)
1479 return (long) buf_used();
1482 /* Update track info after successful a codec track change */
1483 static void audio_update_trackinfo(void)
1485 /* Load the curent track's metadata into curtrack_id3 */
1486 CUR_TI->taginfo_ready = (CUR_TI->id3_hid >= 0);
1487 if (CUR_TI->id3_hid >= 0)
1488 copy_mp3entry(&curtrack_id3, bufgetid3(CUR_TI->id3_hid));
1490 int next_idx = (track_ridx + 1) & MAX_TRACK_MASK;
1491 tracks[next_idx].taginfo_ready = (tracks[next_idx].id3_hid >= 0);
1493 /* Reset current position */
1494 curtrack_id3.elapsed = 0;
1495 curtrack_id3.offset = 0;
1497 /* Update the codec API */
1498 ci.filesize = CUR_TI->filesize;
1499 ci.id3 = &curtrack_id3;
1500 ci.curpos = 0;
1501 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1504 static void buffering_audio_callback(enum callback_event ev, int value)
1506 (void)value;
1507 logf("buffering_audio_callback");
1509 switch (ev)
1511 case EVENT_BUFFER_LOW:
1512 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1513 queue_remove_from_head(&audio_queue, Q_AUDIO_FILL_BUFFER);
1514 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1515 break;
1517 case EVENT_HANDLE_REBUFFER:
1518 LOGFQUEUE("audio >| audio Q_AUDIO_FLUSH");
1519 queue_send(&audio_queue, Q_AUDIO_FLUSH, 0);
1520 break;
1522 case EVENT_HANDLE_FINISHED:
1523 logf("handle %d finished buffering", value);
1524 strip_tags(value);
1525 break;
1527 default:
1528 break;
1532 /* Clear tracks between write and read, non inclusive */
1533 static void audio_clear_track_entries(bool clear_unbuffered)
1535 int cur_idx = track_widx;
1537 logf("Clearing tracks:%d/%d, %d", track_ridx, track_widx, clear_unbuffered);
1539 /* Loop over all tracks from write-to-read */
1540 while (1)
1542 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
1544 if (cur_idx == track_ridx)
1545 break;
1547 /* If the track is buffered, conditionally clear/notify,
1548 * otherwise clear the track if that option is selected */
1549 if (tracks[cur_idx].event_sent || clear_unbuffered)
1550 clear_track_info(&tracks[cur_idx]);
1554 /* Clear all tracks */
1555 static bool audio_release_tracks(void)
1557 int i, cur_idx;
1559 logf("releasing all tracks");
1561 for(i = 0; i < MAX_TRACK; i++)
1563 cur_idx = (track_ridx + i) & MAX_TRACK_MASK;
1564 if (!clear_track_info(&tracks[cur_idx]))
1565 return false;
1568 return true;
1571 static bool audio_loadcodec(bool start_play)
1573 int prev_track;
1574 char codec_path[MAX_PATH]; /* Full path to codec */
1576 if (tracks[track_widx].id3_hid < 0) {
1577 return false;
1580 const char * codec_fn =
1581 get_codec_filename(bufgetid3(tracks[track_widx].id3_hid)->codectype);
1582 if (codec_fn == NULL)
1583 return false;
1585 tracks[track_widx].codec_hid = -1;
1587 if (start_play)
1589 /* Load the codec directly from disk and save some memory. */
1590 track_ridx = track_widx;
1591 ci.filesize = CUR_TI->filesize;
1592 ci.id3 = &curtrack_id3;
1593 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1594 ci.curpos = 0;
1595 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1596 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (intptr_t)codec_fn);
1597 return true;
1599 else
1601 /* If we already have another track than this one buffered */
1602 if (track_widx != track_ridx)
1604 prev_track = (track_widx - 1) & MAX_TRACK_MASK;
1606 /* If the previous codec is the same as this one, there is no need
1607 * to put another copy of it on the file buffer */
1608 if (get_codec_base_type(
1609 bufgetid3(tracks[track_widx].id3_hid)->codectype) ==
1610 get_codec_base_type(
1611 bufgetid3(tracks[prev_track].id3_hid)->codectype)
1612 && audio_codec_loaded)
1614 logf("Reusing prev. codec");
1615 return true;
1620 codec_get_full_path(codec_path, codec_fn);
1622 tracks[track_widx].codec_hid = bufopen(codec_path, 0, TYPE_CODEC);
1623 if (tracks[track_widx].codec_hid < 0)
1624 return false;
1626 logf("Loaded codec");
1628 return true;
1631 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
1632 static void audio_set_elapsed(struct mp3entry* id3)
1634 unsigned long offset = id3->offset > id3->first_frame_offset ?
1635 id3->offset - id3->first_frame_offset : 0;
1637 if ( id3->vbr ) {
1638 if ( id3->has_toc ) {
1639 /* calculate elapsed time using TOC */
1640 int i;
1641 unsigned int remainder, plen, relpos, nextpos;
1643 /* find wich percent we're at */
1644 for (i=0; i<100; i++ )
1645 if ( offset < id3->toc[i] * (id3->filesize / 256) )
1646 break;
1648 i--;
1649 if (i < 0)
1650 i = 0;
1652 relpos = id3->toc[i];
1654 if (i < 99)
1655 nextpos = id3->toc[i+1];
1656 else
1657 nextpos = 256;
1659 remainder = offset - (relpos * (id3->filesize / 256));
1661 /* set time for this percent (divide before multiply to prevent
1662 overflow on long files. loss of precision is negligible on
1663 short files) */
1664 id3->elapsed = i * (id3->length / 100);
1666 /* calculate remainder time */
1667 plen = (nextpos - relpos) * (id3->filesize / 256);
1668 id3->elapsed += (((remainder * 100) / plen) *
1669 (id3->length / 10000));
1671 else {
1672 /* no TOC exists. set a rough estimate using average bitrate */
1673 int tpk = id3->length /
1674 ((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
1675 1024);
1676 id3->elapsed = offset / 1024 * tpk;
1679 else
1681 /* constant bitrate, use exact calculation */
1682 if (id3->bitrate != 0)
1683 id3->elapsed = offset / (id3->bitrate / 8);
1687 /* Load one track by making the appropriate bufopen calls. Return true if
1688 everything required was loaded correctly, false if not. */
1689 static bool audio_load_track(int offset, bool start_play)
1691 char *trackname;
1692 char msgbuf[80];
1693 int fd = -1;
1694 int file_offset = 0;
1695 struct mp3entry id3;
1697 /* Stop buffer filling if there is no free track entries.
1698 Don't fill up the last track entry (we wan't to store next track
1699 metadata there). */
1700 if (!audio_free_track_count())
1702 logf("No free tracks");
1703 return false;
1706 last_peek_offset++;
1707 tracks[track_widx].taginfo_ready = false;
1709 peek_again:
1710 logf("Buffering track:%d/%d", track_widx, track_ridx);
1711 /* Get track name from current playlist read position. */
1712 while ((trackname = playlist_peek(last_peek_offset)) != NULL)
1714 /* Handle broken playlists. */
1715 fd = open(trackname, O_RDONLY);
1716 if (fd < 0)
1718 logf("Open failed");
1719 /* Skip invalid entry from playlist. */
1720 playlist_skip_entry(NULL, last_peek_offset);
1722 else
1723 break;
1726 if (!trackname)
1728 logf("End-of-playlist");
1729 playlist_end = true;
1730 memset(&lasttrack_id3, 0, sizeof(struct mp3entry));
1731 return false;
1734 tracks[track_widx].filesize = filesize(fd);
1736 if ((unsigned)offset > tracks[track_widx].filesize)
1737 offset = 0;
1739 /* Set default values */
1740 if (start_play)
1742 buf_set_watermark(AUDIO_DEFAULT_WATERMARK);
1743 dsp_configure(ci.dsp, DSP_RESET, 0);
1744 track_changed = true;
1745 playlist_update_resume_info(audio_current_track());
1748 /* Get track metadata if we don't already have it. */
1749 if (tracks[track_widx].id3_hid < 0)
1751 if (get_metadata(&id3, fd, trackname))
1753 if (track_buffer_callback)
1754 track_buffer_callback(&id3);
1756 tracks[track_widx].id3_hid =
1757 bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3);
1759 if (tracks[track_widx].id3_hid < 0)
1761 last_peek_offset--;
1762 close(fd);
1763 copy_mp3entry(&lasttrack_id3, &id3);
1764 return false;
1767 if (track_widx == track_ridx)
1768 copy_mp3entry(&curtrack_id3, &id3);
1770 if (start_play)
1772 track_changed = true;
1773 playlist_update_resume_info(audio_current_track());
1776 else
1778 logf("mde:%s!",trackname);
1780 /* Skip invalid entry from playlist. */
1781 playlist_skip_entry(NULL, last_peek_offset);
1782 close(fd);
1783 goto peek_again;
1788 close(fd);
1790 #if 0
1791 if (cuesheet_is_enabled() && tracks[track_widx].id3.cuesheet_type == 1)
1793 char cuepath[MAX_PATH];
1795 struct cuesheet *cue = start_play ? curr_cue : temp_cue;
1797 if (look_for_cuesheet_file(trackname, cuepath) &&
1798 parse_cuesheet(cuepath, cue))
1800 strcpy((cue)->audio_filename, trackname);
1801 if (start_play)
1802 cue_spoof_id3(curr_cue, &tracks[track_widx].id3);
1805 #endif
1807 struct mp3entry *track_id3;
1809 if (track_widx == track_ridx)
1810 track_id3 = &curtrack_id3;
1811 else
1812 track_id3 = bufgetid3(tracks[track_widx].id3_hid);
1814 #ifdef HAVE_ALBUMART
1815 if (tracks[track_widx].aa_hid < 0 && gui_sync_wps_uses_albumart())
1817 char aa_path[MAX_PATH];
1818 if (find_albumart(track_id3, aa_path, sizeof(aa_path)))
1819 tracks[track_widx].aa_hid = bufopen(aa_path, 0, TYPE_BITMAP);
1821 #endif
1823 /* Load the codec. */
1824 if (!audio_loadcodec(start_play))
1826 if (tracks[track_widx].codec_hid == ERR_BUFFER_FULL)
1828 /* No space for codec on buffer, not an error */
1829 return false;
1832 /* This is an error condition, either no codec was found, or reading
1833 * the codec file failed part way through, either way, skip the track */
1834 snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname);
1835 /* We should not use gui_syncplash from audio thread! */
1836 gui_syncsplash(HZ*2, msgbuf);
1837 /* Skip invalid entry from playlist. */
1838 playlist_skip_entry(NULL, last_peek_offset);
1839 goto peek_again;
1842 track_id3->elapsed = 0;
1844 enum data_type type = TYPE_PACKET_AUDIO;
1846 switch (track_id3->codectype) {
1847 case AFMT_MPA_L1:
1848 case AFMT_MPA_L2:
1849 case AFMT_MPA_L3:
1850 if (offset > 0) {
1851 file_offset = offset;
1852 track_id3->offset = offset;
1853 audio_set_elapsed(track_id3);
1855 break;
1857 case AFMT_WAVPACK:
1858 if (offset > 0) {
1859 file_offset = offset;
1860 track_id3->offset = offset;
1861 track_id3->elapsed = track_id3->length / 2;
1863 break;
1865 case AFMT_OGG_VORBIS:
1866 case AFMT_SPEEX:
1867 case AFMT_FLAC:
1868 case AFMT_PCM_WAV:
1869 case AFMT_A52:
1870 case AFMT_AAC:
1871 case AFMT_MPC:
1872 case AFMT_APE:
1873 if (offset > 0)
1874 track_id3->offset = offset;
1875 break;
1877 case AFMT_NSF:
1878 case AFMT_SPC:
1879 case AFMT_SID:
1880 logf("Loading atomic %d",track_id3->codectype);
1881 type = TYPE_ATOMIC_AUDIO;
1882 break;
1885 logf("alt:%s", trackname);
1887 if (file_offset > AUDIO_REBUFFER_GUESS_SIZE)
1888 file_offset -= AUDIO_REBUFFER_GUESS_SIZE;
1889 else if (track_id3->first_frame_offset)
1890 file_offset = track_id3->first_frame_offset;
1891 else
1892 file_offset = 0;
1894 tracks[track_widx].audio_hid = bufopen(trackname, file_offset, type);
1896 if (tracks[track_widx].audio_hid < 0)
1897 return false;
1899 /* All required data is now available for the codec. */
1900 tracks[track_widx].taginfo_ready = true;
1902 if (start_play)
1904 ci.curpos=file_offset;
1905 buf_request_buffer_handle(tracks[track_widx].audio_hid);
1908 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
1910 return true;
1913 /* Send callback events to notify about new tracks. */
1914 static void audio_generate_postbuffer_events(void)
1916 int cur_idx;
1918 logf("Postbuffer:%d/%d",track_ridx,track_widx);
1920 if (audio_have_tracks())
1922 cur_idx = track_ridx;
1924 while (1) {
1925 if (!tracks[cur_idx].event_sent)
1927 /* Mark the event 'sent' even if we don't really send one */
1928 tracks[cur_idx].event_sent = true;
1930 if (cur_idx == track_widx)
1931 break;
1932 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
1937 static void audio_fill_file_buffer(bool start_play, size_t offset)
1939 struct queue_event ev;
1940 bool had_next_track = audio_next_track() != NULL;
1941 bool continue_buffering;
1943 /* No need to rebuffer if there are track skips pending. */
1944 if (ci.new_track != 0)
1945 return;
1947 /* Must reset the buffer before use if trashed or voice only - voice
1948 file size shouldn't have changed so we can go straight from
1949 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
1950 if (buffer_state != BUFFER_STATE_INITIALIZED)
1951 audio_reset_buffer();
1953 logf("Starting buffer fill");
1955 if (!start_play)
1956 audio_clear_track_entries(false);
1958 /* Save the current resume position once. */
1959 playlist_update_resume_info(audio_current_track());
1961 do {
1962 continue_buffering = audio_load_track(offset, start_play);
1963 start_play = false;
1964 offset = 0;
1965 sleep(1);
1966 if (queue_peek(&audio_queue, &ev)) {
1967 if (ev.id != Q_AUDIO_FILL_BUFFER)
1969 /* There's a message in the queue. break the loop to treat it,
1970 and go back to filling after that. */
1971 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1972 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1974 break;
1976 } while (continue_buffering);
1978 if (!had_next_track && audio_next_track())
1979 track_changed = true;
1981 audio_generate_postbuffer_events();
1984 static void audio_rebuffer(void)
1986 logf("Forcing rebuffer");
1988 clear_track_info(CUR_TI);
1990 /* Reset track pointers */
1991 track_widx = track_ridx;
1992 audio_clear_track_entries(true);
1994 /* Fill the buffer */
1995 last_peek_offset = -1;
1996 ci.curpos = 0;
1998 if (!CUR_TI->taginfo_ready)
1999 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
2001 audio_fill_file_buffer(false, 0);
2004 /* Called on request from the codec to get a new track. This is the codec part
2005 of the track transition. */
2006 static int audio_check_new_track(void)
2008 int track_count = audio_track_count();
2009 int old_track_ridx = track_ridx;
2010 int i, idx;
2011 int next_playlist_index;
2012 bool forward;
2013 bool end_of_playlist; /* Temporary flag, not the same as playlist_end */
2015 if (dir_skip)
2017 dir_skip = false;
2018 if (playlist_next_dir(ci.new_track))
2020 ci.new_track = 0;
2021 audio_rebuffer();
2022 goto skip_done;
2024 else
2026 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2027 return Q_CODEC_REQUEST_FAILED;
2031 if (new_playlist)
2032 ci.new_track = 0;
2034 end_of_playlist = playlist_peek(automatic_skip ? ci.new_track : 0) == NULL;
2035 auto_dir_skip = end_of_playlist && global_settings.next_folder;
2037 /* If the playlist isn't that big */
2038 if (automatic_skip && !playlist_check(ci.new_track))
2040 if (ci.new_track >= 0)
2042 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2043 return Q_CODEC_REQUEST_FAILED;
2045 /* Find the beginning backward if the user over-skips it */
2046 while (!playlist_check(++ci.new_track))
2047 if (ci.new_track >= 0)
2049 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2050 return Q_CODEC_REQUEST_FAILED;
2054 /* Update the playlist */
2055 last_peek_offset -= ci.new_track;
2057 if (auto_dir_skip)
2059 /* If the track change was the result of an auto dir skip,
2060 we need to update the playlist now */
2061 next_playlist_index = playlist_next(ci.new_track);
2063 if (next_playlist_index < 0)
2065 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2066 return Q_CODEC_REQUEST_FAILED;
2070 if (new_playlist)
2072 ci.new_track = 1;
2073 new_playlist = false;
2076 /* Save the track metadata to allow the WPS to display it
2077 while PCM finishes playing that track */
2078 copy_mp3entry(&prevtrack_id3, &curtrack_id3);
2080 /* Update the main buffer copy of the track metadata with the one
2081 the codec has been using (for the unbuffer callbacks) */
2082 if (CUR_TI->id3_hid >= 0)
2083 copy_mp3entry(bufgetid3(CUR_TI->id3_hid), &curtrack_id3);
2085 /* Save a pointer to the old track to allow later clearing */
2086 prev_ti = CUR_TI;
2088 for (i = 0; i < ci.new_track; i++)
2090 idx = (track_ridx + i) & MAX_TRACK_MASK;
2091 struct mp3entry *id3 = bufgetid3(tracks[idx].id3_hid);
2092 ssize_t offset = buf_handle_offset(tracks[idx].audio_hid);
2093 if (!id3 || offset < 0 || (unsigned)offset > id3->first_frame_offset)
2095 /* We don't have all the audio data for that track, so clear it,
2096 but keep the metadata. */
2097 if (tracks[idx].audio_hid >= 0 && bufclose(tracks[idx].audio_hid))
2099 tracks[idx].audio_hid = -1;
2100 tracks[idx].filesize = 0;
2105 /* Move to the new track */
2106 track_ridx = (track_ridx + ci.new_track) & MAX_TRACK_MASK;
2108 buf_set_base_handle(CUR_TI->audio_hid);
2110 if (automatic_skip)
2112 playlist_end = false;
2113 wps_offset = -ci.new_track;
2114 track_changed = true;
2117 /* If it is not safe to even skip this many track entries */
2118 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
2120 ci.new_track = 0;
2121 audio_rebuffer();
2122 goto skip_done;
2125 forward = ci.new_track > 0;
2126 ci.new_track = 0;
2128 /* If the target track is clearly not in memory */
2129 if (CUR_TI->filesize == 0 || !CUR_TI->taginfo_ready)
2131 audio_rebuffer();
2132 goto skip_done;
2135 /* When skipping backwards, it is possible that we've found a track that's
2136 * buffered, but which is around the track-wrap and therefor not the track
2137 * we are looking for */
2138 if (!forward)
2140 int cur_idx = track_ridx;
2141 bool taginfo_ready = true;
2142 /* We've wrapped the buffer backwards if new > old */
2143 bool wrap = track_ridx > old_track_ridx;
2145 while (1)
2147 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
2149 /* if we've advanced past the wrap when cur_idx is zeroed */
2150 if (!cur_idx)
2151 wrap = false;
2153 /* if we aren't still on the wrap and we've caught the old track */
2154 if (!(wrap || cur_idx < old_track_ridx))
2155 break;
2157 /* If we hit a track in between without valid tag info, bail */
2158 if (!tracks[cur_idx].taginfo_ready)
2160 taginfo_ready = false;
2161 break;
2164 if (!taginfo_ready)
2166 audio_rebuffer();
2170 skip_done:
2171 audio_update_trackinfo();
2172 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2173 return Q_CODEC_REQUEST_COMPLETE;
2176 void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3))
2178 track_buffer_callback = handler;
2181 void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3))
2183 track_unbuffer_callback = handler;
2186 void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3))
2188 track_changed_callback = handler;
2191 unsigned long audio_prev_elapsed(void)
2193 return prev_track_elapsed;
2196 static void audio_stop_codec_flush(void)
2198 ci.stop_codec = true;
2199 pcmbuf_pause(true);
2201 while (audio_codec_loaded)
2202 yield();
2204 /* If the audio codec is not loaded any more, and the audio is still
2205 * playing, it is now and _only_ now safe to call this function from the
2206 * audio thread */
2207 if (pcm_is_playing())
2209 pcmbuf_play_stop();
2210 pcmbuf_queue_clear();
2212 pcmbuf_pause(paused);
2215 static void audio_stop_playback(void)
2217 /* If we were playing, save resume information */
2218 if (playing)
2220 struct mp3entry *id3 = NULL;
2222 if (!playlist_end || !ci.stop_codec)
2224 /* Set this early, the outside code yields and may allow the codec
2225 to try to wait for a reply on a buffer wait */
2226 ci.stop_codec = true;
2227 id3 = audio_current_track();
2230 /* Save the current playing spot, or NULL if the playlist has ended */
2231 playlist_update_resume_info(id3);
2233 /* TODO: Create auto bookmark too? */
2235 prev_track_elapsed = curtrack_id3.elapsed;
2237 /* At end of playlist save current id3 (id3.elapsed!) to buffer and
2238 * Increment index so runtime info is saved in audio_clear_track_entries().
2240 if ((playlist_end) && (tracks[track_ridx].id3_hid >= 0)) {
2241 copy_mp3entry(bufgetid3(tracks[track_ridx].id3_hid), &curtrack_id3);
2242 track_ridx = (track_ridx + 1) & MAX_TRACK_MASK;
2246 paused = false;
2247 audio_stop_codec_flush();
2248 playing = false;
2250 /* Mark all entries null. */
2251 audio_clear_track_entries(false);
2253 /* Close all tracks */
2254 audio_release_tracks();
2256 unregister_buffering_callback(buffering_audio_callback);
2258 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
2261 static void audio_play_start(size_t offset)
2263 int i;
2265 #if INPUT_SRC_CAPS != 0
2266 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2267 audio_set_output_source(AUDIO_SRC_PLAYBACK);
2268 #endif
2270 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2271 paused = false;
2272 audio_stop_codec_flush();
2274 track_changed = true;
2275 playlist_end = false;
2277 playing = true;
2279 ci.new_track = 0;
2280 ci.seek_time = 0;
2281 wps_offset = 0;
2283 sound_set_volume(global_settings.volume);
2284 track_widx = track_ridx = 0;
2286 /* Clear all track entries. */
2287 for (i = 0; i < MAX_TRACK; i++) {
2288 clear_track_info(&tracks[i]);
2291 last_peek_offset = -1;
2293 /* Officially playing */
2294 queue_reply(&audio_queue, 1);
2296 #ifndef HAVE_FLASH_STORAGE
2297 set_filebuf_watermark(buffer_margin, 0);
2298 #endif
2299 audio_fill_file_buffer(true, offset);
2300 register_buffering_callback(buffering_audio_callback);
2302 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2303 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
2307 /* Invalidates all but currently playing track. */
2308 static void audio_invalidate_tracks(void)
2310 if (audio_have_tracks())
2312 last_peek_offset = 0;
2313 playlist_end = false;
2314 track_widx = track_ridx;
2316 /* Mark all other entries null (also buffered wrong metadata). */
2317 audio_clear_track_entries(true);
2319 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2321 audio_fill_file_buffer(false, 0);
2325 static void audio_new_playlist(void)
2327 /* Prepare to start a new fill from the beginning of the playlist */
2328 last_peek_offset = -1;
2329 if (audio_have_tracks())
2331 if (paused)
2332 skipped_during_pause = true;
2333 playlist_end = false;
2334 track_widx = track_ridx;
2335 audio_clear_track_entries(true);
2337 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2339 /* Mark the current track as invalid to prevent skipping back to it */
2340 CUR_TI->taginfo_ready = false;
2343 /* Signal the codec to initiate a track change forward */
2344 new_playlist = true;
2345 ci.new_track = 1;
2347 /* Officially playing */
2348 queue_reply(&audio_queue, 1);
2350 audio_fill_file_buffer(false, 0);
2353 /* Called on manual track skip */
2354 static void audio_initiate_track_change(long direction)
2356 logf("audio_initiate_track_change(%ld)", direction);
2358 playlist_end = false;
2359 ci.new_track += direction;
2360 wps_offset -= direction;
2361 if (paused)
2362 skipped_during_pause = true;
2365 /* Called on manual dir skip */
2366 static void audio_initiate_dir_change(long direction)
2368 playlist_end = false;
2369 dir_skip = true;
2370 ci.new_track = direction;
2371 if (paused)
2372 skipped_during_pause = true;
2375 /* Called when PCM track change is complete */
2376 static void audio_finalise_track_change(void)
2378 logf("audio_finalise_track_change");
2380 if (automatic_skip)
2382 if (!auto_dir_skip)
2383 playlist_next(-wps_offset);
2385 wps_offset = 0;
2386 automatic_skip = false;
2389 auto_dir_skip = false;
2391 /* Invalidate prevtrack_id3 */
2392 prevtrack_id3.path[0] = 0;
2394 if (prev_ti && prev_ti->audio_hid < 0)
2396 /* No audio left so we clear all the track info. */
2397 clear_track_info(prev_ti);
2400 if (prev_ti && prev_ti->id3_hid >= 0)
2402 /* Reset the elapsed time to force the progressbar to be empty if
2403 the user skips back to this track */
2404 bufgetid3(prev_ti->id3_hid)->elapsed = 0;
2407 if (track_changed_callback)
2408 track_changed_callback(&curtrack_id3);
2410 track_changed = true;
2411 playlist_update_resume_info(audio_current_track());
2415 * Layout audio buffer as follows - iram buffer depends on target:
2416 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
2418 static void audio_reset_buffer(void)
2420 /* see audio_get_recording_buffer if this is modified */
2421 logf("audio_reset_buffer");
2423 /* If the setup of anything allocated before the file buffer is
2424 changed, do check the adjustments after the buffer_alloc call
2425 as it will likely be affected and need sliding over */
2427 /* Initially set up file buffer as all space available */
2428 malloc_buf = audiobuf + talk_get_bufsize();
2429 /* Align the malloc buf to line size. Especially important to cf
2430 targets that do line reads/writes. */
2431 malloc_buf = (unsigned char *)(((uintptr_t)malloc_buf + 15) & ~15);
2432 filebuf = malloc_buf + MALLOC_BUFSIZE; /* filebuf line align implied */
2433 filebuflen = audiobufend - filebuf;
2435 filebuflen &= ~15;
2437 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
2438 filebuflen -= pcmbuf_init(filebuf + filebuflen) + GUARD_BUFSIZE;
2440 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
2441 will already be line aligned */
2442 filebuflen &= ~3;
2444 buffering_reset(filebuf, filebuflen);
2446 /* Clear any references to the file buffer */
2447 buffer_state = BUFFER_STATE_INITIALIZED;
2449 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
2450 /* Make sure everything adds up - yes, some info is a bit redundant but
2451 aids viewing and the sumation of certain variables should add up to
2452 the location of others. */
2454 size_t pcmbufsize;
2455 unsigned char * pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
2456 logf("mabuf: %08X", (unsigned)malloc_buf);
2457 logf("mabufe: %08X", (unsigned)(malloc_buf + MALLOC_BUFSIZE));
2458 logf("fbuf: %08X", (unsigned)filebuf);
2459 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
2460 logf("gbuf: %08X", (unsigned)(filebuf + filebuflen));
2461 logf("gbufe: %08X", (unsigned)(filebuf + filebuflen + GUARD_BUFSIZE));
2462 logf("pcmb: %08X", (unsigned)pcmbuf);
2463 logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
2465 #endif
2468 static void audio_thread(void)
2470 struct queue_event ev;
2472 pcm_postinit();
2474 audio_thread_ready = true;
2476 while (1)
2478 cancel_cpu_boost();
2479 if (!pcmbuf_queue_scan(&ev))
2480 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
2482 switch (ev.id) {
2483 case Q_AUDIO_FILL_BUFFER:
2484 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
2485 if (!playing || playlist_end || ci.stop_codec)
2486 break;
2487 audio_fill_file_buffer(false, 0);
2488 break;
2490 case Q_AUDIO_PLAY:
2491 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2492 if (playing && ev.data <= 0)
2493 audio_new_playlist();
2494 else
2496 audio_stop_playback();
2497 audio_play_start((size_t)ev.data);
2499 break;
2501 case Q_AUDIO_STOP:
2502 LOGFQUEUE("audio < Q_AUDIO_STOP");
2503 if (playing)
2504 audio_stop_playback();
2505 if (ev.data != 0)
2506 queue_clear(&audio_queue);
2507 break;
2509 case Q_AUDIO_PAUSE:
2510 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
2511 if (!(bool) ev.data && skipped_during_pause && !pcmbuf_is_crossfade_active())
2512 pcmbuf_play_stop(); /* Flush old track on resume after skip */
2513 skipped_during_pause = false;
2514 if (!playing)
2515 break;
2516 pcmbuf_pause((bool)ev.data);
2517 paused = (bool)ev.data;
2518 break;
2520 case Q_AUDIO_SKIP:
2521 LOGFQUEUE("audio < Q_AUDIO_SKIP");
2522 audio_initiate_track_change((long)ev.data);
2523 break;
2525 case Q_AUDIO_PRE_FF_REWIND:
2526 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
2527 if (!playing)
2528 break;
2529 pcmbuf_pause(true);
2530 break;
2532 case Q_AUDIO_FF_REWIND:
2533 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
2534 if (!playing)
2535 break;
2536 if (automatic_skip)
2538 /* An automatic track skip is in progress. Finalize it,
2539 then go back to the previous track */
2540 audio_finalise_track_change();
2541 ci.new_track = -1;
2543 ci.seek_time = (long)ev.data+1;
2544 break;
2546 case Q_AUDIO_CHECK_NEW_TRACK:
2547 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
2548 queue_reply(&audio_queue, audio_check_new_track());
2549 break;
2551 case Q_AUDIO_DIR_SKIP:
2552 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2553 playlist_end = false;
2554 audio_initiate_dir_change(ev.data);
2555 break;
2557 case Q_AUDIO_FLUSH:
2558 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
2559 audio_invalidate_tracks();
2560 break;
2562 case Q_AUDIO_TRACK_CHANGED:
2563 /* PCM track change done */
2564 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2565 audio_finalise_track_change();
2566 break;
2568 #ifndef SIMULATOR
2569 case SYS_USB_CONNECTED:
2570 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2571 if (playing)
2572 audio_stop_playback();
2573 #ifdef PLAYBACK_VOICE
2574 voice_stop();
2575 #endif
2576 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2577 usb_wait_for_disconnect(&audio_queue);
2579 /* Mark all entries null. */
2580 audio_clear_track_entries(false);
2582 /* release tracks to make sure all handles are closed */
2583 audio_release_tracks();
2584 break;
2585 #endif
2587 case SYS_TIMEOUT:
2588 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
2589 break;
2591 default:
2592 LOGFQUEUE("audio < default");
2593 break;
2594 } /* end switch */
2595 } /* end while */
2598 /* Initialize the audio system - called from init() in main.c.
2599 * Last function because of all the references to internal symbols
2601 void audio_init(void)
2603 struct thread_entry *audio_thread_p;
2605 /* Can never do this twice */
2606 if (audio_is_initialized)
2608 logf("audio: already initialized");
2609 return;
2612 logf("audio: initializing");
2614 /* Initialize queues before giving control elsewhere in case it likes
2615 to send messages. Thread creation will be delayed however so nothing
2616 starts running until ready if something yields such as talk_init. */
2617 queue_init(&audio_queue, true);
2618 queue_enable_queue_send(&audio_queue, &audio_queue_sender_list);
2619 queue_init(&codec_queue, false);
2620 queue_enable_queue_send(&codec_queue, &codec_queue_sender_list);
2621 queue_init(&pcmbuf_queue, false);
2623 pcm_init();
2625 /* Initialize codec api. */
2626 ci.read_filebuf = codec_filebuf_callback;
2627 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
2628 ci.get_codec_memory = codec_get_memory_callback;
2629 ci.request_buffer = codec_request_buffer_callback;
2630 ci.advance_buffer = codec_advance_buffer_callback;
2631 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
2632 ci.request_next_track = codec_request_next_track_callback;
2633 ci.mp3_get_filepos = codec_mp3_get_filepos_callback;
2634 ci.seek_buffer = codec_seek_buffer_callback;
2635 ci.seek_complete = codec_seek_complete_callback;
2636 ci.set_elapsed = codec_set_elapsed_callback;
2637 ci.set_offset = codec_set_offset_callback;
2638 ci.configure = codec_configure_callback;
2639 ci.discard_codec = codec_discard_codec_callback;
2640 ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP,
2641 CODEC_IDX_AUDIO);
2643 /* initialize the buffer */
2644 filebuf = audiobuf;
2646 /* audio_reset_buffer must to know the size of voice buffer so init
2647 talk first */
2648 talk_init();
2650 codec_thread_p = create_thread(
2651 codec_thread, codec_stack, sizeof(codec_stack),
2652 CREATE_THREAD_FROZEN,
2653 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
2654 IF_COP(, CPU));
2656 audio_thread_p = create_thread(audio_thread, audio_stack,
2657 sizeof(audio_stack), CREATE_THREAD_FROZEN,
2658 audio_thread_name IF_PRIO(, PRIORITY_SYSTEM)
2659 IF_COP(, CPU));
2661 #ifdef PLAYBACK_VOICE
2662 voice_thread_init();
2663 #endif
2665 /* Set crossfade setting for next buffer init which should be about... */
2666 pcmbuf_crossfade_enable(global_settings.crossfade);
2668 /* initialize the buffering system */
2670 buffering_init();
2671 /* ...now! Set up the buffers */
2672 audio_reset_buffer();
2674 int i;
2675 for(i = 0; i < MAX_TRACK; i++)
2677 tracks[i].audio_hid = -1;
2678 tracks[i].id3_hid = -1;
2679 tracks[i].codec_hid = -1;
2680 #ifdef HAVE_ALBUMART
2681 tracks[i].aa_hid = -1;
2682 #endif
2685 /* Probably safe to say */
2686 audio_is_initialized = true;
2688 sound_settings_apply();
2689 #ifndef HAVE_FLASH_STORAGE
2690 audio_set_buffer_margin(global_settings.buffer_margin);
2691 #endif
2693 /* it's safe to let the threads run now */
2694 #ifdef PLAYBACK_VOICE
2695 voice_thread_resume();
2696 #endif
2697 thread_thaw(codec_thread_p);
2698 thread_thaw(audio_thread_p);
2700 } /* audio_init */
2702 void audio_wait_for_init(void)
2704 /* audio thread will only set this once after it finished the final
2705 * audio hardware init so this little construct is safe - even
2706 * cross-core. */
2707 while (!audio_thread_ready)
2709 sleep(0);