audio_fill_file_buffer() cleaning and tweaking
[Rockbox.git] / apps / playback.c
blob1a6d0e8d4acb767cfa58c286eeceac589266fcc2
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 "mp3_playback.h"
51 #include "usb.h"
52 #include "status.h"
53 #include "ata.h"
54 #include "screens.h"
55 #include "playlist.h"
56 #include "playback.h"
57 #include "pcmbuf.h"
58 #include "buffer.h"
59 #include "dsp.h"
60 #include "abrepeat.h"
61 #include "cuesheet.h"
62 #ifdef HAVE_TAGCACHE
63 #include "tagcache.h"
64 #endif
65 #ifdef HAVE_LCD_BITMAP
66 #include "icons.h"
67 #include "peakmeter.h"
68 #include "action.h"
69 #endif
70 #include "lang.h"
71 #include "bookmark.h"
72 #include "misc.h"
73 #include "sound.h"
74 #include "metadata.h"
75 #include "splash.h"
76 #include "talk.h"
77 #include "ata_idle_notify.h"
79 #ifdef HAVE_RECORDING
80 #include "recording.h"
81 #include "talk.h"
82 #endif
84 #ifdef HAVE_WM8758
85 #include "menus/eq_menu.h"
86 #endif
88 #define PLAYBACK_VOICE
91 /* Define LOGF_ENABLE to enable logf output in this file */
92 /*#define LOGF_ENABLE*/
93 #include "logf.h"
95 /* macros to enable logf for queues
96 logging on SYS_TIMEOUT can be disabled */
97 #ifdef SIMULATOR
98 /* Define this for logf output of all queuing except SYS_TIMEOUT */
99 #define PLAYBACK_LOGQUEUES
100 /* Define this to logf SYS_TIMEOUT messages */
101 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
102 #endif
104 #ifdef PLAYBACK_LOGQUEUES
105 #define LOGFQUEUE logf
106 #else
107 #define LOGFQUEUE(...)
108 #endif
110 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
111 #define LOGFQUEUE_SYS_TIMEOUT logf
112 #else
113 #define LOGFQUEUE_SYS_TIMEOUT(...)
114 #endif
117 /* Define one constant that includes recording related functionality */
118 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
119 #define AUDIO_HAVE_RECORDING
120 #endif
122 enum {
123 Q_AUDIO_PLAY = 1,
124 Q_AUDIO_STOP,
125 Q_AUDIO_PAUSE,
126 Q_AUDIO_SKIP,
127 Q_AUDIO_PRE_FF_REWIND,
128 Q_AUDIO_FF_REWIND,
129 Q_AUDIO_CHECK_NEW_TRACK,
130 Q_AUDIO_FLUSH,
131 Q_AUDIO_TRACK_CHANGED,
132 Q_AUDIO_DIR_SKIP,
133 Q_AUDIO_POSTINIT,
134 Q_AUDIO_FILL_BUFFER,
135 Q_CODEC_REQUEST_COMPLETE,
136 Q_CODEC_REQUEST_FAILED,
138 Q_VOICE_PLAY,
139 Q_VOICE_STOP,
141 Q_CODEC_LOAD,
142 Q_CODEC_LOAD_DISK,
144 #ifdef AUDIO_HAVE_RECORDING
145 Q_ENCODER_LOAD_DISK,
146 Q_ENCODER_RECORD,
147 #endif
150 /* As defined in plugins/lib/xxx2wav.h */
151 #if MEM > 1
152 #define MALLOC_BUFSIZE (512*1024)
153 #define GUARD_BUFSIZE (32*1024)
154 #else
155 #define MALLOC_BUFSIZE (100*1024)
156 #define GUARD_BUFSIZE (8*1024)
157 #endif
159 /* As defined in plugin.lds */
160 #if defined(CPU_PP)
161 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
162 #define CODEC_IRAM_SIZE ((size_t)0xc000)
163 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
164 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
165 #define CODEC_IRAM_SIZE ((size_t)0x10000)
166 #else
167 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
168 #define CODEC_IRAM_SIZE ((size_t)0xc000)
169 #endif
171 #ifndef IBSS_ATTR_VOICE_STACK
172 #define IBSS_ATTR_VOICE_STACK IBSS_ATTR
173 #endif
175 bool audio_is_initialized = false;
177 /* Variables are commented with the threads that use them: *
178 * A=audio, C=codec, V=voice. A suffix of - indicates that *
179 * the variable is read but not updated on that thread. */
180 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
182 /* Main state control */
183 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR = false; /* Codec loaded? (C/A-) */
184 static volatile bool playing NOCACHEBSS_ATTR = false; /* Is audio playing? (A) */
185 static volatile bool paused NOCACHEBSS_ATTR = false; /* Is audio paused? (A/C-) */
187 /* Ring buffer where compressed audio and codecs are loaded */
188 static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */
189 static unsigned char *malloc_buf = NULL; /* Start of malloc buffer (A/C-) */
190 /* FIXME: make filebuflen static */
191 size_t filebuflen = 0; /* Size of buffer (A/C-) */
192 /* FIXME: make buf_ridx (C/A-) */
194 /* Possible arrangements of the buffer */
195 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
196 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
197 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
198 static int buffer_state = BUFFER_STATE_TRASHED; /* Buffer state */
200 static struct mp3entry prevtrack_id3;
201 static struct mp3entry curtrack_id3;
202 static struct mp3entry nexttrack_id3;
204 /* Track info structure about songs in the file buffer (A/C-) */
205 struct track_info {
206 int audio_hid; /* The ID for the track's buffer handle */
207 int id3_hid; /* The ID for the track's metadata handle */
208 int codec_hid; /* The ID for the track's codec handle */
210 size_t codecsize; /* Codec length in bytes */
211 size_t filesize; /* File total length */
213 bool taginfo_ready; /* Is metadata read */
215 bool event_sent; /* Was this track's buffered event sent */
218 static struct track_info tracks[MAX_TRACK];
219 static volatile int track_ridx = 0; /* Track being decoded (A/C-) */
220 static int track_widx = 0; /* Track being buffered (A) */
222 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
224 /* Set by the audio thread when the current track information has updated
225 * and the WPS may need to update its cached information */
226 static bool track_changed = false;
228 /* Information used only for filling the buffer */
229 /* Playlist steps from playing track to next track to be buffered (A) */
230 static int last_peek_offset = 0;
232 /* Scrobbler support */
233 static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/
235 /* Track change controls */
236 static bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */
237 static bool playlist_end = false; /* Has the current playlist ended? (A) */
238 static bool dir_skip = false; /* Is a directory skip pending? (A) */
239 static bool new_playlist = false; /* Are we starting a new playlist? (A) */
240 static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */
241 static bool skipped_during_pause = false; /* Do we need to clear the PCM buffer when playback resumes (A) */
243 /* Callbacks which applications or plugins may set */
244 /* When the playing track has changed from the user's perspective */
245 void (*track_changed_callback)(struct mp3entry *id3) = NULL;
246 /* When a track has been buffered */
247 void (*track_buffer_callback)(struct mp3entry *id3, bool last_track) = NULL;
248 /* When a track's buffer has been overwritten or cleared */
249 void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track) = NULL;
251 /* Configuration */
252 static size_t conf_watermark = 0; /* Level to trigger filebuf fill (A/C) FIXME */
253 static size_t conf_filechunk = 0; /* Largest chunk the codec accepts (A/C) FIXME */
254 static size_t conf_preseek = 0; /* Codec pre-seek margin (A/C) FIXME */
255 static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */
256 #if MEM > 8
257 static size_t high_watermark = 0; /* High watermark for rebuffer (A/V/other) */
258 #endif
260 /* Multiple threads */
261 static void set_current_codec(int codec_idx);
262 /* Set the watermark to trigger buffer fill (A/C) FIXME */
263 static void set_filebuf_watermark(int seconds);
265 /* Audio thread */
266 static struct event_queue audio_queue NOCACHEBSS_ATTR;
267 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR;
268 static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
269 static const char audio_thread_name[] = "audio";
271 static void audio_thread(void);
272 static void audio_initiate_track_change(long direction);
273 static bool audio_have_tracks(void);
274 static void audio_reset_buffer(void);
276 /* Codec thread */
277 extern struct codec_api ci;
278 static struct event_queue codec_queue NOCACHEBSS_ATTR;
279 static struct queue_sender_list codec_queue_sender_list;
280 static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
281 IBSS_ATTR;
282 static const char codec_thread_name[] = "codec";
283 struct thread_entry *codec_thread_p; /* For modifying thread priority later. */
285 static volatile int current_codec IDATA_ATTR; /* Current codec (normal/voice) */
287 /* Voice thread */
288 #ifdef PLAYBACK_VOICE
290 extern struct codec_api ci_voice;
292 static struct thread_entry *voice_thread_p = NULL;
293 static struct event_queue voice_queue NOCACHEBSS_ATTR;
294 static long voice_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
295 IBSS_ATTR_VOICE_STACK;
296 static const char voice_thread_name[] = "voice codec";
298 /* Voice codec swapping control */
299 extern unsigned char codecbuf[]; /* DRAM codec swap buffer */
301 #ifdef SIMULATOR
302 /* IRAM codec swap buffer for sim*/
303 static unsigned char sim_iram[CODEC_IRAM_SIZE];
304 #undef CODEC_IRAM_ORIGIN
305 #define CODEC_IRAM_ORIGIN sim_iram
306 #endif
308 /* iram_buf and dram_buf are either both NULL or both non-NULL */
309 /* Pointer to IRAM buffer for codec swapping */
310 static unsigned char *iram_buf = NULL;
311 /* Pointer to DRAM buffer for codec swapping */
312 static unsigned char *dram_buf = NULL;
313 /* Parity of swap_codec calls - needed because one codec swapping itself in
314 automatically swaps in the other and the swap when unlocking should not
315 happen if the parity is even.
317 static bool swap_codec_parity NOCACHEBSS_ATTR = false; /* true=odd, false=even */
318 /* Locking to control which codec (normal/voice) is running */
319 static struct semaphore sem_codecthread NOCACHEBSS_ATTR;
320 static struct event event_codecthread NOCACHEBSS_ATTR;
322 /* Voice state */
323 static volatile bool voice_thread_start = false; /* Triggers voice playback (A/V) */
324 static volatile bool voice_is_playing NOCACHEBSS_ATTR = false; /* Is voice currently playing? (V) */
325 static volatile bool voice_codec_loaded NOCACHEBSS_ATTR = false; /* Is voice codec loaded (V/A-) */
326 static unsigned char *voicebuf = NULL;
327 static size_t voice_remaining = 0;
329 #ifdef IRAM_STEAL
330 /* Voice IRAM has been stolen for other use */
331 static bool voice_iram_stolen = false;
332 #endif
334 static void (*voice_getmore)(unsigned char** start, size_t* size) = NULL;
336 struct voice_info {
337 void (*callback)(unsigned char **start, size_t* size);
338 size_t size;
339 unsigned char *buf;
341 static void voice_thread(void);
342 static void voice_stop(void);
344 #endif /* PLAYBACK_VOICE */
347 /* --- Helper functions --- */
349 struct mp3entry *bufgetid3(int handle_id)
351 if (handle_id < 0)
352 return NULL;
354 struct mp3entry *id3;
355 ssize_t ret = bufgetdata(handle_id, 0, (void *)&id3);
357 if (ret < 0 || ret != sizeof(struct mp3entry))
358 return NULL;
360 return id3;
363 void *bufgetcodec(struct track_info *track)
365 void *ptr;
366 ssize_t ret = bufgetdata(track->codec_hid, track->codecsize, &ptr);
368 if (ret == -2) {
369 request_buffer_handle(CUR_TI->audio_hid);
372 while (ret == -2) {
373 sleep(1);
374 ret = bufgetdata(track->codec_hid, track->codecsize, &ptr);
377 if (ret < 0)
378 return NULL;
379 else
380 return ptr;
383 void clear_track_info(struct track_info *track)
385 if (!track)
386 return;
388 if (track->codec_hid > 0) {
389 bufclose(track->codec_hid);
392 if (track->id3_hid > 0) {
393 bufclose(track->id3_hid);
396 if (track->audio_hid > 0) {
397 bufclose(track->audio_hid);
400 memset(track, 0, sizeof(struct track_info));
403 /* --- External interfaces --- */
405 void mp3_play_data(const unsigned char* start, int size,
406 void (*get_more)(unsigned char** start, size_t* size))
408 #ifdef PLAYBACK_VOICE
409 static struct voice_info voice_clip;
410 voice_clip.callback = get_more;
411 voice_clip.buf = (unsigned char*)start;
412 voice_clip.size = size;
413 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
414 queue_post(&voice_queue, Q_VOICE_STOP, 0);
415 LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
416 queue_post(&voice_queue, Q_VOICE_PLAY, (intptr_t)&voice_clip);
417 voice_thread_start = true;
418 trigger_cpu_boost();
419 #else
420 (void) start;
421 (void) size;
422 (void) get_more;
423 #endif
426 void mp3_play_stop(void)
428 #ifdef PLAYBACK_VOICE
429 queue_remove_from_head(&voice_queue, Q_VOICE_STOP);
430 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
431 queue_post(&voice_queue, Q_VOICE_STOP, 1);
432 #endif
435 void mp3_play_pause(bool play)
437 /* a dummy */
438 (void)play;
441 bool mp3_is_playing(void)
443 #ifdef PLAYBACK_VOICE
444 return voice_is_playing;
445 #else
446 return false;
447 #endif
450 /* If voice could be swapped out - wait for it to return
451 * Used by buffer claming functions.
453 static void wait_for_voice_swap_in(void)
455 #ifdef PLAYBACK_VOICE
456 if (NULL == iram_buf)
457 return;
459 event_wait(&event_codecthread, STATE_NONSIGNALED);
460 #endif /* PLAYBACK_VOICE */
463 /* This sends a stop message and the audio thread will dump all it's
464 subsequenct messages */
465 static void audio_hard_stop(void)
467 /* Stop playback */
468 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
469 queue_send(&audio_queue, Q_AUDIO_STOP, 1);
472 unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
474 unsigned char *buf, *end;
476 if (audio_is_initialized)
478 audio_hard_stop();
479 wait_for_voice_swap_in();
480 #ifdef PLAYBACK_VOICE
481 voice_stop();
482 #endif
484 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
486 if (buffer_size == NULL)
488 /* Special case for talk_init to use since it already knows it's
489 trashed */
490 buffer_state = BUFFER_STATE_TRASHED;
491 return NULL;
494 if (talk_buf || buffer_state == BUFFER_STATE_TRASHED
495 || !talk_voice_required())
497 logf("get buffer: talk, audio");
498 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
499 the talk buffer is not needed because voice isn't being used, or
500 could be BUFFER_STATE_TRASHED already. If state is
501 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
502 without the caller knowing what's going on. Changing certain settings
503 may move it to a worse condition but the memory in use by something
504 else will remain undisturbed.
506 if (buffer_state != BUFFER_STATE_TRASHED)
508 talk_buffer_steal();
509 buffer_state = BUFFER_STATE_TRASHED;
512 buf = audiobuf;
513 end = audiobufend;
515 else
517 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
518 still BUFFER_STATE_INITIALIZED */
519 /* Skip talk buffer and move pcm buffer to end to maximize available
520 contiguous memory - no audio running means voice will not need the
521 swap space */
522 logf("get buffer: audio");
523 buf = audiobuf + talk_get_bufsize();
524 end = audiobufend - pcmbuf_init(audiobufend);
525 buffer_state = BUFFER_STATE_VOICED_ONLY;
528 *buffer_size = end - buf;
530 return buf;
533 #ifdef IRAM_STEAL
534 void audio_iram_steal(void)
536 /* We need to stop audio playback in order to use codec IRAM */
537 audio_hard_stop();
539 #ifdef PLAYBACK_VOICE
540 if (NULL != iram_buf)
542 /* Can't already be stolen */
543 if (voice_iram_stolen)
544 return;
546 /* Must wait for voice to be current again if it is swapped which
547 would cause the caller's buffer to get clobbered when voice locks
548 and runs - we'll wait for it to lock and yield again then make sure
549 the ride has come to a complete stop */
550 wait_for_voice_swap_in();
551 voice_stop();
553 /* Save voice IRAM but just memcpy - safe to do here since voice
554 is current and no audio codec is loaded */
555 memcpy(iram_buf, CODEC_IRAM_ORIGIN, CODEC_IRAM_SIZE);
556 voice_iram_stolen = true;
558 else
560 /* Nothing much to do if no voice */
561 voice_iram_stolen = false;
563 #endif
565 #endif /* IRAM_STEAL */
567 #ifdef HAVE_RECORDING
568 unsigned char *audio_get_recording_buffer(size_t *buffer_size)
570 /* Don't allow overwrite of voice swap area or we'll trash the
571 swapped-out voice codec but can use whole thing if none */
572 unsigned char *end;
574 /* Stop audio and voice. Wait for voice to swap in and be clear
575 of pending events to ensure trouble-free operation of encoders */
576 audio_hard_stop();
577 wait_for_voice_swap_in();
578 #ifdef PLAYBACK_VOICE
579 voice_stop();
580 #endif
581 talk_buffer_steal();
583 #ifdef PLAYBACK_VOICE
584 /* If no dram_buf, swap space not used and recording gets more
585 memory. Codec swap areas will remain unaffected by the next init
586 since they're allocated at the end of the buffer and their sizes
587 don't change between calls */
588 end = dram_buf;
589 if (NULL == end)
590 #endif /* PLAYBACK_VOICE */
591 end = audiobufend;
593 buffer_state = BUFFER_STATE_TRASHED;
595 *buffer_size = end - audiobuf;
597 return (unsigned char *)audiobuf;
600 bool audio_load_encoder(int afmt)
602 #ifndef SIMULATOR
603 const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER);
604 if (!enc_fn)
605 return false;
607 audio_remove_encoder();
608 ci.enc_codec_loaded = 0; /* clear any previous error condition */
610 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
611 queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (intptr_t)enc_fn);
613 while (ci.enc_codec_loaded == 0)
614 yield();
616 logf("codec loaded: %d", ci.enc_codec_loaded);
618 return ci.enc_codec_loaded > 0;
619 #else
620 (void)afmt;
621 return true;
622 #endif
623 } /* audio_load_encoder */
625 void audio_remove_encoder(void)
627 #ifndef SIMULATOR
628 /* force encoder codec unload (if currently loaded) */
629 if (ci.enc_codec_loaded <= 0)
630 return;
632 ci.stop_encoder = true;
633 while (ci.enc_codec_loaded > 0)
634 yield();
635 #endif
636 } /* audio_remove_encoder */
638 #endif /* HAVE_RECORDING */
640 struct mp3entry* audio_current_track(void)
642 const char *filename;
643 const char *p;
644 static struct mp3entry temp_id3;
645 int cur_idx;
646 int offset = ci.new_track + wps_offset;
648 cur_idx = track_ridx + offset;
649 cur_idx &= MAX_TRACK_MASK;
651 if (cur_idx == track_ridx && *curtrack_id3.path)
652 return &curtrack_id3;
653 else if (offset == -1 && *prevtrack_id3.path)
654 return &prevtrack_id3;
655 else if (tracks[cur_idx].id3_hid > 0)
656 return bufgetid3(tracks[cur_idx].id3_hid);
658 memset(&temp_id3, 0, sizeof(struct mp3entry));
660 filename = playlist_peek(0);
661 if (!filename)
662 filename = "No file!";
664 #ifdef HAVE_TC_RAMCACHE
665 if (tagcache_fill_tags(&temp_id3, filename))
666 return &temp_id3;
667 #endif
669 p = strrchr(filename, '/');
670 if (!p)
671 p = filename;
672 else
673 p++;
675 strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1);
676 temp_id3.title = &temp_id3.path[0];
678 return &temp_id3;
681 struct mp3entry* audio_next_track(void)
683 int next_idx = track_ridx;
685 if (!audio_have_tracks())
686 return NULL;
688 if (wps_offset == -1 && *prevtrack_id3.path)
689 return &curtrack_id3;
691 next_idx++;
692 next_idx &= MAX_TRACK_MASK;
694 if (tracks[next_idx].id3_hid <= 0)
695 return NULL;
697 return &nexttrack_id3;
700 bool audio_has_changed_track(void)
702 if (track_changed)
704 track_changed = false;
705 return true;
708 return false;
711 void audio_play(long offset)
713 logf("audio_play");
715 #ifdef PLAYBACK_VOICE
716 /* Truncate any existing voice output so we don't have spelling
717 * etc. over the first part of the played track */
718 talk_force_shutup();
719 #endif
721 /* Start playback */
722 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset);
723 /* Don't return until playback has actually started */
724 queue_send(&audio_queue, Q_AUDIO_PLAY, offset);
727 void audio_stop(void)
729 /* Stop playback */
730 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
731 /* Don't return until playback has actually stopped */
732 queue_send(&audio_queue, Q_AUDIO_STOP, 0);
735 void audio_pause(void)
737 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
738 /* Don't return until playback has actually paused */
739 queue_send(&audio_queue, Q_AUDIO_PAUSE, true);
742 void audio_resume(void)
744 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
745 /* Don't return until playback has actually resumed */
746 queue_send(&audio_queue, Q_AUDIO_PAUSE, false);
749 void audio_next(void)
751 if (playlist_check(ci.new_track + wps_offset + 1))
753 if (global_settings.beep)
754 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
756 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
757 queue_post(&audio_queue, Q_AUDIO_SKIP, 1);
758 /* Update wps while our message travels inside deep playback queues. */
759 wps_offset++;
760 track_changed = true;
762 else
764 /* No more tracks. */
765 if (global_settings.beep)
766 pcmbuf_beep(1000, 100, 1000*global_settings.beep);
770 void audio_prev(void)
772 if (playlist_check(ci.new_track + wps_offset - 1))
774 if (global_settings.beep)
775 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
777 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
778 queue_post(&audio_queue, Q_AUDIO_SKIP, -1);
779 /* Update wps while our message travels inside deep playback queues. */
780 wps_offset--;
781 track_changed = true;
783 else
785 /* No more tracks. */
786 if (global_settings.beep)
787 pcmbuf_beep(1000, 100, 1000*global_settings.beep);
791 void audio_next_dir(void)
793 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
794 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, 1);
797 void audio_prev_dir(void)
799 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
800 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, -1);
803 void audio_pre_ff_rewind(void)
805 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
806 queue_post(&audio_queue, Q_AUDIO_PRE_FF_REWIND, 0);
809 void audio_ff_rewind(long newpos)
811 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
812 queue_post(&audio_queue, Q_AUDIO_FF_REWIND, newpos);
815 void audio_flush_and_reload_tracks(void)
817 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
818 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0);
821 void audio_error_clear(void)
823 #ifdef AUDIO_HAVE_RECORDING
824 pcm_rec_error_clear();
825 #endif
828 int audio_status(void)
830 int ret = 0;
832 if (playing)
833 ret |= AUDIO_STATUS_PLAY;
835 if (paused)
836 ret |= AUDIO_STATUS_PAUSE;
838 #ifdef HAVE_RECORDING
839 /* Do this here for constitency with mpeg.c version */
840 ret |= pcm_rec_status();
841 #endif
843 return ret;
846 int audio_get_file_pos(void)
848 return 0;
851 #ifndef HAVE_FLASH_STORAGE
852 void audio_set_buffer_margin(int setting)
854 static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
855 buffer_margin = lookup[setting];
856 logf("buffer margin: %d", buffer_margin);
857 set_filebuf_watermark(buffer_margin);
859 #endif
861 /* Take nescessary steps to enable or disable the crossfade setting */
862 void audio_set_crossfade(int enable)
864 size_t offset;
865 bool was_playing;
866 size_t size;
868 /* Tell it the next setting to use */
869 pcmbuf_crossfade_enable(enable);
871 /* Return if size hasn't changed or this is too early to determine
872 which in the second case there's no way we could be playing
873 anything at all */
874 if (pcmbuf_is_same_size())
876 /* This function is a copout and just syncs some variables -
877 to be removed at a later date */
878 pcmbuf_crossfade_enable_finished();
879 return;
882 offset = 0;
883 was_playing = playing;
885 /* Playback has to be stopped before changing the buffer size */
886 if (was_playing)
888 /* Store the track resume position */
889 offset = curtrack_id3.offset;
890 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK));
893 /* Blast it - audio buffer will have to be setup again next time
894 something plays */
895 audio_get_buffer(true, &size);
897 /* Restart playback if audio was running previously */
898 if (was_playing)
899 audio_play(offset);
902 /* --- Routines called from multiple threads --- */
903 static void set_current_codec(int codec_idx)
905 current_codec = codec_idx;
906 dsp_configure(DSP_SWITCH_CODEC, codec_idx);
909 #ifdef PLAYBACK_VOICE
910 static void swap_codec(void)
912 int my_codec;
914 /* Swap nothing if no swap buffers exist */
915 if (dram_buf == NULL)
917 logf("swap: no swap buffers");
918 return;
921 my_codec = current_codec;
923 logf("swapping out codec: %d", my_codec);
925 /* Invert this when a codec thread enters and leaves */
926 swap_codec_parity = !swap_codec_parity;
928 /* If this is true, an odd number of calls has occurred and there's
929 no codec thread waiting to swap us out when it locks and runs. This
930 occurs when playback is stopped or when just starting playback and
931 the audio thread is loading a codec; parities should always be even
932 on entry when a thread calls this during playback */
933 if (swap_codec_parity)
935 /* Save our current IRAM and DRAM */
936 #ifdef IRAM_STEAL
937 if (voice_iram_stolen)
939 logf("swap: iram restore");
940 voice_iram_stolen = false;
941 /* Don't swap trashed data into buffer as the voice IRAM will
942 already be swapped out - should _always_ be the case if
943 voice_iram_stolen is true since the voice has been swapped
944 in beforehand */
945 if (my_codec == CODEC_IDX_VOICE)
947 logf("voice iram already swapped");
948 goto skip_iram_swap;
951 #endif
953 memswap128(iram_buf, CODEC_IRAM_ORIGIN, CODEC_IRAM_SIZE);
955 #ifdef IRAM_STEAL
956 skip_iram_swap:
957 #endif
959 memswap128(dram_buf, codecbuf, CODEC_SIZE);
960 /* No cache invalidation needed; it will be done in codec_load_ram
961 or we won't be here otherwise */
964 /* Release my semaphore */
965 semaphore_release(&sem_codecthread);
966 logf("unlocked: %d", my_codec);
968 /* Wait for other codec */
969 event_wait(&event_codecthread,
970 (my_codec == CODEC_IDX_AUDIO) ? STATE_NONSIGNALED : STATE_SIGNALED);
972 /* Wait for other codec to unlock */
973 logf("waiting for lock: %d", my_codec);
974 semaphore_wait(&sem_codecthread);
976 /* Take control */
977 set_current_codec(my_codec);
978 event_set_state(&event_codecthread,
979 (my_codec == CODEC_IDX_AUDIO) ? STATE_SIGNALED : STATE_NONSIGNALED);
981 /* Reload our IRAM and DRAM */
982 memswap128(iram_buf, CODEC_IRAM_ORIGIN, CODEC_IRAM_SIZE);
983 memswap128(dram_buf, codecbuf, CODEC_SIZE);
984 invalidate_icache();
986 /* Flip parity again */
987 swap_codec_parity = !swap_codec_parity;
989 logf("resuming codec: %d", my_codec);
992 /* This function is meant to be used by the buffer stealing functions to
993 ensure the codec is no longer active and so voice will be swapped-in
994 before it is called */
995 static void voice_stop(void)
997 /* Must have a voice codec loaded or we'll hang forever here */
998 if (!voice_codec_loaded)
999 return;
1001 talk_force_shutup();
1003 /* Loop until voice empties it's queue, stops and picks up on the new
1004 track; the voice thread must be stopped and waiting for messages
1005 outside the codec */
1006 while (voice_is_playing || !queue_empty(&voice_queue) ||
1007 ci_voice.new_track)
1008 yield();
1010 if (!playing)
1011 pcmbuf_play_stop();
1012 } /* voice_stop */
1014 /* Is voice still speaking */
1015 /* Unfortunately only reliable when music is not also playing. */
1016 static bool is_voice_speaking(void)
1018 return is_voice_queued()
1019 || voice_is_playing
1020 || (!playing && pcm_is_playing());
1023 #endif /* PLAYBACK_VOICE */
1025 /* Wait for voice to finish speaking. */
1026 /* Also only reliable when music is not also playing. */
1027 void voice_wait(void)
1029 #ifdef PLAYBACK_VOICE
1030 while (is_voice_speaking())
1031 sleep(HZ/10);
1032 #endif
1035 static void set_filebuf_watermark(int seconds)
1037 size_t bytes;
1039 if (!filebuf)
1040 return; /* Audio buffers not yet set up */
1042 bytes = MAX(curtrack_id3.bitrate * seconds * (1000/8), conf_watermark);
1043 bytes = MIN(bytes, filebuflen / 2);
1044 conf_watermark = bytes;
1047 const char * get_codec_filename(int cod_spec)
1049 const char *fname;
1051 #ifdef HAVE_RECORDING
1052 /* Can choose decoder or encoder if one available */
1053 int type = cod_spec & CODEC_TYPE_MASK;
1054 int afmt = cod_spec & CODEC_AFMT_MASK;
1056 if ((unsigned)afmt >= AFMT_NUM_CODECS)
1057 type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
1059 fname = (type == CODEC_TYPE_ENCODER) ?
1060 audio_formats[afmt].codec_enc_root_fn :
1061 audio_formats[afmt].codec_root_fn;
1063 logf("%s: %d - %s",
1064 (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
1065 afmt, fname ? fname : "<unknown>");
1066 #else /* !HAVE_RECORDING */
1067 /* Always decoder */
1068 if ((unsigned)cod_spec >= AFMT_NUM_CODECS)
1069 cod_spec = AFMT_UNKNOWN;
1070 fname = audio_formats[cod_spec].codec_root_fn;
1071 logf("Codec: %d - %s", cod_spec, fname ? fname : "<unknown>");
1072 #endif /* HAVE_RECORDING */
1074 return fname;
1075 } /* get_codec_filename */
1078 /* --- Voice thread --- */
1080 #ifdef PLAYBACK_VOICE
1082 static bool voice_pcmbuf_insert_callback(
1083 const void *ch1, const void *ch2, int count)
1085 const char *src[2] = { ch1, ch2 };
1087 while (count > 0)
1089 int out_count = dsp_output_count(count);
1090 int inp_count;
1091 char *dest;
1093 while ((dest = pcmbuf_request_voice_buffer(
1094 &out_count, playing)) == NULL)
1096 if (playing && audio_codec_loaded)
1097 swap_codec();
1098 else
1099 yield();
1102 /* Get the real input_size for output_size bytes, guarding
1103 * against resampling buffer overflows. */
1104 inp_count = dsp_input_count(out_count);
1106 if (inp_count <= 0)
1107 return true;
1109 /* Input size has grown, no error, just don't write more than length */
1110 if (inp_count > count)
1111 inp_count = count;
1113 out_count = dsp_process(dest, src, inp_count);
1115 if (out_count <= 0)
1116 return true;
1118 if (playing)
1120 pcmbuf_mix_voice(out_count);
1121 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
1122 audio_codec_loaded)
1123 swap_codec();
1125 else
1126 pcmbuf_write_complete(out_count);
1128 count -= inp_count;
1131 return true;
1132 } /* voice_pcmbuf_insert_callback */
1134 static void* voice_get_memory_callback(size_t *size)
1136 /* Voice should have no use for this. If it did, we'd have to
1137 swap the malloc buffer as well. */
1138 *size = 0;
1139 return NULL;
1142 static void voice_set_elapsed_callback(unsigned int value)
1144 (void)value;
1147 static void voice_set_offset_callback(size_t value)
1149 (void)value;
1152 static void voice_configure_callback(int setting, intptr_t value)
1154 if (!dsp_configure(setting, value))
1156 logf("Illegal key:%d", setting);
1160 static size_t voice_filebuf_callback(void *ptr, size_t size)
1162 (void)ptr;
1163 (void)size;
1165 return 0;
1168 /* Handle Q_VOICE_STOP and part of SYS_USB_CONNECTED */
1169 static bool voice_on_voice_stop(bool aborting, size_t *realsize)
1171 if (aborting && !playing)
1173 /* Aborting: Slight hack - flush PCM buffer if
1174 only being used for voice */
1175 pcmbuf_play_stop();
1178 if (voice_is_playing)
1180 /* Clear the current buffer */
1181 voice_is_playing = false;
1182 voice_getmore = NULL;
1183 voice_remaining = 0;
1184 voicebuf = NULL;
1186 /* Cancel any automatic boost if no more clips requested. */
1187 if (!playing || !voice_thread_start)
1188 sleep(0);
1190 /* Force the codec to think it's changing tracks */
1191 ci_voice.new_track = 1;
1193 *realsize = 0;
1194 return true; /* Yes, change tracks */
1197 return false;
1200 static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
1202 struct queue_event ev;
1204 if (ci_voice.new_track)
1206 *realsize = 0;
1207 return NULL;
1210 while (1)
1212 if (voice_is_playing || playing)
1214 queue_wait_w_tmo(&voice_queue, &ev, 0);
1215 if (!voice_is_playing && ev.id == SYS_TIMEOUT)
1216 ev.id = Q_AUDIO_PLAY;
1218 else
1220 queue_wait(&voice_queue, &ev);
1223 switch (ev.id) {
1224 case Q_AUDIO_PLAY:
1225 LOGFQUEUE("voice < Q_AUDIO_PLAY");
1226 if (playing)
1228 if (audio_codec_loaded)
1229 swap_codec();
1230 yield();
1232 break;
1234 #ifdef AUDIO_HAVE_RECORDING
1235 case Q_ENCODER_RECORD:
1236 LOGFQUEUE("voice < Q_ENCODER_RECORD");
1237 swap_codec();
1238 break;
1239 #endif
1241 case Q_VOICE_STOP:
1242 LOGFQUEUE("voice < Q_VOICE_STOP");
1243 if (voice_on_voice_stop(ev.data, realsize))
1244 return NULL;
1245 break;
1247 case SYS_USB_CONNECTED:
1249 LOGFQUEUE("voice < SYS_USB_CONNECTED");
1250 bool change_tracks = voice_on_voice_stop(ev.data, realsize);
1251 /* Voice is obviously current so let us swap ourselves away if
1252 playing so audio may stop itself - audio_codec_loaded can
1253 only be true in this case if we're here even if the codec
1254 is only about to load */
1255 if (audio_codec_loaded)
1256 swap_codec();
1257 /* Playback should be finished by now - ack and wait */
1258 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1259 usb_wait_for_disconnect(&voice_queue);
1260 if (change_tracks)
1261 return NULL;
1262 break;
1265 case Q_VOICE_PLAY:
1266 LOGFQUEUE("voice < Q_VOICE_PLAY");
1267 if (!voice_is_playing)
1269 /* Set up new voice data */
1270 struct voice_info *voice_data;
1271 #ifdef IRAM_STEAL
1272 if (voice_iram_stolen)
1274 /* Voice is the first to run again and is currently
1275 loaded */
1276 logf("voice: iram restore");
1277 memcpy(CODEC_IRAM_ORIGIN, iram_buf, CODEC_IRAM_SIZE);
1278 voice_iram_stolen = false;
1280 #endif
1281 /* Must reset the buffer before any playback begins if
1282 needed */
1283 if (buffer_state == BUFFER_STATE_TRASHED)
1284 audio_reset_buffer();
1286 voice_is_playing = true;
1287 trigger_cpu_boost();
1288 voice_data = (struct voice_info *)ev.data;
1289 voice_remaining = voice_data->size;
1290 voicebuf = voice_data->buf;
1291 voice_getmore = voice_data->callback;
1293 goto voice_play_clip; /* To exit both switch and while */
1295 case SYS_TIMEOUT:
1296 LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
1297 goto voice_play_clip;
1299 default:
1300 LOGFQUEUE("voice < default");
1304 voice_play_clip:
1306 if (voice_remaining == 0 || voicebuf == NULL)
1308 if (voice_getmore)
1309 voice_getmore((unsigned char **)&voicebuf, &voice_remaining);
1311 /* If this clip is done */
1312 if (voice_remaining == 0)
1314 LOGFQUEUE("voice > voice Q_VOICE_STOP");
1315 queue_post(&voice_queue, Q_VOICE_STOP, 0);
1316 /* Force pcm playback. */
1317 if (!pcm_is_playing())
1318 pcmbuf_play_start();
1322 *realsize = MIN(voice_remaining, reqsize);
1324 if (*realsize == 0)
1325 return NULL;
1327 return voicebuf;
1328 } /* voice_request_buffer_callback */
1330 static void voice_advance_buffer_callback(size_t amount)
1332 amount = MIN(amount, voice_remaining);
1333 voicebuf += amount;
1334 voice_remaining -= amount;
1337 static void voice_advance_buffer_loc_callback(void *ptr)
1339 size_t amount = (size_t)ptr - (size_t)voicebuf;
1341 voice_advance_buffer_callback(amount);
1344 static off_t voice_mp3_get_filepos_callback(int newtime)
1346 (void)newtime;
1348 return 0;
1351 static void voice_do_nothing(void)
1353 return;
1356 static bool voice_seek_buffer_callback(size_t newpos)
1358 (void)newpos;
1360 return false;
1363 static bool voice_request_next_track_callback(void)
1365 ci_voice.new_track = 0;
1366 return true;
1369 static void voice_thread(void)
1371 logf("Loading voice codec");
1372 voice_codec_loaded = true;
1373 semaphore_wait(&sem_codecthread);
1374 event_set_state(&event_codecthread, false);
1375 set_current_codec(CODEC_IDX_VOICE);
1376 dsp_configure(DSP_RESET, 0);
1377 voice_remaining = 0;
1378 voice_getmore = NULL;
1380 /* FIXME: If we being starting the voice thread without reboot, the
1381 voice_queue could be full of old stuff and we must flush it. */
1382 codec_load_file(get_codec_filename(AFMT_MPA_L3), &ci_voice);
1384 logf("Voice codec finished");
1385 voice_codec_loaded = false;
1386 voice_thread_p = NULL;
1387 semaphore_release(&sem_codecthread);
1388 } /* voice_thread */
1390 #endif /* PLAYBACK_VOICE */
1392 /* --- Codec thread --- */
1393 static bool codec_pcmbuf_insert_callback(
1394 const void *ch1, const void *ch2, int count)
1396 const char *src[2] = { ch1, ch2 };
1398 while (count > 0)
1400 int out_count = dsp_output_count(count);
1401 int inp_count;
1402 char *dest;
1404 /* Prevent audio from a previous track from playing */
1405 if (ci.new_track || ci.stop_codec)
1406 return true;
1408 while ((dest = pcmbuf_request_buffer(&out_count)) == NULL)
1410 sleep(1);
1411 if (ci.seek_time || ci.new_track || ci.stop_codec)
1412 return true;
1415 /* Get the real input_size for output_size bytes, guarding
1416 * against resampling buffer overflows. */
1417 inp_count = dsp_input_count(out_count);
1419 if (inp_count <= 0)
1420 return true;
1422 /* Input size has grown, no error, just don't write more than length */
1423 if (inp_count > count)
1424 inp_count = count;
1426 out_count = dsp_process(dest, src, inp_count);
1428 if (out_count <= 0)
1429 return true;
1431 pcmbuf_write_complete(out_count);
1433 #ifdef PLAYBACK_VOICE
1434 if ((voice_is_playing || voice_thread_start)
1435 && pcm_is_playing() && voice_codec_loaded &&
1436 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1438 voice_thread_start = false;
1439 swap_codec();
1441 #endif
1443 count -= inp_count;
1446 return true;
1447 } /* codec_pcmbuf_insert_callback */
1449 static void* codec_get_memory_callback(size_t *size)
1451 *size = MALLOC_BUFSIZE;
1452 return malloc_buf;
1455 static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
1456 static void codec_pcmbuf_position_callback(size_t size)
1458 /* This is called from an ISR, so be quick */
1459 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
1460 prevtrack_id3.elapsed;
1462 if (time >= prevtrack_id3.length)
1464 pcmbuf_set_position_callback(NULL);
1465 prevtrack_id3.elapsed = prevtrack_id3.length;
1467 else
1468 prevtrack_id3.elapsed = time;
1471 static void codec_set_elapsed_callback(unsigned int value)
1473 unsigned int latency;
1474 if (ci.seek_time)
1475 return;
1477 #ifdef AB_REPEAT_ENABLE
1478 ab_position_report(value);
1479 #endif
1481 latency = pcmbuf_get_latency();
1482 if (value < latency)
1483 curtrack_id3.elapsed = 0;
1484 else if (value - latency > curtrack_id3.elapsed ||
1485 value - latency < curtrack_id3.elapsed - 2)
1487 curtrack_id3.elapsed = value - latency;
1491 static void codec_set_offset_callback(size_t value)
1493 unsigned int latency;
1495 if (ci.seek_time)
1496 return;
1498 latency = pcmbuf_get_latency() * curtrack_id3.bitrate / 8;
1499 if (value < latency)
1500 curtrack_id3.offset = 0;
1501 else
1502 curtrack_id3.offset = value - latency;
1505 static void codec_advance_buffer_counters(size_t amount)
1507 bufadvance(CUR_TI->audio_hid, amount);
1508 ci.curpos += amount;
1511 /* copy up-to size bytes into ptr and return the actual size copied */
1512 static size_t codec_filebuf_callback(void *ptr, size_t size)
1514 ssize_t copy_n;
1516 if (ci.stop_codec || !playing)
1517 return 0;
1519 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
1521 /* Nothing requested OR nothing left */
1522 if (copy_n == 0)
1523 return 0;
1526 if (copy_n == -2)
1528 request_buffer_handle(CUR_TI->audio_hid);
1531 /* Let the disk buffer catch fill until enough data is available */
1532 while (copy_n == -2)
1534 sleep(1);
1536 if (ci.stop_codec || ci.new_track)
1537 return 0;
1539 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
1542 /* Update read and other position pointers */
1543 codec_advance_buffer_counters(copy_n);
1545 /* Return the actual amount of data copied to the buffer */
1546 return copy_n;
1547 } /* codec_filebuf_callback */
1549 static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
1551 size_t copy_n = reqsize;
1552 ssize_t ret;
1553 void *ptr;
1555 if (!playing)
1557 *realsize = 0;
1558 return NULL;
1561 ret = bufgetdata(CUR_TI->audio_hid, reqsize, &ptr);
1562 if (ret >= 0)
1563 copy_n = MIN((size_t)ret, reqsize);
1565 if (copy_n == 0)
1567 *realsize = 0;
1568 return NULL;
1571 if (ret == -2)
1573 request_buffer_handle(CUR_TI->audio_hid);
1576 /* Let the disk buffer catch fill until enough data is available */
1577 while (ret == -2)
1579 sleep(1);
1581 if (ci.stop_codec || ci.new_track)
1583 *realsize = 0;
1584 return NULL;
1586 ret = bufgetdata(CUR_TI->audio_hid, reqsize, &ptr);
1588 copy_n = MIN((size_t)ret, reqsize);
1590 *realsize = copy_n;
1592 return ptr;
1593 } /* codec_request_buffer_callback */
1595 static int get_codec_base_type(int type)
1597 switch (type) {
1598 case AFMT_MPA_L1:
1599 case AFMT_MPA_L2:
1600 case AFMT_MPA_L3:
1601 return AFMT_MPA_L3;
1604 return type;
1607 static void codec_advance_buffer_callback(size_t amount)
1609 codec_advance_buffer_counters(amount);
1610 codec_set_offset_callback(ci.curpos);
1613 static void codec_advance_buffer_loc_callback(void *ptr)
1615 size_t amount = get_offset(CUR_TI->audio_hid, ptr);
1617 codec_advance_buffer_callback(amount);
1620 /* Copied from mpeg.c. Should be moved somewhere else. */
1621 static int codec_get_file_pos(void)
1623 int pos = -1;
1624 struct mp3entry *id3 = audio_current_track();
1626 if (id3->vbr)
1628 if (id3->has_toc)
1630 /* Use the TOC to find the new position */
1631 unsigned int percent, remainder;
1632 int curtoc, nexttoc, plen;
1634 percent = (id3->elapsed*100)/id3->length;
1635 if (percent > 99)
1636 percent = 99;
1638 curtoc = id3->toc[percent];
1640 if (percent < 99)
1641 nexttoc = id3->toc[percent+1];
1642 else
1643 nexttoc = 256;
1645 pos = (id3->filesize/256)*curtoc;
1647 /* Use the remainder to get a more accurate position */
1648 remainder = (id3->elapsed*100)%id3->length;
1649 remainder = (remainder*100)/id3->length;
1650 plen = (nexttoc - curtoc)*(id3->filesize/256);
1651 pos += (plen/100)*remainder;
1653 else
1655 /* No TOC exists, estimate the new position */
1656 pos = (id3->filesize / (id3->length / 1000)) *
1657 (id3->elapsed / 1000);
1660 else if (id3->bitrate)
1661 pos = id3->elapsed * (id3->bitrate / 8);
1662 else
1663 return -1;
1665 pos += id3->first_frame_offset;
1667 /* Don't seek right to the end of the file so that we can
1668 transition properly to the next song */
1669 if (pos >= (int)(id3->filesize - id3->id3v1len))
1670 pos = id3->filesize - id3->id3v1len - 1;
1672 return pos;
1675 static off_t codec_mp3_get_filepos_callback(int newtime)
1677 off_t newpos;
1679 curtrack_id3.elapsed = newtime;
1680 newpos = codec_get_file_pos();
1682 return newpos;
1685 static void codec_seek_complete_callback(void)
1687 logf("seek_complete");
1688 if (pcm_is_paused())
1690 /* If this is not a seamless seek, clear the buffer */
1691 pcmbuf_play_stop();
1692 dsp_configure(DSP_FLUSH, 0);
1694 /* If playback was not 'deliberately' paused, unpause now */
1695 if (!paused)
1696 pcmbuf_pause(false);
1698 ci.seek_time = 0;
1701 static bool codec_seek_buffer_callback(size_t newpos)
1703 logf("codec_seek_buffer_callback");
1705 int ret = bufseek(CUR_TI->audio_hid, newpos);
1706 if (ret == 0) {
1707 ci.curpos = newpos;
1708 return true;
1710 else {
1711 return false;
1715 static void codec_configure_callback(int setting, intptr_t value)
1717 switch (setting) {
1718 case CODEC_SET_FILEBUF_WATERMARK:
1719 conf_watermark = value;
1720 set_filebuf_watermark(buffer_margin);
1721 break;
1723 case CODEC_SET_FILEBUF_CHUNKSIZE:
1724 conf_filechunk = value;
1725 break;
1727 case CODEC_SET_FILEBUF_PRESEEK:
1728 conf_preseek = value;
1729 break;
1731 default:
1732 if (!dsp_configure(setting, value)) { logf("Illegal key:%d", setting); }
1736 static void codec_track_changed(void)
1738 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1739 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1742 static void codec_pcmbuf_track_changed_callback(void)
1744 DEBUGF("codec_pcmbuf_track_changed_callback\n");
1745 pcmbuf_set_position_callback(NULL);
1746 codec_track_changed();
1749 static void codec_discard_codec_callback(void)
1751 if (CUR_TI->codec_hid > 0)
1753 bufclose(CUR_TI->codec_hid);
1754 CUR_TI->codec_hid = 0;
1755 CUR_TI->codecsize = 0;
1759 static inline void codec_gapless_track_change(void) {
1760 /* callback keeps the progress bar moving while the pcmbuf empties */
1761 pcmbuf_set_position_callback(codec_pcmbuf_position_callback);
1762 /* set the pcmbuf callback for when the track really changes */
1763 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
1766 static inline void codec_crossfade_track_change(void) {
1767 /* Initiate automatic crossfade mode */
1768 pcmbuf_crossfade_init(false);
1769 /* Notify the wps that the track change starts now */
1770 codec_track_changed();
1773 static void codec_track_skip_done(bool was_manual)
1775 int crossfade_mode = global_settings.crossfade;
1777 /* Manual track change (always crossfade or flush audio). */
1778 if (was_manual)
1780 pcmbuf_crossfade_init(true);
1781 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1782 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1784 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1785 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1786 && crossfade_mode != CROSSFADE_ENABLE_TRACKSKIP)
1788 if (crossfade_mode == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
1790 if (global_settings.playlist_shuffle)
1791 /* shuffle mode is on, so crossfade: */
1792 codec_crossfade_track_change();
1793 else
1794 /* shuffle mode is off, so do a gapless track change */
1795 codec_gapless_track_change();
1797 else
1798 /* normal crossfade: */
1799 codec_crossfade_track_change();
1801 else
1802 /* normal gapless playback. */
1803 codec_gapless_track_change();
1806 static bool codec_load_next_track(void)
1808 intptr_t result = Q_CODEC_REQUEST_FAILED;
1810 prev_track_elapsed = curtrack_id3.elapsed;
1812 if (ci.seek_time)
1813 codec_seek_complete_callback();
1815 #ifdef AB_REPEAT_ENABLE
1816 ab_end_of_track_report();
1817 #endif
1819 logf("Request new track");
1821 if (ci.new_track == 0)
1823 ci.new_track++;
1824 automatic_skip = true;
1827 if (!ci.stop_codec)
1829 trigger_cpu_boost();
1830 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1831 result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
1834 switch (result)
1836 case Q_CODEC_REQUEST_COMPLETE:
1837 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1838 codec_track_skip_done(!automatic_skip);
1839 return true;
1841 case Q_CODEC_REQUEST_FAILED:
1842 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1843 ci.new_track = 0;
1844 ci.stop_codec = true;
1845 return false;
1847 default:
1848 LOGFQUEUE("codec |< default");
1849 ci.stop_codec = true;
1850 return false;
1854 static bool codec_request_next_track_callback(void)
1856 int prev_codectype;
1858 if (ci.stop_codec || !playing)
1859 return false;
1861 prev_codectype = get_codec_base_type(curtrack_id3.codectype);
1863 if (!codec_load_next_track())
1864 return false;
1866 /* Seek to the beginning of the new track because if the struct mp3entry was
1867 buffered, "elapsed" might not be zero (if the track has been played
1868 already but not unbuffered) */
1869 codec_seek_buffer_callback(0);
1871 /* Check if the next codec is the same file. */
1872 if (prev_codectype == get_codec_base_type(curtrack_id3.codectype))
1874 logf("New track loaded");
1875 codec_discard_codec_callback();
1876 return true;
1878 else
1880 logf("New codec:%d/%d", curtrack_id3.codectype, prev_codectype);
1881 return false;
1885 static void codec_thread(void)
1887 struct queue_event ev;
1888 int status;
1889 size_t wrap;
1891 while (1) {
1892 status = 0;
1893 queue_wait(&codec_queue, &ev);
1895 switch (ev.id) {
1896 case Q_CODEC_LOAD_DISK:
1897 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1898 queue_reply(&codec_queue, 1);
1899 audio_codec_loaded = true;
1900 #ifdef PLAYBACK_VOICE
1901 /* Don't sent messages to voice codec if it's already swapped
1902 out or it will never get this */
1903 if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE)
1905 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1906 queue_post(&voice_queue, Q_AUDIO_PLAY, 0);
1908 semaphore_wait(&sem_codecthread);
1909 event_set_state(&event_codecthread, true);
1910 #endif
1911 set_current_codec(CODEC_IDX_AUDIO);
1912 ci.stop_codec = false;
1913 status = codec_load_file((const char *)ev.data, &ci);
1914 DEBUGF("codec_load = %d\n", status);
1915 #ifdef PLAYBACK_VOICE
1916 semaphore_release(&sem_codecthread);
1917 #endif
1918 break;
1920 case Q_CODEC_LOAD:
1921 LOGFQUEUE("codec < Q_CODEC_LOAD");
1922 if (CUR_TI->codec_hid <= 0) {
1923 logf("Codec slot is empty!");
1924 /* Wait for the pcm buffer to go empty */
1925 while (pcm_is_playing())
1926 yield();
1927 /* This must be set to prevent an infinite loop */
1928 ci.stop_codec = true;
1929 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1930 queue_post(&codec_queue, Q_AUDIO_PLAY, 0);
1931 break;
1934 audio_codec_loaded = true;
1935 #ifdef PLAYBACK_VOICE
1936 if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE)
1938 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1939 queue_post(&voice_queue, Q_AUDIO_PLAY, 0);
1941 semaphore_wait(&sem_codecthread);
1942 event_set_state(&event_codecthread, true);
1943 #endif
1944 set_current_codec(CODEC_IDX_AUDIO);
1945 ci.stop_codec = false;
1946 wrap = (size_t)&filebuf[filebuflen] - (size_t)bufgetcodec(CUR_TI);
1947 status = codec_load_ram(bufgetcodec(CUR_TI), CUR_TI->codecsize,
1948 &filebuf[0], wrap, &ci);
1949 #ifdef PLAYBACK_VOICE
1950 semaphore_release(&sem_codecthread);
1951 #endif
1952 break;
1954 #ifdef AUDIO_HAVE_RECORDING
1955 case Q_ENCODER_LOAD_DISK:
1956 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1957 audio_codec_loaded = false; /* Not audio codec! */
1958 #ifdef PLAYBACK_VOICE
1959 if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE)
1961 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
1962 queue_post(&voice_queue, Q_ENCODER_RECORD, 0);
1964 semaphore_wait(&sem_codecthread);
1965 event_set_state(&event_codecthread, true);
1966 #endif
1967 logf("loading encoder");
1968 set_current_codec(CODEC_IDX_AUDIO);
1969 ci.stop_encoder = false;
1970 status = codec_load_file((const char *)ev.data, &ci);
1971 #ifdef PLAYBACK_VOICE
1972 semaphore_release(&sem_codecthread);
1973 #endif
1974 logf("encoder stopped");
1975 break;
1976 #endif /* AUDIO_HAVE_RECORDING */
1978 #ifndef SIMULATOR
1979 case SYS_USB_CONNECTED:
1980 LOGFQUEUE("codec < SYS_USB_CONNECTED");
1981 queue_clear(&codec_queue);
1982 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1983 usb_wait_for_disconnect(&codec_queue);
1984 break;
1985 #endif
1987 default:
1988 LOGFQUEUE("codec < default");
1991 if (audio_codec_loaded)
1993 if (ci.stop_codec)
1995 status = CODEC_OK;
1996 if (!playing)
1997 pcmbuf_play_stop();
2000 audio_codec_loaded = false;
2003 switch (ev.id) {
2004 case Q_CODEC_LOAD_DISK:
2005 case Q_CODEC_LOAD:
2006 LOGFQUEUE("codec < Q_CODEC_LOAD");
2007 if (playing)
2009 if (ci.new_track || status != CODEC_OK)
2011 if (!ci.new_track)
2013 logf("Codec failure");
2014 gui_syncsplash(HZ*2, "Codec failure");
2017 if (!codec_load_next_track())
2019 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2020 /* End of playlist */
2021 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
2022 break;
2025 else
2027 logf("Codec finished");
2028 if (ci.stop_codec)
2030 /* Wait for the audio to stop playing before
2031 * triggering the WPS exit */
2032 while(pcm_is_playing())
2034 curtrack_id3.elapsed =
2035 curtrack_id3.length - pcmbuf_get_latency();
2036 sleep(1);
2038 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2039 /* End of playlist */
2040 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
2041 break;
2045 if (CUR_TI->codec_hid > 0)
2047 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2048 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
2050 else
2052 const char *codec_fn =
2053 get_codec_filename(curtrack_id3.codectype);
2054 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2055 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
2056 (intptr_t)codec_fn);
2059 break;
2061 #ifdef AUDIO_HAVE_RECORDING
2062 case Q_ENCODER_LOAD_DISK:
2063 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2065 if (status == CODEC_OK)
2066 break;
2068 logf("Encoder failure");
2069 gui_syncsplash(HZ*2, "Encoder failure");
2071 if (ci.enc_codec_loaded < 0)
2072 break;
2074 logf("Encoder failed to load");
2075 ci.enc_codec_loaded = -1;
2076 break;
2077 #endif /* AUDIO_HAVE_RECORDING */
2079 default:
2080 LOGFQUEUE("codec < default");
2082 } /* end switch */
2087 /* --- Audio thread --- */
2089 static bool audio_have_tracks(void)
2091 return track_ridx != track_widx || CUR_TI->filesize;
2094 static bool audio_have_free_tracks(void)
2096 if (track_widx < track_ridx)
2097 return track_widx + 1 < track_ridx;
2098 else if (track_ridx == 0)
2099 return track_widx < MAX_TRACK - 1;
2101 return true;
2104 int audio_track_count(void)
2106 if (audio_have_tracks())
2108 int relative_track_widx = track_widx;
2110 if (track_ridx > track_widx)
2111 relative_track_widx += MAX_TRACK;
2113 return relative_track_widx - track_ridx + 1;
2116 return 0;
2119 long audio_filebufused(void)
2121 return (long) bufused();
2124 static void audio_update_trackinfo(void)
2126 if (CUR_TI->id3_hid > 0)
2127 copy_mp3entry(&curtrack_id3, bufgetid3(CUR_TI->id3_hid));
2129 CUR_TI->taginfo_ready = (CUR_TI->id3_hid > 0);
2131 int next_idx = track_ridx + 1;
2132 next_idx &= MAX_TRACK_MASK;
2134 if (tracks[next_idx].id3_hid > 0)
2135 copy_mp3entry(&nexttrack_id3, bufgetid3(tracks[next_idx].id3_hid));
2137 tracks[next_idx].taginfo_ready = (tracks[next_idx].id3_hid > 0);
2139 ci.filesize = CUR_TI->filesize;
2140 curtrack_id3.elapsed = 0;
2141 curtrack_id3.offset = 0;
2142 ci.id3 = &curtrack_id3;
2143 ci.curpos = 0;
2144 ci.taginfo_ready = &CUR_TI->taginfo_ready;
2147 static void audio_clear_track_entries(bool clear_unbuffered)
2149 int cur_idx = track_widx;
2150 int last_idx = -1;
2152 logf("Clearing tracks:%d/%d, %d", track_ridx, track_widx, clear_unbuffered);
2154 /* Loop over all tracks from write-to-read */
2155 while (1)
2157 cur_idx++;
2158 cur_idx &= MAX_TRACK_MASK;
2160 if (cur_idx == track_ridx)
2161 break;
2163 /* If the track is buffered, conditionally clear/notify,
2164 * otherwise clear the track if that option is selected */
2165 if (tracks[cur_idx].event_sent)
2167 if (last_idx >= 0)
2169 /* If there is an unbuffer callback, call it, otherwise,
2170 * just clear the track */
2171 if (track_unbuffer_callback && tracks[last_idx].id3_hid > 0)
2172 track_unbuffer_callback(bufgetid3(tracks[last_idx].id3_hid), false);
2174 clear_track_info(&tracks[last_idx]);
2176 last_idx = cur_idx;
2178 else if (clear_unbuffered)
2179 clear_track_info(&tracks[cur_idx]);
2182 /* We clear the previous instance of a buffered track throughout
2183 * the above loop to facilitate 'last' detection. Clear/notify
2184 * the last track here */
2185 if (last_idx >= 0)
2187 if (track_unbuffer_callback && tracks[last_idx].id3_hid > 0)
2188 track_unbuffer_callback(bufgetid3(tracks[last_idx].id3_hid), true);
2189 clear_track_info(&tracks[last_idx]);
2193 static void audio_release_tracks(void)
2195 int i, cur_idx;
2197 logf("releasing all tracks");
2199 for(i = 0; i < MAX_TRACKS; i++)
2201 cur_idx = (track_ridx + i) & MAX_TRACK_MASK;
2202 clear_track_info(&tracks[cur_idx]);
2206 #if 0
2207 /* FIXME: This code should be made more generic and move to metadata.c */
2208 static void audio_strip_tags(void)
2210 int i;
2211 static const unsigned char tag[] = "TAG";
2212 static const unsigned char apetag[] = "APETAGEX";
2213 size_t tag_idx;
2214 size_t cur_idx;
2215 size_t len, version;
2217 tag_idx = RINGBUF_SUB(buf_widx, 128);
2219 if (bufused() > 128 && tag_idx > buf_ridx)
2221 cur_idx = tag_idx;
2222 for(i = 0;i < 3;i++)
2224 if(filebuf[cur_idx] != tag[i])
2225 goto strip_ape_tag;
2227 cur_idx = RINGBUF_ADD(cur_idx, 1);
2230 /* Skip id3v1 tag */
2231 logf("Skipping ID3v1 tag");
2232 buf_widx = tag_idx;
2233 tracks[track_widx].available -= 128;
2234 tracks[track_widx].filesize -= 128;
2237 strip_ape_tag:
2238 /* Check for APE tag (look for the APE tag footer) */
2239 tag_idx = RINGBUF_SUB(buf_widx, 32);
2241 if (bufused() > 32 && tag_idx > buf_ridx)
2243 cur_idx = tag_idx;
2244 for(i = 0;i < 8;i++)
2246 if(filebuf[cur_idx] != apetag[i])
2247 return;
2249 cur_idx = RINGBUF_ADD(cur_idx, 1);
2252 /* Read the version and length from the footer */
2253 version = filebuf[tag_idx+8] | (filebuf[tag_idx+9] << 8) |
2254 (filebuf[tag_idx+10] << 16) | (filebuf[tag_idx+11] << 24);
2255 len = filebuf[tag_idx+12] | (filebuf[tag_idx+13] << 8) |
2256 (filebuf[tag_idx+14] << 16) | (filebuf[tag_idx+15] << 24);
2257 if (version == 2000)
2258 len += 32; /* APEv2 has a 32 byte header */
2260 /* Skip APE tag */
2261 if (bufused() > len)
2263 logf("Skipping APE tag (%ldB)", len);
2264 buf_widx = RINGBUF_SUB(buf_widx, len);
2265 tracks[track_widx].available -= len;
2266 tracks[track_widx].filesize -= len;
2270 #endif
2272 static bool audio_loadcodec(bool start_play)
2274 int fd;
2275 int prev_track;
2276 char codec_path[MAX_PATH]; /* Full path to codec */
2278 DEBUGF("audio_loadcodec(start_play = %s)\n", start_play ? "true" : "false");
2280 if (tracks[track_widx].id3_hid <= 0) {
2281 DEBUGF("track ID3 info not ready\n");
2282 return false;
2285 const char * codec_fn =
2286 get_codec_filename(bufgetid3(tracks[track_widx].id3_hid)->codectype);
2287 if (codec_fn == NULL)
2288 return false;
2290 tracks[track_widx].codec_hid = 0;
2292 if (start_play)
2294 /* Load the codec directly from disk and save some memory. */
2295 track_ridx = track_widx;
2296 ci.filesize = CUR_TI->filesize;
2297 ci.id3 = &curtrack_id3;
2298 ci.taginfo_ready = &CUR_TI->taginfo_ready;
2299 ci.curpos = 0;
2300 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2301 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (intptr_t)codec_fn);
2302 return true;
2304 else
2306 /* If we already have another track than this one buffered */
2307 if (track_widx != track_ridx)
2309 prev_track = (track_widx - 1) & MAX_TRACK_MASK;
2311 /* If the previous codec is the same as this one, there is no need
2312 * to put another copy of it on the file buffer */
2313 if (get_codec_base_type(
2314 bufgetid3(tracks[track_widx].id3_hid)->codectype) ==
2315 get_codec_base_type(
2316 bufgetid3(tracks[prev_track].id3_hid)->codectype)
2317 && audio_codec_loaded)
2319 logf("Reusing prev. codec");
2320 return true;
2325 codec_get_full_path(codec_path, codec_fn);
2327 fd = open(codec_path, O_RDONLY);
2328 if (fd < 0)
2330 logf("Codec doesn't exist!");
2331 return false;
2334 tracks[track_widx].codecsize = filesize(fd);
2336 tracks[track_widx].codec_hid = bufopen(codec_path, 0, TYPE_CODEC);
2337 if (tracks[track_widx].codec_hid < 0)
2339 logf("Not enough space");
2340 close(fd);
2341 return false;
2344 close(fd);
2345 logf("Loaded codec");
2347 return true;
2350 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2351 static void audio_set_elapsed(struct mp3entry* id3)
2353 unsigned long offset = id3->offset > id3->first_frame_offset ?
2354 id3->offset - id3->first_frame_offset : 0;
2356 if ( id3->vbr ) {
2357 if ( id3->has_toc ) {
2358 /* calculate elapsed time using TOC */
2359 int i;
2360 unsigned int remainder, plen, relpos, nextpos;
2362 /* find wich percent we're at */
2363 for (i=0; i<100; i++ )
2364 if ( offset < id3->toc[i] * (id3->filesize / 256) )
2365 break;
2367 i--;
2368 if (i < 0)
2369 i = 0;
2371 relpos = id3->toc[i];
2373 if (i < 99)
2374 nextpos = id3->toc[i+1];
2375 else
2376 nextpos = 256;
2378 remainder = offset - (relpos * (id3->filesize / 256));
2380 /* set time for this percent (divide before multiply to prevent
2381 overflow on long files. loss of precision is negligible on
2382 short files) */
2383 id3->elapsed = i * (id3->length / 100);
2385 /* calculate remainder time */
2386 plen = (nextpos - relpos) * (id3->filesize / 256);
2387 id3->elapsed += (((remainder * 100) / plen) *
2388 (id3->length / 10000));
2390 else {
2391 /* no TOC exists. set a rough estimate using average bitrate */
2392 int tpk = id3->length /
2393 ((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
2394 1024);
2395 id3->elapsed = offset / 1024 * tpk;
2398 else
2400 /* constant bitrate, use exact calculation */
2401 if (id3->bitrate != 0)
2402 id3->elapsed = offset / (id3->bitrate / 8);
2406 /* Load one track by making the appropriate bufopen calls. Return true if
2407 everything required was loaded correctly, false if not. */
2408 static bool audio_load_track(int offset, bool start_play, bool rebuffer)
2410 (void)rebuffer;
2411 char *trackname;
2412 char msgbuf[80];
2413 int fd = -1;
2414 int file_offset = 0;
2415 struct mp3entry id3;
2417 /* Stop buffer filling if there is no free track entries.
2418 Don't fill up the last track entry (we wan't to store next track
2419 metadata there). */
2420 if (!audio_have_free_tracks())
2422 logf("No free tracks");
2423 return false;
2426 last_peek_offset++;
2427 peek_again:
2428 logf("Buffering track:%d/%d", track_widx, track_ridx);
2429 /* Get track name from current playlist read position. */
2430 while ((trackname = playlist_peek(last_peek_offset)) != NULL)
2432 /* Handle broken playlists. */
2433 fd = open(trackname, O_RDONLY);
2434 if (fd < 0)
2436 logf("Open failed");
2437 /* Skip invalid entry from playlist. */
2438 playlist_skip_entry(NULL, last_peek_offset);
2440 else
2441 break;
2444 if (!trackname)
2446 logf("End-of-playlist");
2447 playlist_end = true;
2448 return false;
2451 tracks[track_widx].filesize = filesize(fd);
2453 /* Set default values */
2454 if (start_play)
2456 int last_codec = current_codec;
2458 set_current_codec(CODEC_IDX_AUDIO);
2459 conf_watermark = AUDIO_DEFAULT_WATERMARK;
2460 conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
2461 conf_preseek = AUDIO_REBUFFER_GUESS_SIZE;
2462 dsp_configure(DSP_RESET, 0);
2463 set_current_codec(last_codec);
2465 track_changed = true;
2466 playlist_update_resume_info(audio_current_track());
2469 /* Get track metadata if we don't already have it. */
2470 if (tracks[track_widx].id3_hid <= 0)
2472 if (get_metadata(&id3, fd, trackname))
2474 tracks[track_widx].id3_hid = bufalloc(&id3, sizeof(struct mp3entry),
2475 TYPE_ID3);
2476 tracks[track_widx].taginfo_ready = (tracks[track_widx].id3_hid > 0);
2478 if (tracks[track_widx].id3_hid <= 0)
2480 DEBUGF("failed to allocate space for metadata\n");
2481 last_peek_offset--;
2482 close(fd);
2483 return false;
2486 if (track_widx == track_ridx)
2487 copy_mp3entry(&curtrack_id3, &id3);
2488 else if (track_widx == ((track_ridx + 1) & MAX_TRACK_MASK))
2489 copy_mp3entry(&nexttrack_id3, &id3);
2491 if (start_play)
2493 track_changed = true;
2494 playlist_update_resume_info(audio_current_track());
2497 else
2499 logf("mde:%s!",trackname);
2501 /* Skip invalid entry from playlist. */
2502 playlist_skip_entry(NULL, last_peek_offset);
2503 tracks[track_widx].taginfo_ready = false;
2504 goto peek_again;
2509 close(fd);
2511 #if 0
2512 if (cuesheet_is_enabled() && tracks[track_widx].id3.cuesheet_type == 1)
2514 char cuepath[MAX_PATH];
2516 struct cuesheet *cue = start_play ? curr_cue : temp_cue;
2518 if (look_for_cuesheet_file(trackname, cuepath) &&
2519 parse_cuesheet(cuepath, cue))
2521 strcpy((cue)->audio_filename, trackname);
2522 if (start_play)
2523 cue_spoof_id3(curr_cue, &tracks[track_widx].id3);
2526 #endif
2528 /* Load the codec. */
2529 if (!audio_loadcodec(start_play))
2531 if (tracks[track_widx].codecsize)
2533 /* No space for codec on buffer, not an error */
2534 tracks[track_widx].codecsize = 0;
2535 return false;
2538 /* This is an error condition, either no codec was found, or reading
2539 * the codec file failed part way through, either way, skip the track */
2540 snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname);
2541 /* We should not use gui_syncplash from audio thread! */
2542 gui_syncsplash(HZ*2, msgbuf);
2543 /* Skip invalid entry from playlist. */
2544 playlist_skip_entry(NULL, last_peek_offset);
2545 tracks[track_widx].taginfo_ready = false;
2546 goto peek_again;
2549 struct mp3entry *track_id3;
2551 if (track_widx == track_ridx)
2552 track_id3 = &curtrack_id3;
2553 else if (track_widx == ((track_ridx + 1) & MAX_TRACK_MASK))
2554 track_id3 = &nexttrack_id3;
2555 else
2556 track_id3 = bufgetid3(tracks[track_widx].id3_hid);
2558 set_filebuf_watermark(buffer_margin);
2559 track_id3->elapsed = 0;
2561 if (offset > 0)
2563 switch (track_id3->codectype) {
2564 case AFMT_MPA_L1:
2565 case AFMT_MPA_L2:
2566 case AFMT_MPA_L3:
2567 file_offset = offset;
2568 track_id3->offset = offset;
2569 audio_set_elapsed(track_id3);
2570 ci.curpos = offset;
2571 break;
2573 case AFMT_WAVPACK:
2574 file_offset = offset;
2575 track_id3->offset = offset;
2576 track_id3->elapsed = track_id3->length / 2;
2577 ci.curpos = offset;
2578 break;
2580 case AFMT_OGG_VORBIS:
2581 case AFMT_SPEEX:
2582 case AFMT_FLAC:
2583 case AFMT_PCM_WAV:
2584 case AFMT_A52:
2585 case AFMT_AAC:
2586 case AFMT_MPC:
2587 case AFMT_APE:
2588 track_id3->offset = offset;
2589 break;
2593 logf("alt:%s", trackname);
2595 tracks[track_widx].audio_hid = bufopen(trackname, file_offset, TYPE_AUDIO);
2597 if (tracks[track_widx].audio_hid <= 0)
2598 return false;
2600 if (start_play)
2602 request_buffer_handle(tracks[track_widx].audio_hid);
2605 track_widx++;
2606 track_widx &= MAX_TRACK_MASK;
2608 return true;
2611 /* Send callback events to notify about new tracks. */
2612 static void audio_generate_postbuffer_events(void)
2614 int cur_idx;
2615 int last_idx = -1;
2617 logf("Postbuffer:%d/%d",track_ridx,track_widx);
2619 if (audio_have_tracks())
2621 cur_idx = track_ridx;
2623 while (1) {
2624 if (!tracks[cur_idx].event_sent)
2626 if (last_idx >= 0 && !tracks[last_idx].event_sent)
2628 /* Mark the event 'sent' even if we don't really send one */
2629 tracks[last_idx].event_sent = true;
2630 if (track_buffer_callback && tracks[last_idx].id3_hid > 0)
2631 track_buffer_callback(bufgetid3(tracks[last_idx].id3_hid), false);
2633 last_idx = cur_idx;
2635 if (cur_idx == track_widx)
2636 break;
2637 cur_idx++;
2638 cur_idx &= MAX_TRACK_MASK;
2641 if (last_idx >= 0 && !tracks[last_idx].event_sent)
2643 tracks[last_idx].event_sent = true;
2644 if (track_buffer_callback && tracks[last_idx].id3_hid > 0)
2645 track_buffer_callback(bufgetid3(tracks[last_idx].id3_hid), true);
2650 static void low_buffer_callback(void)
2652 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
2653 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
2656 static void audio_fill_file_buffer(
2657 bool start_play, bool rebuffer, size_t offset)
2659 bool had_next_track = audio_next_track() != NULL;
2660 bool continue_buffering;
2662 /* Must reset the buffer before use if trashed or voice only - voice
2663 file size shouldn't have changed so we can go straight from
2664 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
2665 if (buffer_state != BUFFER_STATE_INITIALIZED)
2666 audio_reset_buffer();
2668 logf("Starting buffer fill");
2670 if (!start_play)
2671 audio_clear_track_entries(false);
2673 /* Save the current resume position once. */
2674 playlist_update_resume_info(audio_current_track());
2676 do {
2677 continue_buffering = audio_load_track(offset, start_play, rebuffer);
2678 start_play = false;
2679 offset = 0;
2680 sleep(1);
2681 } while (continue_buffering);
2683 if (!had_next_track && audio_next_track())
2684 track_changed = true;
2686 audio_generate_postbuffer_events();
2687 register_buffer_low_callback(low_buffer_callback);
2690 static void audio_rebuffer(void)
2692 logf("Forcing rebuffer");
2694 clear_track_info(CUR_TI);
2696 /* Reset track pointers */
2697 track_widx = track_ridx;
2698 audio_clear_track_entries(true);
2700 /* Just to make sure none were forgotten */
2701 audio_release_tracks();
2703 /* Fill the buffer */
2704 last_peek_offset = -1;
2705 ci.curpos = 0;
2707 if (!CUR_TI->taginfo_ready)
2708 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
2710 audio_fill_file_buffer(false, true, 0);
2713 static int audio_check_new_track(void)
2715 DEBUGF("audio_check_new_track\n");
2717 int track_count = audio_track_count();
2718 int old_track_ridx = track_ridx;
2719 bool forward;
2721 if (dir_skip)
2723 dir_skip = false;
2724 if (playlist_next_dir(ci.new_track))
2726 ci.new_track = 0;
2727 audio_rebuffer();
2728 goto skip_done;
2730 else
2732 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2733 return Q_CODEC_REQUEST_FAILED;
2737 if (new_playlist)
2738 ci.new_track = 0;
2740 /* If the playlist isn't that big */
2741 if (!playlist_check(ci.new_track))
2743 if (ci.new_track >= 0)
2745 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2746 return Q_CODEC_REQUEST_FAILED;
2748 /* Find the beginning backward if the user over-skips it */
2749 while (!playlist_check(++ci.new_track))
2750 if (ci.new_track >= 0)
2752 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2753 return Q_CODEC_REQUEST_FAILED;
2756 /* Update the playlist */
2757 last_peek_offset -= ci.new_track;
2759 if (!automatic_skip && playlist_next(ci.new_track) < 0)
2761 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2762 return Q_CODEC_REQUEST_FAILED;
2765 if (new_playlist)
2767 ci.new_track = 1;
2768 new_playlist = false;
2771 /* Save the old track */
2772 /* prev_ti = CUR_TI; */
2773 copy_mp3entry(&prevtrack_id3, &curtrack_id3);
2775 int i, idx;
2776 for (i = 0; i < ci.new_track; i++)
2778 idx = (track_ridx + i) & MAX_TRACK_MASK;
2779 if (handleoffset(tracks[idx].audio_hid) > 0)
2780 clear_track_info(&tracks[idx]);
2783 /* Move to the new track */
2784 track_ridx += ci.new_track;
2785 track_ridx &= MAX_TRACK_MASK;
2787 set_base_handle(CUR_TI->audio_hid);
2789 if (automatic_skip)
2791 playlist_end = false;
2792 wps_offset = -ci.new_track;
2795 track_changed = true;
2797 /* If it is not safe to even skip this many track entries */
2798 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
2800 ci.new_track = 0;
2801 audio_rebuffer();
2802 goto skip_done;
2805 forward = ci.new_track > 0;
2806 ci.new_track = 0;
2808 /* If the target track is clearly not in memory */
2809 if (CUR_TI->filesize == 0 || !CUR_TI->taginfo_ready)
2811 audio_rebuffer();
2812 goto skip_done;
2815 /* The track may be in memory, see if it really is */
2816 if (!forward)
2818 int cur_idx = track_ridx;
2819 bool taginfo_ready = true;
2820 bool wrap = track_ridx > old_track_ridx;
2822 while (1)
2824 cur_idx++;
2825 cur_idx &= MAX_TRACK_MASK;
2826 if (!(wrap || cur_idx < old_track_ridx))
2827 break;
2829 /* If we hit a track in between without valid tag info, bail */
2830 if (!tracks[cur_idx].taginfo_ready)
2832 taginfo_ready = false;
2833 break;
2836 if (!taginfo_ready)
2838 audio_rebuffer();
2842 skip_done:
2843 audio_update_trackinfo();
2844 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2845 return Q_CODEC_REQUEST_COMPLETE;
2848 void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3,
2849 bool last_track))
2851 track_buffer_callback = handler;
2854 void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3,
2855 bool last_track))
2857 track_unbuffer_callback = handler;
2860 void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3))
2862 track_changed_callback = handler;
2865 unsigned long audio_prev_elapsed(void)
2867 return prev_track_elapsed;
2870 static void audio_stop_codec_flush(void)
2872 ci.stop_codec = true;
2873 pcmbuf_pause(true);
2875 while (audio_codec_loaded)
2876 yield();
2878 /* If the audio codec is not loaded any more, and the audio is still
2879 * playing, it is now and _only_ now safe to call this function from the
2880 * audio thread */
2881 if (pcm_is_playing())
2882 pcmbuf_play_stop();
2883 pcmbuf_pause(paused);
2886 static void audio_stop_playback(void)
2888 /* If we were playing, save resume information */
2889 if (playing)
2891 struct mp3entry *id3 = NULL;
2893 if (!playlist_end || !ci.stop_codec)
2895 /* Set this early, the outside code yields and may allow the codec
2896 to try to wait for a reply on a buffer wait */
2897 ci.stop_codec = true;
2898 id3 = audio_current_track();
2901 /* Save the current playing spot, or NULL if the playlist has ended */
2902 playlist_update_resume_info(id3);
2904 prev_track_elapsed = curtrack_id3.elapsed;
2906 /* Increment index so runtime info is saved in audio_clear_track_entries().
2907 * Done here, as audio_stop_playback() may be called more than once.
2908 * Don't update runtime unless playback is stopped because of end of playlist.
2909 * Updating runtime when manually stopping a tracks, can destroy autoscores
2910 * and playcounts.
2912 if (playlist_end)
2914 track_ridx++;
2915 track_ridx &= MAX_TRACK_MASK;
2919 paused = false;
2920 audio_stop_codec_flush();
2921 playing = false;
2923 /* Close all tracks */
2924 audio_release_tracks();
2926 /* Mark all entries null. */
2927 audio_clear_track_entries(false);
2929 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
2930 memset(&nexttrack_id3, 0, sizeof(struct mp3entry));
2933 static void audio_play_start(size_t offset)
2935 #if INPUT_SRC_CAPS != 0
2936 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2937 audio_set_output_source(AUDIO_SRC_PLAYBACK);
2938 #endif
2940 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2941 paused = false;
2942 audio_stop_codec_flush();
2944 track_changed = true;
2945 playlist_end = false;
2947 playing = true;
2949 ci.new_track = 0;
2950 ci.seek_time = 0;
2951 wps_offset = 0;
2953 sound_set_volume(global_settings.volume);
2954 track_widx = track_ridx = 0;
2956 /* Mark all entries null. */
2957 memset(tracks, 0, sizeof(struct track_info) * MAX_TRACK);
2959 last_peek_offset = -1;
2961 /* Officially playing */
2962 queue_reply(&audio_queue, 1);
2964 audio_fill_file_buffer(true, false, offset);
2966 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2967 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
2971 /* Invalidates all but currently playing track. */
2972 static void audio_invalidate_tracks(void)
2974 if (audio_have_tracks())
2976 last_peek_offset = 0;
2977 playlist_end = false;
2978 track_widx = track_ridx;
2980 /* Mark all other entries null (also buffered wrong metadata). */
2981 audio_clear_track_entries(true);
2983 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2985 audio_fill_file_buffer(false, true, 0);
2989 static void audio_new_playlist(void)
2991 /* Prepare to start a new fill from the beginning of the playlist */
2992 last_peek_offset = -1;
2993 if (audio_have_tracks())
2995 if (paused)
2996 skipped_during_pause = true;
2997 playlist_end = false;
2998 track_widx = track_ridx;
2999 audio_clear_track_entries(true);
3001 track_widx++;
3002 track_widx &= MAX_TRACK_MASK;
3004 /* Mark the current track as invalid to prevent skipping back to it */
3005 CUR_TI->taginfo_ready = false;
3008 /* Signal the codec to initiate a track change forward */
3009 new_playlist = true;
3010 ci.new_track = 1;
3012 /* Officially playing */
3013 queue_reply(&audio_queue, 1);
3015 audio_fill_file_buffer(false, true, 0);
3018 static void audio_initiate_track_change(long direction)
3020 playlist_end = false;
3021 ci.new_track += direction;
3022 wps_offset -= direction;
3023 if (paused)
3024 skipped_during_pause = true;
3027 static void audio_initiate_dir_change(long direction)
3029 playlist_end = false;
3030 dir_skip = true;
3031 ci.new_track = direction;
3032 if (paused)
3033 skipped_during_pause = true;
3037 * Layout audio buffer as follows - iram buffer depends on target:
3038 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
3040 static void audio_reset_buffer(void)
3042 /* see audio_get_recording_buffer if this is modified */
3043 logf("audio_reset_buffer");
3045 /* If the setup of anything allocated before the file buffer is
3046 changed, do check the adjustments after the buffer_alloc call
3047 as it will likely be affected and need sliding over */
3049 /* Initially set up file buffer as all space available */
3050 malloc_buf = audiobuf + talk_get_bufsize();
3051 /* Align the malloc buf to line size. Especially important to cf
3052 targets that do line reads/writes. */
3053 malloc_buf = (unsigned char *)(((uintptr_t)malloc_buf + 15) & ~15);
3054 filebuf = malloc_buf + MALLOC_BUFSIZE; /* filebuf line align implied */
3055 filebuflen = audiobufend - filebuf;
3057 /* Allow for codec swap space at end of audio buffer */
3058 if (talk_voice_required())
3060 /* Layout of swap buffer:
3061 * #ifdef IRAM_STEAL (dedicated iram_buf):
3062 * |iram_buf|...audiobuf...|dram_buf|audiobufend
3063 * #else:
3064 * audiobuf...|dram_buf|iram_buf|audiobufend
3066 #ifdef PLAYBACK_VOICE
3067 /* Check for an absolutely nasty situation which should never,
3068 ever happen - frankly should just panic */
3069 if (voice_codec_loaded && current_codec != CODEC_IDX_VOICE)
3071 logf("buffer reset with voice swapped");
3073 /* line align length which line aligns the calculations below since
3074 all sizes are also at least line aligned - needed for memswap128 */
3075 filebuflen &= ~15;
3076 #ifdef IRAM_STEAL
3077 filebuflen -= CODEC_SIZE;
3078 #else
3079 filebuflen -= CODEC_SIZE + CODEC_IRAM_SIZE;
3080 #endif
3081 /* Allocate buffers for swapping voice <=> audio */
3082 /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
3083 and out of the way of buffer usage or else a call to audio_get_buffer
3084 and subsequent buffer use might trash the swap space. A plugin
3085 initializing IRAM after getting the full buffer would present similar
3086 problem. Options include: failing the request if the other buffer
3087 has been obtained already or never allowing use of the voice IRAM
3088 buffer within the audio buffer. Using buffer_alloc basically
3089 implements the second in a more convenient way. */
3090 dram_buf = filebuf + filebuflen;
3092 #ifdef IRAM_STEAL
3093 /* Allocate voice IRAM swap buffer once */
3094 if (iram_buf == NULL)
3096 iram_buf = buffer_alloc(CODEC_IRAM_SIZE);
3097 /* buffer_alloc moves audiobuf; this is safe because only the end
3098 * has been touched so far in this function and the address of
3099 * filebuf + filebuflen is not changed */
3100 malloc_buf += CODEC_IRAM_SIZE;
3101 filebuf += CODEC_IRAM_SIZE;
3102 filebuflen -= CODEC_IRAM_SIZE;
3104 #else
3105 /* Allocate iram_buf after dram_buf */
3106 iram_buf = dram_buf + CODEC_SIZE;
3107 #endif /* IRAM_STEAL */
3108 #endif /* PLAYBACK_VOICE */
3110 else
3112 #ifdef PLAYBACK_VOICE
3113 /* No swap buffers needed */
3114 iram_buf = NULL;
3115 dram_buf = NULL;
3116 #endif
3119 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
3120 filebuflen -= pcmbuf_init(filebuf + filebuflen) + GUARD_BUFSIZE;
3122 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
3123 will already be line aligned */
3124 filebuflen &= ~3;
3126 /* Set the high watermark as 75% full...or 25% empty :) */
3127 #if MEM > 8
3128 high_watermark = 3*filebuflen / 4;
3129 #endif
3131 /* Clear any references to the file buffer */
3132 buffer_state = BUFFER_STATE_INITIALIZED;
3134 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
3135 /* Make sure everything adds up - yes, some info is a bit redundant but
3136 aids viewing and the sumation of certain variables should add up to
3137 the location of others. */
3139 size_t pcmbufsize;
3140 unsigned char * pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
3141 logf("mabuf: %08X", (unsigned)malloc_buf);
3142 logf("mabufe: %08X", (unsigned)(malloc_buf + MALLOC_BUFSIZE));
3143 logf("fbuf: %08X", (unsigned)filebuf);
3144 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
3145 logf("gbuf: %08X", (unsigned)(filebuf + filebuflen));
3146 logf("gbufe: %08X", (unsigned)(filebuf + filebuflen + GUARD_BUFSIZE));
3147 logf("pcmb: %08X", (unsigned)pcmbuf);
3148 logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
3149 if (dram_buf)
3151 logf("dramb: %08X", (unsigned)dram_buf);
3152 logf("drambe: %08X", (unsigned)(dram_buf + CODEC_SIZE));
3154 if (iram_buf)
3156 logf("iramb: %08X", (unsigned)iram_buf);
3157 logf("irambe: %08X", (unsigned)(iram_buf + CODEC_IRAM_SIZE));
3160 #endif
3163 static void audio_thread(void)
3165 struct queue_event ev;
3167 pcm_postinit();
3169 #ifdef PLAYBACK_VOICE
3170 /* Unlock semaphore that init stage locks before creating this thread */
3171 semaphore_release(&sem_codecthread);
3173 /* Buffers must be set up by now - should panic - really */
3174 if (buffer_state != BUFFER_STATE_INITIALIZED)
3176 logf("audio_thread start: no buffer");
3179 /* Have to wait for voice to load up or else the codec swap will be
3180 invalid when an audio codec is loaded */
3181 wait_for_voice_swap_in();
3182 #endif
3184 while (1)
3186 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
3188 switch (ev.id) {
3189 case Q_AUDIO_FILL_BUFFER:
3190 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3191 if (!playing || playlist_end || ci.stop_codec)
3192 break;
3193 audio_fill_file_buffer(false, false, 0);
3194 break;
3196 case Q_AUDIO_PLAY:
3197 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3198 if (playing && ev.data <= 0)
3199 audio_new_playlist();
3200 else
3202 audio_stop_playback();
3203 audio_play_start((size_t)ev.data);
3205 break;
3207 case Q_AUDIO_STOP:
3208 LOGFQUEUE("audio < Q_AUDIO_STOP");
3209 if (playing)
3210 audio_stop_playback();
3211 if (ev.data != 0)
3212 queue_clear(&audio_queue);
3213 break;
3215 case Q_AUDIO_PAUSE:
3216 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3217 if (!(bool) ev.data && skipped_during_pause && !pcmbuf_is_crossfade_active())
3218 pcmbuf_play_stop(); /* Flush old track on resume after skip */
3219 skipped_during_pause = false;
3220 if (!playing)
3221 break;
3222 pcmbuf_pause((bool)ev.data);
3223 paused = (bool)ev.data;
3224 break;
3226 case Q_AUDIO_SKIP:
3227 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3228 audio_initiate_track_change((long)ev.data);
3229 break;
3231 case Q_AUDIO_PRE_FF_REWIND:
3232 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3233 if (!playing)
3234 break;
3235 pcmbuf_pause(true);
3236 break;
3238 case Q_AUDIO_FF_REWIND:
3239 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3240 if (!playing)
3241 break;
3242 ci.seek_time = (long)ev.data+1;
3243 break;
3245 case Q_AUDIO_CHECK_NEW_TRACK:
3246 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3247 queue_reply(&audio_queue, audio_check_new_track());
3248 break;
3250 case Q_AUDIO_DIR_SKIP:
3251 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3252 playlist_end = false;
3253 audio_initiate_dir_change(ev.data);
3254 break;
3256 case Q_AUDIO_FLUSH:
3257 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3258 audio_invalidate_tracks();
3259 break;
3261 case Q_AUDIO_TRACK_CHANGED:
3262 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3263 if (automatic_skip)
3265 playlist_next(-wps_offset);
3266 wps_offset = 0;
3267 automatic_skip = false;
3268 prevtrack_id3.path[0] = 0;
3270 if (track_changed_callback)
3271 track_changed_callback(&curtrack_id3);
3272 track_changed = true;
3273 playlist_update_resume_info(audio_current_track());
3274 break;
3276 #ifndef SIMULATOR
3277 case SYS_USB_CONNECTED:
3278 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3279 if (playing)
3280 audio_stop_playback();
3281 usb_acknowledge(SYS_USB_CONNECTED_ACK);
3282 usb_wait_for_disconnect(&audio_queue);
3283 break;
3284 #endif
3286 case SYS_TIMEOUT:
3287 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3288 break;
3290 default:
3291 //LOGFQUEUE("audio < default");
3292 break;
3293 } /* end switch */
3294 } /* end while */
3297 #ifdef ROCKBOX_HAS_LOGF
3298 static void audio_test_track_changed_event(struct mp3entry *id3)
3300 (void)id3;
3302 logf("tce:%s", id3->path);
3304 #endif
3306 /* Initialize the audio system - called from init() in main.c.
3307 * Last function because of all the references to internal symbols
3309 void audio_init(void)
3311 #ifdef PLAYBACK_VOICE
3312 static bool voicetagtrue = true;
3313 static struct mp3entry id3_voice;
3314 struct thread_entry *voice_thread_p = NULL;
3315 #endif
3316 struct thread_entry *audio_thread_p;
3318 /* Can never do this twice */
3319 if (audio_is_initialized)
3321 logf("audio: already initialized");
3322 return;
3325 logf("audio: initializing");
3327 /* Initialize queues before giving control elsewhere in case it likes
3328 to send messages. Thread creation will be delayed however so nothing
3329 starts running until ready if something yields such as talk_init. */
3330 #ifdef PLAYBACK_VOICE
3331 /* Take ownership of lock to prevent playback of anything before audio
3332 hardware is initialized - audio thread unlocks it after final init
3333 stage */
3334 semaphore_init(&sem_codecthread, 1, 0);
3335 event_init(&event_codecthread, EVENT_MANUAL | STATE_SIGNALED);
3336 #endif
3337 queue_init(&audio_queue, true);
3338 queue_enable_queue_send(&audio_queue, &audio_queue_sender_list);
3339 queue_init(&codec_queue, true);
3340 queue_enable_queue_send(&codec_queue, &codec_queue_sender_list);
3342 pcm_init();
3344 #ifdef ROCKBOX_HAS_LOGF
3345 audio_set_track_changed_event(audio_test_track_changed_event);
3346 #endif
3348 /* Initialize codec api. */
3349 ci.read_filebuf = codec_filebuf_callback;
3350 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
3351 ci.get_codec_memory = codec_get_memory_callback;
3352 ci.request_buffer = codec_request_buffer_callback;
3353 ci.advance_buffer = codec_advance_buffer_callback;
3354 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
3355 ci.request_next_track = codec_request_next_track_callback;
3356 ci.mp3_get_filepos = codec_mp3_get_filepos_callback;
3357 ci.seek_buffer = codec_seek_buffer_callback;
3358 ci.seek_complete = codec_seek_complete_callback;
3359 ci.set_elapsed = codec_set_elapsed_callback;
3360 ci.set_offset = codec_set_offset_callback;
3361 ci.configure = codec_configure_callback;
3362 ci.discard_codec = codec_discard_codec_callback;
3364 /* Initialize voice codec api. */
3365 #ifdef PLAYBACK_VOICE
3366 memcpy(&ci_voice, &ci, sizeof(ci_voice));
3367 memset(&id3_voice, 0, sizeof(id3_voice));
3368 ci_voice.read_filebuf = voice_filebuf_callback;
3369 ci_voice.pcmbuf_insert = voice_pcmbuf_insert_callback;
3370 ci_voice.get_codec_memory = voice_get_memory_callback;
3371 ci_voice.request_buffer = voice_request_buffer_callback;
3372 ci_voice.advance_buffer = voice_advance_buffer_callback;
3373 ci_voice.advance_buffer_loc = voice_advance_buffer_loc_callback;
3374 ci_voice.request_next_track = voice_request_next_track_callback;
3375 ci_voice.mp3_get_filepos = voice_mp3_get_filepos_callback;
3376 ci_voice.seek_buffer = voice_seek_buffer_callback;
3377 ci_voice.seek_complete = voice_do_nothing;
3378 ci_voice.set_elapsed = voice_set_elapsed_callback;
3379 ci_voice.set_offset = voice_set_offset_callback;
3380 ci_voice.configure = voice_configure_callback;
3381 ci_voice.discard_codec = voice_do_nothing;
3382 ci_voice.taginfo_ready = &voicetagtrue;
3383 ci_voice.id3 = &id3_voice;
3384 id3_voice.frequency = 11200;
3385 id3_voice.length = 1000000L;
3386 #endif
3388 /* initialize the buffer */
3389 filebuf = audiobuf;
3391 /* audio_reset_buffer must to know the size of voice buffer so init
3392 talk first */
3393 talk_init();
3395 codec_thread_p = create_thread(
3396 codec_thread, codec_stack, sizeof(codec_stack),
3397 CREATE_THREAD_FROZEN,
3398 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
3399 IF_COP(, CPU));
3401 audio_thread_p = create_thread(audio_thread, audio_stack,
3402 sizeof(audio_stack), CREATE_THREAD_FROZEN,
3403 audio_thread_name IF_PRIO(, PRIORITY_BACKGROUND)
3404 IF_COP(, CPU));
3406 #ifdef PLAYBACK_VOICE
3407 /* TODO: Change this around when various speech codecs can be used */
3408 if (talk_voice_required())
3410 logf("Starting voice codec");
3411 queue_init(&voice_queue, true);
3412 voice_thread_p = create_thread(voice_thread, voice_stack,
3413 sizeof(voice_stack), CREATE_THREAD_FROZEN,
3414 voice_thread_name
3415 IF_PRIO(, PRIORITY_PLAYBACK) IF_COP(, CPU));
3417 #endif
3419 /* Set crossfade setting for next buffer init which should be about... */
3420 pcmbuf_crossfade_enable(global_settings.crossfade);
3422 /* ...now! Set up the buffers */
3423 audio_reset_buffer();
3425 buffering_init(filebuf, filebuflen);
3427 /* Probably safe to say */
3428 audio_is_initialized = true;
3430 sound_settings_apply();
3431 #ifdef HAVE_WM8758
3432 eq_hw_enable(global_settings.eq_hw_enabled);
3433 #endif
3434 #ifndef HAVE_FLASH_STORAGE
3435 audio_set_buffer_margin(global_settings.buffer_margin);
3436 #endif
3438 /* it's safe to let the threads run now */
3439 thread_thaw(codec_thread_p);
3440 #ifdef PLAYBACK_VOICE
3441 if (voice_thread_p)
3442 thread_thaw(voice_thread_p);
3443 #endif
3444 thread_thaw(audio_thread_p);
3445 } /* audio_init */