Do the wait for the audio thread init in such a way to avoid an unlikely but possible...
[Rockbox.git] / apps / playback.c
blobe2ef2602cf608f06772817d815d3f936aaac487a
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: Can use the track changed callback to detect end of track and seek
21 * in the previous track until this happens */
22 /* Design: we have prev_ti already, have a conditional for what type of seek
23 * to do on a seek request, if it is a previous track seek, skip previous,
24 * and in the request_next_track callback set the offset up the same way that
25 * starting from an offset works. */
26 /* TODO: Pause should be handled in here, rather than PCMBUF so that voice can
27 * play whilst audio is paused */
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <ctype.h>
34 #include "system.h"
35 #include "thread.h"
36 #include "file.h"
37 #include "panic.h"
38 #include "memory.h"
39 #include "lcd.h"
40 #include "font.h"
41 #include "button.h"
42 #include "kernel.h"
43 #include "tree.h"
44 #include "debug.h"
45 #include "sprintf.h"
46 #include "settings.h"
47 #include "codecs.h"
48 #include "audio.h"
49 #include "buffering.h"
50 #include "voice_thread.h"
51 #include "mp3_playback.h"
52 #include "usb.h"
53 #include "status.h"
54 #include "ata.h"
55 #include "screens.h"
56 #include "playlist.h"
57 #include "playback.h"
58 #include "pcmbuf.h"
59 #include "buffer.h"
60 #include "dsp.h"
61 #include "abrepeat.h"
62 #include "cuesheet.h"
63 #ifdef HAVE_TAGCACHE
64 #include "tagcache.h"
65 #endif
66 #ifdef HAVE_LCD_BITMAP
67 #include "icons.h"
68 #include "peakmeter.h"
69 #include "action.h"
70 #include "albumart.h"
71 #endif
72 #include "lang.h"
73 #include "bookmark.h"
74 #include "misc.h"
75 #include "sound.h"
76 #include "metadata.h"
77 #include "splash.h"
78 #include "talk.h"
79 #include "ata_idle_notify.h"
81 #ifdef HAVE_RECORDING
82 #include "recording.h"
83 #include "talk.h"
84 #endif
86 #ifdef HAVE_WM8758
87 #include "menus/eq_menu.h"
88 #endif
90 #define PLAYBACK_VOICE
92 /* default point to start buffer refill */
93 #define AUDIO_DEFAULT_WATERMARK (1024*512)
94 /* amount of guess-space to allow for codecs that must hunt and peck
95 * for their correct seeek target, 32k seems a good size */
96 #define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
98 /* Define LOGF_ENABLE to enable logf output in this file */
99 /*#define LOGF_ENABLE*/
100 #include "logf.h"
102 /* macros to enable logf for queues
103 logging on SYS_TIMEOUT can be disabled */
104 #ifdef SIMULATOR
105 /* Define this for logf output of all queuing except SYS_TIMEOUT */
106 #define PLAYBACK_LOGQUEUES
107 /* Define this to logf SYS_TIMEOUT messages */
108 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
109 #endif
111 #ifdef PLAYBACK_LOGQUEUES
112 #define LOGFQUEUE logf
113 #else
114 #define LOGFQUEUE(...)
115 #endif
117 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
118 #define LOGFQUEUE_SYS_TIMEOUT logf
119 #else
120 #define LOGFQUEUE_SYS_TIMEOUT(...)
121 #endif
124 /* Define one constant that includes recording related functionality */
125 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
126 #define AUDIO_HAVE_RECORDING
127 #endif
129 enum {
130 Q_NULL = 0,
131 Q_AUDIO_PLAY = 1,
132 Q_AUDIO_STOP,
133 Q_AUDIO_PAUSE,
134 Q_AUDIO_SKIP,
135 Q_AUDIO_PRE_FF_REWIND,
136 Q_AUDIO_FF_REWIND,
137 Q_AUDIO_CHECK_NEW_TRACK,
138 Q_AUDIO_FLUSH,
139 Q_AUDIO_TRACK_CHANGED,
140 Q_AUDIO_DIR_SKIP,
141 Q_AUDIO_POSTINIT,
142 Q_AUDIO_FILL_BUFFER,
143 Q_CODEC_REQUEST_COMPLETE,
144 Q_CODEC_REQUEST_FAILED,
146 Q_CODEC_LOAD,
147 Q_CODEC_LOAD_DISK,
149 #ifdef AUDIO_HAVE_RECORDING
150 Q_ENCODER_LOAD_DISK,
151 Q_ENCODER_RECORD,
152 #endif
155 /* As defined in plugins/lib/xxx2wav.h */
156 #if MEM > 1
157 #define MALLOC_BUFSIZE (512*1024)
158 #define GUARD_BUFSIZE (32*1024)
159 #else
160 #define MALLOC_BUFSIZE (100*1024)
161 #define GUARD_BUFSIZE (8*1024)
162 #endif
164 /* As defined in plugin.lds */
165 #if defined(CPU_PP)
166 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
167 #define CODEC_IRAM_SIZE ((size_t)0xc000)
168 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
169 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
170 #define CODEC_IRAM_SIZE ((size_t)0x10000)
171 #else
172 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
173 #define CODEC_IRAM_SIZE ((size_t)0xc000)
174 #endif
176 bool audio_is_initialized = false;
177 static bool audio_thread_ready NOCACHEBSS_ATTR = false;
179 /* Variables are commented with the threads that use them: *
180 * A=audio, C=codec, V=voice. A suffix of - indicates that *
181 * the variable is read but not updated on that thread. */
182 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
184 /* Main state control */
185 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR = false; /* Codec loaded? (C/A-) */
186 static volatile bool playing NOCACHEBSS_ATTR = false; /* Is audio playing? (A) */
187 static volatile bool paused NOCACHEBSS_ATTR = false; /* Is audio paused? (A/C-) */
189 /* Ring buffer where compressed audio and codecs are loaded */
190 static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */
191 static unsigned char *malloc_buf = NULL; /* Start of malloc buffer (A/C-) */
192 /* FIXME: make filebuflen static */
193 size_t filebuflen = 0; /* Size of buffer (A/C-) */
194 /* FIXME: make buf_ridx (C/A-) */
196 /* Possible arrangements of the buffer */
197 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
198 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
199 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
200 static int buffer_state = BUFFER_STATE_TRASHED; /* Buffer state */
202 /* Used to keep the WPS up-to-date during track transtition */
203 static struct mp3entry prevtrack_id3;
205 /* Used to provide the codec with a pointer */
206 static struct mp3entry curtrack_id3;
208 /* Used to make next track info available while playing last track on buffer */
209 static struct mp3entry lasttrack_id3;
211 /* Track info structure about songs in the file buffer (A/C-) */
212 struct track_info {
213 int audio_hid; /* The ID for the track's buffer handle */
214 int id3_hid; /* The ID for the track's metadata handle */
215 int codec_hid; /* The ID for the track's codec handle */
216 #ifdef HAVE_ALBUMART
217 int aa_hid; /* The ID for the track's album art handle */
218 #endif
220 size_t filesize; /* File total length */
222 bool taginfo_ready; /* Is metadata read */
224 bool event_sent; /* Was this track's buffered event sent */
227 static struct track_info tracks[MAX_TRACK];
228 static volatile int track_ridx = 0; /* Track being decoded (A/C-) */
229 static int track_widx = 0; /* Track being buffered (A) */
231 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
232 static struct track_info *prev_ti = NULL; /* Pointer to the previously played
233 track */
235 /* Set by the audio thread when the current track information has updated
236 * and the WPS may need to update its cached information */
237 static bool track_changed = false;
239 /* Information used only for filling the buffer */
240 /* Playlist steps from playing track to next track to be buffered (A) */
241 static int last_peek_offset = 0;
243 /* Scrobbler support */
244 static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/
246 /* Track change controls */
247 static bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */
248 static bool playlist_end = false; /* Has the current playlist ended? (A) */
249 static bool dir_skip = false; /* Is a directory skip pending? (A) */
250 static bool new_playlist = false; /* Are we starting a new playlist? (A) */
251 static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */
252 static bool skipped_during_pause = false; /* Do we need to clear the PCM buffer when playback resumes (A) */
254 /* Callbacks which applications or plugins may set */
255 /* When the playing track has changed from the user's perspective */
256 void (*track_changed_callback)(struct mp3entry *id3) = NULL;
257 /* When a track has been buffered */
258 void (*track_buffer_callback)(struct mp3entry *id3) = NULL;
259 /* When a track's buffer has been overwritten or cleared */
260 void (*track_unbuffer_callback)(struct mp3entry *id3) = NULL;
262 static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */
264 /* Multiple threads */
265 /* Set the watermark to trigger buffer fill (A/C) FIXME */
266 static void set_filebuf_watermark(int seconds, size_t max);
268 /* Audio thread */
269 static struct event_queue audio_queue NOCACHEBSS_ATTR;
270 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR;
271 static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
272 static const char audio_thread_name[] = "audio";
274 static void audio_thread(void);
275 static void audio_initiate_track_change(long direction);
276 static bool audio_have_tracks(void);
277 static void audio_reset_buffer(void);
279 /* Codec thread */
280 extern struct codec_api ci;
281 static struct event_queue codec_queue NOCACHEBSS_ATTR;
282 static struct queue_sender_list codec_queue_sender_list;
283 static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
284 IBSS_ATTR;
285 static const char codec_thread_name[] = "codec";
286 struct thread_entry *codec_thread_p; /* For modifying thread priority later. */
288 /* --- Helper functions --- */
290 static struct mp3entry *bufgetid3(int handle_id)
292 if (handle_id < 0)
293 return NULL;
295 struct mp3entry *id3;
296 ssize_t ret = bufgetdata(handle_id, 0, (void *)&id3);
298 if (ret < 0 || ret != sizeof(struct mp3entry))
299 return NULL;
301 return id3;
304 static bool clear_track_info(struct track_info *track)
306 /* bufclose returns true if the handle is not found, or if it is closed
307 * successfully, so these checks are safe on non-existant handles */
308 if (!track)
309 return false;
311 if (track->codec_hid >= 0) {
312 if (bufclose(track->codec_hid))
313 track->codec_hid = -1;
314 else
315 return false;
318 if (track->id3_hid >= 0) {
319 if (bufclose(track->id3_hid))
320 track->id3_hid = -1;
321 else
322 return false;
325 if (track->audio_hid >= 0) {
326 if (bufclose(track->audio_hid))
327 track->audio_hid = -1;
328 else
329 return false;
332 #ifdef HAVE_ALBUMART
333 if (track->aa_hid >= 0) {
334 if (bufclose(track->aa_hid))
335 track->aa_hid = -1;
336 else
337 return false;
339 #endif
341 track->filesize = 0;
342 track->taginfo_ready = false;
343 track->event_sent = false;
345 return true;
348 /* --- External interfaces --- */
350 /* This sends a stop message and the audio thread will dump all it's
351 subsequenct messages */
352 void audio_hard_stop(void)
354 /* Stop playback */
355 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
356 queue_send(&audio_queue, Q_AUDIO_STOP, 1);
357 #ifdef PLAYBACK_VOICE
358 voice_stop();
359 #endif
362 bool audio_restore_playback(int type)
364 switch (type)
366 case AUDIO_WANT_PLAYBACK:
367 if (buffer_state != BUFFER_STATE_INITIALIZED)
368 audio_reset_buffer();
369 return true;
370 case AUDIO_WANT_VOICE:
371 if (buffer_state == BUFFER_STATE_TRASHED)
372 audio_reset_buffer();
373 return true;
374 default:
375 return false;
379 unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
381 unsigned char *buf, *end;
383 if (audio_is_initialized)
385 audio_hard_stop();
387 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
389 if (buffer_size == NULL)
391 /* Special case for talk_init to use since it already knows it's
392 trashed */
393 buffer_state = BUFFER_STATE_TRASHED;
394 return NULL;
397 if (talk_buf || buffer_state == BUFFER_STATE_TRASHED
398 || !talk_voice_required())
400 logf("get buffer: talk, audio");
401 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
402 the talk buffer is not needed because voice isn't being used, or
403 could be BUFFER_STATE_TRASHED already. If state is
404 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
405 without the caller knowing what's going on. Changing certain settings
406 may move it to a worse condition but the memory in use by something
407 else will remain undisturbed.
409 if (buffer_state != BUFFER_STATE_TRASHED)
411 talk_buffer_steal();
412 buffer_state = BUFFER_STATE_TRASHED;
415 buf = audiobuf;
416 end = audiobufend;
418 else
420 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
421 still BUFFER_STATE_INITIALIZED */
422 /* Skip talk buffer and move pcm buffer to end to maximize available
423 contiguous memory - no audio running means voice will not need the
424 swap space */
425 logf("get buffer: audio");
426 buf = audiobuf + talk_get_bufsize();
427 end = audiobufend - pcmbuf_init(audiobufend);
428 buffer_state = BUFFER_STATE_VOICED_ONLY;
431 *buffer_size = end - buf;
433 return buf;
436 #ifdef HAVE_RECORDING
437 unsigned char *audio_get_recording_buffer(size_t *buffer_size)
439 /* Stop audio, voice and obtain all available buffer space */
440 audio_hard_stop();
441 talk_buffer_steal();
443 unsigned char *end = audiobufend;
444 buffer_state = BUFFER_STATE_TRASHED;
445 *buffer_size = end - audiobuf;
447 return (unsigned char *)audiobuf;
450 bool audio_load_encoder(int afmt)
452 #ifndef SIMULATOR
453 const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER);
454 if (!enc_fn)
455 return false;
457 audio_remove_encoder();
458 ci.enc_codec_loaded = 0; /* clear any previous error condition */
460 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
461 queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (intptr_t)enc_fn);
463 while (ci.enc_codec_loaded == 0)
464 yield();
466 logf("codec loaded: %d", ci.enc_codec_loaded);
468 return ci.enc_codec_loaded > 0;
469 #else
470 (void)afmt;
471 return true;
472 #endif
473 } /* audio_load_encoder */
475 void audio_remove_encoder(void)
477 #ifndef SIMULATOR
478 /* force encoder codec unload (if currently loaded) */
479 if (ci.enc_codec_loaded <= 0)
480 return;
482 ci.stop_encoder = true;
483 while (ci.enc_codec_loaded > 0)
484 yield();
485 #endif
486 } /* audio_remove_encoder */
488 #endif /* HAVE_RECORDING */
490 #ifdef HAVE_ALBUMART
491 int audio_current_aa_hid(void)
493 int cur_idx;
494 int offset = ci.new_track + wps_offset;
496 cur_idx = track_ridx + offset;
497 cur_idx &= MAX_TRACK_MASK;
499 return tracks[cur_idx].aa_hid;
501 #endif
503 struct mp3entry* audio_current_track(void)
505 const char *filename;
506 const char *p;
507 static struct mp3entry temp_id3;
508 int cur_idx;
509 int offset = ci.new_track + wps_offset;
511 cur_idx = track_ridx + offset;
512 cur_idx &= MAX_TRACK_MASK;
514 if (cur_idx == track_ridx && *curtrack_id3.path)
516 /* The usual case */
517 return &curtrack_id3;
519 else if (offset == -1 && *prevtrack_id3.path)
521 /* We're in a track transition. The codec has moved on to the nex track,
522 but the audio being played is still the same (now previous) track.
523 prevtrack_id3.elapsed is being updated in an ISR by
524 codec_pcmbuf_position_callback */
525 return &prevtrack_id3;
527 else if (tracks[cur_idx].id3_hid >= 0)
529 /* Get the ID3 metadata from the main buffer */
530 return bufgetid3(tracks[cur_idx].id3_hid);
533 /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info
534 we have and return that. */
536 memset(&temp_id3, 0, sizeof(struct mp3entry));
538 filename = playlist_peek(0);
539 if (!filename)
540 filename = "No file!";
542 #ifdef HAVE_TC_RAMCACHE
543 if (tagcache_fill_tags(&temp_id3, filename))
544 return &temp_id3;
545 #endif
547 p = strrchr(filename, '/');
548 if (!p)
549 p = filename;
550 else
551 p++;
553 strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1);
554 temp_id3.title = &temp_id3.path[0];
556 return &temp_id3;
559 struct mp3entry* audio_next_track(void)
561 int next_idx = track_ridx;
563 if (!audio_have_tracks())
564 return NULL;
566 if (wps_offset == -1 && *prevtrack_id3.path)
568 /* We're in a track transition. The next track for the WPS is the one
569 currently being decoded. */
570 return &curtrack_id3;
573 next_idx++;
574 next_idx &= MAX_TRACK_MASK;
576 if (next_idx == track_widx)
578 /* The next track hasn't been buffered yet, so we return the static
579 version of its metadata. */
580 return &lasttrack_id3;
583 if (tracks[next_idx].id3_hid < 0)
584 return NULL;
585 else
586 return bufgetid3(tracks[next_idx].id3_hid);
589 bool audio_has_changed_track(void)
591 if (track_changed)
593 track_changed = false;
594 return true;
597 return false;
600 void audio_play(long offset)
602 logf("audio_play");
604 #ifdef PLAYBACK_VOICE
605 /* Truncate any existing voice output so we don't have spelling
606 * etc. over the first part of the played track */
607 talk_force_shutup();
608 #endif
610 /* Start playback */
611 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset);
612 /* Don't return until playback has actually started */
613 queue_send(&audio_queue, Q_AUDIO_PLAY, offset);
616 void audio_stop(void)
618 /* Stop playback */
619 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
620 /* Don't return until playback has actually stopped */
621 queue_send(&audio_queue, Q_AUDIO_STOP, 0);
624 void audio_pause(void)
626 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
627 /* Don't return until playback has actually paused */
628 queue_send(&audio_queue, Q_AUDIO_PAUSE, true);
631 void audio_resume(void)
633 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
634 /* Don't return until playback has actually resumed */
635 queue_send(&audio_queue, Q_AUDIO_PAUSE, false);
638 void audio_next(void)
640 if (playlist_check(ci.new_track + wps_offset + 1))
642 if (global_settings.beep)
643 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
645 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
646 queue_post(&audio_queue, Q_AUDIO_SKIP, 1);
647 /* Update wps while our message travels inside deep playback queues. */
648 wps_offset++;
649 track_changed = true;
651 else
653 /* No more tracks. */
654 if (global_settings.beep)
655 pcmbuf_beep(1000, 100, 1000*global_settings.beep);
659 void audio_prev(void)
661 if (playlist_check(ci.new_track + wps_offset - 1))
663 if (global_settings.beep)
664 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
666 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
667 queue_post(&audio_queue, Q_AUDIO_SKIP, -1);
668 /* Update wps while our message travels inside deep playback queues. */
669 wps_offset--;
670 track_changed = true;
672 else
674 /* No more tracks. */
675 if (global_settings.beep)
676 pcmbuf_beep(1000, 100, 1000*global_settings.beep);
680 void audio_next_dir(void)
682 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
683 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, 1);
686 void audio_prev_dir(void)
688 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
689 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, -1);
692 void audio_pre_ff_rewind(void)
694 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
695 queue_post(&audio_queue, Q_AUDIO_PRE_FF_REWIND, 0);
698 void audio_ff_rewind(long newpos)
700 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
701 queue_post(&audio_queue, Q_AUDIO_FF_REWIND, newpos);
704 void audio_flush_and_reload_tracks(void)
706 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
707 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0);
710 void audio_error_clear(void)
712 #ifdef AUDIO_HAVE_RECORDING
713 pcm_rec_error_clear();
714 #endif
717 int audio_status(void)
719 int ret = 0;
721 if (playing)
722 ret |= AUDIO_STATUS_PLAY;
724 if (paused)
725 ret |= AUDIO_STATUS_PAUSE;
727 #ifdef HAVE_RECORDING
728 /* Do this here for constitency with mpeg.c version */
729 ret |= pcm_rec_status();
730 #endif
732 return ret;
735 int audio_get_file_pos(void)
737 return 0;
740 #ifndef HAVE_FLASH_STORAGE
741 void audio_set_buffer_margin(int setting)
743 static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
744 buffer_margin = lookup[setting];
745 logf("buffer margin: %ld", (long)buffer_margin);
746 set_filebuf_watermark(buffer_margin, 0);
748 #endif
750 /* Take nescessary steps to enable or disable the crossfade setting */
751 void audio_set_crossfade(int enable)
753 size_t offset;
754 bool was_playing;
755 size_t size;
757 /* Tell it the next setting to use */
758 pcmbuf_crossfade_enable(enable);
760 /* Return if size hasn't changed or this is too early to determine
761 which in the second case there's no way we could be playing
762 anything at all */
763 if (pcmbuf_is_same_size())
765 /* This function is a copout and just syncs some variables -
766 to be removed at a later date */
767 pcmbuf_crossfade_enable_finished();
768 return;
771 offset = 0;
772 was_playing = playing;
774 /* Playback has to be stopped before changing the buffer size */
775 if (was_playing)
777 /* Store the track resume position */
778 offset = curtrack_id3.offset;
779 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK));
782 /* Blast it - audio buffer will have to be setup again next time
783 something plays */
784 audio_get_buffer(true, &size);
786 /* Restart playback if audio was running previously */
787 if (was_playing)
788 audio_play(offset);
791 /* --- Routines called from multiple threads --- */
793 static void set_filebuf_watermark(int seconds, size_t max)
795 size_t bytes;
797 if (!filebuf)
798 return; /* Audio buffers not yet set up */
800 bytes = seconds?MAX(curtrack_id3.bitrate * seconds * (1000/8), max):max;
801 bytes = MIN(bytes, filebuflen / 2);
802 buf_set_watermark(bytes);
805 const char * get_codec_filename(int cod_spec)
807 const char *fname;
809 #ifdef HAVE_RECORDING
810 /* Can choose decoder or encoder if one available */
811 int type = cod_spec & CODEC_TYPE_MASK;
812 int afmt = cod_spec & CODEC_AFMT_MASK;
814 if ((unsigned)afmt >= AFMT_NUM_CODECS)
815 type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
817 fname = (type == CODEC_TYPE_ENCODER) ?
818 audio_formats[afmt].codec_enc_root_fn :
819 audio_formats[afmt].codec_root_fn;
821 logf("%s: %d - %s",
822 (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
823 afmt, fname ? fname : "<unknown>");
824 #else /* !HAVE_RECORDING */
825 /* Always decoder */
826 if ((unsigned)cod_spec >= AFMT_NUM_CODECS)
827 cod_spec = AFMT_UNKNOWN;
828 fname = audio_formats[cod_spec].codec_root_fn;
829 logf("Codec: %d - %s", cod_spec, fname ? fname : "<unknown>");
830 #endif /* HAVE_RECORDING */
832 return fname;
833 } /* get_codec_filename */
835 /* --- Codec thread --- */
836 static bool codec_pcmbuf_insert_callback(
837 const void *ch1, const void *ch2, int count)
839 const char *src[2] = { ch1, ch2 };
841 while (count > 0)
843 int out_count = dsp_output_count(ci.dsp, count);
844 int inp_count;
845 char *dest;
847 /* Prevent audio from a previous track from playing */
848 if (ci.new_track || ci.stop_codec)
849 return true;
851 while ((dest = pcmbuf_request_buffer(&out_count)) == NULL)
853 sleep(1);
854 if (ci.seek_time || ci.new_track || ci.stop_codec)
855 return true;
858 /* Get the real input_size for output_size bytes, guarding
859 * against resampling buffer overflows. */
860 inp_count = dsp_input_count(ci.dsp, out_count);
862 if (inp_count <= 0)
863 return true;
865 /* Input size has grown, no error, just don't write more than length */
866 if (inp_count > count)
867 inp_count = count;
869 out_count = dsp_process(ci.dsp, dest, src, inp_count);
871 if (out_count <= 0)
872 return true;
874 pcmbuf_write_complete(out_count);
876 count -= inp_count;
879 return true;
880 } /* codec_pcmbuf_insert_callback */
882 static void* codec_get_memory_callback(size_t *size)
884 *size = MALLOC_BUFSIZE;
885 return malloc_buf;
888 /* Between the codec and PCM track change, we need to keep updating the
889 "elapsed" value of the previous (to the codec, but current to the
890 user/PCM/WPS) track, so that the progressbar reaches the end.
891 During that transition, the WPS will display prevtrack_id3. */
892 static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
893 static void codec_pcmbuf_position_callback(size_t size)
895 /* This is called from an ISR, so be quick */
896 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
897 prevtrack_id3.elapsed;
899 if (time >= prevtrack_id3.length)
901 pcmbuf_set_position_callback(NULL);
902 prevtrack_id3.elapsed = prevtrack_id3.length;
904 else
905 prevtrack_id3.elapsed = time;
908 static void codec_set_elapsed_callback(unsigned int value)
910 unsigned int latency;
911 if (ci.seek_time)
912 return;
914 #ifdef AB_REPEAT_ENABLE
915 ab_position_report(value);
916 #endif
918 latency = pcmbuf_get_latency();
919 if (value < latency)
920 curtrack_id3.elapsed = 0;
921 else if (value - latency > curtrack_id3.elapsed ||
922 value - latency < curtrack_id3.elapsed - 2)
924 curtrack_id3.elapsed = value - latency;
928 static void codec_set_offset_callback(size_t value)
930 unsigned int latency;
932 if (ci.seek_time)
933 return;
935 latency = pcmbuf_get_latency() * curtrack_id3.bitrate / 8;
936 if (value < latency)
937 curtrack_id3.offset = 0;
938 else
939 curtrack_id3.offset = value - latency;
942 static void codec_advance_buffer_counters(size_t amount)
944 bufadvance(CUR_TI->audio_hid, amount);
945 ci.curpos += amount;
948 /* copy up-to size bytes into ptr and return the actual size copied */
949 static size_t codec_filebuf_callback(void *ptr, size_t size)
951 ssize_t copy_n;
953 if (ci.stop_codec || !playing)
954 return 0;
956 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
958 /* Nothing requested OR nothing left */
959 if (copy_n == 0)
960 return 0;
962 /* Update read and other position pointers */
963 codec_advance_buffer_counters(copy_n);
965 /* Return the actual amount of data copied to the buffer */
966 return copy_n;
967 } /* codec_filebuf_callback */
969 static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
971 size_t copy_n = reqsize;
972 ssize_t ret;
973 void *ptr;
975 if (!playing)
977 *realsize = 0;
978 return NULL;
981 ret = bufgetdata(CUR_TI->audio_hid, reqsize, &ptr);
982 if (ret >= 0)
983 copy_n = MIN((size_t)ret, reqsize);
985 if (copy_n == 0)
987 *realsize = 0;
988 return NULL;
991 *realsize = copy_n;
993 return ptr;
994 } /* codec_request_buffer_callback */
996 static int get_codec_base_type(int type)
998 switch (type) {
999 case AFMT_MPA_L1:
1000 case AFMT_MPA_L2:
1001 case AFMT_MPA_L3:
1002 return AFMT_MPA_L3;
1005 return type;
1008 static void codec_advance_buffer_callback(size_t amount)
1010 codec_advance_buffer_counters(amount);
1011 codec_set_offset_callback(ci.curpos);
1014 static void codec_advance_buffer_loc_callback(void *ptr)
1016 size_t amount = buf_get_offset(CUR_TI->audio_hid, ptr);
1017 codec_advance_buffer_callback(amount);
1020 /* Copied from mpeg.c. Should be moved somewhere else. */
1021 static int codec_get_file_pos(void)
1023 int pos = -1;
1024 struct mp3entry *id3 = audio_current_track();
1026 if (id3->vbr)
1028 if (id3->has_toc)
1030 /* Use the TOC to find the new position */
1031 unsigned int percent, remainder;
1032 int curtoc, nexttoc, plen;
1034 percent = (id3->elapsed*100)/id3->length;
1035 if (percent > 99)
1036 percent = 99;
1038 curtoc = id3->toc[percent];
1040 if (percent < 99)
1041 nexttoc = id3->toc[percent+1];
1042 else
1043 nexttoc = 256;
1045 pos = (id3->filesize/256)*curtoc;
1047 /* Use the remainder to get a more accurate position */
1048 remainder = (id3->elapsed*100)%id3->length;
1049 remainder = (remainder*100)/id3->length;
1050 plen = (nexttoc - curtoc)*(id3->filesize/256);
1051 pos += (plen/100)*remainder;
1053 else
1055 /* No TOC exists, estimate the new position */
1056 pos = (id3->filesize / (id3->length / 1000)) *
1057 (id3->elapsed / 1000);
1060 else if (id3->bitrate)
1061 pos = id3->elapsed * (id3->bitrate / 8);
1062 else
1063 return -1;
1065 pos += id3->first_frame_offset;
1067 /* Don't seek right to the end of the file so that we can
1068 transition properly to the next song */
1069 if (pos >= (int)(id3->filesize - id3->id3v1len))
1070 pos = id3->filesize - id3->id3v1len - 1;
1072 return pos;
1075 static off_t codec_mp3_get_filepos_callback(int newtime)
1077 off_t newpos;
1079 curtrack_id3.elapsed = newtime;
1080 newpos = codec_get_file_pos();
1082 return newpos;
1085 static void codec_seek_complete_callback(void)
1087 logf("seek_complete");
1088 if (pcm_is_paused())
1090 /* If this is not a seamless seek, clear the buffer */
1091 pcmbuf_play_stop();
1092 dsp_configure(ci.dsp, DSP_FLUSH, 0);
1094 /* If playback was not 'deliberately' paused, unpause now */
1095 if (!paused)
1096 pcmbuf_pause(false);
1098 ci.seek_time = 0;
1101 static bool codec_seek_buffer_callback(size_t newpos)
1103 logf("codec_seek_buffer_callback");
1105 int ret = bufseek(CUR_TI->audio_hid, newpos);
1106 if (ret == 0) {
1107 ci.curpos = newpos;
1108 return true;
1110 else {
1111 return false;
1115 static void codec_configure_callback(int setting, intptr_t value)
1117 switch (setting) {
1118 case CODEC_SET_FILEBUF_WATERMARK:
1119 set_filebuf_watermark(buffer_margin, value);
1120 break;
1122 default:
1123 if (!dsp_configure(ci.dsp, setting, value))
1124 { logf("Illegal key:%d", setting); }
1128 static void codec_track_changed(void)
1130 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1131 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1134 static void codec_pcmbuf_track_changed_callback(void)
1136 pcmbuf_set_position_callback(NULL);
1137 codec_track_changed();
1140 static void codec_discard_codec_callback(void)
1142 if (CUR_TI->codec_hid >= 0)
1144 bufclose(CUR_TI->codec_hid);
1145 CUR_TI->codec_hid = -1;
1149 static inline void codec_gapless_track_change(void)
1151 /* callback keeps the progress bar moving while the pcmbuf empties */
1152 pcmbuf_set_position_callback(codec_pcmbuf_position_callback);
1153 /* set the pcmbuf callback for when the track really changes */
1154 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
1157 static inline void codec_crossfade_track_change(void)
1159 /* Initiate automatic crossfade mode */
1160 pcmbuf_crossfade_init(false);
1161 /* Notify the wps that the track change starts now */
1162 codec_track_changed();
1165 static void codec_track_skip_done(bool was_manual)
1167 /* Manual track change (always crossfade or flush audio). */
1168 if (was_manual)
1170 pcmbuf_crossfade_init(true);
1171 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1172 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1174 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1175 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1176 && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP)
1178 if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
1180 if (global_settings.playlist_shuffle)
1181 /* shuffle mode is on, so crossfade: */
1182 codec_crossfade_track_change();
1183 else
1184 /* shuffle mode is off, so do a gapless track change */
1185 codec_gapless_track_change();
1187 else
1188 /* normal crossfade: */
1189 codec_crossfade_track_change();
1191 else
1192 /* normal gapless playback. */
1193 codec_gapless_track_change();
1196 static bool codec_load_next_track(void)
1198 intptr_t result = Q_CODEC_REQUEST_FAILED;
1200 prev_track_elapsed = curtrack_id3.elapsed;
1202 if (ci.seek_time)
1203 codec_seek_complete_callback();
1205 #ifdef AB_REPEAT_ENABLE
1206 ab_end_of_track_report();
1207 #endif
1209 logf("Request new track");
1211 if (ci.new_track == 0)
1213 ci.new_track++;
1214 automatic_skip = true;
1217 if (!ci.stop_codec)
1219 trigger_cpu_boost();
1220 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1221 result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
1224 switch (result)
1226 case Q_CODEC_REQUEST_COMPLETE:
1227 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1228 codec_track_skip_done(!automatic_skip);
1229 return true;
1231 case Q_CODEC_REQUEST_FAILED:
1232 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1233 ci.new_track = 0;
1234 ci.stop_codec = true;
1235 return false;
1237 default:
1238 LOGFQUEUE("codec |< default");
1239 ci.stop_codec = true;
1240 return false;
1244 static bool codec_request_next_track_callback(void)
1246 int prev_codectype;
1248 if (ci.stop_codec || !playing)
1249 return false;
1251 prev_codectype = get_codec_base_type(curtrack_id3.codectype);
1253 if (!codec_load_next_track())
1254 return false;
1256 /* Seek to the beginning of the new track because if the struct mp3entry was
1257 buffered, "elapsed" might not be zero (if the track has been played
1258 already but not unbuffered) */
1259 codec_seek_buffer_callback(curtrack_id3.first_frame_offset);
1261 /* Check if the next codec is the same file. */
1262 if (prev_codectype == get_codec_base_type(curtrack_id3.codectype))
1264 logf("New track loaded");
1265 codec_discard_codec_callback();
1266 return true;
1268 else
1270 logf("New codec:%d/%d", curtrack_id3.codectype, prev_codectype);
1271 return false;
1275 static void codec_thread(void)
1277 struct queue_event ev;
1278 int status;
1280 while (1) {
1281 status = 0;
1282 queue_wait(&codec_queue, &ev);
1284 switch (ev.id) {
1285 case Q_CODEC_LOAD_DISK:
1286 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1287 queue_reply(&codec_queue, 1);
1288 audio_codec_loaded = true;
1289 ci.stop_codec = false;
1290 status = codec_load_file((const char *)ev.data, &ci);
1291 break;
1293 case Q_CODEC_LOAD:
1294 LOGFQUEUE("codec < Q_CODEC_LOAD");
1295 if (CUR_TI->codec_hid < 0) {
1296 logf("Codec slot is empty!");
1297 /* Wait for the pcm buffer to go empty */
1298 while (pcm_is_playing())
1299 yield();
1300 /* This must be set to prevent an infinite loop */
1301 ci.stop_codec = true;
1302 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1303 queue_post(&codec_queue, Q_AUDIO_PLAY, 0);
1304 break;
1307 audio_codec_loaded = true;
1308 ci.stop_codec = false;
1309 status = codec_load_buf(CUR_TI->codec_hid, &ci);
1310 break;
1312 #ifdef AUDIO_HAVE_RECORDING
1313 case Q_ENCODER_LOAD_DISK:
1314 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1315 audio_codec_loaded = false; /* Not audio codec! */
1316 logf("loading encoder");
1317 ci.stop_encoder = false;
1318 status = codec_load_file((const char *)ev.data, &ci);
1319 logf("encoder stopped");
1320 break;
1321 #endif /* AUDIO_HAVE_RECORDING */
1323 default:
1324 LOGFQUEUE("codec < default");
1327 if (audio_codec_loaded)
1329 if (ci.stop_codec)
1331 status = CODEC_OK;
1332 if (!playing)
1333 pcmbuf_play_stop();
1336 audio_codec_loaded = false;
1339 switch (ev.id) {
1340 case Q_CODEC_LOAD_DISK:
1341 case Q_CODEC_LOAD:
1342 LOGFQUEUE("codec < Q_CODEC_LOAD");
1343 if (playing)
1345 if (ci.new_track || status != CODEC_OK)
1347 if (!ci.new_track)
1349 logf("Codec failure");
1350 gui_syncsplash(HZ*2, "Codec failure");
1353 if (!codec_load_next_track())
1355 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1356 /* End of playlist */
1357 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1358 break;
1361 else
1363 logf("Codec finished");
1364 if (ci.stop_codec)
1366 /* Wait for the audio to stop playing before
1367 * triggering the WPS exit */
1368 while(pcm_is_playing())
1370 curtrack_id3.elapsed =
1371 curtrack_id3.length - pcmbuf_get_latency();
1372 sleep(1);
1374 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1375 /* End of playlist */
1376 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1377 break;
1381 if (CUR_TI->codec_hid >= 0)
1383 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1384 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
1386 else
1388 const char *codec_fn =
1389 get_codec_filename(curtrack_id3.codectype);
1390 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1391 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
1392 (intptr_t)codec_fn);
1395 break;
1397 #ifdef AUDIO_HAVE_RECORDING
1398 case Q_ENCODER_LOAD_DISK:
1399 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1401 if (status == CODEC_OK)
1402 break;
1404 logf("Encoder failure");
1405 gui_syncsplash(HZ*2, "Encoder failure");
1407 if (ci.enc_codec_loaded < 0)
1408 break;
1410 logf("Encoder failed to load");
1411 ci.enc_codec_loaded = -1;
1412 break;
1413 #endif /* AUDIO_HAVE_RECORDING */
1415 default:
1416 LOGFQUEUE("codec < default");
1418 } /* end switch */
1423 /* --- Audio thread --- */
1425 static bool audio_have_tracks(void)
1427 return track_ridx != track_widx || CUR_TI->filesize;
1430 static bool audio_have_free_tracks(void)
1432 if (track_widx < track_ridx)
1433 return track_widx + 1 < track_ridx;
1434 else if (track_ridx == 0)
1435 return track_widx < MAX_TRACK - 1;
1437 return true;
1440 int audio_track_count(void)
1442 if (audio_have_tracks())
1444 int relative_track_widx = track_widx;
1446 if (track_ridx > track_widx)
1447 relative_track_widx += MAX_TRACK;
1449 return relative_track_widx - track_ridx + 1;
1452 return 0;
1455 long audio_filebufused(void)
1457 return (long) buf_used();
1460 static void audio_update_trackinfo(void)
1462 if (CUR_TI->id3_hid >= 0)
1463 copy_mp3entry(&curtrack_id3, bufgetid3(CUR_TI->id3_hid));
1465 CUR_TI->taginfo_ready = (CUR_TI->id3_hid >= 0);
1467 int next_idx = track_ridx + 1;
1468 next_idx &= MAX_TRACK_MASK;
1470 tracks[next_idx].taginfo_ready = (tracks[next_idx].id3_hid >= 0);
1472 ci.filesize = CUR_TI->filesize;
1473 curtrack_id3.elapsed = 0;
1474 curtrack_id3.offset = 0;
1475 ci.id3 = &curtrack_id3;
1476 ci.curpos = 0;
1477 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1480 static void low_buffer_callback(void)
1482 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1483 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1486 static void audio_clear_track_entries(bool clear_unbuffered)
1488 int cur_idx = track_widx;
1490 logf("Clearing tracks:%d/%d, %d", track_ridx, track_widx, clear_unbuffered);
1492 /* This function is always called in association with a stop or a rebuffer,
1493 * we will reregister the callback at the end of a rebuffer if needed */
1494 unregister_buffer_low_callback(low_buffer_callback);
1496 /* Loop over all tracks from write-to-read */
1497 while (1)
1499 cur_idx++;
1500 cur_idx &= MAX_TRACK_MASK;
1502 if (cur_idx == track_ridx)
1503 break;
1505 /* If the track is buffered, conditionally clear/notify,
1506 * otherwise clear the track if that option is selected */
1507 if (tracks[cur_idx].event_sent)
1509 /* If there is an unbuffer callback, call it, otherwise,
1510 * just clear the track */
1511 if (track_unbuffer_callback && tracks[cur_idx].id3_hid >= 0)
1512 track_unbuffer_callback(bufgetid3(tracks[cur_idx].id3_hid));
1514 clear_track_info(&tracks[cur_idx]);
1516 else if (clear_unbuffered)
1517 clear_track_info(&tracks[cur_idx]);
1521 static bool audio_release_tracks(void)
1523 int i, cur_idx;
1525 logf("releasing all tracks");
1527 for(i = 0; i < MAX_TRACK; i++)
1529 cur_idx = (track_ridx + i) & MAX_TRACK_MASK;
1530 if (!clear_track_info(&tracks[cur_idx]))
1531 return false;
1534 return true;
1537 static bool audio_loadcodec(bool start_play)
1539 int prev_track;
1540 char codec_path[MAX_PATH]; /* Full path to codec */
1542 if (tracks[track_widx].id3_hid < 0) {
1543 return false;
1546 const char * codec_fn =
1547 get_codec_filename(bufgetid3(tracks[track_widx].id3_hid)->codectype);
1548 if (codec_fn == NULL)
1549 return false;
1551 tracks[track_widx].codec_hid = -1;
1553 if (start_play)
1555 /* Load the codec directly from disk and save some memory. */
1556 track_ridx = track_widx;
1557 ci.filesize = CUR_TI->filesize;
1558 ci.id3 = &curtrack_id3;
1559 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1560 ci.curpos = 0;
1561 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1562 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (intptr_t)codec_fn);
1563 return true;
1565 else
1567 /* If we already have another track than this one buffered */
1568 if (track_widx != track_ridx)
1570 prev_track = (track_widx - 1) & MAX_TRACK_MASK;
1572 /* If the previous codec is the same as this one, there is no need
1573 * to put another copy of it on the file buffer */
1574 if (get_codec_base_type(
1575 bufgetid3(tracks[track_widx].id3_hid)->codectype) ==
1576 get_codec_base_type(
1577 bufgetid3(tracks[prev_track].id3_hid)->codectype)
1578 && audio_codec_loaded)
1580 logf("Reusing prev. codec");
1581 return true;
1586 codec_get_full_path(codec_path, codec_fn);
1588 tracks[track_widx].codec_hid = bufopen(codec_path, 0, TYPE_CODEC);
1589 if (tracks[track_widx].codec_hid < 0)
1590 return false;
1592 logf("Loaded codec");
1594 return true;
1597 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
1598 static void audio_set_elapsed(struct mp3entry* id3)
1600 unsigned long offset = id3->offset > id3->first_frame_offset ?
1601 id3->offset - id3->first_frame_offset : 0;
1603 if ( id3->vbr ) {
1604 if ( id3->has_toc ) {
1605 /* calculate elapsed time using TOC */
1606 int i;
1607 unsigned int remainder, plen, relpos, nextpos;
1609 /* find wich percent we're at */
1610 for (i=0; i<100; i++ )
1611 if ( offset < id3->toc[i] * (id3->filesize / 256) )
1612 break;
1614 i--;
1615 if (i < 0)
1616 i = 0;
1618 relpos = id3->toc[i];
1620 if (i < 99)
1621 nextpos = id3->toc[i+1];
1622 else
1623 nextpos = 256;
1625 remainder = offset - (relpos * (id3->filesize / 256));
1627 /* set time for this percent (divide before multiply to prevent
1628 overflow on long files. loss of precision is negligible on
1629 short files) */
1630 id3->elapsed = i * (id3->length / 100);
1632 /* calculate remainder time */
1633 plen = (nextpos - relpos) * (id3->filesize / 256);
1634 id3->elapsed += (((remainder * 100) / plen) *
1635 (id3->length / 10000));
1637 else {
1638 /* no TOC exists. set a rough estimate using average bitrate */
1639 int tpk = id3->length /
1640 ((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
1641 1024);
1642 id3->elapsed = offset / 1024 * tpk;
1645 else
1647 /* constant bitrate, use exact calculation */
1648 if (id3->bitrate != 0)
1649 id3->elapsed = offset / (id3->bitrate / 8);
1653 /* Load one track by making the appropriate bufopen calls. Return true if
1654 everything required was loaded correctly, false if not. */
1655 static bool audio_load_track(int offset, bool start_play)
1657 char *trackname;
1658 char msgbuf[80];
1659 int fd = -1;
1660 int file_offset = 0;
1661 struct mp3entry id3;
1663 /* Stop buffer filling if there is no free track entries.
1664 Don't fill up the last track entry (we wan't to store next track
1665 metadata there). */
1666 if (!audio_have_free_tracks())
1668 logf("No free tracks");
1669 return false;
1672 last_peek_offset++;
1673 peek_again:
1674 logf("Buffering track:%d/%d", track_widx, track_ridx);
1675 /* Get track name from current playlist read position. */
1676 while ((trackname = playlist_peek(last_peek_offset)) != NULL)
1678 /* Handle broken playlists. */
1679 fd = open(trackname, O_RDONLY);
1680 if (fd < 0)
1682 logf("Open failed");
1683 /* Skip invalid entry from playlist. */
1684 playlist_skip_entry(NULL, last_peek_offset);
1686 else
1687 break;
1690 if (!trackname)
1692 logf("End-of-playlist");
1693 playlist_end = true;
1694 memset(&lasttrack_id3, 0, sizeof(struct mp3entry));
1695 return false;
1698 tracks[track_widx].filesize = filesize(fd);
1700 /* Set default values */
1701 if (start_play)
1703 buf_set_watermark(AUDIO_DEFAULT_WATERMARK);
1704 dsp_configure(ci.dsp, DSP_RESET, 0);
1705 track_changed = true;
1706 playlist_update_resume_info(audio_current_track());
1709 /* Get track metadata if we don't already have it. */
1710 if (tracks[track_widx].id3_hid < 0)
1712 if (get_metadata(&id3, fd, trackname))
1714 tracks[track_widx].id3_hid =
1715 bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3);
1716 tracks[track_widx].taginfo_ready = (tracks[track_widx].id3_hid >= 0);
1718 if (tracks[track_widx].id3_hid < 0)
1720 last_peek_offset--;
1721 close(fd);
1722 copy_mp3entry(&lasttrack_id3, &id3);
1723 return false;
1726 if (track_widx == track_ridx)
1727 copy_mp3entry(&curtrack_id3, &id3);
1729 if (start_play)
1731 track_changed = true;
1732 playlist_update_resume_info(audio_current_track());
1735 else
1737 logf("mde:%s!",trackname);
1739 /* Skip invalid entry from playlist. */
1740 playlist_skip_entry(NULL, last_peek_offset);
1741 tracks[track_widx].taginfo_ready = false;
1742 close(fd);
1743 goto peek_again;
1748 close(fd);
1750 #if 0
1751 if (cuesheet_is_enabled() && tracks[track_widx].id3.cuesheet_type == 1)
1753 char cuepath[MAX_PATH];
1755 struct cuesheet *cue = start_play ? curr_cue : temp_cue;
1757 if (look_for_cuesheet_file(trackname, cuepath) &&
1758 parse_cuesheet(cuepath, cue))
1760 strcpy((cue)->audio_filename, trackname);
1761 if (start_play)
1762 cue_spoof_id3(curr_cue, &tracks[track_widx].id3);
1765 #endif
1767 struct mp3entry *track_id3;
1769 if (track_widx == track_ridx)
1770 track_id3 = &curtrack_id3;
1771 else
1772 track_id3 = bufgetid3(tracks[track_widx].id3_hid);
1774 #ifdef HAVE_ALBUMART
1775 if (tracks[track_widx].aa_hid < 0 && gui_sync_wps_uses_albumart())
1777 char aa_path[MAX_PATH];
1778 if (find_albumart(track_id3, aa_path, sizeof(aa_path)))
1779 tracks[track_widx].aa_hid = bufopen(aa_path, 0, TYPE_BITMAP);
1781 #endif
1783 /* Load the codec. */
1784 if (!audio_loadcodec(start_play))
1786 if (tracks[track_widx].codec_hid == ERR_BUFFER_FULL)
1788 /* No space for codec on buffer, not an error */
1789 return false;
1792 /* This is an error condition, either no codec was found, or reading
1793 * the codec file failed part way through, either way, skip the track */
1794 snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname);
1795 /* We should not use gui_syncplash from audio thread! */
1796 gui_syncsplash(HZ*2, msgbuf);
1797 /* Skip invalid entry from playlist. */
1798 playlist_skip_entry(NULL, last_peek_offset);
1799 tracks[track_widx].taginfo_ready = false;
1800 goto peek_again;
1803 track_id3->elapsed = 0;
1805 enum data_type type = TYPE_PACKET_AUDIO;
1807 switch (track_id3->codectype) {
1808 case AFMT_MPA_L1:
1809 case AFMT_MPA_L2:
1810 case AFMT_MPA_L3:
1811 if (offset > 0) {
1812 file_offset = offset;
1813 track_id3->offset = offset;
1814 audio_set_elapsed(track_id3);
1816 break;
1818 case AFMT_WAVPACK:
1819 if (offset > 0) {
1820 file_offset = offset;
1821 track_id3->offset = offset;
1822 track_id3->elapsed = track_id3->length / 2;
1824 break;
1826 case AFMT_OGG_VORBIS:
1827 case AFMT_SPEEX:
1828 case AFMT_FLAC:
1829 case AFMT_PCM_WAV:
1830 case AFMT_A52:
1831 case AFMT_AAC:
1832 case AFMT_MPC:
1833 case AFMT_APE:
1834 if (offset > 0)
1835 track_id3->offset = offset;
1836 break;
1838 case AFMT_NSF:
1839 case AFMT_SPC:
1840 case AFMT_SID:
1841 logf("Loading atomic %d",track_id3->codectype);
1842 type = TYPE_ATOMIC_AUDIO;
1843 break;
1846 logf("alt:%s", trackname);
1848 if (file_offset > AUDIO_REBUFFER_GUESS_SIZE)
1849 file_offset -= AUDIO_REBUFFER_GUESS_SIZE;
1850 else if (track_id3->first_frame_offset)
1851 file_offset = track_id3->first_frame_offset;
1852 else
1853 file_offset = 0;
1855 tracks[track_widx].audio_hid = bufopen(trackname, file_offset, type);
1857 if (tracks[track_widx].audio_hid < 0)
1858 return false;
1860 if (start_play)
1862 ci.curpos=file_offset;
1863 buf_request_buffer_handle(tracks[track_widx].audio_hid);
1866 track_widx++;
1867 track_widx &= MAX_TRACK_MASK;
1869 return true;
1872 /* Send callback events to notify about new tracks. */
1873 static void audio_generate_postbuffer_events(void)
1875 int cur_idx;
1877 logf("Postbuffer:%d/%d",track_ridx,track_widx);
1879 if (audio_have_tracks())
1881 cur_idx = track_ridx;
1883 while (1) {
1884 if (!tracks[cur_idx].event_sent)
1886 /* Mark the event 'sent' even if we don't really send one */
1887 tracks[cur_idx].event_sent = true;
1888 if (track_buffer_callback && tracks[cur_idx].id3_hid >= 0)
1889 track_buffer_callback(bufgetid3(tracks[cur_idx].id3_hid));
1891 if (cur_idx == track_widx)
1892 break;
1893 cur_idx++;
1894 cur_idx &= MAX_TRACK_MASK;
1899 static void audio_fill_file_buffer(bool start_play, size_t offset)
1901 struct queue_event ev;
1902 bool had_next_track = audio_next_track() != NULL;
1903 bool continue_buffering;
1905 /* Must reset the buffer before use if trashed or voice only - voice
1906 file size shouldn't have changed so we can go straight from
1907 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
1908 if (buffer_state != BUFFER_STATE_INITIALIZED)
1909 audio_reset_buffer();
1911 logf("Starting buffer fill");
1913 if (!start_play)
1914 audio_clear_track_entries(false);
1916 /* Save the current resume position once. */
1917 playlist_update_resume_info(audio_current_track());
1919 do {
1920 continue_buffering = audio_load_track(offset, start_play);
1921 start_play = false;
1922 offset = 0;
1923 sleep(1);
1924 if (queue_peek(&audio_queue, &ev)) {
1925 if (ev.id != Q_AUDIO_FILL_BUFFER)
1927 /* There's a message in the queue. break the loop to treat it,
1928 and go back to filling after that. */
1929 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1930 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1932 break;
1934 } while (continue_buffering);
1936 if (!had_next_track && audio_next_track())
1937 track_changed = true;
1939 audio_generate_postbuffer_events();
1941 if (!continue_buffering)
1942 register_buffer_low_callback(low_buffer_callback);
1945 static void audio_rebuffer(void)
1947 logf("Forcing rebuffer");
1949 clear_track_info(CUR_TI);
1951 /* Reset track pointers */
1952 track_widx = track_ridx;
1953 audio_clear_track_entries(true);
1955 /* Fill the buffer */
1956 last_peek_offset = -1;
1957 ci.curpos = 0;
1959 if (!CUR_TI->taginfo_ready)
1960 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
1962 audio_fill_file_buffer(false, 0);
1965 /* Called on request from the codec to get a new track. This is the codec part
1966 of the track transition. */
1967 static int audio_check_new_track(void)
1969 int track_count = audio_track_count();
1970 int old_track_ridx = track_ridx;
1971 int i, idx;
1972 bool forward;
1974 if (dir_skip)
1976 dir_skip = false;
1977 if (playlist_next_dir(ci.new_track))
1979 ci.new_track = 0;
1980 audio_rebuffer();
1981 goto skip_done;
1983 else
1985 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1986 return Q_CODEC_REQUEST_FAILED;
1990 if (new_playlist)
1991 ci.new_track = 0;
1993 /* If the playlist isn't that big */
1994 if (!playlist_check(ci.new_track))
1996 if (ci.new_track >= 0)
1998 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1999 return Q_CODEC_REQUEST_FAILED;
2001 /* Find the beginning backward if the user over-skips it */
2002 while (!playlist_check(++ci.new_track))
2003 if (ci.new_track >= 0)
2005 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2006 return Q_CODEC_REQUEST_FAILED;
2009 /* Update the playlist */
2010 last_peek_offset -= ci.new_track;
2012 if (playlist_next(ci.new_track) < 0)
2014 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2015 return Q_CODEC_REQUEST_FAILED;
2018 if (new_playlist)
2020 ci.new_track = 1;
2021 new_playlist = false;
2024 /* Save the old track's metadata to allow the WPS to display it */
2025 copy_mp3entry(&prevtrack_id3, &curtrack_id3);
2027 /* Save a pointer to the old track to allow later clearing */
2028 prev_ti = CUR_TI;
2030 for (i = 0; i < ci.new_track; i++)
2032 idx = (track_ridx + i) & MAX_TRACK_MASK;
2033 struct mp3entry *id3 = bufgetid3(tracks[idx].id3_hid);
2034 ssize_t offset = buf_handle_offset(tracks[idx].audio_hid);
2035 if (!id3 || offset < 0 || (unsigned)offset > id3->first_frame_offset)
2037 /* We don't have all the audio data for that track, so clear it,
2038 but keep the metadata. */
2039 if (tracks[idx].audio_hid >= 0 && bufclose(tracks[idx].audio_hid))
2041 tracks[idx].audio_hid = -1;
2042 tracks[idx].filesize = 0;
2047 /* Move to the new track */
2048 track_ridx += ci.new_track;
2049 track_ridx &= MAX_TRACK_MASK;
2051 buf_set_base_handle(CUR_TI->audio_hid);
2053 if (automatic_skip)
2055 playlist_end = false;
2056 wps_offset = -ci.new_track;
2059 track_changed = true;
2061 /* If it is not safe to even skip this many track entries */
2062 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
2064 ci.new_track = 0;
2065 audio_rebuffer();
2066 goto skip_done;
2069 forward = ci.new_track > 0;
2070 ci.new_track = 0;
2072 /* If the target track is clearly not in memory */
2073 if (CUR_TI->filesize == 0 || !CUR_TI->taginfo_ready)
2075 audio_rebuffer();
2076 goto skip_done;
2079 /* When skipping backwards, it is possible that we've found a track that's
2080 * buffered, but which is around the track-wrap and therefor not the track
2081 * we are looking for */
2082 if (!forward)
2084 int cur_idx = track_ridx;
2085 bool taginfo_ready = true;
2086 /* We've wrapped the buffer backwards if new > old */
2087 bool wrap = track_ridx > old_track_ridx;
2089 while (1)
2091 cur_idx++;
2092 cur_idx &= MAX_TRACK_MASK;
2094 /* if we've advanced past the wrap when cur_idx is zeroed */
2095 if (!cur_idx)
2096 wrap = false;
2098 /* if we aren't still on the wrap and we've caught the old track */
2099 if (!(wrap || cur_idx < old_track_ridx))
2100 break;
2102 /* If we hit a track in between without valid tag info, bail */
2103 if (!tracks[cur_idx].taginfo_ready)
2105 taginfo_ready = false;
2106 break;
2109 if (!taginfo_ready)
2111 audio_rebuffer();
2115 skip_done:
2116 audio_update_trackinfo();
2117 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2118 return Q_CODEC_REQUEST_COMPLETE;
2121 void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3))
2123 track_buffer_callback = handler;
2126 void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3))
2128 track_unbuffer_callback = handler;
2131 void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3))
2133 track_changed_callback = handler;
2136 unsigned long audio_prev_elapsed(void)
2138 return prev_track_elapsed;
2141 static void audio_stop_codec_flush(void)
2143 ci.stop_codec = true;
2144 pcmbuf_pause(true);
2146 while (audio_codec_loaded)
2147 yield();
2149 /* If the audio codec is not loaded any more, and the audio is still
2150 * playing, it is now and _only_ now safe to call this function from the
2151 * audio thread */
2152 if (pcm_is_playing())
2153 pcmbuf_play_stop();
2154 pcmbuf_pause(paused);
2157 static void audio_stop_playback(void)
2159 /* If we were playing, save resume information */
2160 if (playing)
2162 struct mp3entry *id3 = NULL;
2164 if (!playlist_end || !ci.stop_codec)
2166 /* Set this early, the outside code yields and may allow the codec
2167 to try to wait for a reply on a buffer wait */
2168 ci.stop_codec = true;
2169 id3 = audio_current_track();
2172 /* Save the current playing spot, or NULL if the playlist has ended */
2173 playlist_update_resume_info(id3);
2175 prev_track_elapsed = curtrack_id3.elapsed;
2177 /* Increment index so runtime info is saved in audio_clear_track_entries().
2178 * Done here, as audio_stop_playback() may be called more than once.
2179 * Don't update runtime unless playback is stopped because of end of playlist.
2180 * Updating runtime when manually stopping a tracks, can destroy autoscores
2181 * and playcounts.
2183 if (playlist_end)
2185 track_ridx++;
2186 track_ridx &= MAX_TRACK_MASK;
2190 paused = false;
2191 audio_stop_codec_flush();
2192 playing = false;
2194 /* Mark all entries null. */
2195 audio_clear_track_entries(false);
2197 /* Close all tracks */
2198 audio_release_tracks();
2200 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
2203 static void audio_play_start(size_t offset)
2205 int i;
2207 #if INPUT_SRC_CAPS != 0
2208 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2209 audio_set_output_source(AUDIO_SRC_PLAYBACK);
2210 #endif
2212 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2213 paused = false;
2214 audio_stop_codec_flush();
2216 track_changed = true;
2217 playlist_end = false;
2219 playing = true;
2221 ci.new_track = 0;
2222 ci.seek_time = 0;
2223 wps_offset = 0;
2225 sound_set_volume(global_settings.volume);
2226 track_widx = track_ridx = 0;
2228 /* Clear all track entries. */
2229 for (i = 0; i < MAX_TRACK; i++) {
2230 clear_track_info(&tracks[i]);
2233 last_peek_offset = -1;
2235 /* Officially playing */
2236 queue_reply(&audio_queue, 1);
2238 #ifndef HAVE_FLASH_STORAGE
2239 set_filebuf_watermark(buffer_margin, 0);
2240 #endif
2241 audio_fill_file_buffer(true, offset);
2243 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2244 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
2248 /* Invalidates all but currently playing track. */
2249 static void audio_invalidate_tracks(void)
2251 if (audio_have_tracks())
2253 last_peek_offset = 0;
2254 playlist_end = false;
2255 track_widx = track_ridx;
2257 /* Mark all other entries null (also buffered wrong metadata). */
2258 audio_clear_track_entries(true);
2260 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2262 audio_fill_file_buffer(false, 0);
2266 static void audio_new_playlist(void)
2268 /* Prepare to start a new fill from the beginning of the playlist */
2269 last_peek_offset = -1;
2270 if (audio_have_tracks())
2272 if (paused)
2273 skipped_during_pause = true;
2274 playlist_end = false;
2275 track_widx = track_ridx;
2276 audio_clear_track_entries(true);
2278 track_widx++;
2279 track_widx &= MAX_TRACK_MASK;
2281 /* Mark the current track as invalid to prevent skipping back to it */
2282 CUR_TI->taginfo_ready = false;
2285 /* Signal the codec to initiate a track change forward */
2286 new_playlist = true;
2287 ci.new_track = 1;
2289 /* Officially playing */
2290 queue_reply(&audio_queue, 1);
2292 audio_fill_file_buffer(false, 0);
2295 static void audio_initiate_track_change(long direction)
2297 playlist_end = false;
2298 ci.new_track += direction;
2299 wps_offset -= direction;
2300 if (paused)
2301 skipped_during_pause = true;
2304 static void audio_initiate_dir_change(long direction)
2306 playlist_end = false;
2307 dir_skip = true;
2308 ci.new_track = direction;
2309 if (paused)
2310 skipped_during_pause = true;
2313 /* Called when PCM track change is complete */
2314 static void audio_finalise_track_change(void)
2316 logf("audio_finalise_track_change");
2318 if (automatic_skip)
2320 wps_offset = 0;
2321 automatic_skip = false;
2323 prevtrack_id3.path[0] = 0;
2325 if (prev_ti && prev_ti->audio_hid < 0)
2327 /* No audio left so we clear all the track info. */
2328 clear_track_info(prev_ti);
2331 if (track_changed_callback)
2332 track_changed_callback(&curtrack_id3);
2333 track_changed = true;
2334 playlist_update_resume_info(audio_current_track());
2338 * Layout audio buffer as follows - iram buffer depends on target:
2339 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
2341 static void audio_reset_buffer(void)
2343 /* see audio_get_recording_buffer if this is modified */
2344 logf("audio_reset_buffer");
2346 /* If the setup of anything allocated before the file buffer is
2347 changed, do check the adjustments after the buffer_alloc call
2348 as it will likely be affected and need sliding over */
2350 /* Initially set up file buffer as all space available */
2351 malloc_buf = audiobuf + talk_get_bufsize();
2352 /* Align the malloc buf to line size. Especially important to cf
2353 targets that do line reads/writes. */
2354 malloc_buf = (unsigned char *)(((uintptr_t)malloc_buf + 15) & ~15);
2355 filebuf = malloc_buf + MALLOC_BUFSIZE; /* filebuf line align implied */
2356 filebuflen = audiobufend - filebuf;
2358 filebuflen &= ~15;
2360 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
2361 filebuflen -= pcmbuf_init(filebuf + filebuflen) + GUARD_BUFSIZE;
2363 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
2364 will already be line aligned */
2365 filebuflen &= ~3;
2367 buffering_reset(filebuf, filebuflen);
2369 /* Clear any references to the file buffer */
2370 buffer_state = BUFFER_STATE_INITIALIZED;
2372 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
2373 /* Make sure everything adds up - yes, some info is a bit redundant but
2374 aids viewing and the sumation of certain variables should add up to
2375 the location of others. */
2377 size_t pcmbufsize;
2378 unsigned char * pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
2379 logf("mabuf: %08X", (unsigned)malloc_buf);
2380 logf("mabufe: %08X", (unsigned)(malloc_buf + MALLOC_BUFSIZE));
2381 logf("fbuf: %08X", (unsigned)filebuf);
2382 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
2383 logf("gbuf: %08X", (unsigned)(filebuf + filebuflen));
2384 logf("gbufe: %08X", (unsigned)(filebuf + filebuflen + GUARD_BUFSIZE));
2385 logf("pcmb: %08X", (unsigned)pcmbuf);
2386 logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
2388 #endif
2391 static void audio_thread(void)
2393 struct queue_event ev;
2395 pcm_postinit();
2397 audio_thread_ready = true;
2399 while (1)
2401 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
2403 switch (ev.id) {
2404 case Q_AUDIO_FILL_BUFFER:
2405 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
2406 if (!playing || playlist_end || ci.stop_codec)
2407 break;
2408 audio_fill_file_buffer(false, 0);
2409 break;
2411 case Q_AUDIO_PLAY:
2412 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2413 if (playing && ev.data <= 0)
2414 audio_new_playlist();
2415 else
2417 audio_stop_playback();
2418 audio_play_start((size_t)ev.data);
2420 break;
2422 case Q_AUDIO_STOP:
2423 LOGFQUEUE("audio < Q_AUDIO_STOP");
2424 if (playing)
2425 audio_stop_playback();
2426 if (ev.data != 0)
2427 queue_clear(&audio_queue);
2428 break;
2430 case Q_AUDIO_PAUSE:
2431 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
2432 if (!(bool) ev.data && skipped_during_pause && !pcmbuf_is_crossfade_active())
2433 pcmbuf_play_stop(); /* Flush old track on resume after skip */
2434 skipped_during_pause = false;
2435 if (!playing)
2436 break;
2437 pcmbuf_pause((bool)ev.data);
2438 paused = (bool)ev.data;
2439 break;
2441 case Q_AUDIO_SKIP:
2442 LOGFQUEUE("audio < Q_AUDIO_SKIP");
2443 audio_initiate_track_change((long)ev.data);
2444 break;
2446 case Q_AUDIO_PRE_FF_REWIND:
2447 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
2448 if (!playing)
2449 break;
2450 pcmbuf_pause(true);
2451 break;
2453 case Q_AUDIO_FF_REWIND:
2454 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
2455 if (!playing)
2456 break;
2457 ci.seek_time = (long)ev.data+1;
2458 break;
2460 case Q_AUDIO_CHECK_NEW_TRACK:
2461 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
2462 queue_reply(&audio_queue, audio_check_new_track());
2463 break;
2465 case Q_AUDIO_DIR_SKIP:
2466 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2467 playlist_end = false;
2468 audio_initiate_dir_change(ev.data);
2469 break;
2471 case Q_AUDIO_FLUSH:
2472 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
2473 audio_invalidate_tracks();
2474 break;
2476 case Q_AUDIO_TRACK_CHANGED:
2477 /* PCM track change done */
2478 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2479 audio_finalise_track_change();
2480 break;
2482 #ifndef SIMULATOR
2483 case SYS_USB_CONNECTED:
2484 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2485 if (playing)
2486 audio_stop_playback();
2487 #ifdef PLAYBACK_VOICE
2488 voice_stop();
2489 #endif
2490 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2491 usb_wait_for_disconnect(&audio_queue);
2493 /* Mark all entries null. */
2494 audio_clear_track_entries(false);
2496 /* release tracks to make sure all handles are closed */
2497 audio_release_tracks();
2498 break;
2499 #endif
2501 case SYS_TIMEOUT:
2502 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
2503 break;
2505 default:
2506 LOGFQUEUE("audio < default");
2507 break;
2508 } /* end switch */
2509 } /* end while */
2512 #ifdef ROCKBOX_HAS_LOGF
2513 static void audio_test_track_changed_event(struct mp3entry *id3)
2515 (void)id3;
2517 logf("tce:%s", id3->path);
2519 #endif
2521 /* Initialize the audio system - called from init() in main.c.
2522 * Last function because of all the references to internal symbols
2524 void audio_init(void)
2526 struct thread_entry *audio_thread_p;
2528 /* Can never do this twice */
2529 if (audio_is_initialized)
2531 logf("audio: already initialized");
2532 return;
2535 logf("audio: initializing");
2537 /* Initialize queues before giving control elsewhere in case it likes
2538 to send messages. Thread creation will be delayed however so nothing
2539 starts running until ready if something yields such as talk_init. */
2540 queue_init(&audio_queue, true);
2541 queue_enable_queue_send(&audio_queue, &audio_queue_sender_list);
2542 queue_init(&codec_queue, false);
2543 queue_enable_queue_send(&codec_queue, &codec_queue_sender_list);
2545 pcm_init();
2547 #ifdef ROCKBOX_HAS_LOGF
2548 audio_set_track_changed_event(audio_test_track_changed_event);
2549 #endif
2551 /* Initialize codec api. */
2552 ci.read_filebuf = codec_filebuf_callback;
2553 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
2554 ci.get_codec_memory = codec_get_memory_callback;
2555 ci.request_buffer = codec_request_buffer_callback;
2556 ci.advance_buffer = codec_advance_buffer_callback;
2557 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
2558 ci.request_next_track = codec_request_next_track_callback;
2559 ci.mp3_get_filepos = codec_mp3_get_filepos_callback;
2560 ci.seek_buffer = codec_seek_buffer_callback;
2561 ci.seek_complete = codec_seek_complete_callback;
2562 ci.set_elapsed = codec_set_elapsed_callback;
2563 ci.set_offset = codec_set_offset_callback;
2564 ci.configure = codec_configure_callback;
2565 ci.discard_codec = codec_discard_codec_callback;
2566 ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP,
2567 CODEC_IDX_AUDIO);
2569 /* initialize the buffer */
2570 filebuf = audiobuf;
2572 /* audio_reset_buffer must to know the size of voice buffer so init
2573 talk first */
2574 talk_init();
2576 codec_thread_p = create_thread(
2577 codec_thread, codec_stack, sizeof(codec_stack),
2578 CREATE_THREAD_FROZEN,
2579 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
2580 IF_COP(, CPU));
2582 audio_thread_p = create_thread(audio_thread, audio_stack,
2583 sizeof(audio_stack), CREATE_THREAD_FROZEN,
2584 audio_thread_name IF_PRIO(, PRIORITY_BACKGROUND)
2585 IF_COP(, CPU));
2587 #ifdef PLAYBACK_VOICE
2588 voice_thread_init();
2589 #endif
2591 /* Set crossfade setting for next buffer init which should be about... */
2592 pcmbuf_crossfade_enable(global_settings.crossfade);
2594 /* initialize the buffering system */
2596 buffering_init();
2597 /* ...now! Set up the buffers */
2598 audio_reset_buffer();
2600 int i;
2601 for(i = 0; i < MAX_TRACK; i++)
2603 tracks[i].audio_hid = -1;
2604 tracks[i].id3_hid = -1;
2605 tracks[i].codec_hid = -1;
2606 #ifdef HAVE_ALBUMART
2607 tracks[i].aa_hid = -1;
2608 #endif
2611 /* Probably safe to say */
2612 audio_is_initialized = true;
2614 sound_settings_apply();
2615 #ifdef HAVE_WM8758
2616 eq_hw_enable(global_settings.eq_hw_enabled);
2617 #endif
2618 #ifndef HAVE_FLASH_STORAGE
2619 audio_set_buffer_margin(global_settings.buffer_margin);
2620 #endif
2622 /* it's safe to let the threads run now */
2623 #ifdef PLAYBACK_VOICE
2624 voice_thread_resume();
2625 #endif
2626 thread_thaw(codec_thread_p);
2627 thread_thaw(audio_thread_p);
2629 } /* audio_init */
2631 void audio_wait_for_init(void)
2633 /* audio thread will only set this once after it finished the final
2634 * audio hardware init so this little construct is safe - even
2635 * cross-core. */
2636 while (!audio_thread_ready)
2638 sleep(0);