fix red and remove tabs
[kugel-rb.git] / apps / playback.c
blob222af769b137855ef478e409914e5d13e77d13f8
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 "events.h"
45 #include "voice_thread.h"
46 #include "mp3_playback.h"
47 #include "usb.h"
48 #include "status.h"
49 #include "ata.h"
50 #include "screens.h"
51 #include "playlist.h"
52 #include "playback.h"
53 #include "pcmbuf.h"
54 #include "buffer.h"
55 #include "dsp.h"
56 #include "abrepeat.h"
57 #include "cuesheet.h"
58 #ifdef HAVE_TAGCACHE
59 #include "tagcache.h"
60 #endif
61 #ifdef HAVE_LCD_BITMAP
62 #include "icons.h"
63 #include "peakmeter.h"
64 #include "action.h"
65 #include "albumart.h"
66 #endif
67 #include "lang.h"
68 #include "bookmark.h"
69 #include "misc.h"
70 #include "sound.h"
71 #include "metadata.h"
72 #include "splash.h"
73 #include "talk.h"
74 #include "ata_idle_notify.h"
76 #ifdef HAVE_RECORDING
77 #include "recording.h"
78 #include "talk.h"
79 #endif
81 #define PLAYBACK_VOICE
83 /* default point to start buffer refill */
84 #define AUDIO_DEFAULT_WATERMARK (1024*512)
85 /* amount of guess-space to allow for codecs that must hunt and peck
86 * for their correct seeek target, 32k seems a good size */
87 #define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
89 /* Define LOGF_ENABLE to enable logf output in this file */
90 /*#define LOGF_ENABLE*/
91 #include "logf.h"
93 /* macros to enable logf for queues
94 logging on SYS_TIMEOUT can be disabled */
95 #ifdef SIMULATOR
96 /* Define this for logf output of all queuing except SYS_TIMEOUT */
97 #define PLAYBACK_LOGQUEUES
98 /* Define this to logf SYS_TIMEOUT messages */
99 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
100 #endif
102 #ifdef PLAYBACK_LOGQUEUES
103 #define LOGFQUEUE logf
104 #else
105 #define LOGFQUEUE(...)
106 #endif
108 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
109 #define LOGFQUEUE_SYS_TIMEOUT logf
110 #else
111 #define LOGFQUEUE_SYS_TIMEOUT(...)
112 #endif
115 /* Define one constant that includes recording related functionality */
116 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
117 #define AUDIO_HAVE_RECORDING
118 #endif
120 enum {
121 Q_NULL = 0,
122 Q_AUDIO_PLAY = 1,
123 Q_AUDIO_STOP,
124 Q_AUDIO_PAUSE,
125 Q_AUDIO_SKIP,
126 Q_AUDIO_PRE_FF_REWIND,
127 Q_AUDIO_FF_REWIND,
128 Q_AUDIO_CHECK_NEW_TRACK,
129 Q_AUDIO_FLUSH,
130 Q_AUDIO_TRACK_CHANGED,
131 Q_AUDIO_DIR_SKIP,
132 Q_AUDIO_POSTINIT,
133 Q_AUDIO_FILL_BUFFER,
134 Q_AUDIO_FINISH_LOAD,
135 Q_CODEC_REQUEST_COMPLETE,
136 Q_CODEC_REQUEST_FAILED,
138 Q_CODEC_LOAD,
139 Q_CODEC_LOAD_DISK,
141 #ifdef AUDIO_HAVE_RECORDING
142 Q_ENCODER_LOAD_DISK,
143 Q_ENCODER_RECORD,
144 #endif
147 enum filling_state {
148 STATE_IDLE, /* audio is stopped: nothing to do */
149 STATE_FILLING, /* adding tracks to the buffer */
150 STATE_FULL, /* can't add any more tracks */
151 STATE_FINISHED, /* all remaining tracks have been added */
154 /* As defined in plugins/lib/xxx2wav.h */
155 #if MEM > 1
156 #define MALLOC_BUFSIZE (512*1024)
157 #define GUARD_BUFSIZE (32*1024)
158 #else
159 #define MALLOC_BUFSIZE (100*1024)
160 #define GUARD_BUFSIZE (8*1024)
161 #endif
163 /* As defined in plugin.lds */
164 #if defined(CPU_PP)
165 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
166 #define CODEC_IRAM_SIZE ((size_t)0xc000)
167 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
168 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
169 #define CODEC_IRAM_SIZE ((size_t)0x10000)
170 #else
171 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
172 #define CODEC_IRAM_SIZE ((size_t)0xc000)
173 #endif
175 bool audio_is_initialized = false;
176 static bool audio_thread_ready SHAREDBSS_ATTR = false;
178 /* Variables are commented with the threads that use them: *
179 * A=audio, C=codec, V=voice. A suffix of - indicates that *
180 * the variable is read but not updated on that thread. */
181 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
183 /* Main state control */
184 static volatile bool audio_codec_loaded SHAREDBSS_ATTR = false; /* Codec loaded? (C/A-) */
185 static volatile bool playing SHAREDBSS_ATTR = false; /* Is audio playing? (A) */
186 static volatile bool paused SHAREDBSS_ATTR = false; /* Is audio paused? (A/C-) */
188 /* Ring buffer where compressed audio and codecs are loaded */
189 static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */
190 static unsigned char *malloc_buf = NULL; /* Start of malloc buffer (A/C-) */
191 /* FIXME: make filebuflen static */
192 size_t filebuflen = 0; /* Size of buffer (A/C-) */
193 /* FIXME: make buf_ridx (C/A-) */
195 /* Possible arrangements of the buffer */
196 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
197 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
198 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
199 static int buffer_state = BUFFER_STATE_TRASHED; /* Buffer state */
201 /* Used to keep the WPS up-to-date during track transtition */
202 static struct mp3entry prevtrack_id3;
204 /* Used to provide the codec with a pointer */
205 static struct mp3entry curtrack_id3;
207 /* Used to make next track info available while playing last track on buffer */
208 static struct mp3entry lasttrack_id3;
210 /* Track info structure about songs in the file buffer (A/C-) */
211 struct track_info {
212 int audio_hid; /* The ID for the track's buffer handle */
213 int id3_hid; /* The ID for the track's metadata handle */
214 int codec_hid; /* The ID for the track's codec handle */
215 #ifdef HAVE_ALBUMART
216 int aa_hid; /* The ID for the track's album art handle */
217 #endif
219 size_t filesize; /* File total length */
221 bool taginfo_ready; /* Is metadata read */
224 static struct track_info tracks[MAX_TRACK];
225 static volatile int track_ridx = 0; /* Track being decoded (A/C-) */
226 static int track_widx = 0; /* Track being buffered (A) */
228 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
229 static struct track_info *prev_ti = NULL; /* Pointer to the previously played
230 track */
232 /* Set by the audio thread when the current track information has updated
233 * and the WPS may need to update its cached information */
234 static bool track_changed = false;
236 /* Information used only for filling the buffer */
237 /* Playlist steps from playing track to next track to be buffered (A) */
238 static int last_peek_offset = 0;
240 /* Scrobbler support */
241 static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/
243 static enum filling_state filling;
245 /* Track change controls */
246 static bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */
247 static bool dir_skip = false; /* Is a directory skip pending? (A) */
248 static bool new_playlist = false; /* Are we starting a new playlist? (A) */
249 static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */
250 static bool skipped_during_pause = false; /* Do we need to clear the PCM buffer when playback resumes (A) */
252 static bool start_play_g = false; /* Used by audio_load_track to notify
253 audio_finish_load_track about start_play */
255 /* Set to true if the codec thread should send an audio stop request
256 * (typically because the end of the playlist has been reached).
258 static bool codec_requested_stop = false;
260 static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */
262 /* Multiple threads */
263 /* Set the watermark to trigger buffer fill (A/C) FIXME */
264 static void set_filebuf_watermark(int seconds, size_t max);
266 /* Audio thread */
267 static struct event_queue audio_queue SHAREDBSS_ATTR;
268 static struct queue_sender_list audio_queue_sender_list SHAREDBSS_ATTR;
269 static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
270 static const char audio_thread_name[] = "audio";
272 static void audio_thread(void);
273 static void audio_initiate_track_change(long direction);
274 static bool audio_have_tracks(void);
275 static void audio_reset_buffer(void);
277 /* Codec thread */
278 extern struct codec_api ci;
279 static struct event_queue codec_queue SHAREDBSS_ATTR;
280 static struct queue_sender_list codec_queue_sender_list;
281 static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
282 IBSS_ATTR;
283 static const char codec_thread_name[] = "codec";
284 struct thread_entry *codec_thread_p; /* For modifying thread priority later. */
286 /* PCM buffer messaging */
287 static struct event_queue pcmbuf_queue SHAREDBSS_ATTR;
289 /* Function to be called by pcm buffer callbacks.
290 * Permissible Context(s): Audio interrupt
292 static void pcmbuf_callback_queue_post(long id, intptr_t data)
294 /* No lock since we're already in audio interrupt context */
295 queue_post(&pcmbuf_queue, id, data);
298 /* Scan the pcmbuf queue and return true if a message pulled.
299 * Permissible Context(s): Thread
301 static bool pcmbuf_queue_scan(struct queue_event *ev)
303 if (!queue_empty(&pcmbuf_queue))
305 /* Transfer message to audio queue */
306 pcm_play_lock();
307 /* Pull message - never, ever any blocking call! */
308 queue_wait_w_tmo(&pcmbuf_queue, ev, 0);
309 pcm_play_unlock();
310 return true;
313 return false;
316 /* Clear the pcmbuf queue of messages
317 * Permissible Context(s): Thread
319 static void pcmbuf_queue_clear(void)
321 pcm_play_lock();
322 queue_clear(&pcmbuf_queue);
323 pcm_play_unlock();
326 /* --- Helper functions --- */
328 static struct mp3entry *bufgetid3(int handle_id)
330 if (handle_id < 0)
331 return NULL;
333 struct mp3entry *id3;
334 ssize_t ret = bufgetdata(handle_id, 0, (void *)&id3);
336 if (ret < 0 || ret != sizeof(struct mp3entry))
337 return NULL;
339 return id3;
342 static bool clear_track_info(struct track_info *track)
344 /* bufclose returns true if the handle is not found, or if it is closed
345 * successfully, so these checks are safe on non-existant handles */
346 if (!track)
347 return false;
349 if (track->codec_hid >= 0) {
350 if (bufclose(track->codec_hid))
351 track->codec_hid = -1;
352 else
353 return false;
356 if (track->id3_hid >= 0) {
357 if (bufclose(track->id3_hid))
358 track->id3_hid = -1;
359 else
360 return false;
363 if (track->audio_hid >= 0) {
364 if (bufclose(track->audio_hid))
365 track->audio_hid = -1;
366 else
367 return false;
370 #ifdef HAVE_ALBUMART
371 if (track->aa_hid >= 0) {
372 if (bufclose(track->aa_hid))
373 track->aa_hid = -1;
374 else
375 return false;
377 #endif
379 track->filesize = 0;
380 track->taginfo_ready = false;
382 return true;
385 /* --- External interfaces --- */
387 /* This sends a stop message and the audio thread will dump all it's
388 subsequenct messages */
389 void audio_hard_stop(void)
391 /* Stop playback */
392 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
393 queue_send(&audio_queue, Q_AUDIO_STOP, 1);
394 #ifdef PLAYBACK_VOICE
395 voice_stop();
396 #endif
399 bool audio_restore_playback(int type)
401 switch (type)
403 case AUDIO_WANT_PLAYBACK:
404 if (buffer_state != BUFFER_STATE_INITIALIZED)
405 audio_reset_buffer();
406 return true;
407 case AUDIO_WANT_VOICE:
408 if (buffer_state == BUFFER_STATE_TRASHED)
409 audio_reset_buffer();
410 return true;
411 default:
412 return false;
416 unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
418 unsigned char *buf, *end;
420 if (audio_is_initialized)
422 audio_hard_stop();
424 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
426 if (buffer_size == NULL)
428 /* Special case for talk_init to use since it already knows it's
429 trashed */
430 buffer_state = BUFFER_STATE_TRASHED;
431 return NULL;
434 if (talk_buf || buffer_state == BUFFER_STATE_TRASHED
435 || !talk_voice_required())
437 logf("get buffer: talk, audio");
438 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
439 the talk buffer is not needed because voice isn't being used, or
440 could be BUFFER_STATE_TRASHED already. If state is
441 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
442 without the caller knowing what's going on. Changing certain settings
443 may move it to a worse condition but the memory in use by something
444 else will remain undisturbed.
446 if (buffer_state != BUFFER_STATE_TRASHED)
448 talk_buffer_steal();
449 buffer_state = BUFFER_STATE_TRASHED;
452 buf = audiobuf;
453 end = audiobufend;
455 else
457 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
458 still BUFFER_STATE_INITIALIZED */
459 /* Skip talk buffer and move pcm buffer to end to maximize available
460 contiguous memory - no audio running means voice will not need the
461 swap space */
462 logf("get buffer: audio");
463 buf = audiobuf + talk_get_bufsize();
464 end = audiobufend - pcmbuf_init(audiobufend);
465 buffer_state = BUFFER_STATE_VOICED_ONLY;
468 *buffer_size = end - buf;
470 return buf;
473 #ifdef HAVE_RECORDING
474 unsigned char *audio_get_recording_buffer(size_t *buffer_size)
476 /* Stop audio, voice and obtain all available buffer space */
477 audio_hard_stop();
478 talk_buffer_steal();
480 unsigned char *end = audiobufend;
481 buffer_state = BUFFER_STATE_TRASHED;
482 *buffer_size = end - audiobuf;
484 return (unsigned char *)audiobuf;
487 bool audio_load_encoder(int afmt)
489 #ifndef SIMULATOR
490 const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER);
491 if (!enc_fn)
492 return false;
494 audio_remove_encoder();
495 ci.enc_codec_loaded = 0; /* clear any previous error condition */
497 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
498 queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (intptr_t)enc_fn);
500 while (ci.enc_codec_loaded == 0)
501 yield();
503 logf("codec loaded: %d", ci.enc_codec_loaded);
505 return ci.enc_codec_loaded > 0;
506 #else
507 (void)afmt;
508 return true;
509 #endif
510 } /* audio_load_encoder */
512 void audio_remove_encoder(void)
514 #ifndef SIMULATOR
515 /* force encoder codec unload (if currently loaded) */
516 if (ci.enc_codec_loaded <= 0)
517 return;
519 ci.stop_encoder = true;
520 while (ci.enc_codec_loaded > 0)
521 yield();
522 #endif
523 } /* audio_remove_encoder */
525 #endif /* HAVE_RECORDING */
527 #ifdef HAVE_ALBUMART
528 int audio_current_aa_hid(void)
530 int cur_idx;
531 int offset = ci.new_track + wps_offset;
533 cur_idx = track_ridx + offset;
534 cur_idx &= MAX_TRACK_MASK;
536 return tracks[cur_idx].aa_hid;
538 #endif
540 struct mp3entry* audio_current_track(void)
542 const char *filename;
543 const char *p;
544 static struct mp3entry temp_id3;
545 struct playlist_track_info trackinfo;
546 int cur_idx;
547 int offset = ci.new_track + wps_offset;
549 cur_idx = (track_ridx + offset) & MAX_TRACK_MASK;
551 if (cur_idx == track_ridx && *curtrack_id3.path)
553 /* The usual case */
554 return &curtrack_id3;
556 else if (automatic_skip && offset == -1 && *prevtrack_id3.path)
558 /* We're in a track transition. The codec has moved on to the nex track,
559 but the audio being played is still the same (now previous) track.
560 prevtrack_id3.elapsed is being updated in an ISR by
561 codec_pcmbuf_position_callback */
562 return &prevtrack_id3;
564 else if (tracks[cur_idx].id3_hid >= 0)
566 /* Get the ID3 metadata from the main buffer */
567 struct mp3entry *ret = bufgetid3(tracks[cur_idx].id3_hid);
568 if (ret) return ret;
571 /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info
572 we have and return that. */
574 memset(&temp_id3, 0, sizeof(struct mp3entry));
576 playlist_get_track_info(NULL, playlist_next(0)+wps_offset, &trackinfo);
577 filename = trackinfo.filename;
578 if (!filename)
579 filename = "No file!";
581 #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
582 if (tagcache_fill_tags(&temp_id3, filename))
583 return &temp_id3;
584 #endif
586 p = strrchr(filename, '/');
587 if (!p)
588 p = filename;
589 else
590 p++;
592 strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1);
593 temp_id3.title = &temp_id3.path[0];
595 return &temp_id3;
598 struct mp3entry* audio_next_track(void)
600 int next_idx;
601 int offset = ci.new_track + wps_offset;
603 if (!audio_have_tracks())
604 return NULL;
606 if (wps_offset == -1 && *prevtrack_id3.path)
608 /* We're in a track transition. The next track for the WPS is the one
609 currently being decoded. */
610 return &curtrack_id3;
613 next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK;
615 if (tracks[next_idx].id3_hid >= 0)
616 return bufgetid3(tracks[next_idx].id3_hid);
618 if (next_idx == track_widx)
620 /* The next track hasn't been buffered yet, so we return the static
621 version of its metadata. */
622 return &lasttrack_id3;
625 return NULL;
628 bool audio_has_changed_track(void)
630 if (track_changed)
632 track_changed = false;
633 return true;
636 return false;
639 void audio_play(long offset)
641 logf("audio_play");
643 #ifdef PLAYBACK_VOICE
644 /* Truncate any existing voice output so we don't have spelling
645 * etc. over the first part of the played track */
646 talk_force_shutup();
647 #endif
649 /* Start playback */
650 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset);
651 /* Don't return until playback has actually started */
652 queue_send(&audio_queue, Q_AUDIO_PLAY, offset);
655 void audio_stop(void)
657 /* Stop playback */
658 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
659 /* Don't return until playback has actually stopped */
660 queue_send(&audio_queue, Q_AUDIO_STOP, 0);
663 void audio_pause(void)
665 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
666 /* Don't return until playback has actually paused */
667 queue_send(&audio_queue, Q_AUDIO_PAUSE, true);
670 void audio_resume(void)
672 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
673 /* Don't return until playback has actually resumed */
674 queue_send(&audio_queue, Q_AUDIO_PAUSE, false);
677 static void audio_skip(int direction)
679 if (playlist_check(ci.new_track + wps_offset + direction))
681 if (global_settings.beep)
682 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
684 LOGFQUEUE("audio > audio Q_AUDIO_SKIP %d", direction);
685 queue_post(&audio_queue, Q_AUDIO_SKIP, direction);
686 /* Update wps while our message travels inside deep playback queues. */
687 wps_offset += direction;
688 track_changed = true;
690 else
692 /* No more tracks. */
693 if (global_settings.beep)
694 pcmbuf_beep(1000, 100, 1000*global_settings.beep);
698 void audio_next(void)
700 audio_skip(1);
703 void audio_prev(void)
705 audio_skip(-1);
708 void audio_next_dir(void)
710 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
711 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, 1);
714 void audio_prev_dir(void)
716 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
717 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, -1);
720 void audio_pre_ff_rewind(void)
722 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
723 queue_post(&audio_queue, Q_AUDIO_PRE_FF_REWIND, 0);
726 void audio_ff_rewind(long newpos)
728 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
729 queue_post(&audio_queue, Q_AUDIO_FF_REWIND, newpos);
732 void audio_flush_and_reload_tracks(void)
734 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
735 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0);
738 void audio_error_clear(void)
740 #ifdef AUDIO_HAVE_RECORDING
741 pcm_rec_error_clear();
742 #endif
745 int audio_status(void)
747 int ret = 0;
749 if (playing)
750 ret |= AUDIO_STATUS_PLAY;
752 if (paused)
753 ret |= AUDIO_STATUS_PAUSE;
755 #ifdef HAVE_RECORDING
756 /* Do this here for constitency with mpeg.c version */
757 ret |= pcm_rec_status();
758 #endif
760 return ret;
763 int audio_get_file_pos(void)
765 return 0;
768 #ifndef HAVE_FLASH_STORAGE
769 void audio_set_buffer_margin(int setting)
771 static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
772 buffer_margin = lookup[setting];
773 logf("buffer margin: %ld", (long)buffer_margin);
774 set_filebuf_watermark(buffer_margin, 0);
776 #endif
778 /* Take necessary steps to enable or disable the crossfade setting */
779 void audio_set_crossfade(int enable)
781 size_t offset;
782 bool was_playing;
783 size_t size;
785 /* Tell it the next setting to use */
786 pcmbuf_crossfade_enable(enable);
788 /* Return if size hasn't changed or this is too early to determine
789 which in the second case there's no way we could be playing
790 anything at all */
791 if (pcmbuf_is_same_size())
793 /* This function is a copout and just syncs some variables -
794 to be removed at a later date */
795 pcmbuf_crossfade_enable_finished();
796 return;
799 offset = 0;
800 was_playing = playing;
802 /* Playback has to be stopped before changing the buffer size */
803 if (was_playing)
805 /* Store the track resume position */
806 offset = curtrack_id3.offset;
807 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK));
810 /* Blast it - audio buffer will have to be setup again next time
811 something plays */
812 audio_get_buffer(true, &size);
814 /* Restart playback if audio was running previously */
815 if (was_playing)
816 audio_play(offset);
819 /* --- Routines called from multiple threads --- */
821 static void set_filebuf_watermark(int seconds, size_t max)
823 size_t bytes;
825 if (!filebuf)
826 return; /* Audio buffers not yet set up */
828 bytes = seconds?MAX(curtrack_id3.bitrate * seconds * (1000/8), max):max;
829 bytes = MIN(bytes, filebuflen / 2);
830 buf_set_watermark(bytes);
833 const char *get_codec_filename(int cod_spec)
835 const char *fname;
837 #ifdef HAVE_RECORDING
838 /* Can choose decoder or encoder if one available */
839 int type = cod_spec & CODEC_TYPE_MASK;
840 int afmt = cod_spec & CODEC_AFMT_MASK;
842 if ((unsigned)afmt >= AFMT_NUM_CODECS)
843 type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
845 fname = (type == CODEC_TYPE_ENCODER) ?
846 audio_formats[afmt].codec_enc_root_fn :
847 audio_formats[afmt].codec_root_fn;
849 logf("%s: %d - %s",
850 (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
851 afmt, fname ? fname : "<unknown>");
852 #else /* !HAVE_RECORDING */
853 /* Always decoder */
854 if ((unsigned)cod_spec >= AFMT_NUM_CODECS)
855 cod_spec = AFMT_UNKNOWN;
856 fname = audio_formats[cod_spec].codec_root_fn;
857 logf("Codec: %d - %s", cod_spec, fname ? fname : "<unknown>");
858 #endif /* HAVE_RECORDING */
860 return fname;
861 } /* get_codec_filename */
863 /* --- Codec thread --- */
864 static bool codec_pcmbuf_insert_callback(
865 const void *ch1, const void *ch2, int count)
867 const char *src[2] = { ch1, ch2 };
869 while (count > 0)
871 int out_count = dsp_output_count(ci.dsp, count);
872 int inp_count;
873 char *dest;
875 /* Prevent audio from a previous track from playing */
876 if (ci.new_track || ci.stop_codec)
877 return true;
879 while ((dest = pcmbuf_request_buffer(&out_count)) == NULL)
881 cancel_cpu_boost();
882 sleep(1);
883 if (ci.seek_time || ci.new_track || ci.stop_codec)
884 return true;
887 /* Get the real input_size for output_size bytes, guarding
888 * against resampling buffer overflows. */
889 inp_count = dsp_input_count(ci.dsp, out_count);
891 if (inp_count <= 0)
892 return true;
894 /* Input size has grown, no error, just don't write more than length */
895 if (inp_count > count)
896 inp_count = count;
898 out_count = dsp_process(ci.dsp, dest, src, inp_count);
900 if (out_count <= 0)
901 return true;
903 pcmbuf_write_complete(out_count);
905 count -= inp_count;
908 return true;
909 } /* codec_pcmbuf_insert_callback */
911 static void* codec_get_memory_callback(size_t *size)
913 *size = MALLOC_BUFSIZE;
914 return malloc_buf;
917 /* Between the codec and PCM track change, we need to keep updating the
918 "elapsed" value of the previous (to the codec, but current to the
919 user/PCM/WPS) track, so that the progressbar reaches the end.
920 During that transition, the WPS will display prevtrack_id3. */
921 static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
922 static void codec_pcmbuf_position_callback(size_t size)
924 /* This is called from an ISR, so be quick */
925 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
926 prevtrack_id3.elapsed;
928 if (time >= prevtrack_id3.length)
930 pcmbuf_set_position_callback(NULL);
931 prevtrack_id3.elapsed = prevtrack_id3.length;
933 else
934 prevtrack_id3.elapsed = time;
937 static void codec_set_elapsed_callback(unsigned int value)
939 unsigned int latency;
940 if (ci.seek_time)
941 return;
943 #ifdef AB_REPEAT_ENABLE
944 ab_position_report(value);
945 #endif
947 latency = pcmbuf_get_latency();
948 if (value < latency)
949 curtrack_id3.elapsed = 0;
950 else if (value - latency > curtrack_id3.elapsed ||
951 value - latency < curtrack_id3.elapsed - 2)
953 curtrack_id3.elapsed = value - latency;
957 static void codec_set_offset_callback(size_t value)
959 unsigned int latency;
961 if (ci.seek_time)
962 return;
964 latency = pcmbuf_get_latency() * curtrack_id3.bitrate / 8;
965 if (value < latency)
966 curtrack_id3.offset = 0;
967 else
968 curtrack_id3.offset = value - latency;
971 static void codec_advance_buffer_counters(size_t amount)
973 bufadvance(CUR_TI->audio_hid, amount);
974 ci.curpos += amount;
977 /* copy up-to size bytes into ptr and return the actual size copied */
978 static size_t codec_filebuf_callback(void *ptr, size_t size)
980 ssize_t copy_n;
982 if (ci.stop_codec || !playing)
983 return 0;
985 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
987 /* Nothing requested OR nothing left */
988 if (copy_n == 0)
989 return 0;
991 /* Update read and other position pointers */
992 codec_advance_buffer_counters(copy_n);
994 /* Return the actual amount of data copied to the buffer */
995 return copy_n;
996 } /* codec_filebuf_callback */
998 static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
1000 size_t copy_n = reqsize;
1001 ssize_t ret;
1002 void *ptr;
1004 if (!playing)
1006 *realsize = 0;
1007 return NULL;
1010 ret = bufgetdata(CUR_TI->audio_hid, reqsize, &ptr);
1011 if (ret >= 0)
1012 copy_n = MIN((size_t)ret, reqsize);
1014 if (copy_n == 0)
1016 *realsize = 0;
1017 return NULL;
1020 *realsize = copy_n;
1022 return ptr;
1023 } /* codec_request_buffer_callback */
1025 static int get_codec_base_type(int type)
1027 switch (type) {
1028 case AFMT_MPA_L1:
1029 case AFMT_MPA_L2:
1030 case AFMT_MPA_L3:
1031 return AFMT_MPA_L3;
1034 return type;
1037 static void codec_advance_buffer_callback(size_t amount)
1039 codec_advance_buffer_counters(amount);
1040 codec_set_offset_callback(ci.curpos);
1043 static void codec_advance_buffer_loc_callback(void *ptr)
1045 size_t amount = buf_get_offset(CUR_TI->audio_hid, ptr);
1046 codec_advance_buffer_callback(amount);
1049 static void codec_seek_complete_callback(void)
1051 logf("seek_complete");
1052 if (pcm_is_paused())
1054 /* If this is not a seamless seek, clear the buffer */
1055 pcmbuf_play_stop();
1056 dsp_configure(ci.dsp, DSP_FLUSH, 0);
1058 /* If playback was not 'deliberately' paused, unpause now */
1059 if (!paused)
1060 pcmbuf_pause(false);
1062 ci.seek_time = 0;
1065 static bool codec_seek_buffer_callback(size_t newpos)
1067 logf("codec_seek_buffer_callback");
1069 int ret = bufseek(CUR_TI->audio_hid, newpos);
1070 if (ret == 0) {
1071 ci.curpos = newpos;
1072 return true;
1074 else {
1075 return false;
1079 static void codec_configure_callback(int setting, intptr_t value)
1081 switch (setting) {
1082 case CODEC_SET_FILEBUF_WATERMARK:
1083 set_filebuf_watermark(buffer_margin, value);
1084 break;
1086 default:
1087 if (!dsp_configure(ci.dsp, setting, value))
1088 { logf("Illegal key:%d", setting); }
1092 static void codec_track_changed(void)
1094 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1095 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1098 static void codec_pcmbuf_track_changed_callback(void)
1100 pcmbuf_set_position_callback(NULL);
1101 pcmbuf_callback_queue_post(Q_AUDIO_TRACK_CHANGED, 0);
1104 static void codec_discard_codec_callback(void)
1106 if (CUR_TI->codec_hid >= 0)
1108 bufclose(CUR_TI->codec_hid);
1109 CUR_TI->codec_hid = -1;
1113 static inline void codec_gapless_track_change(void)
1115 /* callback keeps the progress bar moving while the pcmbuf empties */
1116 pcmbuf_set_position_callback(codec_pcmbuf_position_callback);
1117 /* set the pcmbuf callback for when the track really changes */
1118 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
1121 static inline void codec_crossfade_track_change(void)
1123 /* Initiate automatic crossfade mode */
1124 pcmbuf_crossfade_init(false);
1125 /* Notify the wps that the track change starts now */
1126 codec_track_changed();
1129 static void codec_track_skip_done(bool was_manual)
1131 /* Manual track change (always crossfade or flush audio). */
1132 if (was_manual)
1134 pcmbuf_crossfade_init(true);
1135 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1136 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1138 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1139 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1140 && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP)
1142 if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
1144 if (global_settings.playlist_shuffle)
1145 /* shuffle mode is on, so crossfade: */
1146 codec_crossfade_track_change();
1147 else
1148 /* shuffle mode is off, so do a gapless track change */
1149 codec_gapless_track_change();
1151 else
1152 /* normal crossfade: */
1153 codec_crossfade_track_change();
1155 else
1156 /* normal gapless playback. */
1157 codec_gapless_track_change();
1160 static bool codec_load_next_track(void)
1162 intptr_t result = Q_CODEC_REQUEST_FAILED;
1164 prev_track_elapsed = curtrack_id3.elapsed;
1166 #ifdef AB_REPEAT_ENABLE
1167 ab_end_of_track_report();
1168 #endif
1170 logf("Request new track");
1172 if (ci.new_track == 0)
1174 ci.new_track++;
1175 automatic_skip = true;
1178 if (!ci.stop_codec)
1180 trigger_cpu_boost();
1181 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1182 result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
1185 switch (result)
1187 case Q_CODEC_REQUEST_COMPLETE:
1188 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1189 codec_track_skip_done(!automatic_skip);
1190 return true;
1192 case Q_CODEC_REQUEST_FAILED:
1193 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1194 ci.new_track = 0;
1195 ci.stop_codec = true;
1196 codec_requested_stop = true;
1197 return false;
1199 default:
1200 LOGFQUEUE("codec |< default");
1201 ci.stop_codec = true;
1202 codec_requested_stop = true;
1203 return false;
1207 static bool codec_request_next_track_callback(void)
1209 int prev_codectype;
1211 if (ci.stop_codec || !playing)
1212 return false;
1214 prev_codectype = get_codec_base_type(curtrack_id3.codectype);
1216 if (!codec_load_next_track())
1217 return false;
1219 /* Seek to the beginning of the new track because if the struct
1220 mp3entry was buffered, "elapsed" might not be zero (if the track has
1221 been played already but not unbuffered) */
1222 codec_seek_buffer_callback(curtrack_id3.first_frame_offset);
1224 /* Check if the next codec is the same file. */
1225 if (prev_codectype == get_codec_base_type(curtrack_id3.codectype))
1227 logf("New track loaded");
1228 codec_discard_codec_callback();
1229 return true;
1231 else
1233 logf("New codec:%d/%d", curtrack_id3.codectype, prev_codectype);
1234 return false;
1238 static void codec_thread(void)
1240 struct queue_event ev;
1241 int status;
1243 while (1) {
1244 status = 0;
1246 if (!pcmbuf_is_crossfade_active()) {
1247 cancel_cpu_boost();
1250 queue_wait(&codec_queue, &ev);
1251 codec_requested_stop = false;
1253 switch (ev.id) {
1254 case Q_CODEC_LOAD_DISK:
1255 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1256 queue_reply(&codec_queue, 1);
1257 audio_codec_loaded = true;
1258 ci.stop_codec = false;
1259 status = codec_load_file((const char *)ev.data, &ci);
1260 break;
1262 case Q_CODEC_LOAD:
1263 LOGFQUEUE("codec < Q_CODEC_LOAD");
1264 if (CUR_TI->codec_hid < 0) {
1265 logf("Codec slot is empty!");
1266 /* Wait for the pcm buffer to go empty */
1267 while (pcm_is_playing())
1268 yield();
1269 /* This must be set to prevent an infinite loop */
1270 ci.stop_codec = true;
1271 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1272 queue_post(&codec_queue, Q_AUDIO_PLAY, 0);
1273 break;
1276 audio_codec_loaded = true;
1277 ci.stop_codec = false;
1278 status = codec_load_buf(CUR_TI->codec_hid, &ci);
1279 break;
1281 #ifdef AUDIO_HAVE_RECORDING
1282 case Q_ENCODER_LOAD_DISK:
1283 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1284 audio_codec_loaded = false; /* Not audio codec! */
1285 logf("loading encoder");
1286 ci.stop_encoder = false;
1287 status = codec_load_file((const char *)ev.data, &ci);
1288 logf("encoder stopped");
1289 break;
1290 #endif /* AUDIO_HAVE_RECORDING */
1292 default:
1293 LOGFQUEUE("codec < default");
1296 if (audio_codec_loaded)
1298 if (ci.stop_codec)
1300 status = CODEC_OK;
1301 if (!playing)
1302 pcmbuf_play_stop();
1305 audio_codec_loaded = false;
1308 switch (ev.id) {
1309 case Q_CODEC_LOAD_DISK:
1310 case Q_CODEC_LOAD:
1311 LOGFQUEUE("codec < Q_CODEC_LOAD");
1312 if (playing)
1314 if (ci.new_track || status != CODEC_OK)
1316 if (!ci.new_track)
1318 logf("Codec failure");
1319 gui_syncsplash(HZ*2, "Codec failure");
1322 if (!codec_load_next_track())
1324 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1325 /* End of playlist */
1326 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1327 break;
1330 else
1332 logf("Codec finished");
1333 if (ci.stop_codec)
1335 /* Wait for the audio to stop playing before
1336 * triggering the WPS exit */
1337 while(pcm_is_playing())
1339 curtrack_id3.elapsed =
1340 curtrack_id3.length - pcmbuf_get_latency();
1341 sleep(1);
1344 if (codec_requested_stop)
1346 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1347 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1349 break;
1353 if (CUR_TI->codec_hid >= 0)
1355 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1356 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
1358 else
1360 const char *codec_fn =
1361 get_codec_filename(curtrack_id3.codectype);
1362 if (codec_fn)
1364 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1365 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
1366 (intptr_t)codec_fn);
1370 break;
1372 #ifdef AUDIO_HAVE_RECORDING
1373 case Q_ENCODER_LOAD_DISK:
1374 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1376 if (status == CODEC_OK)
1377 break;
1379 logf("Encoder failure");
1380 gui_syncsplash(HZ*2, "Encoder failure");
1382 if (ci.enc_codec_loaded < 0)
1383 break;
1385 logf("Encoder failed to load");
1386 ci.enc_codec_loaded = -1;
1387 break;
1388 #endif /* AUDIO_HAVE_RECORDING */
1390 default:
1391 LOGFQUEUE("codec < default");
1393 } /* end switch */
1398 /* --- Buffering callbacks --- */
1400 static void buffering_low_buffer_callback(void *data)
1402 (void)data;
1403 logf("low buffer callback");
1405 if (filling == STATE_FULL) {
1406 /* force a refill */
1407 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1408 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1412 static void buffering_handle_rebuffer_callback(void *data)
1414 (void)data;
1415 LOGFQUEUE("audio >| audio Q_AUDIO_FLUSH");
1416 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0);
1419 static void buffering_handle_finished_callback(int *data)
1421 logf("handle %d finished buffering", *data);
1423 if (*data == tracks[track_widx].id3_hid)
1425 /* The metadata handle for the last loaded track has been buffered.
1426 We can ask the audio thread to load the rest of the track's data. */
1427 LOGFQUEUE("audio >| audio Q_AUDIO_FINISH_LOAD");
1428 queue_post(&audio_queue, Q_AUDIO_FINISH_LOAD, 0);
1430 else
1432 /* This is most likely an audio handle, so we strip the useless
1433 trailing tags that are left. */
1434 strip_tags(*data);
1439 /* --- Audio thread --- */
1441 static bool audio_have_tracks(void)
1443 return (audio_track_count() != 0);
1446 static int audio_free_track_count(void)
1448 /* Used tracks + free tracks adds up to MAX_TRACK - 1 */
1449 return MAX_TRACK - 1 - audio_track_count();
1452 int audio_track_count(void)
1454 /* Calculate difference from track_ridx to track_widx
1455 * taking into account a possible wrap-around. */
1456 return (MAX_TRACK + track_widx - track_ridx) & MAX_TRACK_MASK;
1459 long audio_filebufused(void)
1461 return (long) buf_used();
1464 /* Update track info after successful a codec track change */
1465 static void audio_update_trackinfo(void)
1467 /* Load the curent track's metadata into curtrack_id3 */
1468 if (CUR_TI->id3_hid >= 0)
1469 copy_mp3entry(&curtrack_id3, bufgetid3(CUR_TI->id3_hid));
1471 /* Reset current position */
1472 curtrack_id3.elapsed = 0;
1473 curtrack_id3.offset = 0;
1475 /* Update the codec API */
1476 ci.filesize = CUR_TI->filesize;
1477 ci.id3 = &curtrack_id3;
1478 ci.curpos = 0;
1479 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1482 /* Clear tracks between write and read, non inclusive */
1483 static void audio_clear_track_entries(void)
1485 int cur_idx = track_widx;
1487 logf("Clearing tracks:%d/%d", track_ridx, track_widx);
1489 /* Loop over all tracks from write-to-read */
1490 while (1)
1492 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
1494 if (cur_idx == track_ridx)
1495 break;
1497 clear_track_info(&tracks[cur_idx]);
1501 /* Clear all tracks */
1502 static bool audio_release_tracks(void)
1504 int i, cur_idx;
1506 logf("releasing all tracks");
1508 for(i = 0; i < MAX_TRACK; i++)
1510 cur_idx = (track_ridx + i) & MAX_TRACK_MASK;
1511 if (!clear_track_info(&tracks[cur_idx]))
1512 return false;
1515 return true;
1518 static bool audio_loadcodec(bool start_play)
1520 int prev_track;
1521 char codec_path[MAX_PATH]; /* Full path to codec */
1522 const struct mp3entry *id3, *prev_id3;
1524 if (tracks[track_widx].id3_hid < 0) {
1525 return false;
1528 id3 = bufgetid3(tracks[track_widx].id3_hid);
1529 if (!id3)
1530 return false;
1532 const char *codec_fn = get_codec_filename(id3->codectype);
1533 if (codec_fn == NULL)
1534 return false;
1536 tracks[track_widx].codec_hid = -1;
1538 if (start_play)
1540 /* Load the codec directly from disk and save some memory. */
1541 track_ridx = track_widx;
1542 ci.filesize = CUR_TI->filesize;
1543 ci.id3 = &curtrack_id3;
1544 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1545 ci.curpos = 0;
1546 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1547 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (intptr_t)codec_fn);
1548 return true;
1550 else
1552 /* If we already have another track than this one buffered */
1553 if (track_widx != track_ridx)
1555 prev_track = (track_widx - 1) & MAX_TRACK_MASK;
1557 id3 = bufgetid3(tracks[track_widx].id3_hid);
1558 prev_id3 = bufgetid3(tracks[prev_track].id3_hid);
1560 /* If the previous codec is the same as this one, there is no need
1561 * to put another copy of it on the file buffer */
1562 if (id3 && prev_id3 &&
1563 get_codec_base_type(id3->codectype) ==
1564 get_codec_base_type(prev_id3->codectype)
1565 && audio_codec_loaded)
1567 logf("Reusing prev. codec");
1568 return true;
1573 codec_get_full_path(codec_path, codec_fn);
1575 tracks[track_widx].codec_hid = bufopen(codec_path, 0, TYPE_CODEC);
1576 if (tracks[track_widx].codec_hid < 0)
1577 return false;
1579 logf("Loaded codec");
1581 return true;
1584 /* Load metadata for the next track (with bufopen). The rest of the track
1585 loading will be handled by audio_finish_load_track once the metadata has been
1586 actually loaded by the buffering thread. */
1587 static bool audio_load_track(size_t offset, bool start_play)
1589 const char *trackname;
1590 int fd = -1;
1592 start_play_g = start_play; /* will be read by audio_finish_load_track */
1594 /* Stop buffer filling if there is no free track entries.
1595 Don't fill up the last track entry (we wan't to store next track
1596 metadata there). */
1597 if (!audio_free_track_count())
1599 logf("No free tracks");
1600 return false;
1603 last_peek_offset++;
1604 tracks[track_widx].taginfo_ready = false;
1606 logf("Buffering track:%d/%d", track_widx, track_ridx);
1607 /* Get track name from current playlist read position. */
1608 while ((trackname = playlist_peek(last_peek_offset)) != NULL)
1610 /* Handle broken playlists. */
1611 fd = open(trackname, O_RDONLY);
1612 if (fd < 0)
1614 logf("Open failed");
1615 /* Skip invalid entry from playlist. */
1616 playlist_skip_entry(NULL, last_peek_offset);
1618 else
1619 break;
1622 if (!trackname)
1624 logf("End-of-playlist");
1625 memset(&lasttrack_id3, 0, sizeof(struct mp3entry));
1626 filling = STATE_FINISHED;
1627 return false;
1630 tracks[track_widx].filesize = filesize(fd);
1632 if (offset > tracks[track_widx].filesize)
1633 offset = 0;
1635 /* Set default values */
1636 if (start_play)
1638 buf_set_watermark(AUDIO_DEFAULT_WATERMARK);
1639 dsp_configure(ci.dsp, DSP_RESET, 0);
1640 track_changed = true;
1641 playlist_update_resume_info(audio_current_track());
1644 /* Get track metadata if we don't already have it. */
1645 if (tracks[track_widx].id3_hid < 0)
1647 tracks[track_widx].id3_hid = bufopen(trackname, 0, TYPE_ID3);
1649 if (tracks[track_widx].id3_hid < 0)
1651 /* Buffer is full. */
1652 get_metadata(&lasttrack_id3, fd, trackname);
1653 last_peek_offset--;
1654 close(fd);
1655 logf("buffer is full for now");
1656 filling = STATE_FULL;
1657 return false;
1660 if (track_widx == track_ridx)
1662 buf_request_buffer_handle(tracks[track_widx].id3_hid);
1663 copy_mp3entry(&curtrack_id3, bufgetid3(tracks[track_widx].id3_hid));
1664 curtrack_id3.offset = offset;
1667 if (start_play)
1669 track_changed = true;
1670 playlist_update_resume_info(audio_current_track());
1674 close(fd);
1675 return true;
1678 /* Second part of the track loading: We now have the metadata available, so we
1679 can load the codec, the album art and finally the audio data.
1680 This is called on the audio thread after the buffering thread calls the
1681 buffering_handle_finished_callback callback. */
1682 static void audio_finish_load_track(void)
1684 char msgbuf[80];
1685 size_t file_offset = 0;
1686 size_t offset = 0;
1687 bool start_play = start_play_g;
1689 #if 0
1690 if (cuesheet_is_enabled() && tracks[track_widx].id3.cuesheet_type == 1)
1692 char cuepath[MAX_PATH];
1694 struct cuesheet *cue = start_play ? curr_cue : temp_cue;
1696 if (look_for_cuesheet_file(trackname, cuepath) &&
1697 parse_cuesheet(cuepath, cue))
1699 strcpy((cue)->audio_filename, trackname);
1700 if (start_play)
1701 cue_spoof_id3(curr_cue, &tracks[track_widx].id3);
1704 #endif
1706 if (tracks[track_widx].id3_hid < 0) {
1707 logf("no metatdata");
1708 return;
1711 struct mp3entry *track_id3;
1713 if (track_widx == track_ridx)
1714 track_id3 = &curtrack_id3;
1715 else
1716 track_id3 = bufgetid3(tracks[track_widx].id3_hid);
1718 if (track_id3->length == 0 && track_id3->filesize == 0)
1720 logf("audio_finish_load_track: invalid metadata");
1722 /* Invalid metadata */
1723 bufclose(tracks[track_widx].id3_hid);
1724 tracks[track_widx].id3_hid = -1;
1726 /* Skip invalid entry from playlist. */
1727 playlist_skip_entry(NULL, last_peek_offset--);
1729 /* load next track */
1730 LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER %d", (int)start_play);
1731 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, start_play);
1733 return;
1736 #ifdef HAVE_ALBUMART
1737 if (tracks[track_widx].aa_hid < 0 && gui_sync_wps_uses_albumart())
1739 char aa_path[MAX_PATH];
1740 if (find_albumart(track_id3, aa_path, sizeof(aa_path)))
1741 tracks[track_widx].aa_hid = bufopen(aa_path, 0, TYPE_BITMAP);
1743 #endif
1745 /* Load the codec. */
1746 if (!audio_loadcodec(start_play))
1748 if (tracks[track_widx].codec_hid == ERR_BUFFER_FULL)
1750 /* No space for codec on buffer, not an error */
1751 return;
1754 /* This is an error condition, either no codec was found, or reading
1755 * the codec file failed part way through, either way, skip the track */
1756 snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", track_id3->path);
1757 /* We should not use gui_syncplash from audio thread! */
1758 gui_syncsplash(HZ*2, msgbuf);
1759 /* Skip invalid entry from playlist. */
1760 playlist_skip_entry(NULL, last_peek_offset);
1761 return;
1764 track_id3->elapsed = 0;
1765 offset = track_id3->offset;
1767 enum data_type type = TYPE_PACKET_AUDIO;
1769 switch (track_id3->codectype) {
1770 case AFMT_MPA_L1:
1771 case AFMT_MPA_L2:
1772 case AFMT_MPA_L3:
1773 if (offset > 0) {
1774 file_offset = offset;
1775 track_id3->offset = offset;
1777 break;
1779 case AFMT_WAVPACK:
1780 if (offset > 0) {
1781 file_offset = offset;
1782 track_id3->offset = offset;
1783 track_id3->elapsed = track_id3->length / 2;
1785 break;
1787 case AFMT_OGG_VORBIS:
1788 case AFMT_SPEEX:
1789 case AFMT_FLAC:
1790 case AFMT_PCM_WAV:
1791 case AFMT_A52:
1792 case AFMT_AAC:
1793 case AFMT_MPC:
1794 case AFMT_APE:
1795 case AFMT_WMA:
1796 if (offset > 0)
1797 track_id3->offset = offset;
1798 break;
1800 case AFMT_NSF:
1801 case AFMT_SPC:
1802 case AFMT_SID:
1803 logf("Loading atomic %d",track_id3->codectype);
1804 type = TYPE_ATOMIC_AUDIO;
1805 break;
1808 logf("alt:%s", track_id3->path);
1810 if (file_offset > AUDIO_REBUFFER_GUESS_SIZE)
1811 file_offset -= AUDIO_REBUFFER_GUESS_SIZE;
1812 else if (track_id3->first_frame_offset)
1813 file_offset = track_id3->first_frame_offset;
1814 else
1815 file_offset = 0;
1817 tracks[track_widx].audio_hid = bufopen(track_id3->path, file_offset, type);
1819 if (tracks[track_widx].audio_hid < 0)
1820 return;
1822 /* All required data is now available for the codec. */
1823 tracks[track_widx].taginfo_ready = true;
1825 if (start_play)
1827 ci.curpos=file_offset;
1828 buf_request_buffer_handle(tracks[track_widx].audio_hid);
1831 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
1833 send_event(PLAYBACK_EVENT_TRACK_BUFFER, track_id3);
1835 /* load next track */
1836 LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER");
1837 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1839 return;
1842 static void audio_fill_file_buffer(bool start_play, size_t offset)
1844 bool had_next_track = audio_next_track() != NULL;
1846 filling = STATE_FILLING;
1847 trigger_cpu_boost();
1849 /* No need to rebuffer if there are track skips pending. */
1850 if (ci.new_track != 0)
1851 return;
1853 /* Must reset the buffer before use if trashed or voice only - voice
1854 file size shouldn't have changed so we can go straight from
1855 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
1856 if (buffer_state != BUFFER_STATE_INITIALIZED)
1857 audio_reset_buffer();
1859 logf("Starting buffer fill");
1861 if (!start_play)
1862 audio_clear_track_entries();
1864 /* Save the current resume position once. */
1865 playlist_update_resume_info(audio_current_track());
1867 audio_load_track(offset, start_play);
1869 if (!had_next_track && audio_next_track())
1870 track_changed = true;
1873 static void audio_rebuffer(void)
1875 logf("Forcing rebuffer");
1877 clear_track_info(CUR_TI);
1879 /* Reset track pointers */
1880 track_widx = track_ridx;
1881 audio_clear_track_entries();
1883 /* Fill the buffer */
1884 last_peek_offset = -1;
1885 ci.curpos = 0;
1887 if (!CUR_TI->taginfo_ready)
1888 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
1890 audio_fill_file_buffer(false, 0);
1893 /* Called on request from the codec to get a new track. This is the codec part
1894 of the track transition. */
1895 static int audio_check_new_track(void)
1897 int track_count = audio_track_count();
1898 int old_track_ridx = track_ridx;
1899 int i, idx;
1900 bool forward;
1902 /* Now it's good time to send track finish events. */
1903 send_event(PLAYBACK_EVENT_TRACK_FINISH, &curtrack_id3);
1904 if (dir_skip)
1906 dir_skip = false;
1907 if (playlist_next_dir(ci.new_track))
1909 ci.new_track = 0;
1910 audio_rebuffer();
1911 goto skip_done;
1913 else
1915 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1916 return Q_CODEC_REQUEST_FAILED;
1920 if (new_playlist)
1921 ci.new_track = 0;
1923 /* If the playlist isn't that big */
1924 if (automatic_skip)
1926 while (!playlist_check(ci.new_track))
1928 if (ci.new_track >= 0)
1930 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1931 return Q_CODEC_REQUEST_FAILED;
1933 ci.new_track++;
1937 /* Update the playlist */
1938 last_peek_offset -= ci.new_track;
1940 if (playlist_next(ci.new_track) < 0)
1942 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1943 return Q_CODEC_REQUEST_FAILED;
1946 if (new_playlist)
1948 ci.new_track = 1;
1949 new_playlist = false;
1952 /* Save the track metadata to allow the WPS to display it
1953 while PCM finishes playing that track */
1954 copy_mp3entry(&prevtrack_id3, &curtrack_id3);
1956 /* Update the main buffer copy of the track metadata with the one
1957 the codec has been using (for the unbuffer callbacks) */
1958 if (CUR_TI->id3_hid >= 0)
1959 copy_mp3entry(bufgetid3(CUR_TI->id3_hid), &curtrack_id3);
1961 /* Save a pointer to the old track to allow later clearing */
1962 prev_ti = CUR_TI;
1964 for (i = 0; i < ci.new_track; i++)
1966 idx = (track_ridx + i) & MAX_TRACK_MASK;
1967 struct mp3entry *id3 = bufgetid3(tracks[idx].id3_hid);
1968 ssize_t offset = buf_handle_offset(tracks[idx].audio_hid);
1969 if (!id3 || offset < 0 || (unsigned)offset > id3->first_frame_offset)
1971 /* We don't have all the audio data for that track, so clear it,
1972 but keep the metadata. */
1973 if (tracks[idx].audio_hid >= 0 && bufclose(tracks[idx].audio_hid))
1975 tracks[idx].audio_hid = -1;
1976 tracks[idx].filesize = 0;
1981 /* Move to the new track */
1982 track_ridx = (track_ridx + ci.new_track) & MAX_TRACK_MASK;
1984 buf_set_base_handle(CUR_TI->audio_hid);
1986 if (automatic_skip)
1988 wps_offset = -ci.new_track;
1989 track_changed = true;
1992 /* If it is not safe to even skip this many track entries */
1993 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
1995 ci.new_track = 0;
1996 audio_rebuffer();
1997 goto skip_done;
2000 forward = ci.new_track > 0;
2001 ci.new_track = 0;
2003 /* If the target track is clearly not in memory */
2004 if (CUR_TI->filesize == 0 || !CUR_TI->taginfo_ready)
2006 audio_rebuffer();
2007 goto skip_done;
2010 /* When skipping backwards, it is possible that we've found a track that's
2011 * buffered, but which is around the track-wrap and therefore not the track
2012 * we are looking for */
2013 if (!forward)
2015 int cur_idx = track_ridx;
2016 bool taginfo_ready = true;
2017 /* We've wrapped the buffer backwards if new > old */
2018 bool wrap = track_ridx > old_track_ridx;
2020 while (1)
2022 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
2024 /* if we've advanced past the wrap when cur_idx is zeroed */
2025 if (!cur_idx)
2026 wrap = false;
2028 /* if we aren't still on the wrap and we've caught the old track */
2029 if (!(wrap || cur_idx < old_track_ridx))
2030 break;
2032 /* If we hit a track in between without valid tag info, bail */
2033 if (!tracks[cur_idx].taginfo_ready)
2035 taginfo_ready = false;
2036 break;
2039 if (!taginfo_ready)
2041 audio_rebuffer();
2045 skip_done:
2046 audio_update_trackinfo();
2047 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2048 return Q_CODEC_REQUEST_COMPLETE;
2051 unsigned long audio_prev_elapsed(void)
2053 return prev_track_elapsed;
2056 static void audio_stop_codec_flush(void)
2058 ci.stop_codec = true;
2059 pcmbuf_pause(true);
2061 while (audio_codec_loaded)
2062 yield();
2064 /* If the audio codec is not loaded any more, and the audio is still
2065 * playing, it is now and _only_ now safe to call this function from the
2066 * audio thread */
2067 if (pcm_is_playing())
2069 pcmbuf_play_stop();
2070 pcmbuf_queue_clear();
2072 pcmbuf_pause(paused);
2075 static void audio_stop_playback(void)
2077 /* If we were playing, save resume information */
2078 if (playing)
2080 struct mp3entry *id3 = NULL;
2082 if (!ci.stop_codec)
2084 /* Set this early, the outside code yields and may allow the codec
2085 to try to wait for a reply on a buffer wait */
2086 ci.stop_codec = true;
2087 id3 = audio_current_track();
2090 /* Save the current playing spot, or NULL if the playlist has ended */
2091 playlist_update_resume_info(id3);
2093 /* TODO: Create auto bookmark too? */
2095 prev_track_elapsed = curtrack_id3.elapsed;
2097 remove_event(EVENT_BUFFER_LOW, buffering_low_buffer_callback);
2100 paused = false;
2101 audio_stop_codec_flush();
2102 playing = false;
2104 filling = STATE_IDLE;
2106 /* Mark all entries null. */
2107 audio_clear_track_entries();
2109 /* Close all tracks */
2110 audio_release_tracks();
2112 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
2115 static void audio_play_start(size_t offset)
2117 int i;
2119 #if INPUT_SRC_CAPS != 0
2120 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2121 audio_set_output_source(AUDIO_SRC_PLAYBACK);
2122 #endif
2124 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2125 paused = false;
2126 audio_stop_codec_flush();
2128 track_changed = true;
2130 playing = true;
2132 ci.new_track = 0;
2133 ci.seek_time = 0;
2134 wps_offset = 0;
2136 sound_set_volume(global_settings.volume);
2137 track_widx = track_ridx = 0;
2139 /* Clear all track entries. */
2140 for (i = 0; i < MAX_TRACK; i++) {
2141 clear_track_info(&tracks[i]);
2144 last_peek_offset = -1;
2146 /* Officially playing */
2147 queue_reply(&audio_queue, 1);
2149 #ifndef HAVE_FLASH_STORAGE
2150 set_filebuf_watermark(buffer_margin, 0);
2151 #endif
2153 audio_fill_file_buffer(true, offset);
2155 add_event(EVENT_BUFFER_LOW, false, buffering_low_buffer_callback);
2157 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2158 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
2162 /* Invalidates all but currently playing track. */
2163 static void audio_invalidate_tracks(void)
2165 if (audio_have_tracks())
2167 last_peek_offset = 0;
2168 track_widx = track_ridx;
2170 /* Mark all other entries null (also buffered wrong metadata). */
2171 audio_clear_track_entries();
2173 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2175 audio_fill_file_buffer(false, 0);
2179 static void audio_new_playlist(void)
2181 /* Prepare to start a new fill from the beginning of the playlist */
2182 last_peek_offset = -1;
2183 if (audio_have_tracks())
2185 if (paused)
2186 skipped_during_pause = true;
2187 track_widx = track_ridx;
2188 audio_clear_track_entries();
2190 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2192 /* Mark the current track as invalid to prevent skipping back to it */
2193 CUR_TI->taginfo_ready = false;
2196 /* Signal the codec to initiate a track change forward */
2197 new_playlist = true;
2198 ci.new_track = 1;
2200 /* Officially playing */
2201 queue_reply(&audio_queue, 1);
2203 audio_fill_file_buffer(false, 0);
2206 /* Called on manual track skip */
2207 static void audio_initiate_track_change(long direction)
2209 logf("audio_initiate_track_change(%ld)", direction);
2211 ci.new_track += direction;
2212 wps_offset -= direction;
2213 if (paused)
2214 skipped_during_pause = true;
2217 /* Called on manual dir skip */
2218 static void audio_initiate_dir_change(long direction)
2220 dir_skip = true;
2221 ci.new_track = direction;
2222 if (paused)
2223 skipped_during_pause = true;
2226 /* Called when PCM track change is complete */
2227 static void audio_finalise_track_change(void)
2229 logf("audio_finalise_track_change");
2231 if (automatic_skip)
2233 wps_offset = 0;
2234 automatic_skip = false;
2236 /* Invalidate prevtrack_id3 */
2237 prevtrack_id3.path[0] = 0;
2239 if (prev_ti && prev_ti->audio_hid < 0)
2241 /* No audio left so we clear all the track info. */
2242 clear_track_info(prev_ti);
2245 if (prev_ti && prev_ti->id3_hid >= 0)
2247 /* Reset the elapsed time to force the progressbar to be empty if
2248 the user skips back to this track */
2249 bufgetid3(prev_ti->id3_hid)->elapsed = 0;
2253 send_event(PLAYBACK_EVENT_TRACK_CHANGE, &curtrack_id3);
2255 track_changed = true;
2256 playlist_update_resume_info(audio_current_track());
2260 * Layout audio buffer as follows - iram buffer depends on target:
2261 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
2263 static void audio_reset_buffer(void)
2265 /* see audio_get_recording_buffer if this is modified */
2266 logf("audio_reset_buffer");
2268 /* If the setup of anything allocated before the file buffer is
2269 changed, do check the adjustments after the buffer_alloc call
2270 as it will likely be affected and need sliding over */
2272 /* Initially set up file buffer as all space available */
2273 malloc_buf = audiobuf + talk_get_bufsize();
2274 /* Align the malloc buf to line size. Especially important to cf
2275 targets that do line reads/writes. */
2276 malloc_buf = (unsigned char *)(((uintptr_t)malloc_buf + 15) & ~15);
2277 filebuf = malloc_buf + MALLOC_BUFSIZE; /* filebuf line align implied */
2278 filebuflen = audiobufend - filebuf;
2280 filebuflen &= ~15;
2282 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
2283 filebuflen -= pcmbuf_init(filebuf + filebuflen) + GUARD_BUFSIZE;
2285 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
2286 will already be line aligned */
2287 filebuflen &= ~3;
2289 buffering_reset(filebuf, filebuflen);
2291 /* Clear any references to the file buffer */
2292 buffer_state = BUFFER_STATE_INITIALIZED;
2294 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
2295 /* Make sure everything adds up - yes, some info is a bit redundant but
2296 aids viewing and the sumation of certain variables should add up to
2297 the location of others. */
2299 size_t pcmbufsize;
2300 const unsigned char *pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
2301 logf("mabuf: %08X", (unsigned)malloc_buf);
2302 logf("mabufe: %08X", (unsigned)(malloc_buf + MALLOC_BUFSIZE));
2303 logf("fbuf: %08X", (unsigned)filebuf);
2304 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
2305 logf("gbuf: %08X", (unsigned)(filebuf + filebuflen));
2306 logf("gbufe: %08X", (unsigned)(filebuf + filebuflen + GUARD_BUFSIZE));
2307 logf("pcmb: %08X", (unsigned)pcmbuf);
2308 logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
2310 #endif
2313 static void audio_thread(void)
2315 struct queue_event ev;
2317 pcm_postinit();
2319 audio_thread_ready = true;
2321 while (1)
2323 if (filling != STATE_FILLING) {
2324 cancel_cpu_boost();
2327 if (!pcmbuf_queue_scan(&ev))
2328 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
2330 switch (ev.id) {
2332 case Q_AUDIO_FILL_BUFFER:
2333 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER %d", (int)ev.data);
2334 audio_fill_file_buffer((bool)ev.data, 0);
2335 break;
2337 case Q_AUDIO_FINISH_LOAD:
2338 LOGFQUEUE("audio < Q_AUDIO_FINISH_LOAD");
2339 audio_finish_load_track();
2340 break;
2342 case Q_AUDIO_PLAY:
2343 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2344 if (playing && ev.data <= 0)
2345 audio_new_playlist();
2346 else
2348 audio_stop_playback();
2349 audio_play_start((size_t)ev.data);
2351 break;
2353 case Q_AUDIO_STOP:
2354 LOGFQUEUE("audio < Q_AUDIO_STOP");
2355 if (playing)
2356 audio_stop_playback();
2357 if (ev.data != 0)
2358 queue_clear(&audio_queue);
2359 break;
2361 case Q_AUDIO_PAUSE:
2362 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
2363 if (!(bool) ev.data && skipped_during_pause && !pcmbuf_is_crossfade_active())
2364 pcmbuf_play_stop(); /* Flush old track on resume after skip */
2365 skipped_during_pause = false;
2366 if (!playing)
2367 break;
2368 pcmbuf_pause((bool)ev.data);
2369 paused = (bool)ev.data;
2370 break;
2372 case Q_AUDIO_SKIP:
2373 LOGFQUEUE("audio < Q_AUDIO_SKIP");
2374 audio_initiate_track_change((long)ev.data);
2375 break;
2377 case Q_AUDIO_PRE_FF_REWIND:
2378 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
2379 if (!playing)
2380 break;
2381 pcmbuf_pause(true);
2382 break;
2384 case Q_AUDIO_FF_REWIND:
2385 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
2386 if (!playing)
2387 break;
2388 if (automatic_skip)
2390 /* An automatic track skip is in progress. Finalize it,
2391 then go back to the previous track */
2392 audio_finalise_track_change();
2393 ci.new_track = -1;
2395 ci.seek_time = (long)ev.data+1;
2396 break;
2398 case Q_AUDIO_CHECK_NEW_TRACK:
2399 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
2400 queue_reply(&audio_queue, audio_check_new_track());
2401 break;
2403 case Q_AUDIO_DIR_SKIP:
2404 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2405 audio_initiate_dir_change(ev.data);
2406 break;
2408 case Q_AUDIO_FLUSH:
2409 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
2410 audio_invalidate_tracks();
2411 break;
2413 case Q_AUDIO_TRACK_CHANGED:
2414 /* PCM track change done */
2415 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2416 audio_finalise_track_change();
2417 break;
2419 #ifndef SIMULATOR
2420 case SYS_USB_CONNECTED:
2421 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2422 if (playing)
2423 audio_stop_playback();
2424 #ifdef PLAYBACK_VOICE
2425 voice_stop();
2426 #endif
2427 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2428 usb_wait_for_disconnect(&audio_queue);
2430 /* Mark all entries null. */
2431 audio_clear_track_entries();
2433 /* release tracks to make sure all handles are closed */
2434 audio_release_tracks();
2435 break;
2436 #endif
2438 case SYS_TIMEOUT:
2439 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
2440 break;
2442 default:
2443 LOGFQUEUE("audio < default");
2444 break;
2445 } /* end switch */
2446 } /* end while */
2449 /* Initialize the audio system - called from init() in main.c.
2450 * Last function because of all the references to internal symbols
2452 void audio_init(void)
2454 struct thread_entry *audio_thread_p;
2456 /* Can never do this twice */
2457 if (audio_is_initialized)
2459 logf("audio: already initialized");
2460 return;
2463 logf("audio: initializing");
2465 /* Initialize queues before giving control elsewhere in case it likes
2466 to send messages. Thread creation will be delayed however so nothing
2467 starts running until ready if something yields such as talk_init. */
2468 queue_init(&audio_queue, true);
2469 queue_init(&codec_queue, false);
2470 queue_init(&pcmbuf_queue, false);
2472 pcm_init();
2474 /* Initialize codec api. */
2475 ci.read_filebuf = codec_filebuf_callback;
2476 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
2477 ci.get_codec_memory = codec_get_memory_callback;
2478 ci.request_buffer = codec_request_buffer_callback;
2479 ci.advance_buffer = codec_advance_buffer_callback;
2480 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
2481 ci.request_next_track = codec_request_next_track_callback;
2482 ci.seek_buffer = codec_seek_buffer_callback;
2483 ci.seek_complete = codec_seek_complete_callback;
2484 ci.set_elapsed = codec_set_elapsed_callback;
2485 ci.set_offset = codec_set_offset_callback;
2486 ci.configure = codec_configure_callback;
2487 ci.discard_codec = codec_discard_codec_callback;
2488 ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP,
2489 CODEC_IDX_AUDIO);
2491 /* initialize the buffer */
2492 filebuf = audiobuf;
2494 /* audio_reset_buffer must to know the size of voice buffer so init
2495 talk first */
2496 talk_init();
2498 codec_thread_p = create_thread(
2499 codec_thread, codec_stack, sizeof(codec_stack),
2500 CREATE_THREAD_FROZEN,
2501 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
2502 IF_COP(, CPU));
2504 queue_enable_queue_send(&codec_queue, &codec_queue_sender_list,
2505 codec_thread_p);
2507 audio_thread_p = create_thread(audio_thread, audio_stack,
2508 sizeof(audio_stack), CREATE_THREAD_FROZEN,
2509 audio_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE)
2510 IF_COP(, CPU));
2512 queue_enable_queue_send(&audio_queue, &audio_queue_sender_list,
2513 audio_thread_p);
2515 #ifdef PLAYBACK_VOICE
2516 voice_thread_init();
2517 #endif
2519 /* Set crossfade setting for next buffer init which should be about... */
2520 pcmbuf_crossfade_enable(global_settings.crossfade);
2522 /* initialize the buffering system */
2524 buffering_init();
2525 /* ...now! Set up the buffers */
2526 audio_reset_buffer();
2528 int i;
2529 for(i = 0; i < MAX_TRACK; i++)
2531 tracks[i].audio_hid = -1;
2532 tracks[i].id3_hid = -1;
2533 tracks[i].codec_hid = -1;
2534 #ifdef HAVE_ALBUMART
2535 tracks[i].aa_hid = -1;
2536 #endif
2539 add_event(EVENT_HANDLE_REBUFFER, false, buffering_handle_rebuffer_callback);
2540 add_event(EVENT_HANDLE_FINISHED, false, buffering_handle_finished_callback);
2542 /* Probably safe to say */
2543 audio_is_initialized = true;
2545 sound_settings_apply();
2546 #ifndef HAVE_FLASH_STORAGE
2547 audio_set_buffer_margin(global_settings.buffer_margin);
2548 #endif
2550 /* it's safe to let the threads run now */
2551 #ifdef PLAYBACK_VOICE
2552 voice_thread_resume();
2553 #endif
2554 thread_thaw(codec_thread_p);
2555 thread_thaw(audio_thread_p);
2557 } /* audio_init */
2559 void audio_wait_for_init(void)
2561 /* audio thread will only set this once after it finished the final
2562 * audio hardware init so this little construct is safe - even
2563 * cross-core. */
2564 while (!audio_thread_ready)
2566 sleep(0);