Minor cleanup
[Rockbox.git] / apps / playback.c
blobe852165800286923f8fc4efd7de4c3e47675c950
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_REBUFFER_SEEK, */
130 Q_AUDIO_CHECK_NEW_TRACK,
131 Q_AUDIO_FLUSH,
132 Q_AUDIO_TRACK_CHANGED,
133 Q_AUDIO_DIR_SKIP,
134 Q_AUDIO_POSTINIT,
135 Q_AUDIO_FILL_BUFFER,
136 #if MEM > 8
137 Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA,
138 #endif
139 Q_CODEC_REQUEST_COMPLETE,
140 Q_CODEC_REQUEST_FAILED,
142 Q_VOICE_PLAY,
143 Q_VOICE_STOP,
145 Q_CODEC_LOAD,
146 Q_CODEC_LOAD_DISK,
148 #ifdef AUDIO_HAVE_RECORDING
149 Q_ENCODER_LOAD_DISK,
150 Q_ENCODER_RECORD,
151 #endif
154 /* As defined in plugins/lib/xxx2wav.h */
155 #if MEM > 1
156 #define MALLOC_BUFSIZE (512*1024)
157 #define GUARD_BUFSIZE (32*1024)
158 #else
159 #define MALLOC_BUFSIZE (100*1024)
160 #define GUARD_BUFSIZE (8*1024)
161 #endif
163 /* As defined in plugin.lds */
164 #if defined(CPU_PP)
165 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
166 #define CODEC_IRAM_SIZE ((size_t)0xc000)
167 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
168 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
169 #define CODEC_IRAM_SIZE ((size_t)0x10000)
170 #else
171 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
172 #define CODEC_IRAM_SIZE ((size_t)0xc000)
173 #endif
175 #ifndef IBSS_ATTR_VOICE_STACK
176 #define IBSS_ATTR_VOICE_STACK IBSS_ATTR
177 #endif
179 bool audio_is_initialized = false;
181 /* Variables are commented with the threads that use them: *
182 * A=audio, C=codec, V=voice. A suffix of - indicates that *
183 * the variable is read but not updated on that thread. */
184 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
186 /* Main state control */
187 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR = false; /* Codec loaded? (C/A-) */
188 static volatile bool playing NOCACHEBSS_ATTR = false; /* Is audio playing? (A) */
189 static volatile bool paused NOCACHEBSS_ATTR = false; /* Is audio paused? (A/C-) */
190 static volatile bool filling IDATA_ATTR = false; /* Is file buffer refilling? (A/C-) */
192 /* Ring buffer where compressed audio and codecs are loaded */
193 static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */
194 static unsigned char *malloc_buf = NULL; /* Start of malloc buffer (A/C-) */
195 /* FIXME: make filebuflen static */
196 size_t filebuflen = 0; /* Size of buffer (A/C-) */
197 /* FIXME: make buf_ridx (C/A-) */
199 /* Possible arrangements of the buffer */
200 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
201 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
202 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
203 static int buffer_state = BUFFER_STATE_TRASHED; /* Buffer state */
205 struct mp3entry curtrack_id3;
206 struct mp3entry nexttrack_id3;
208 /* Track info structure about songs in the file buffer (A/C-) */
209 struct track_info {
210 int audio_hid; /* The ID for the track's buffer handle */
211 int id3_hid; /* The ID for the track's metadata handle */
212 int codec_hid; /* The ID for the track's codec handle */
214 size_t codecsize; /* Codec length in bytes */
215 size_t filesize; /* File total length */
217 bool taginfo_ready; /* Is metadata read */
219 bool event_sent; /* Was this track's buffered event sent */
222 static struct track_info tracks[MAX_TRACK];
223 static volatile int track_ridx = 0; /* Track being decoded (A/C-) */
224 static int track_widx = 0; /* Track being buffered (A) */
226 #if 0
227 static struct track_info *prev_ti = NULL; /* Previous track info pointer (A/C-) */
228 #endif
230 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
232 /* Set by the audio thread when the current track information has updated
233 * and the WPS may need to update its cached information */
234 static bool track_changed = false;
236 /* Information used only for filling the buffer */
237 /* Playlist steps from playing track to next track to be buffered (A) */
238 static int last_peek_offset = 0;
240 /* Scrobbler support */
241 static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/
243 /* Track change controls */
244 static bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */
245 static bool playlist_end = false; /* Has the current playlist ended? (A) */
246 static bool dir_skip = false; /* Is a directory skip pending? (A) */
247 static bool new_playlist = false; /* Are we starting a new playlist? (A) */
248 static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */
249 static bool skipped_during_pause = false; /* Do we need to clear the PCM buffer when playback resumes (A) */
251 /* Callbacks which applications or plugins may set */
252 /* When the playing track has changed from the user's perspective */
253 void (*track_changed_callback)(struct mp3entry *id3) = NULL;
254 /* When a track has been buffered */
255 void (*track_buffer_callback)(struct mp3entry *id3, bool last_track) = NULL;
256 /* When a track's buffer has been overwritten or cleared */
257 void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track) = NULL;
259 /* Configuration */
260 static size_t conf_watermark = 0; /* Level to trigger filebuf fill (A/C) FIXME */
261 static size_t conf_filechunk = 0; /* Largest chunk the codec accepts (A/C) FIXME */
262 static size_t conf_preseek = 0; /* Codec pre-seek margin (A/C) FIXME */
263 static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */
264 #if MEM > 8
265 static size_t high_watermark = 0; /* High watermark for rebuffer (A/V/other) */
266 #endif
268 /* Multiple threads */
269 static void set_current_codec(int codec_idx);
270 /* Set the watermark to trigger buffer fill (A/C) FIXME */
271 static void set_filebuf_watermark(int seconds);
273 /* Audio thread */
274 static struct event_queue audio_queue NOCACHEBSS_ATTR;
275 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR;
276 static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
277 static const char audio_thread_name[] = "audio";
279 static void audio_thread(void);
280 static void audio_initiate_track_change(long direction);
281 static bool audio_have_tracks(void);
282 static void audio_reset_buffer(void);
284 /* Codec thread */
285 extern struct codec_api ci;
286 static struct event_queue codec_queue NOCACHEBSS_ATTR;
287 static struct queue_sender_list codec_queue_sender_list;
288 static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
289 IBSS_ATTR;
290 static const char codec_thread_name[] = "codec";
291 struct thread_entry *codec_thread_p; /* For modifying thread priority later. */
293 static volatile int current_codec IDATA_ATTR; /* Current codec (normal/voice) */
295 /* Buffering thread */
296 void buffering_thread(void);
297 static long buffering_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)];
298 static const char buffering_thread_name[] = "buffering";
299 struct thread_entry *buffering_thread_p;
301 /* Voice thread */
302 #ifdef PLAYBACK_VOICE
304 extern struct codec_api ci_voice;
306 static struct thread_entry *voice_thread_p = NULL;
307 static struct event_queue voice_queue NOCACHEBSS_ATTR;
308 static long voice_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
309 IBSS_ATTR_VOICE_STACK;
310 static const char voice_thread_name[] = "voice codec";
312 /* Voice codec swapping control */
313 extern unsigned char codecbuf[]; /* DRAM codec swap buffer */
315 #ifdef SIMULATOR
316 /* IRAM codec swap buffer for sim*/
317 static unsigned char sim_iram[CODEC_IRAM_SIZE];
318 #undef CODEC_IRAM_ORIGIN
319 #define CODEC_IRAM_ORIGIN sim_iram
320 #endif
322 /* iram_buf and dram_buf are either both NULL or both non-NULL */
323 /* Pointer to IRAM buffer for codec swapping */
324 static unsigned char *iram_buf = NULL;
325 /* Pointer to DRAM buffer for codec swapping */
326 static unsigned char *dram_buf = NULL;
327 /* Parity of swap_codec calls - needed because one codec swapping itself in
328 automatically swaps in the other and the swap when unlocking should not
329 happen if the parity is even.
331 static bool swap_codec_parity NOCACHEBSS_ATTR = false; /* true=odd, false=even */
332 /* Locking to control which codec (normal/voice) is running */
333 static struct semaphore sem_codecthread NOCACHEBSS_ATTR;
334 static struct event event_codecthread NOCACHEBSS_ATTR;
336 /* Voice state */
337 static volatile bool voice_thread_start = false; /* Triggers voice playback (A/V) */
338 static volatile bool voice_is_playing NOCACHEBSS_ATTR = false; /* Is voice currently playing? (V) */
339 static volatile bool voice_codec_loaded NOCACHEBSS_ATTR = false; /* Is voice codec loaded (V/A-) */
340 static unsigned char *voicebuf = NULL;
341 static size_t voice_remaining = 0;
343 #ifdef IRAM_STEAL
344 /* Voice IRAM has been stolen for other use */
345 static bool voice_iram_stolen = false;
346 #endif
348 static void (*voice_getmore)(unsigned char** start, size_t* size) = NULL;
350 struct voice_info {
351 void (*callback)(unsigned char **start, size_t* size);
352 size_t size;
353 unsigned char *buf;
355 static void voice_thread(void);
356 static void voice_stop(void);
358 #endif /* PLAYBACK_VOICE */
361 /* --- Helper functions --- */
363 struct mp3entry *bufgetid3(int handle_id)
365 if (handle_id < 0)
366 return NULL;
368 struct mp3entry *id3;
369 ssize_t ret = bufgetdata(handle_id, 0, (unsigned char **)&id3);
371 if (ret < 0 || ret != sizeof(struct mp3entry))
372 return NULL;
374 return id3;
377 unsigned char *getptr(int handle_id)
379 unsigned char *ptr;
380 ssize_t ret = bufgetdata(handle_id, 0, &ptr);
382 if (ret < 0)
383 return 0;
385 return ptr;
388 void clear_track_info(struct track_info *track)
390 if (!track)
391 return;
393 if (track->codec_hid > 0) {
394 bufclose(track->codec_hid);
397 if (track->id3_hid > 0) {
398 bufclose(track->id3_hid);
401 if (track->audio_hid > 0) {
402 bufclose(track->audio_hid);
405 memset(track, 0, sizeof(struct track_info));
408 /* --- External interfaces --- */
410 void mp3_play_data(const unsigned char* start, int size,
411 void (*get_more)(unsigned char** start, size_t* size))
413 #ifdef PLAYBACK_VOICE
414 static struct voice_info voice_clip;
415 voice_clip.callback = get_more;
416 voice_clip.buf = (unsigned char*)start;
417 voice_clip.size = size;
418 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
419 queue_post(&voice_queue, Q_VOICE_STOP, 0);
420 LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
421 queue_post(&voice_queue, Q_VOICE_PLAY, (intptr_t)&voice_clip);
422 voice_thread_start = true;
423 trigger_cpu_boost();
424 #else
425 (void) start;
426 (void) size;
427 (void) get_more;
428 #endif
431 void mp3_play_stop(void)
433 #ifdef PLAYBACK_VOICE
434 queue_remove_from_head(&voice_queue, Q_VOICE_STOP);
435 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
436 queue_post(&voice_queue, Q_VOICE_STOP, 1);
437 #endif
440 void mp3_play_pause(bool play)
442 /* a dummy */
443 (void)play;
446 bool mp3_is_playing(void)
448 #ifdef PLAYBACK_VOICE
449 return voice_is_playing;
450 #else
451 return false;
452 #endif
455 /* If voice could be swapped out - wait for it to return
456 * Used by buffer claming functions.
458 static void wait_for_voice_swap_in(void)
460 #ifdef PLAYBACK_VOICE
461 if (NULL == iram_buf)
462 return;
464 event_wait(&event_codecthread, STATE_NONSIGNALED);
465 #endif /* PLAYBACK_VOICE */
468 /* This sends a stop message and the audio thread will dump all it's
469 subsequenct messages */
470 static void audio_hard_stop(void)
472 /* Stop playback */
473 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
474 queue_send(&audio_queue, Q_AUDIO_STOP, 1);
477 unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
479 unsigned char *buf, *end;
481 if (audio_is_initialized)
483 audio_hard_stop();
484 wait_for_voice_swap_in();
485 #ifdef PLAYBACK_VOICE
486 voice_stop();
487 #endif
489 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
491 if (buffer_size == NULL)
493 /* Special case for talk_init to use since it already knows it's
494 trashed */
495 buffer_state = BUFFER_STATE_TRASHED;
496 return NULL;
499 if (talk_buf || buffer_state == BUFFER_STATE_TRASHED
500 || !talk_voice_required())
502 logf("get buffer: talk, audio");
503 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
504 the talk buffer is not needed because voice isn't being used, or
505 could be BUFFER_STATE_TRASHED already. If state is
506 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
507 without the caller knowing what's going on. Changing certain settings
508 may move it to a worse condition but the memory in use by something
509 else will remain undisturbed.
511 if (buffer_state != BUFFER_STATE_TRASHED)
513 talk_buffer_steal();
514 buffer_state = BUFFER_STATE_TRASHED;
517 buf = audiobuf;
518 end = audiobufend;
520 else
522 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
523 still BUFFER_STATE_INITIALIZED */
524 /* Skip talk buffer and move pcm buffer to end to maximize available
525 contiguous memory - no audio running means voice will not need the
526 swap space */
527 logf("get buffer: audio");
528 buf = audiobuf + talk_get_bufsize();
529 end = audiobufend - pcmbuf_init(audiobufend);
530 buffer_state = BUFFER_STATE_VOICED_ONLY;
533 *buffer_size = end - buf;
535 return buf;
538 #ifdef IRAM_STEAL
539 void audio_iram_steal(void)
541 /* We need to stop audio playback in order to use codec IRAM */
542 audio_hard_stop();
544 #ifdef PLAYBACK_VOICE
545 if (NULL != iram_buf)
547 /* Can't already be stolen */
548 if (voice_iram_stolen)
549 return;
551 /* Must wait for voice to be current again if it is swapped which
552 would cause the caller's buffer to get clobbered when voice locks
553 and runs - we'll wait for it to lock and yield again then make sure
554 the ride has come to a complete stop */
555 wait_for_voice_swap_in();
556 voice_stop();
558 /* Save voice IRAM but just memcpy - safe to do here since voice
559 is current and no audio codec is loaded */
560 memcpy(iram_buf, CODEC_IRAM_ORIGIN, CODEC_IRAM_SIZE);
561 voice_iram_stolen = true;
563 else
565 /* Nothing much to do if no voice */
566 voice_iram_stolen = false;
568 #endif
570 #endif /* IRAM_STEAL */
572 #ifdef HAVE_RECORDING
573 unsigned char *audio_get_recording_buffer(size_t *buffer_size)
575 /* Don't allow overwrite of voice swap area or we'll trash the
576 swapped-out voice codec but can use whole thing if none */
577 unsigned char *end;
579 /* Stop audio and voice. Wait for voice to swap in and be clear
580 of pending events to ensure trouble-free operation of encoders */
581 audio_hard_stop();
582 wait_for_voice_swap_in();
583 #ifdef PLAYBACK_VOICE
584 voice_stop();
585 #endif
586 talk_buffer_steal();
588 #ifdef PLAYBACK_VOICE
589 /* If no dram_buf, swap space not used and recording gets more
590 memory. Codec swap areas will remain unaffected by the next init
591 since they're allocated at the end of the buffer and their sizes
592 don't change between calls */
593 end = dram_buf;
594 if (NULL == end)
595 #endif /* PLAYBACK_VOICE */
596 end = audiobufend;
598 buffer_state = BUFFER_STATE_TRASHED;
600 *buffer_size = end - audiobuf;
602 return (unsigned char *)audiobuf;
605 bool audio_load_encoder(int afmt)
607 #ifndef SIMULATOR
608 const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER);
609 if (!enc_fn)
610 return false;
612 audio_remove_encoder();
613 ci.enc_codec_loaded = 0; /* clear any previous error condition */
615 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
616 queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (intptr_t)enc_fn);
618 while (ci.enc_codec_loaded == 0)
619 yield();
621 logf("codec loaded: %d", ci.enc_codec_loaded);
623 return ci.enc_codec_loaded > 0;
624 #else
625 (void)afmt;
626 return true;
627 #endif
628 } /* audio_load_encoder */
630 void audio_remove_encoder(void)
632 #ifndef SIMULATOR
633 /* force encoder codec unload (if currently loaded) */
634 if (ci.enc_codec_loaded <= 0)
635 return;
637 ci.stop_encoder = true;
638 while (ci.enc_codec_loaded > 0)
639 yield();
640 #endif
641 } /* audio_remove_encoder */
643 #endif /* HAVE_RECORDING */
645 struct mp3entry* audio_current_track(void)
647 const char *filename;
648 const char *p;
649 static struct mp3entry temp_id3;
650 int cur_idx;
651 int offset = ci.new_track + wps_offset;
653 cur_idx = track_ridx + offset;
654 cur_idx &= MAX_TRACK_MASK;
656 if (tracks[cur_idx].id3_hid > 0)
657 return &curtrack_id3;
659 memset(&temp_id3, 0, sizeof(struct mp3entry));
661 filename = playlist_peek(0);
662 if (!filename)
663 filename = "No file!";
665 #ifdef HAVE_TC_RAMCACHE
666 if (tagcache_fill_tags(&temp_id3, filename))
667 return &temp_id3;
668 #endif
670 p = strrchr(filename, '/');
671 if (!p)
672 p = filename;
673 else
674 p++;
676 strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1);
677 temp_id3.title = &temp_id3.path[0];
679 return &temp_id3;
682 struct mp3entry* audio_next_track(void)
684 int next_idx = track_ridx;
686 if (!audio_have_tracks())
687 return NULL;
689 next_idx++;
690 next_idx &= MAX_TRACK_MASK;
692 if (tracks[next_idx].id3_hid <= 0)
693 return NULL;
695 return &nexttrack_id3;
698 bool audio_has_changed_track(void)
700 if (track_changed)
702 track_changed = false;
703 return true;
706 return false;
709 void audio_play(long offset)
711 logf("audio_play");
713 #ifdef PLAYBACK_VOICE
714 /* Truncate any existing voice output so we don't have spelling
715 * etc. over the first part of the played track */
716 talk_force_shutup();
717 #endif
719 /* Start playback */
720 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset);
721 /* Don't return until playback has actually started */
722 queue_send(&audio_queue, Q_AUDIO_PLAY, offset);
725 void audio_stop(void)
727 /* Stop playback */
728 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
729 /* Don't return until playback has actually stopped */
730 queue_send(&audio_queue, Q_AUDIO_STOP, 0);
733 void audio_pause(void)
735 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
736 /* Don't return until playback has actually paused */
737 queue_send(&audio_queue, Q_AUDIO_PAUSE, true);
740 void audio_resume(void)
742 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
743 /* Don't return until playback has actually resumed */
744 queue_send(&audio_queue, Q_AUDIO_PAUSE, false);
747 void audio_next(void)
749 if (playlist_check(ci.new_track + wps_offset + 1))
751 if (global_settings.beep)
752 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
754 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
755 queue_post(&audio_queue, Q_AUDIO_SKIP, 1);
756 /* Update wps while our message travels inside deep playback queues. */
757 wps_offset++;
758 track_changed = true;
760 else
762 /* No more tracks. */
763 if (global_settings.beep)
764 pcmbuf_beep(1000, 100, 1000*global_settings.beep);
768 void audio_prev(void)
770 if (playlist_check(ci.new_track + wps_offset - 1))
772 if (global_settings.beep)
773 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
775 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
776 queue_post(&audio_queue, Q_AUDIO_SKIP, -1);
777 /* Update wps while our message travels inside deep playback queues. */
778 wps_offset--;
779 track_changed = true;
781 else
783 /* No more tracks. */
784 if (global_settings.beep)
785 pcmbuf_beep(1000, 100, 1000*global_settings.beep);
789 void audio_next_dir(void)
791 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
792 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, 1);
795 void audio_prev_dir(void)
797 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
798 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, -1);
801 void audio_pre_ff_rewind(void)
803 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
804 queue_post(&audio_queue, Q_AUDIO_PRE_FF_REWIND, 0);
807 void audio_ff_rewind(long newpos)
809 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
810 queue_post(&audio_queue, Q_AUDIO_FF_REWIND, newpos);
813 void audio_flush_and_reload_tracks(void)
815 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
816 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0);
819 void audio_error_clear(void)
821 #ifdef AUDIO_HAVE_RECORDING
822 pcm_rec_error_clear();
823 #endif
826 int audio_status(void)
828 int ret = 0;
830 if (playing)
831 ret |= AUDIO_STATUS_PLAY;
833 if (paused)
834 ret |= AUDIO_STATUS_PAUSE;
836 #ifdef HAVE_RECORDING
837 /* Do this here for constitency with mpeg.c version */
838 ret |= pcm_rec_status();
839 #endif
841 return ret;
844 int audio_get_file_pos(void)
846 return 0;
849 #ifndef HAVE_FLASH_STORAGE
850 void audio_set_buffer_margin(int setting)
852 static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
853 buffer_margin = lookup[setting];
854 logf("buffer margin: %d", buffer_margin);
855 set_filebuf_watermark(buffer_margin);
857 #endif
859 /* Take nescessary steps to enable or disable the crossfade setting */
860 void audio_set_crossfade(int enable)
862 size_t offset;
863 bool was_playing;
864 size_t size;
866 /* Tell it the next setting to use */
867 pcmbuf_crossfade_enable(enable);
869 /* Return if size hasn't changed or this is too early to determine
870 which in the second case there's no way we could be playing
871 anything at all */
872 if (pcmbuf_is_same_size())
874 /* This function is a copout and just syncs some variables -
875 to be removed at a later date */
876 pcmbuf_crossfade_enable_finished();
877 return;
880 offset = 0;
881 was_playing = playing;
883 /* Playback has to be stopped before changing the buffer size */
884 if (was_playing)
886 /* Store the track resume position */
887 offset = curtrack_id3.offset;
888 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK));
891 /* Blast it - audio buffer will have to be setup again next time
892 something plays */
893 audio_get_buffer(true, &size);
895 /* Restart playback if audio was running previously */
896 if (was_playing)
897 audio_play(offset);
900 /* --- Routines called from multiple threads --- */
901 static void set_current_codec(int codec_idx)
903 current_codec = codec_idx;
904 dsp_configure(DSP_SWITCH_CODEC, codec_idx);
907 #ifdef PLAYBACK_VOICE
908 static void swap_codec(void)
910 int my_codec;
912 /* Swap nothing if no swap buffers exist */
913 if (dram_buf == NULL)
915 logf("swap: no swap buffers");
916 return;
919 my_codec = current_codec;
921 logf("swapping out codec: %d", my_codec);
923 /* Invert this when a codec thread enters and leaves */
924 swap_codec_parity = !swap_codec_parity;
926 /* If this is true, an odd number of calls has occurred and there's
927 no codec thread waiting to swap us out when it locks and runs. This
928 occurs when playback is stopped or when just starting playback and
929 the audio thread is loading a codec; parities should always be even
930 on entry when a thread calls this during playback */
931 if (swap_codec_parity)
933 /* Save our current IRAM and DRAM */
934 #ifdef IRAM_STEAL
935 if (voice_iram_stolen)
937 logf("swap: iram restore");
938 voice_iram_stolen = false;
939 /* Don't swap trashed data into buffer as the voice IRAM will
940 already be swapped out - should _always_ be the case if
941 voice_iram_stolen is true since the voice has been swapped
942 in beforehand */
943 if (my_codec == CODEC_IDX_VOICE)
945 logf("voice iram already swapped");
946 goto skip_iram_swap;
949 #endif
951 memswap128(iram_buf, CODEC_IRAM_ORIGIN, CODEC_IRAM_SIZE);
953 #ifdef IRAM_STEAL
954 skip_iram_swap:
955 #endif
957 memswap128(dram_buf, codecbuf, CODEC_SIZE);
958 /* No cache invalidation needed; it will be done in codec_load_ram
959 or we won't be here otherwise */
962 /* Release my semaphore */
963 semaphore_release(&sem_codecthread);
964 logf("unlocked: %d", my_codec);
966 /* Wait for other codec */
967 event_wait(&event_codecthread,
968 (my_codec == CODEC_IDX_AUDIO) ? STATE_NONSIGNALED : STATE_SIGNALED);
970 /* Wait for other codec to unlock */
971 logf("waiting for lock: %d", my_codec);
972 semaphore_wait(&sem_codecthread);
974 /* Take control */
975 set_current_codec(my_codec);
976 event_set_state(&event_codecthread,
977 (my_codec == CODEC_IDX_AUDIO) ? STATE_SIGNALED : STATE_NONSIGNALED);
979 /* Reload our IRAM and DRAM */
980 memswap128(iram_buf, CODEC_IRAM_ORIGIN, CODEC_IRAM_SIZE);
981 memswap128(dram_buf, codecbuf, CODEC_SIZE);
982 invalidate_icache();
984 /* Flip parity again */
985 swap_codec_parity = !swap_codec_parity;
987 logf("resuming codec: %d", my_codec);
990 /* This function is meant to be used by the buffer stealing functions to
991 ensure the codec is no longer active and so voice will be swapped-in
992 before it is called */
993 static void voice_stop(void)
995 /* Must have a voice codec loaded or we'll hang forever here */
996 if (!voice_codec_loaded)
997 return;
999 talk_force_shutup();
1001 /* Loop until voice empties it's queue, stops and picks up on the new
1002 track; the voice thread must be stopped and waiting for messages
1003 outside the codec */
1004 while (voice_is_playing || !queue_empty(&voice_queue) ||
1005 ci_voice.new_track)
1006 yield();
1008 if (!playing)
1009 pcmbuf_play_stop();
1010 } /* voice_stop */
1012 /* Is voice still speaking */
1013 /* Unfortunately only reliable when music is not also playing. */
1014 static bool is_voice_speaking(void)
1016 return is_voice_queued()
1017 || voice_is_playing
1018 || (!playing && pcm_is_playing());
1021 #endif /* PLAYBACK_VOICE */
1023 /* Wait for voice to finish speaking. */
1024 /* Also only reliable when music is not also playing. */
1025 void voice_wait(void)
1027 #ifdef PLAYBACK_VOICE
1028 while (is_voice_speaking())
1029 sleep(HZ/10);
1030 #endif
1033 static void set_filebuf_watermark(int seconds)
1035 size_t bytes;
1037 if (!filebuf)
1038 return; /* Audio buffers not yet set up */
1040 bytes = MAX(curtrack_id3.bitrate * seconds * (1000/8), conf_watermark);
1041 bytes = MIN(bytes, filebuflen / 2);
1042 conf_watermark = bytes;
1045 const char * get_codec_filename(int cod_spec)
1047 const char *fname;
1049 #ifdef HAVE_RECORDING
1050 /* Can choose decoder or encoder if one available */
1051 int type = cod_spec & CODEC_TYPE_MASK;
1052 int afmt = cod_spec & CODEC_AFMT_MASK;
1054 if ((unsigned)afmt >= AFMT_NUM_CODECS)
1055 type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
1057 fname = (type == CODEC_TYPE_ENCODER) ?
1058 audio_formats[afmt].codec_enc_root_fn :
1059 audio_formats[afmt].codec_root_fn;
1061 logf("%s: %d - %s",
1062 (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
1063 afmt, fname ? fname : "<unknown>");
1064 #else /* !HAVE_RECORDING */
1065 /* Always decoder */
1066 if ((unsigned)cod_spec >= AFMT_NUM_CODECS)
1067 cod_spec = AFMT_UNKNOWN;
1068 fname = audio_formats[cod_spec].codec_root_fn;
1069 logf("Codec: %d - %s", cod_spec, fname ? fname : "<unknown>");
1070 #endif /* HAVE_RECORDING */
1072 return fname;
1073 } /* get_codec_filename */
1076 /* --- Voice thread --- */
1078 #ifdef PLAYBACK_VOICE
1080 static bool voice_pcmbuf_insert_callback(
1081 const void *ch1, const void *ch2, int count)
1083 const char *src[2] = { ch1, ch2 };
1085 while (count > 0)
1087 int out_count = dsp_output_count(count);
1088 int inp_count;
1089 char *dest;
1091 while ((dest = pcmbuf_request_voice_buffer(
1092 &out_count, playing)) == NULL)
1094 if (playing && audio_codec_loaded)
1095 swap_codec();
1096 else
1097 yield();
1100 /* Get the real input_size for output_size bytes, guarding
1101 * against resampling buffer overflows. */
1102 inp_count = dsp_input_count(out_count);
1104 if (inp_count <= 0)
1105 return true;
1107 /* Input size has grown, no error, just don't write more than length */
1108 if (inp_count > count)
1109 inp_count = count;
1111 out_count = dsp_process(dest, src, inp_count);
1113 if (out_count <= 0)
1114 return true;
1116 if (playing)
1118 pcmbuf_mix_voice(out_count);
1119 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
1120 audio_codec_loaded)
1121 swap_codec();
1123 else
1124 pcmbuf_write_complete(out_count);
1126 count -= inp_count;
1129 return true;
1130 } /* voice_pcmbuf_insert_callback */
1132 static void* voice_get_memory_callback(size_t *size)
1134 /* Voice should have no use for this. If it did, we'd have to
1135 swap the malloc buffer as well. */
1136 *size = 0;
1137 return NULL;
1140 static void voice_set_elapsed_callback(unsigned int value)
1142 (void)value;
1145 static void voice_set_offset_callback(size_t value)
1147 (void)value;
1150 static void voice_configure_callback(int setting, intptr_t value)
1152 if (!dsp_configure(setting, value))
1154 logf("Illegal key:%d", setting);
1158 static size_t voice_filebuf_callback(void *ptr, size_t size)
1160 (void)ptr;
1161 (void)size;
1163 return 0;
1166 /* Handle Q_VOICE_STOP and part of SYS_USB_CONNECTED */
1167 static bool voice_on_voice_stop(bool aborting, size_t *realsize)
1169 if (aborting && !playing)
1171 /* Aborting: Slight hack - flush PCM buffer if
1172 only being used for voice */
1173 pcmbuf_play_stop();
1176 if (voice_is_playing)
1178 /* Clear the current buffer */
1179 voice_is_playing = false;
1180 voice_getmore = NULL;
1181 voice_remaining = 0;
1182 voicebuf = NULL;
1184 /* Cancel any automatic boost if no more clips requested. */
1185 if (!playing || !voice_thread_start)
1186 sleep(0);
1188 /* Force the codec to think it's changing tracks */
1189 ci_voice.new_track = 1;
1191 *realsize = 0;
1192 return true; /* Yes, change tracks */
1195 return false;
1198 static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
1200 struct queue_event ev;
1202 if (ci_voice.new_track)
1204 *realsize = 0;
1205 return NULL;
1208 while (1)
1210 if (voice_is_playing || playing)
1212 queue_wait_w_tmo(&voice_queue, &ev, 0);
1213 if (!voice_is_playing && ev.id == SYS_TIMEOUT)
1214 ev.id = Q_AUDIO_PLAY;
1216 else
1218 queue_wait(&voice_queue, &ev);
1221 switch (ev.id) {
1222 case Q_AUDIO_PLAY:
1223 LOGFQUEUE("voice < Q_AUDIO_PLAY");
1224 if (playing)
1226 if (audio_codec_loaded)
1227 swap_codec();
1228 yield();
1230 break;
1232 #ifdef AUDIO_HAVE_RECORDING
1233 case Q_ENCODER_RECORD:
1234 LOGFQUEUE("voice < Q_ENCODER_RECORD");
1235 swap_codec();
1236 break;
1237 #endif
1239 case Q_VOICE_STOP:
1240 LOGFQUEUE("voice < Q_VOICE_STOP");
1241 if (voice_on_voice_stop(ev.data, realsize))
1242 return NULL;
1243 break;
1245 case SYS_USB_CONNECTED:
1247 LOGFQUEUE("voice < SYS_USB_CONNECTED");
1248 bool change_tracks = voice_on_voice_stop(ev.data, realsize);
1249 /* Voice is obviously current so let us swap ourselves away if
1250 playing so audio may stop itself - audio_codec_loaded can
1251 only be true in this case if we're here even if the codec
1252 is only about to load */
1253 if (audio_codec_loaded)
1254 swap_codec();
1255 /* Playback should be finished by now - ack and wait */
1256 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1257 usb_wait_for_disconnect(&voice_queue);
1258 if (change_tracks)
1259 return NULL;
1260 break;
1263 case Q_VOICE_PLAY:
1264 LOGFQUEUE("voice < Q_VOICE_PLAY");
1265 if (!voice_is_playing)
1267 /* Set up new voice data */
1268 struct voice_info *voice_data;
1269 #ifdef IRAM_STEAL
1270 if (voice_iram_stolen)
1272 /* Voice is the first to run again and is currently
1273 loaded */
1274 logf("voice: iram restore");
1275 memcpy(CODEC_IRAM_ORIGIN, iram_buf, CODEC_IRAM_SIZE);
1276 voice_iram_stolen = false;
1278 #endif
1279 /* Must reset the buffer before any playback begins if
1280 needed */
1281 if (buffer_state == BUFFER_STATE_TRASHED)
1282 audio_reset_buffer();
1284 voice_is_playing = true;
1285 trigger_cpu_boost();
1286 voice_data = (struct voice_info *)ev.data;
1287 voice_remaining = voice_data->size;
1288 voicebuf = voice_data->buf;
1289 voice_getmore = voice_data->callback;
1291 goto voice_play_clip; /* To exit both switch and while */
1293 case SYS_TIMEOUT:
1294 LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
1295 goto voice_play_clip;
1297 default:
1298 LOGFQUEUE("voice < default");
1302 voice_play_clip:
1304 if (voice_remaining == 0 || voicebuf == NULL)
1306 if (voice_getmore)
1307 voice_getmore((unsigned char **)&voicebuf, &voice_remaining);
1309 /* If this clip is done */
1310 if (voice_remaining == 0)
1312 LOGFQUEUE("voice > voice Q_VOICE_STOP");
1313 queue_post(&voice_queue, Q_VOICE_STOP, 0);
1314 /* Force pcm playback. */
1315 if (!pcm_is_playing())
1316 pcmbuf_play_start();
1320 *realsize = MIN(voice_remaining, reqsize);
1322 if (*realsize == 0)
1323 return NULL;
1325 return voicebuf;
1326 } /* voice_request_buffer_callback */
1328 static void voice_advance_buffer_callback(size_t amount)
1330 amount = MIN(amount, voice_remaining);
1331 voicebuf += amount;
1332 voice_remaining -= amount;
1335 static void voice_advance_buffer_loc_callback(void *ptr)
1337 size_t amount = (size_t)ptr - (size_t)voicebuf;
1339 voice_advance_buffer_callback(amount);
1342 static off_t voice_mp3_get_filepos_callback(int newtime)
1344 (void)newtime;
1346 return 0;
1349 static void voice_do_nothing(void)
1351 return;
1354 static bool voice_seek_buffer_callback(size_t newpos)
1356 (void)newpos;
1358 return false;
1361 static bool voice_request_next_track_callback(void)
1363 ci_voice.new_track = 0;
1364 return true;
1367 static void voice_thread(void)
1369 logf("Loading voice codec");
1370 voice_codec_loaded = true;
1371 semaphore_wait(&sem_codecthread);
1372 event_set_state(&event_codecthread, false);
1373 set_current_codec(CODEC_IDX_VOICE);
1374 dsp_configure(DSP_RESET, 0);
1375 voice_remaining = 0;
1376 voice_getmore = NULL;
1378 /* FIXME: If we being starting the voice thread without reboot, the
1379 voice_queue could be full of old stuff and we must flush it. */
1380 codec_load_file(get_codec_filename(AFMT_MPA_L3), &ci_voice);
1382 logf("Voice codec finished");
1383 voice_codec_loaded = false;
1384 voice_thread_p = NULL;
1385 semaphore_release(&sem_codecthread);
1386 } /* voice_thread */
1388 #endif /* PLAYBACK_VOICE */
1390 /* --- Codec thread --- */
1391 static bool codec_pcmbuf_insert_callback(
1392 const void *ch1, const void *ch2, int count)
1394 const char *src[2] = { ch1, ch2 };
1396 while (count > 0)
1398 int out_count = dsp_output_count(count);
1399 int inp_count;
1400 char *dest;
1402 /* Prevent audio from a previous track from playing */
1403 if (ci.new_track || ci.stop_codec)
1404 return true;
1406 while ((dest = pcmbuf_request_buffer(&out_count)) == NULL)
1408 sleep(1);
1409 if (ci.seek_time || ci.new_track || ci.stop_codec)
1410 return true;
1413 /* Get the real input_size for output_size bytes, guarding
1414 * against resampling buffer overflows. */
1415 inp_count = dsp_input_count(out_count);
1417 if (inp_count <= 0)
1418 return true;
1420 /* Input size has grown, no error, just don't write more than length */
1421 if (inp_count > count)
1422 inp_count = count;
1424 out_count = dsp_process(dest, src, inp_count);
1426 if (out_count <= 0)
1427 return true;
1429 pcmbuf_write_complete(out_count);
1431 #ifdef PLAYBACK_VOICE
1432 if ((voice_is_playing || voice_thread_start)
1433 && pcm_is_playing() && voice_codec_loaded &&
1434 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1436 voice_thread_start = false;
1437 swap_codec();
1439 #endif
1441 count -= inp_count;
1444 return true;
1445 } /* codec_pcmbuf_insert_callback */
1447 static void* codec_get_memory_callback(size_t *size)
1449 *size = MALLOC_BUFSIZE;
1450 return malloc_buf;
1453 #if 0
1454 static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
1455 static void codec_pcmbuf_position_callback(size_t size)
1457 /* This is called from an ISR, so be quick */
1458 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
1459 prev_ti->id3.elapsed;
1461 if (time >= prev_ti->id3.length)
1463 pcmbuf_set_position_callback(NULL);
1464 prev_ti->id3.elapsed = prev_ti->id3.length;
1466 else
1467 prev_ti->id3.elapsed = time;
1469 #endif
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 /* copy up-to size bytes into ptr and return the actual size copied */
1506 static size_t codec_filebuf_callback(void *ptr, size_t size)
1508 ssize_t copy_n;
1510 if (ci.stop_codec || !playing)
1511 return 0;
1513 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
1515 /* Nothing requested OR nothing left */
1516 if (copy_n == 0)
1517 return 0;
1519 /* Let the disk buffer catch fill until enough data is available */
1520 while (copy_n == -2)
1522 #if 0
1523 if (!filling)
1525 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1526 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1528 #endif
1530 LOGFQUEUE("codec >| buffering Q_BUFFER_HANDLE");
1531 queue_send(&buffering_queue, Q_BUFFER_HANDLE, CUR_TI->audio_hid);
1533 if (ci.stop_codec || ci.new_track)
1534 return 0;
1536 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
1539 /* Update read and other position pointers */
1540 bufadvance(CUR_TI->audio_hid, copy_n);
1541 ci.curpos += copy_n;
1543 /* Return the actual amount of data copied to the buffer */
1544 return copy_n;
1545 } /* codec_filebuf_callback */
1547 static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
1549 size_t copy_n = reqsize;
1550 ssize_t ret;
1551 char *ptr;
1553 if (!playing)
1555 *realsize = 0;
1556 return NULL;
1559 ret = bufgetdata(CUR_TI->audio_hid, reqsize, (unsigned char **)&ptr);
1560 if (ret >= 0)
1561 copy_n = MIN((size_t)ret, reqsize);
1563 if (copy_n == 0)
1565 *realsize = 0;
1566 return NULL;
1569 while (ret == -2)
1571 #if 0
1572 if (!filling)
1574 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1575 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1577 #endif
1579 LOGFQUEUE("codec >| buffering Q_BUFFER_HANDLE");
1580 queue_send(&buffering_queue, Q_BUFFER_HANDLE, CUR_TI->audio_hid);
1582 sleep(1);
1584 if (ci.stop_codec || ci.new_track)
1586 *realsize = 0;
1587 return NULL;
1589 ret = bufgetdata(CUR_TI->audio_hid, reqsize, (unsigned char **)&ptr);
1591 copy_n = MIN((size_t)ret, reqsize);
1593 *realsize = copy_n;
1595 return ptr;
1596 } /* codec_request_buffer_callback */
1598 static int get_codec_base_type(int type)
1600 switch (type) {
1601 case AFMT_MPA_L1:
1602 case AFMT_MPA_L2:
1603 case AFMT_MPA_L3:
1604 return AFMT_MPA_L3;
1607 return type;
1610 static void codec_advance_buffer_callback(size_t amount)
1612 #if 0
1613 int ret;
1615 while ((ret = bufadvance(CUR_TI->audio_hid, amount) == -2) && filling)
1616 sleep(1);
1618 if (ret == -2)
1620 intptr_t result = Q_CODEC_REQUEST_FAILED;
1622 if (!ci.stop_codec)
1624 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1625 result = queue_send(&audio_queue, Q_AUDIO_REBUFFER_SEEK,
1626 ci.curpos + amount);
1629 switch (result)
1631 case Q_CODEC_REQUEST_FAILED:
1632 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1633 ci.stop_codec = true;
1634 return;
1636 case Q_CODEC_REQUEST_COMPLETE:
1637 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1638 return;
1640 default:
1641 LOGFQUEUE("codec |< default");
1642 ci.stop_codec = true;
1643 return;
1647 /* Start buffer filling as necessary. */
1648 if (!pcmbuf_is_lowdata() && !filling)
1650 if (bufused() < conf_watermark && playing && !playlist_end)
1652 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1653 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1656 #endif
1658 bufadvance(CUR_TI->audio_hid, amount);
1660 ci.curpos += amount;
1661 codec_set_offset_callback(ci.curpos);
1664 static void codec_advance_buffer_loc_callback(void *ptr)
1666 size_t amount = get_offset(CUR_TI->audio_hid, ptr);
1668 codec_advance_buffer_callback(amount);
1671 /* Copied from mpeg.c. Should be moved somewhere else. */
1672 static int codec_get_file_pos(void)
1674 int pos = -1;
1675 struct mp3entry *id3 = audio_current_track();
1677 if (id3->vbr)
1679 if (id3->has_toc)
1681 /* Use the TOC to find the new position */
1682 unsigned int percent, remainder;
1683 int curtoc, nexttoc, plen;
1685 percent = (id3->elapsed*100)/id3->length;
1686 if (percent > 99)
1687 percent = 99;
1689 curtoc = id3->toc[percent];
1691 if (percent < 99)
1692 nexttoc = id3->toc[percent+1];
1693 else
1694 nexttoc = 256;
1696 pos = (id3->filesize/256)*curtoc;
1698 /* Use the remainder to get a more accurate position */
1699 remainder = (id3->elapsed*100)%id3->length;
1700 remainder = (remainder*100)/id3->length;
1701 plen = (nexttoc - curtoc)*(id3->filesize/256);
1702 pos += (plen/100)*remainder;
1704 else
1706 /* No TOC exists, estimate the new position */
1707 pos = (id3->filesize / (id3->length / 1000)) *
1708 (id3->elapsed / 1000);
1711 else if (id3->bitrate)
1712 pos = id3->elapsed * (id3->bitrate / 8);
1713 else
1714 return -1;
1716 pos += id3->first_frame_offset;
1718 /* Don't seek right to the end of the file so that we can
1719 transition properly to the next song */
1720 if (pos >= (int)(id3->filesize - id3->id3v1len))
1721 pos = id3->filesize - id3->id3v1len - 1;
1723 return pos;
1726 static off_t codec_mp3_get_filepos_callback(int newtime)
1728 off_t newpos;
1730 curtrack_id3.elapsed = newtime;
1731 newpos = codec_get_file_pos();
1733 return newpos;
1736 static void codec_seek_complete_callback(void)
1738 logf("seek_complete");
1739 if (pcm_is_paused())
1741 /* If this is not a seamless seek, clear the buffer */
1742 pcmbuf_play_stop();
1743 dsp_configure(DSP_FLUSH, 0);
1745 /* If playback was not 'deliberately' paused, unpause now */
1746 if (!paused)
1747 pcmbuf_pause(false);
1749 ci.seek_time = 0;
1752 static bool codec_seek_buffer_callback(size_t newpos)
1754 int difference;
1756 logf("codec_seek_buffer_callback");
1758 if (newpos >= CUR_TI->filesize)
1759 newpos = CUR_TI->filesize - 1;
1761 difference = newpos - ci.curpos;
1762 if (difference >= 0)
1764 /* Seeking forward */
1765 logf("seek: +%d", difference);
1766 codec_advance_buffer_callback(difference);
1767 return true;
1770 /* Seeking backward */
1771 difference = -difference;
1772 if (ci.curpos - difference < 0)
1773 difference = ci.curpos;
1775 #if 0
1776 /* We need to reload the song. */
1777 if (newpos < CUR_TI->start_pos)
1779 intptr_t result = Q_CODEC_REQUEST_FAILED;
1781 if (!ci.stop_codec)
1783 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1784 result = queue_send(&audio_queue, Q_AUDIO_REBUFFER_SEEK,
1785 newpos);
1788 switch (result)
1790 case Q_CODEC_REQUEST_COMPLETE:
1791 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1792 return true;
1794 case Q_CODEC_REQUEST_FAILED:
1795 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1796 ci.stop_codec = true;
1797 return false;
1799 default:
1800 LOGFQUEUE("codec |< default");
1801 return false;
1804 #endif
1806 /* Seeking inside buffer space. */
1807 logf("seek: -%d", difference);
1808 bufadvance(CUR_TI->audio_hid, -difference);
1809 ci.curpos -= difference;
1810 return true;
1813 static void codec_configure_callback(int setting, intptr_t value)
1815 switch (setting) {
1816 case CODEC_SET_FILEBUF_WATERMARK:
1817 conf_watermark = value;
1818 set_filebuf_watermark(buffer_margin);
1819 break;
1821 case CODEC_SET_FILEBUF_CHUNKSIZE:
1822 conf_filechunk = value;
1823 break;
1825 case CODEC_SET_FILEBUF_PRESEEK:
1826 conf_preseek = value;
1827 break;
1829 default:
1830 if (!dsp_configure(setting, value)) { logf("Illegal key:%d", setting); }
1834 static void codec_track_changed(void)
1836 automatic_skip = false;
1837 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1838 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1841 static void codec_pcmbuf_track_changed_callback(void)
1843 pcmbuf_set_position_callback(NULL);
1844 codec_track_changed();
1847 static void codec_discard_codec_callback(void)
1849 if (CUR_TI->codec_hid > 0)
1851 bufclose(CUR_TI->codec_hid);
1852 CUR_TI->codec_hid = 0;
1855 #if 0
1856 /* Check if a buffer desync has happened, log it and stop playback. */
1857 if (buf_ridx != CUR_TI->buf_idx)
1859 int offset = CUR_TI->buf_idx - buf_ridx;
1860 size_t new_used = bufused() - offset;
1862 logf("Buf off :%d=%d-%d", offset, CUR_TI->buf_idx, buf_ridx);
1863 logf("Used off:%d",bufused() - new_used);
1865 /* This is a fatal internal error and it's not safe to
1866 * continue playback. */
1867 ci.stop_codec = true;
1868 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1870 #endif
1873 static inline void codec_gapless_track_change(void) {
1874 /* callback keeps the progress bar moving while the pcmbuf empties */
1875 /* pcmbuf_set_position_callback(codec_pcmbuf_position_callback); */
1876 /* set the pcmbuf callback for when the track really changes */
1877 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
1880 static inline void codec_crossfade_track_change(void) {
1881 /* Initiate automatic crossfade mode */
1882 pcmbuf_crossfade_init(false);
1883 /* Notify the wps that the track change starts now */
1884 codec_track_changed();
1887 static void codec_track_skip_done(bool was_manual)
1889 int crossfade_mode = global_settings.crossfade;
1891 /* Manual track change (always crossfade or flush audio). */
1892 if (was_manual)
1894 pcmbuf_crossfade_init(true);
1895 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1896 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1898 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1899 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1900 && crossfade_mode != CROSSFADE_ENABLE_TRACKSKIP)
1902 if (crossfade_mode == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
1904 if (global_settings.playlist_shuffle)
1905 /* shuffle mode is on, so crossfade: */
1906 codec_crossfade_track_change();
1907 else
1908 /* shuffle mode is off, so do a gapless track change */
1909 codec_gapless_track_change();
1911 else
1912 /* normal crossfade: */
1913 codec_crossfade_track_change();
1915 else
1916 /* normal gapless playback. */
1917 codec_gapless_track_change();
1920 static bool codec_load_next_track(void)
1922 intptr_t result = Q_CODEC_REQUEST_FAILED;
1924 prev_track_elapsed = curtrack_id3.elapsed;
1926 if (ci.seek_time)
1927 codec_seek_complete_callback();
1929 #ifdef AB_REPEAT_ENABLE
1930 ab_end_of_track_report();
1931 #endif
1933 logf("Request new track");
1935 if (ci.new_track == 0)
1937 ci.new_track++;
1938 automatic_skip = true;
1941 if (!ci.stop_codec)
1943 trigger_cpu_boost();
1944 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1945 result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
1948 switch (result)
1950 case Q_CODEC_REQUEST_COMPLETE:
1951 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1952 codec_track_skip_done(!automatic_skip);
1953 return true;
1955 case Q_CODEC_REQUEST_FAILED:
1956 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1957 ci.new_track = 0;
1958 ci.stop_codec = true;
1959 return false;
1961 default:
1962 LOGFQUEUE("codec |< default");
1963 ci.stop_codec = true;
1964 return false;
1968 static bool codec_request_next_track_callback(void)
1970 int prev_codectype;
1972 if (ci.stop_codec || !playing)
1973 return false;
1975 prev_codectype = get_codec_base_type(curtrack_id3.codectype);
1977 if (!codec_load_next_track())
1978 return false;
1980 /* Check if the next codec is the same file. */
1981 if (prev_codectype == get_codec_base_type(curtrack_id3.codectype))
1983 logf("New track loaded");
1984 codec_discard_codec_callback();
1985 return true;
1987 else
1989 logf("New codec:%d/%d", curtrack_id3.codectype, prev_codectype);
1990 return false;
1994 static void codec_thread(void)
1996 struct queue_event ev;
1997 int status;
1998 size_t wrap;
2000 while (1) {
2001 status = 0;
2002 queue_wait(&codec_queue, &ev);
2004 switch (ev.id) {
2005 case Q_CODEC_LOAD_DISK:
2006 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
2007 queue_reply(&codec_queue, 1);
2008 audio_codec_loaded = true;
2009 #ifdef PLAYBACK_VOICE
2010 /* Don't sent messages to voice codec if it's already swapped
2011 out or it will never get this */
2012 if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE)
2014 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
2015 queue_post(&voice_queue, Q_AUDIO_PLAY, 0);
2017 semaphore_wait(&sem_codecthread);
2018 event_set_state(&event_codecthread, true);
2019 #endif
2020 set_current_codec(CODEC_IDX_AUDIO);
2021 ci.stop_codec = false;
2022 status = codec_load_file((const char *)ev.data, &ci);
2023 DEBUGF("codec_load = %d\n", status);
2024 #ifdef PLAYBACK_VOICE
2025 semaphore_release(&sem_codecthread);
2026 #endif
2027 break;
2029 case Q_CODEC_LOAD:
2030 LOGFQUEUE("codec < Q_CODEC_LOAD");
2031 if (CUR_TI->codec_hid <= 0) {
2032 logf("Codec slot is empty!");
2033 /* Wait for the pcm buffer to go empty */
2034 while (pcm_is_playing())
2035 yield();
2036 /* This must be set to prevent an infinite loop */
2037 ci.stop_codec = true;
2038 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
2039 queue_post(&codec_queue, Q_AUDIO_PLAY, 0);
2040 break;
2043 audio_codec_loaded = true;
2044 #ifdef PLAYBACK_VOICE
2045 if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE)
2047 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
2048 queue_post(&voice_queue, Q_AUDIO_PLAY, 0);
2050 semaphore_wait(&sem_codecthread);
2051 event_set_state(&event_codecthread, true);
2052 #endif
2053 set_current_codec(CODEC_IDX_AUDIO);
2054 ci.stop_codec = false;
2055 wrap = (size_t)&filebuf[filebuflen] - (size_t)getptr(CUR_TI->codec_hid);
2056 status = codec_load_ram(getptr(CUR_TI->codec_hid), CUR_TI->codecsize,
2057 &filebuf[0], wrap, &ci);
2058 #ifdef PLAYBACK_VOICE
2059 semaphore_release(&sem_codecthread);
2060 #endif
2061 break;
2063 #ifdef AUDIO_HAVE_RECORDING
2064 case Q_ENCODER_LOAD_DISK:
2065 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2066 audio_codec_loaded = false; /* Not audio codec! */
2067 #ifdef PLAYBACK_VOICE
2068 if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE)
2070 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
2071 queue_post(&voice_queue, Q_ENCODER_RECORD, 0);
2073 semaphore_wait(&sem_codecthread);
2074 event_set_state(&event_codecthread, true);
2075 #endif
2076 logf("loading encoder");
2077 set_current_codec(CODEC_IDX_AUDIO);
2078 ci.stop_encoder = false;
2079 status = codec_load_file((const char *)ev.data, &ci);
2080 #ifdef PLAYBACK_VOICE
2081 semaphore_release(&sem_codecthread);
2082 #endif
2083 logf("encoder stopped");
2084 break;
2085 #endif /* AUDIO_HAVE_RECORDING */
2087 #ifndef SIMULATOR
2088 case SYS_USB_CONNECTED:
2089 LOGFQUEUE("codec < SYS_USB_CONNECTED");
2090 queue_clear(&codec_queue);
2091 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2092 usb_wait_for_disconnect(&codec_queue);
2093 break;
2094 #endif
2096 default:
2097 LOGFQUEUE("codec < default");
2100 if (audio_codec_loaded)
2102 if (ci.stop_codec)
2104 status = CODEC_OK;
2105 if (!playing)
2106 pcmbuf_play_stop();
2109 audio_codec_loaded = false;
2112 switch (ev.id) {
2113 case Q_CODEC_LOAD_DISK:
2114 case Q_CODEC_LOAD:
2115 LOGFQUEUE("codec < Q_CODEC_LOAD");
2116 if (playing)
2118 if (ci.new_track || status != CODEC_OK)
2120 if (!ci.new_track)
2122 logf("Codec failure");
2123 gui_syncsplash(HZ*2, "Codec failure");
2126 if (!codec_load_next_track())
2128 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2129 /* End of playlist */
2130 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
2131 break;
2134 else
2136 logf("Codec finished");
2137 if (ci.stop_codec)
2139 /* Wait for the audio to stop playing before
2140 * triggering the WPS exit */
2141 while(pcm_is_playing())
2143 curtrack_id3.elapsed =
2144 curtrack_id3.length - pcmbuf_get_latency();
2145 sleep(1);
2147 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2148 /* End of playlist */
2149 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
2150 break;
2154 if (CUR_TI->codec_hid > 0)
2156 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2157 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
2159 else
2161 const char *codec_fn =
2162 get_codec_filename(curtrack_id3.codectype);
2163 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2164 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
2165 (intptr_t)codec_fn);
2168 break;
2170 #ifdef AUDIO_HAVE_RECORDING
2171 case Q_ENCODER_LOAD_DISK:
2172 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2174 if (status == CODEC_OK)
2175 break;
2177 logf("Encoder failure");
2178 gui_syncsplash(HZ*2, "Encoder failure");
2180 if (ci.enc_codec_loaded < 0)
2181 break;
2183 logf("Encoder failed to load");
2184 ci.enc_codec_loaded = -1;
2185 break;
2186 #endif /* AUDIO_HAVE_RECORDING */
2188 default:
2189 LOGFQUEUE("codec < default");
2191 } /* end switch */
2196 /* --- Audio thread --- */
2198 #if 0
2199 static bool audio_filebuf_is_lowdata(void)
2201 return bufused() < AUDIO_FILEBUF_CRITICAL;
2203 #endif
2205 static bool audio_have_tracks(void)
2207 return track_ridx != track_widx || CUR_TI->filesize;
2210 static bool audio_have_free_tracks(void)
2212 if (track_widx < track_ridx)
2213 return track_widx + 1 < track_ridx;
2214 else if (track_ridx == 0)
2215 return track_widx < MAX_TRACK - 1;
2217 return true;
2220 int audio_track_count(void)
2222 if (audio_have_tracks())
2224 int relative_track_widx = track_widx;
2226 if (track_ridx > track_widx)
2227 relative_track_widx += MAX_TRACK;
2229 return relative_track_widx - track_ridx + 1;
2232 return 0;
2235 long audio_filebufused(void)
2237 return (long) bufused();
2240 #if 0
2241 /* Count the data BETWEEN the selected tracks */
2242 static size_t audio_buffer_count_tracks(int from_track, int to_track)
2244 size_t amount = 0;
2245 bool need_wrap = to_track < from_track;
2247 while (1)
2249 if (++from_track >= MAX_TRACK)
2251 from_track -= MAX_TRACK;
2252 need_wrap = false;
2255 if (from_track >= to_track && !need_wrap)
2256 break;
2258 amount += tracks[from_track].codecsize + tracks[from_track].filesize;
2260 return amount;
2262 #endif
2264 static bool audio_buffer_wind_forward(int new_track_ridx, int old_track_ridx)
2266 (void)new_track_ridx;
2267 (void)old_track_ridx;
2268 #if 0
2269 size_t amount;
2271 /* Start with the remainder of the previously playing track */
2272 amount = tracks[old_track_ridx].filesize - ci.curpos;
2273 /* Then collect all data from tracks in between them */
2274 amount += audio_buffer_count_tracks(old_track_ridx, new_track_ridx);
2275 logf("bwf:%ldB", (long) amount);
2277 if (amount > bufused())
2278 return false;
2280 /* Wind the buffer to the beginning of the target track or its codec */
2281 buf_ridx = RINGBUF_ADD(buf_ridx, amount);
2282 #endif
2283 return true;
2286 static bool audio_buffer_wind_backward(int new_track_ridx, int old_track_ridx)
2288 (void)new_track_ridx;
2289 (void)old_track_ridx;
2290 #if 0
2291 /* Available buffer data */
2292 size_t buf_back;
2293 /* Start with the previously playing track's data and our data */
2294 size_t amount;
2296 amount = ci.curpos;
2297 buf_back = RINGBUF_SUB(buf_ridx, buf_widx);
2299 /* If we're not just resetting the current track */
2300 if (new_track_ridx != old_track_ridx)
2302 /* Need to wind to before the old track's codec and our filesize */
2303 amount += tracks[old_track_ridx].codecsize;
2304 amount += tracks[new_track_ridx].filesize;
2306 /* Rewind the old track to its beginning */
2307 tracks[old_track_ridx].available =
2308 tracks[old_track_ridx].filesize - tracks[old_track_ridx].filerem;
2311 /* If the codec was ever buffered */
2312 if (tracks[new_track_ridx].codecsize)
2314 /* Add the codec to the needed size */
2315 amount += tracks[new_track_ridx].codecsize;
2316 tracks[new_track_ridx].has_codec = true;
2319 /* Then collect all data from tracks between new and old */
2320 amount += audio_buffer_count_tracks(new_track_ridx, old_track_ridx);
2322 /* Do we have space to make this skip? */
2323 if (amount > buf_back)
2324 return false;
2326 logf("bwb:%ldB",amount);
2328 /* Rewind the buffer to the beginning of the target track or its codec */
2329 buf_ridx = RINGBUF_SUB(buf_ridx, amount);
2331 /* Reset to the beginning of the new track */
2332 tracks[new_track_ridx].available = tracks[new_track_ridx].filesize;
2333 #endif
2334 return true;
2337 static void audio_update_trackinfo(void)
2339 ci.filesize = CUR_TI->filesize;
2340 curtrack_id3.elapsed = 0;
2341 curtrack_id3.offset = 0;
2342 ci.id3 = &curtrack_id3;
2343 ci.curpos = 0;
2344 ci.taginfo_ready = &CUR_TI->taginfo_ready;
2347 #if 0
2348 /* Yield to codecs for as long as possible if they are in need of data
2349 * return true if the caller should break to let the audio thread process
2350 * new events */
2351 static bool audio_yield_codecs(void)
2353 yield();
2355 if (!queue_empty(&audio_queue))
2356 return true;
2358 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
2359 && !ci.stop_codec && playing && !audio_filebuf_is_lowdata())
2361 if (filling)
2362 yield();
2363 else
2364 sleep(2);
2366 if (!queue_empty(&audio_queue))
2367 return true;
2370 return false;
2372 #endif
2374 static void audio_clear_track_entries(bool clear_unbuffered)
2376 int cur_idx = track_widx;
2377 int last_idx = -1;
2379 logf("Clearing tracks:%d/%d, %d", track_ridx, track_widx, clear_unbuffered);
2381 /* Loop over all tracks from write-to-read */
2382 while (1)
2384 cur_idx++;
2385 cur_idx &= MAX_TRACK_MASK;
2387 if (cur_idx == track_ridx)
2388 break;
2390 /* If the track is buffered, conditionally clear/notify,
2391 * otherwise clear the track if that option is selected */
2392 if (tracks[cur_idx].event_sent)
2394 if (last_idx >= 0)
2396 /* If there is an unbuffer callback, call it, otherwise,
2397 * just clear the track */
2398 if (track_unbuffer_callback)
2399 track_unbuffer_callback(bufgetid3(tracks[last_idx].id3_hid), false);
2401 clear_track_info(&tracks[last_idx]);
2403 last_idx = cur_idx;
2405 else if (clear_unbuffered)
2407 clear_track_info(&tracks[cur_idx]);
2411 /* We clear the previous instance of a buffered track throughout
2412 * the above loop to facilitate 'last' detection. Clear/notify
2413 * the last track here */
2414 if (last_idx >= 0)
2416 if (track_unbuffer_callback)
2417 track_unbuffer_callback(bufgetid3(tracks[last_idx].id3_hid), true);
2418 clear_track_info(&tracks[last_idx]);
2422 static void audio_release_tracks(void)
2424 int cur_idx = track_ridx;
2426 logf("releasing all tracks");
2428 while (1)
2430 clear_track_info(&tracks[cur_idx]);
2432 cur_idx++;
2433 cur_idx &= MAX_TRACK_MASK;
2435 if (cur_idx == track_widx)
2436 break;
2440 #if 0
2441 /* FIXME: This code should be made more generic and move to metadata.c */
2442 static void audio_strip_tags(void)
2444 int i;
2445 static const unsigned char tag[] = "TAG";
2446 static const unsigned char apetag[] = "APETAGEX";
2447 size_t tag_idx;
2448 size_t cur_idx;
2449 size_t len, version;
2451 tag_idx = RINGBUF_SUB(buf_widx, 128);
2453 if (bufused() > 128 && tag_idx > buf_ridx)
2455 cur_idx = tag_idx;
2456 for(i = 0;i < 3;i++)
2458 if(filebuf[cur_idx] != tag[i])
2459 goto strip_ape_tag;
2461 cur_idx = RINGBUF_ADD(cur_idx, 1);
2464 /* Skip id3v1 tag */
2465 logf("Skipping ID3v1 tag");
2466 buf_widx = tag_idx;
2467 tracks[track_widx].available -= 128;
2468 tracks[track_widx].filesize -= 128;
2471 strip_ape_tag:
2472 /* Check for APE tag (look for the APE tag footer) */
2473 tag_idx = RINGBUF_SUB(buf_widx, 32);
2475 if (bufused() > 32 && tag_idx > buf_ridx)
2477 cur_idx = tag_idx;
2478 for(i = 0;i < 8;i++)
2480 if(filebuf[cur_idx] != apetag[i])
2481 return;
2483 cur_idx = RINGBUF_ADD(cur_idx, 1);
2486 /* Read the version and length from the footer */
2487 version = filebuf[tag_idx+8] | (filebuf[tag_idx+9] << 8) |
2488 (filebuf[tag_idx+10] << 16) | (filebuf[tag_idx+11] << 24);
2489 len = filebuf[tag_idx+12] | (filebuf[tag_idx+13] << 8) |
2490 (filebuf[tag_idx+14] << 16) | (filebuf[tag_idx+15] << 24);
2491 if (version == 2000)
2492 len += 32; /* APEv2 has a 32 byte header */
2494 /* Skip APE tag */
2495 if (bufused() > len)
2497 logf("Skipping APE tag (%ldB)", len);
2498 buf_widx = RINGBUF_SUB(buf_widx, len);
2499 tracks[track_widx].available -= len;
2500 tracks[track_widx].filesize -= len;
2504 #endif
2506 #if 0
2507 /* Returns true if a whole file is read, false otherwise */
2508 static bool audio_read_file(size_t minimum)
2510 bool ret_val = false;
2512 /* If we're called and no file is open, this is an error */
2513 if (current_fd < 0)
2515 logf("Bad fd in arf");
2516 /* Give some hope of miraculous recovery by forcing a track reload */
2517 tracks[track_widx].filesize = 0;
2518 /* Stop this buffering run */
2519 return ret_val;
2522 trigger_cpu_boost();
2523 while (tracks[track_widx].filerem > 0)
2525 size_t copy_n;
2526 int overlap;
2527 int rc;
2529 /* copy_n is the largest chunk that is safe to read */
2530 copy_n = MIN(conf_filechunk, filebuflen - buf_widx);
2532 /* buf_widx == buf_ridx is defined as buffer empty, not buffer full */
2533 if (RINGBUF_ADD_CROSS(buf_widx,copy_n,buf_ridx) >= 0)
2534 break;
2536 /* rc is the actual amount read */
2537 rc = read(current_fd, &filebuf[buf_widx], copy_n);
2539 if (rc < 0)
2541 logf("File ended %ldB early", tracks[track_widx].filerem);
2542 tracks[track_widx].filesize -= tracks[track_widx].filerem;
2543 tracks[track_widx].filerem = 0;
2544 break;
2547 /* How much of the playing track did we overwrite */
2548 if (buf_widx == CUR_TI->buf_idx)
2550 /* Special handling; zero or full overlap? */
2551 if (track_widx == track_ridx && CUR_TI->available == 0)
2552 overlap = 0;
2553 else
2554 overlap = rc;
2556 else
2557 overlap = RINGBUF_ADD_CROSS(buf_widx,rc,CUR_TI->buf_idx);
2559 if ((unsigned)rc > tracks[track_widx].filerem)
2561 logf("Bad: rc-filerem=%ld, fixing", rc-tracks[track_widx].filerem);
2562 tracks[track_widx].filesize += rc - tracks[track_widx].filerem;
2563 tracks[track_widx].filerem = rc;
2566 /* Advance buffer */
2567 buf_widx = RINGBUF_ADD(buf_widx, rc);
2568 tracks[track_widx].available += rc;
2569 tracks[track_widx].filerem -= rc;
2571 /* If we write into the playing track, adjust it's buffer info */
2572 if (overlap > 0)
2574 CUR_TI->buf_idx += overlap;
2575 CUR_TI->start_pos += overlap;
2578 /* For a rebuffer, fill at least this minimum */
2579 if (minimum > (unsigned)rc)
2580 minimum -= rc;
2581 /* Let the codec process up to the watermark */
2582 /* Break immediately if this is a quick buffer, or there is an event */
2583 else if (minimum || audio_yield_codecs())
2585 /* Exit quickly, but don't stop the overall buffering process */
2586 ret_val = true;
2587 break;
2591 if (tracks[track_widx].filerem == 0)
2593 logf("Finished buf:%ldB", tracks[track_widx].filesize);
2594 close(current_fd);
2595 current_fd = -1;
2596 audio_strip_tags();
2598 track_widx++;
2599 track_widx &= MAX_TRACK_MASK;
2601 tracks[track_widx].filesize = 0;
2602 return true;
2604 else
2606 logf("%s buf:%ldB", ret_val?"Quick":"Partially",
2607 tracks[track_widx].filesize - tracks[track_widx].filerem);
2608 return ret_val;
2611 #endif
2613 static bool audio_loadcodec(bool start_play)
2615 int fd;
2616 int prev_track;
2617 char codec_path[MAX_PATH]; /* Full path to codec */
2619 DEBUGF("audio_loadcodec(start_play = %s)\n", start_play ? "true" : "false");
2621 if (tracks[track_widx].id3_hid <= 0) {
2622 DEBUGF("track ID3 info not ready\n");
2623 return false;
2626 const char * codec_fn =
2627 get_codec_filename(bufgetid3(tracks[track_widx].id3_hid)->codectype);
2628 if (codec_fn == NULL)
2629 return false;
2631 tracks[track_widx].codec_hid = 0;
2633 if (start_play)
2635 /* Load the codec directly from disk and save some memory. */
2636 track_ridx = track_widx;
2637 ci.filesize = CUR_TI->filesize;
2638 ci.id3 = &curtrack_id3;
2639 ci.taginfo_ready = &CUR_TI->taginfo_ready;
2640 ci.curpos = 0;
2641 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2642 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (intptr_t)codec_fn);
2643 return true;
2645 else
2647 /* If we already have another track than this one buffered */
2648 if (track_widx != track_ridx)
2650 prev_track = (track_widx - 1) & MAX_TRACK_MASK;
2652 /* If the previous codec is the same as this one, there is no need
2653 * to put another copy of it on the file buffer */
2654 if (get_codec_base_type(
2655 bufgetid3(tracks[track_widx].id3_hid)->codectype) ==
2656 get_codec_base_type(
2657 bufgetid3(tracks[prev_track].id3_hid)->codectype)
2658 && audio_codec_loaded)
2660 logf("Reusing prev. codec");
2661 return true;
2666 codec_get_full_path(codec_path, codec_fn);
2668 fd = open(codec_path, O_RDONLY);
2669 if (fd < 0)
2671 logf("Codec doesn't exist!");
2672 return false;
2675 tracks[track_widx].codecsize = filesize(fd);
2677 tracks[track_widx].codec_hid = bufopen(codec_path, 0, TYPE_CODEC);
2678 if (tracks[track_widx].codec_hid < 0)
2680 logf("Not enough space");
2681 close(fd);
2682 return false;
2685 close(fd);
2686 logf("Loaded codec");
2688 return true;
2691 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2692 static void audio_set_elapsed(struct mp3entry* id3)
2694 unsigned long offset = id3->offset > id3->first_frame_offset ?
2695 id3->offset - id3->first_frame_offset : 0;
2697 if ( id3->vbr ) {
2698 if ( id3->has_toc ) {
2699 /* calculate elapsed time using TOC */
2700 int i;
2701 unsigned int remainder, plen, relpos, nextpos;
2703 /* find wich percent we're at */
2704 for (i=0; i<100; i++ )
2705 if ( offset < id3->toc[i] * (id3->filesize / 256) )
2706 break;
2708 i--;
2709 if (i < 0)
2710 i = 0;
2712 relpos = id3->toc[i];
2714 if (i < 99)
2715 nextpos = id3->toc[i+1];
2716 else
2717 nextpos = 256;
2719 remainder = offset - (relpos * (id3->filesize / 256));
2721 /* set time for this percent (divide before multiply to prevent
2722 overflow on long files. loss of precision is negligible on
2723 short files) */
2724 id3->elapsed = i * (id3->length / 100);
2726 /* calculate remainder time */
2727 plen = (nextpos - relpos) * (id3->filesize / 256);
2728 id3->elapsed += (((remainder * 100) / plen) *
2729 (id3->length / 10000));
2731 else {
2732 /* no TOC exists. set a rough estimate using average bitrate */
2733 int tpk = id3->length /
2734 ((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
2735 1024);
2736 id3->elapsed = offset / 1024 * tpk;
2739 else
2741 /* constant bitrate, use exact calculation */
2742 if (id3->bitrate != 0)
2743 id3->elapsed = offset / (id3->bitrate / 8);
2747 /* Load one track by making the appropriate bufopen calls. Return true if
2748 everything required was loaded correctly, false if not. */
2749 static bool audio_load_track(int offset, bool start_play, bool rebuffer)
2751 (void)rebuffer;
2752 char *trackname;
2753 /* char msgbuf[80]; */
2754 int fd;
2755 int file_offset = 0;
2756 struct mp3entry id3;
2758 /* Stop buffer filling if there is no free track entries.
2759 Don't fill up the last track entry (we wan't to store next track
2760 metadata there). */
2761 if (!audio_have_free_tracks())
2763 logf("No free tracks");
2764 return false;
2767 last_peek_offset++;
2768 peek_again:
2769 logf("Buffering track:%d/%d", track_widx, track_ridx);
2770 /* Get track name from current playlist read position. */
2771 while ((trackname = playlist_peek(last_peek_offset)) != NULL)
2773 /* Handle broken playlists. */
2774 fd = open(trackname, O_RDONLY);
2775 if (fd < 0)
2777 logf("Open failed");
2778 /* Skip invalid entry from playlist. */
2779 playlist_skip_entry(NULL, last_peek_offset);
2781 else
2782 break;
2785 if (!trackname)
2787 logf("End-of-playlist");
2788 playlist_end = true;
2789 return false;
2792 tracks[track_widx].filesize = filesize(fd);
2794 /* Get track metadata if we don't already have it. */
2795 if (tracks[track_widx].id3_hid <= 0)
2797 if (get_metadata(&id3, fd, trackname))
2799 tracks[track_widx].id3_hid = bufalloc(&id3, sizeof(struct mp3entry),
2800 TYPE_ID3);
2801 tracks[track_widx].taginfo_ready = (tracks[track_widx].id3_hid > 0);
2803 if (tracks[track_widx].id3_hid <= 0)
2805 DEBUGF("failed to allocate space for metadata\n");
2806 last_peek_offset--;
2807 close(fd);
2808 return false;
2811 if (track_widx == track_ridx)
2812 copy_mp3entry(&curtrack_id3, &id3);
2813 else if (track_widx == ((track_ridx + 1) & MAX_TRACK_MASK))
2814 copy_mp3entry(&nexttrack_id3, &id3);
2816 if (start_play)
2818 track_changed = true;
2819 playlist_update_resume_info(audio_current_track());
2822 else
2824 logf("mde:%s!",trackname);
2826 /* Skip invalid entry from playlist. */
2827 playlist_skip_entry(NULL, last_peek_offset);
2828 tracks[track_widx].taginfo_ready = false;
2829 goto peek_again;
2834 close(fd);
2836 /* Set default values */
2837 if (start_play)
2839 int last_codec = current_codec;
2841 set_current_codec(CODEC_IDX_AUDIO);
2842 conf_watermark = AUDIO_DEFAULT_WATERMARK;
2843 conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
2844 conf_preseek = AUDIO_REBUFFER_GUESS_SIZE;
2845 dsp_configure(DSP_RESET, 0);
2846 set_current_codec(last_codec);
2848 track_changed = true;
2849 playlist_update_resume_info(audio_current_track());
2852 #if 0
2853 if (cuesheet_is_enabled() && tracks[track_widx].id3.cuesheet_type == 1)
2855 char cuepath[MAX_PATH];
2857 struct cuesheet *cue = start_play ? curr_cue : temp_cue;
2859 if (look_for_cuesheet_file(trackname, cuepath) &&
2860 parse_cuesheet(cuepath, cue))
2862 strcpy((cue)->audio_filename, trackname);
2863 if (start_play)
2864 cue_spoof_id3(curr_cue, &tracks[track_widx].id3);
2867 #endif
2869 /* Load the codec. */
2870 if (!audio_loadcodec(start_play))
2872 #if 0
2873 /* Set filesize to zero to indicate no file was loaded. */
2874 /* tracks[track_widx].filesize = 0;
2875 tracks[track_widx].filerem = 0;
2876 close(current_fd);
2877 current_fd = -1; */
2879 if (tracks[track_widx].codecsize)
2881 /* No space for codec on buffer, not an error */
2882 tracks[track_widx].codecsize = 0;
2883 return false;
2886 /* This is an error condition, either no codec was found, or reading
2887 * the codec file failed part way through, either way, skip the track */
2888 snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname);
2889 /* We should not use gui_syncplash from audio thread! */
2890 gui_syncsplash(HZ*2, msgbuf);
2891 /* Skip invalid entry from playlist. */
2892 playlist_skip_entry(NULL, last_peek_offset);
2893 tracks[track_widx].taginfo_ready = false;
2894 goto peek_again;
2895 #endif
2896 return false;
2899 struct mp3entry *track_id3;
2901 if (track_widx == track_ridx)
2902 track_id3 = &curtrack_id3;
2903 else if (track_widx == ((track_ridx + 1) & MAX_TRACK_MASK))
2904 track_id3 = &nexttrack_id3;
2905 else
2906 track_id3 = bufgetid3(tracks[track_widx].id3_hid);
2908 /* tracks[track_widx].start_pos = 0; */
2909 set_filebuf_watermark(buffer_margin);
2910 track_id3->elapsed = 0;
2912 if (offset > 0)
2914 switch (track_id3->codectype) {
2915 case AFMT_MPA_L1:
2916 case AFMT_MPA_L2:
2917 case AFMT_MPA_L3:
2918 file_offset = offset;
2919 track_id3->offset = offset;
2920 audio_set_elapsed(track_id3);
2921 ci.curpos = offset;
2922 break;
2924 case AFMT_WAVPACK:
2925 file_offset = offset;
2926 track_id3->offset = offset;
2927 track_id3->elapsed = track_id3->length / 2;
2928 ci.curpos = offset;
2929 break;
2931 case AFMT_OGG_VORBIS:
2932 case AFMT_SPEEX:
2933 case AFMT_FLAC:
2934 case AFMT_PCM_WAV:
2935 case AFMT_A52:
2936 case AFMT_AAC:
2937 case AFMT_MPC:
2938 case AFMT_APE:
2939 track_id3->offset = offset;
2940 break;
2944 logf("alt:%s", trackname);
2945 /* tracks[track_widx].buf_idx = buf_widx; */
2947 //return audio_read_file(rebuffer);
2949 tracks[track_widx].audio_hid = bufopen(trackname, file_offset, TYPE_AUDIO);
2951 if (tracks[track_widx].audio_hid <= 0)
2952 return false;
2954 if (start_play)
2956 LOGFQUEUE("audio >| buffering Q_BUFFER_HANDLE");
2957 queue_send(&buffering_queue, Q_BUFFER_HANDLE, tracks[track_widx].audio_hid);
2960 track_widx++;
2961 track_widx &= MAX_TRACK_MASK;
2963 return true;
2966 #if 0
2967 static bool audio_read_next_metadata(void)
2969 int fd;
2970 char *trackname;
2971 int next_idx;
2972 int status;
2974 next_idx = track_widx;
2975 if (tracks[next_idx].id3_hid > 0)
2977 next_idx++;
2978 next_idx &= MAX_TRACK_MASK;
2980 if (tracks[next_idx].id3_hid > 0)
2981 return true;
2984 trackname = playlist_peek(last_peek_offset + 1);
2985 if (!trackname)
2986 return false;
2988 fd = open(trackname, O_RDONLY);
2989 if (fd < 0)
2990 return false;
2992 struct mp3entry id3;
2994 status = get_metadata(&id3, fd, trackname);
2995 /* Preload the glyphs in the tags */
2996 if (status)
2998 tracks[next_idx].id3_hid = bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3);
3000 if (tracks[next_idx].id3_hid > 0)
3002 tracks[next_idx].taginfo_ready = true;
3003 if (id3.title)
3004 lcd_getstringsize(id3.title, NULL, NULL);
3005 if (id3.artist)
3006 lcd_getstringsize(id3.artist, NULL, NULL);
3007 if (id3.album)
3008 lcd_getstringsize(id3.album, NULL, NULL);
3010 else
3011 status = false;
3013 close(fd);
3015 return status;
3017 #endif
3019 /* Send callback events to notify about new tracks. */
3020 static void audio_generate_postbuffer_events(void)
3022 int cur_idx;
3023 int last_idx = -1;
3025 logf("Postbuffer:%d/%d",track_ridx,track_widx);
3027 if (audio_have_tracks())
3029 cur_idx = track_ridx;
3031 while (1) {
3032 if (!tracks[cur_idx].event_sent)
3034 if (last_idx >= 0 && !tracks[last_idx].event_sent)
3036 /* Mark the event 'sent' even if we don't really send one */
3037 tracks[last_idx].event_sent = true;
3038 if (track_buffer_callback)
3039 track_buffer_callback(bufgetid3(tracks[last_idx].id3_hid), false);
3041 last_idx = cur_idx;
3043 if (cur_idx == track_widx)
3044 break;
3045 cur_idx++;
3046 cur_idx &= MAX_TRACK_MASK;
3049 if (last_idx >= 0 && !tracks[last_idx].event_sent)
3051 tracks[last_idx].event_sent = true;
3052 if (track_buffer_callback)
3053 track_buffer_callback(bufgetid3(tracks[last_idx].id3_hid), true);
3058 static bool audio_initialize_buffer_fill(bool clear_tracks)
3060 /* Don't initialize if we're already initialized */
3061 if (filling)
3062 return true;
3064 logf("Starting buffer fill");
3066 /* Set the filling flag true before calling audio_clear_tracks as that
3067 * function can yield and we start looping. */
3068 filling = true;
3070 if (clear_tracks)
3071 audio_clear_track_entries(false);
3073 /* Save the current resume position once. */
3074 playlist_update_resume_info(audio_current_track());
3076 return true;
3079 static void audio_fill_file_buffer(
3080 bool start_play, bool rebuffer, size_t offset)
3082 bool had_next_track = audio_next_track() != NULL;
3083 bool continue_buffering;
3085 /* Must reset the buffer before use if trashed or voice only - voice
3086 file size shouldn't have changed so we can go straight from
3087 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
3088 if (buffer_state != BUFFER_STATE_INITIALIZED)
3089 audio_reset_buffer();
3091 if (!audio_initialize_buffer_fill(!start_play))
3092 return ;
3094 continue_buffering = audio_load_track(offset, start_play, rebuffer);
3096 if (!had_next_track && audio_next_track())
3097 track_changed = true;
3099 /* If we're done buffering */
3100 if (!continue_buffering)
3102 //audio_read_next_metadata();
3104 audio_generate_postbuffer_events();
3105 filling = false;
3107 #ifndef SIMULATOR
3108 ata_sleep();
3109 #endif
3113 static void audio_rebuffer(void)
3115 logf("Forcing rebuffer");
3117 /* Reset track pointers */
3118 track_widx = track_ridx;
3119 audio_clear_track_entries(true);
3121 /* Fill the buffer */
3122 last_peek_offset = -1;
3123 CUR_TI->filesize = 0;
3124 ci.curpos = 0;
3126 if (!CUR_TI->taginfo_ready)
3127 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
3129 audio_fill_file_buffer(false, true, 0);
3132 static int audio_check_new_track(void)
3134 DEBUGF("audio_check_new_track\n");
3136 int track_count = audio_track_count();
3137 int old_track_ridx = track_ridx;
3138 int next_idx;
3139 bool forward;
3141 if (dir_skip)
3143 dir_skip = false;
3144 if (playlist_next_dir(ci.new_track))
3146 ci.new_track = 0;
3147 CUR_TI->taginfo_ready = false;
3148 audio_rebuffer();
3149 goto skip_done;
3151 else
3153 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3154 return Q_CODEC_REQUEST_FAILED;
3158 if (new_playlist)
3159 ci.new_track = 0;
3161 /* If the playlist isn't that big */
3162 if (!playlist_check(ci.new_track))
3164 if (ci.new_track >= 0)
3166 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3167 return Q_CODEC_REQUEST_FAILED;
3169 /* Find the beginning backward if the user over-skips it */
3170 while (!playlist_check(++ci.new_track))
3171 if (ci.new_track >= 0)
3173 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3174 return Q_CODEC_REQUEST_FAILED;
3177 /* Update the playlist */
3178 last_peek_offset -= ci.new_track;
3180 if (playlist_next(ci.new_track) < 0)
3182 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3183 return Q_CODEC_REQUEST_FAILED;
3186 if (new_playlist)
3188 ci.new_track = 1;
3189 new_playlist = false;
3192 /* Save the old track */
3193 /* prev_ti = CUR_TI; */
3195 int i, idx;
3196 for (i = 0; i < ci.new_track; i++)
3198 idx = (track_ridx + i) & MAX_TRACK_MASK;
3199 clear_track_info(&tracks[idx]);
3202 /* Move to the new track */
3203 track_ridx += ci.new_track;
3204 track_ridx &= MAX_TRACK_MASK;
3206 if (CUR_TI->id3_hid > 0)
3207 copy_mp3entry(&curtrack_id3, bufgetid3(CUR_TI->id3_hid));
3209 next_idx = track_ridx + 1;
3210 next_idx &= MAX_TRACK_MASK;
3212 if (tracks[next_idx].id3_hid > 0)
3213 copy_mp3entry(&nexttrack_id3, bufgetid3(tracks[next_idx].id3_hid));
3215 if (automatic_skip)
3216 playlist_end = false;
3218 track_changed = !automatic_skip;
3220 /* If it is not safe to even skip this many track entries */
3221 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
3223 ci.new_track = 0;
3224 CUR_TI->taginfo_ready = false;
3225 audio_rebuffer();
3226 goto skip_done;
3229 forward = ci.new_track > 0;
3230 ci.new_track = 0;
3232 /* If the target track is clearly not in memory */
3233 if (CUR_TI->filesize == 0 || !CUR_TI->taginfo_ready)
3235 audio_rebuffer();
3236 goto skip_done;
3239 /* The track may be in memory, see if it really is */
3240 if (forward)
3242 if (!audio_buffer_wind_forward(track_ridx, old_track_ridx))
3243 audio_rebuffer();
3245 else
3247 int cur_idx = track_ridx;
3248 bool taginfo_ready = true;
3249 bool wrap = track_ridx > old_track_ridx;
3251 while (1)
3253 cur_idx++;
3254 cur_idx &= MAX_TRACK_MASK;
3255 if (!(wrap || cur_idx < old_track_ridx))
3256 break;
3258 /* If we hit a track in between without valid tag info, bail */
3259 if (!tracks[cur_idx].taginfo_ready)
3261 taginfo_ready = false;
3262 break;
3265 tracks[cur_idx].available = tracks[cur_idx].filesize;
3266 if (tracks[cur_idx].codecsize)
3267 tracks[cur_idx].has_codec = true;*/
3269 if (taginfo_ready)
3271 if (!audio_buffer_wind_backward(track_ridx, old_track_ridx))
3272 audio_rebuffer();
3274 else
3276 CUR_TI->taginfo_ready = false;
3277 audio_rebuffer();
3281 skip_done:
3282 audio_update_trackinfo();
3283 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3284 return Q_CODEC_REQUEST_COMPLETE;
3287 #if 0
3288 static int audio_rebuffer_and_seek(size_t newpos)
3290 size_t real_preseek;
3291 int fd;
3292 char *trackname;
3294 /* (Re-)open current track's file handle. */
3295 trackname = playlist_peek(0);
3296 fd = open(trackname, O_RDONLY);
3297 if (fd < 0)
3299 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3300 return Q_CODEC_REQUEST_FAILED;
3303 if (current_fd >= 0)
3304 close(current_fd);
3305 current_fd = fd;
3307 playlist_end = false;
3309 ci.curpos = newpos;
3311 /* Clear codec buffer. */
3312 track_widx = track_ridx;
3313 tracks[track_widx].buf_idx = buf_widx = buf_ridx = 0;
3315 last_peek_offset = 0;
3316 filling = false;
3317 audio_initialize_buffer_fill(true);
3319 /* This may have been tweaked by the id3v1 code */
3320 CUR_TI->filesize=filesize(fd);
3321 if (newpos > conf_preseek)
3323 CUR_TI->start_pos = newpos - conf_preseek;
3324 lseek(current_fd, CUR_TI->start_pos, SEEK_SET);
3325 CUR_TI->filerem = CUR_TI->filesize - CUR_TI->start_pos;
3326 real_preseek = conf_preseek;
3328 else
3330 CUR_TI->start_pos = 0;
3331 CUR_TI->filerem = CUR_TI->filesize;
3332 real_preseek = newpos;
3335 CUR_TI->available = 0;
3337 audio_read_file(real_preseek);
3339 /* Account for the data we just read that is 'behind' us now */
3340 CUR_TI->available -= real_preseek;
3342 buf_ridx = RINGBUF_ADD(buf_ridx, real_preseek);
3344 (void)newpos;
3345 DEBUGF("/!\\ not implemented /!\\");
3346 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3347 return Q_CODEC_REQUEST_COMPLETE;
3349 #endif
3351 void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3,
3352 bool last_track))
3354 track_buffer_callback = handler;
3357 void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3,
3358 bool last_track))
3360 track_unbuffer_callback = handler;
3363 void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3))
3365 track_changed_callback = handler;
3368 unsigned long audio_prev_elapsed(void)
3370 return prev_track_elapsed;
3373 static void audio_stop_codec_flush(void)
3375 ci.stop_codec = true;
3376 pcmbuf_pause(true);
3378 while (audio_codec_loaded)
3379 yield();
3381 /* If the audio codec is not loaded any more, and the audio is still
3382 * playing, it is now and _only_ now safe to call this function from the
3383 * audio thread */
3384 if (pcm_is_playing())
3385 pcmbuf_play_stop();
3386 pcmbuf_pause(paused);
3389 static void audio_stop_playback(void)
3391 /* If we were playing, save resume information */
3392 if (playing)
3394 struct mp3entry *id3 = NULL;
3396 if (!playlist_end || !ci.stop_codec)
3398 /* Set this early, the outside code yields and may allow the codec
3399 to try to wait for a reply on a buffer wait */
3400 ci.stop_codec = true;
3401 id3 = audio_current_track();
3404 /* Save the current playing spot, or NULL if the playlist has ended */
3405 playlist_update_resume_info(id3);
3407 prev_track_elapsed = curtrack_id3.elapsed;
3409 /* Increment index so runtime info is saved in audio_clear_track_entries().
3410 * Done here, as audio_stop_playback() may be called more than once.
3411 * Don't update runtime unless playback is stopped because of end of playlist.
3412 * Updating runtime when manually stopping a tracks, can destroy autoscores
3413 * and playcounts.
3415 if (playlist_end)
3417 track_ridx++;
3418 track_ridx &= MAX_TRACK_MASK;
3422 filling = false;
3423 paused = false;
3424 audio_stop_codec_flush();
3425 playing = false;
3427 /* Close all tracks */
3428 audio_release_tracks();
3430 /* Mark all entries null. */
3431 audio_clear_track_entries(false);
3434 static void audio_play_start(size_t offset)
3436 #if INPUT_SRC_CAPS != 0
3437 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
3438 audio_set_output_source(AUDIO_SRC_PLAYBACK);
3439 #endif
3441 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
3442 paused = false;
3443 audio_stop_codec_flush();
3445 track_changed = true;
3446 playlist_end = false;
3448 playing = true;
3450 ci.new_track = 0;
3451 ci.seek_time = 0;
3452 wps_offset = 0;
3454 sound_set_volume(global_settings.volume);
3455 track_widx = track_ridx = 0;
3457 /* Mark all entries null. */
3458 memset(tracks, 0, sizeof(struct track_info) * MAX_TRACK);
3460 last_peek_offset = -1;
3462 /* Officially playing */
3463 queue_reply(&audio_queue, 1);
3465 audio_fill_file_buffer(true, false, offset);
3467 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
3468 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
3472 /* Invalidates all but currently playing track. */
3473 static void audio_invalidate_tracks(void)
3475 #if 0
3476 if (audio_have_tracks())
3478 last_peek_offset = 0;
3479 playlist_end = false;
3480 track_widx = track_ridx;
3482 /* Mark all other entries null (also buffered wrong metadata). */
3483 audio_clear_track_entries(true);
3485 /* If the current track is fully buffered, advance the write pointer */
3486 if (tracks[track_widx].filerem == 0)
3487 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
3489 buf_widx = RINGBUF_ADD(buf_ridx, CUR_TI->available);
3491 audio_read_next_metadata();
3493 #endif
3496 static void audio_new_playlist(void)
3498 /* Prepare to start a new fill from the beginning of the playlist */
3499 last_peek_offset = -1;
3500 if (audio_have_tracks())
3502 if (paused)
3503 skipped_during_pause = true;
3504 playlist_end = false;
3505 track_widx = track_ridx;
3506 audio_clear_track_entries(true);
3508 track_widx++;
3509 track_widx &= MAX_TRACK_MASK;
3511 /* Mark the current track as invalid to prevent skipping back to it */
3512 CUR_TI->taginfo_ready = false;
3515 /* Signal the codec to initiate a track change forward */
3516 new_playlist = true;
3517 ci.new_track = 1;
3519 /* Officially playing */
3520 queue_reply(&audio_queue, 1);
3522 audio_fill_file_buffer(false, true, 0);
3525 static void audio_initiate_track_change(long direction)
3527 playlist_end = false;
3528 ci.new_track += direction;
3529 wps_offset -= direction;
3530 if (paused)
3531 skipped_during_pause = true;
3534 static void audio_initiate_dir_change(long direction)
3536 playlist_end = false;
3537 dir_skip = true;
3538 ci.new_track = direction;
3539 if (paused)
3540 skipped_during_pause = true;
3544 * Layout audio buffer as follows - iram buffer depends on target:
3545 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
3547 static void audio_reset_buffer(void)
3549 /* see audio_get_recording_buffer if this is modified */
3550 logf("audio_reset_buffer");
3552 /* If the setup of anything allocated before the file buffer is
3553 changed, do check the adjustments after the buffer_alloc call
3554 as it will likely be affected and need sliding over */
3556 /* Initially set up file buffer as all space available */
3557 malloc_buf = audiobuf + talk_get_bufsize();
3558 /* Align the malloc buf to line size. Especially important to cf
3559 targets that do line reads/writes. */
3560 malloc_buf = (unsigned char *)(((uintptr_t)malloc_buf + 15) & ~15);
3561 filebuf = malloc_buf + MALLOC_BUFSIZE; /* filebuf line align implied */
3562 filebuflen = audiobufend - filebuf;
3564 /* Allow for codec swap space at end of audio buffer */
3565 if (talk_voice_required())
3567 /* Layout of swap buffer:
3568 * #ifdef IRAM_STEAL (dedicated iram_buf):
3569 * |iram_buf|...audiobuf...|dram_buf|audiobufend
3570 * #else:
3571 * audiobuf...|dram_buf|iram_buf|audiobufend
3573 #ifdef PLAYBACK_VOICE
3574 /* Check for an absolutely nasty situation which should never,
3575 ever happen - frankly should just panic */
3576 if (voice_codec_loaded && current_codec != CODEC_IDX_VOICE)
3578 logf("buffer reset with voice swapped");
3580 /* line align length which line aligns the calculations below since
3581 all sizes are also at least line aligned - needed for memswap128 */
3582 filebuflen &= ~15;
3583 #ifdef IRAM_STEAL
3584 filebuflen -= CODEC_SIZE;
3585 #else
3586 filebuflen -= CODEC_SIZE + CODEC_IRAM_SIZE;
3587 #endif
3588 /* Allocate buffers for swapping voice <=> audio */
3589 /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
3590 and out of the way of buffer usage or else a call to audio_get_buffer
3591 and subsequent buffer use might trash the swap space. A plugin
3592 initializing IRAM after getting the full buffer would present similar
3593 problem. Options include: failing the request if the other buffer
3594 has been obtained already or never allowing use of the voice IRAM
3595 buffer within the audio buffer. Using buffer_alloc basically
3596 implements the second in a more convenient way. */
3597 dram_buf = filebuf + filebuflen;
3599 #ifdef IRAM_STEAL
3600 /* Allocate voice IRAM swap buffer once */
3601 if (iram_buf == NULL)
3603 iram_buf = buffer_alloc(CODEC_IRAM_SIZE);
3604 /* buffer_alloc moves audiobuf; this is safe because only the end
3605 * has been touched so far in this function and the address of
3606 * filebuf + filebuflen is not changed */
3607 malloc_buf += CODEC_IRAM_SIZE;
3608 filebuf += CODEC_IRAM_SIZE;
3609 filebuflen -= CODEC_IRAM_SIZE;
3611 #else
3612 /* Allocate iram_buf after dram_buf */
3613 iram_buf = dram_buf + CODEC_SIZE;
3614 #endif /* IRAM_STEAL */
3615 #endif /* PLAYBACK_VOICE */
3617 else
3619 #ifdef PLAYBACK_VOICE
3620 /* No swap buffers needed */
3621 iram_buf = NULL;
3622 dram_buf = NULL;
3623 #endif
3626 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
3627 filebuflen -= pcmbuf_init(filebuf + filebuflen) + GUARD_BUFSIZE;
3629 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
3630 will already be line aligned */
3631 filebuflen &= ~3;
3633 /* Set the high watermark as 75% full...or 25% empty :) */
3634 #if MEM > 8
3635 high_watermark = 3*filebuflen / 4;
3636 #endif
3638 /* Clear any references to the file buffer */
3639 buffer_state = BUFFER_STATE_INITIALIZED;
3641 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
3642 /* Make sure everything adds up - yes, some info is a bit redundant but
3643 aids viewing and the sumation of certain variables should add up to
3644 the location of others. */
3646 size_t pcmbufsize;
3647 unsigned char * pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
3648 logf("mabuf: %08X", (unsigned)malloc_buf);
3649 logf("mabufe: %08X", (unsigned)(malloc_buf + MALLOC_BUFSIZE));
3650 logf("fbuf: %08X", (unsigned)filebuf);
3651 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
3652 logf("gbuf: %08X", (unsigned)(filebuf + filebuflen));
3653 logf("gbufe: %08X", (unsigned)(filebuf + filebuflen + GUARD_BUFSIZE));
3654 logf("pcmb: %08X", (unsigned)pcmbuf);
3655 logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
3656 if (dram_buf)
3658 logf("dramb: %08X", (unsigned)dram_buf);
3659 logf("drambe: %08X", (unsigned)(dram_buf + CODEC_SIZE));
3661 if (iram_buf)
3663 logf("iramb: %08X", (unsigned)iram_buf);
3664 logf("irambe: %08X", (unsigned)(iram_buf + CODEC_IRAM_SIZE));
3667 #endif
3670 #if MEM > 8
3671 /* we dont want this rebuffering on targets with little ram
3672 because the disk may never spin down */
3673 static bool ata_fillbuffer_callback(void)
3675 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA, 0);
3676 return true;
3678 #endif
3680 static void audio_thread(void)
3682 struct queue_event ev;
3684 pcm_postinit();
3686 #ifdef PLAYBACK_VOICE
3687 /* Unlock semaphore that init stage locks before creating this thread */
3688 semaphore_release(&sem_codecthread);
3690 /* Buffers must be set up by now - should panic - really */
3691 if (buffer_state != BUFFER_STATE_INITIALIZED)
3693 logf("audio_thread start: no buffer");
3696 /* Have to wait for voice to load up or else the codec swap will be
3697 invalid when an audio codec is loaded */
3698 wait_for_voice_swap_in();
3699 #endif
3701 while (1)
3703 if (filling)
3705 queue_wait_w_tmo(&audio_queue, &ev, 0);
3706 if (ev.id == SYS_TIMEOUT)
3707 ev.id = Q_AUDIO_FILL_BUFFER;
3709 else
3711 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
3712 #if MEM > 8
3713 if (playing && (ev.id == SYS_TIMEOUT) &&
3714 (bufused() < high_watermark))
3715 register_ata_idle_func(ata_fillbuffer_callback);
3716 #endif
3719 switch (ev.id) {
3720 #if MEM > 8
3721 case Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA:
3722 /* only fill if the disk is still spining */
3723 #ifndef SIMULATOR
3724 if (!ata_disk_is_active())
3725 break;
3726 #endif
3727 #endif /* MEM > 8 */
3728 /* else fall through to Q_AUDIO_FILL_BUFFER */
3729 case Q_AUDIO_FILL_BUFFER:
3730 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3731 if (!filling)
3732 if (!playing || playlist_end || ci.stop_codec)
3733 break;
3734 audio_fill_file_buffer(false, false, 0);
3735 break;
3737 case Q_AUDIO_PLAY:
3738 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3739 if (playing && ev.data <= 0)
3740 audio_new_playlist();
3741 else
3743 audio_stop_playback();
3744 audio_play_start((size_t)ev.data);
3746 break;
3748 case Q_AUDIO_STOP:
3749 LOGFQUEUE("audio < Q_AUDIO_STOP");
3750 if (playing)
3751 audio_stop_playback();
3752 if (ev.data != 0)
3753 queue_clear(&audio_queue);
3754 break;
3756 case Q_AUDIO_PAUSE:
3757 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3758 if (!(bool) ev.data && skipped_during_pause && !pcmbuf_is_crossfade_active())
3759 pcmbuf_play_stop(); /* Flush old track on resume after skip */
3760 skipped_during_pause = false;
3761 if (!playing)
3762 break;
3763 pcmbuf_pause((bool)ev.data);
3764 paused = (bool)ev.data;
3765 break;
3767 case Q_AUDIO_SKIP:
3768 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3769 audio_initiate_track_change((long)ev.data);
3770 break;
3772 case Q_AUDIO_PRE_FF_REWIND:
3773 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3774 if (!playing)
3775 break;
3776 pcmbuf_pause(true);
3777 break;
3779 case Q_AUDIO_FF_REWIND:
3780 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3781 if (!playing)
3782 break;
3783 ci.seek_time = (long)ev.data+1;
3784 break;
3786 #if 0
3787 case Q_AUDIO_REBUFFER_SEEK:
3788 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
3789 queue_reply(&audio_queue, audio_rebuffer_and_seek(ev.data));
3790 break;
3791 #endif
3793 case Q_AUDIO_CHECK_NEW_TRACK:
3794 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3795 queue_reply(&audio_queue, audio_check_new_track());
3796 break;
3798 case Q_AUDIO_DIR_SKIP:
3799 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3800 playlist_end = false;
3801 audio_initiate_dir_change(ev.data);
3802 break;
3804 case Q_AUDIO_FLUSH:
3805 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3806 audio_invalidate_tracks();
3807 break;
3809 case Q_AUDIO_TRACK_CHANGED:
3810 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3811 if (track_changed_callback)
3812 track_changed_callback(&curtrack_id3);
3813 track_changed = true;
3814 playlist_update_resume_info(audio_current_track());
3815 break;
3817 #ifndef SIMULATOR
3818 case SYS_USB_CONNECTED:
3819 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3820 if (playing)
3821 audio_stop_playback();
3822 usb_acknowledge(SYS_USB_CONNECTED_ACK);
3823 usb_wait_for_disconnect(&audio_queue);
3824 break;
3825 #endif
3827 case SYS_TIMEOUT:
3828 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3829 break;
3831 default:
3832 //LOGFQUEUE("audio < default");
3833 break;
3834 } /* end switch */
3835 } /* end while */
3838 #ifdef ROCKBOX_HAS_LOGF
3839 static void audio_test_track_changed_event(struct mp3entry *id3)
3841 (void)id3;
3843 logf("tce:%s", id3->path);
3845 #endif
3847 /* Initialize the audio system - called from init() in main.c.
3848 * Last function because of all the references to internal symbols
3850 void audio_init(void)
3852 #ifdef PLAYBACK_VOICE
3853 static bool voicetagtrue = true;
3854 static struct mp3entry id3_voice;
3855 struct thread_entry *voice_thread_p = NULL;
3856 #endif
3857 struct thread_entry *audio_thread_p;
3859 /* Can never do this twice */
3860 if (audio_is_initialized)
3862 logf("audio: already initialized");
3863 return;
3866 logf("audio: initializing");
3868 /* Initialize queues before giving control elsewhere in case it likes
3869 to send messages. Thread creation will be delayed however so nothing
3870 starts running until ready if something yields such as talk_init. */
3871 #ifdef PLAYBACK_VOICE
3872 /* Take ownership of lock to prevent playback of anything before audio
3873 hardware is initialized - audio thread unlocks it after final init
3874 stage */
3875 semaphore_init(&sem_codecthread, 1, 0);
3876 event_init(&event_codecthread, EVENT_MANUAL | STATE_SIGNALED);
3877 #endif
3878 queue_init(&audio_queue, true);
3879 queue_enable_queue_send(&audio_queue, &audio_queue_sender_list);
3880 queue_init(&codec_queue, true);
3881 queue_enable_queue_send(&codec_queue, &codec_queue_sender_list);
3883 pcm_init();
3885 #ifdef ROCKBOX_HAS_LOGF
3886 audio_set_track_changed_event(audio_test_track_changed_event);
3887 #endif
3889 /* Initialize codec api. */
3890 ci.read_filebuf = codec_filebuf_callback;
3891 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
3892 ci.get_codec_memory = codec_get_memory_callback;
3893 ci.request_buffer = codec_request_buffer_callback;
3894 ci.advance_buffer = codec_advance_buffer_callback;
3895 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
3896 ci.request_next_track = codec_request_next_track_callback;
3897 ci.mp3_get_filepos = codec_mp3_get_filepos_callback;
3898 ci.seek_buffer = codec_seek_buffer_callback;
3899 ci.seek_complete = codec_seek_complete_callback;
3900 ci.set_elapsed = codec_set_elapsed_callback;
3901 ci.set_offset = codec_set_offset_callback;
3902 ci.configure = codec_configure_callback;
3903 ci.discard_codec = codec_discard_codec_callback;
3905 /* Initialize voice codec api. */
3906 #ifdef PLAYBACK_VOICE
3907 memcpy(&ci_voice, &ci, sizeof(ci_voice));
3908 memset(&id3_voice, 0, sizeof(id3_voice));
3909 ci_voice.read_filebuf = voice_filebuf_callback;
3910 ci_voice.pcmbuf_insert = voice_pcmbuf_insert_callback;
3911 ci_voice.get_codec_memory = voice_get_memory_callback;
3912 ci_voice.request_buffer = voice_request_buffer_callback;
3913 ci_voice.advance_buffer = voice_advance_buffer_callback;
3914 ci_voice.advance_buffer_loc = voice_advance_buffer_loc_callback;
3915 ci_voice.request_next_track = voice_request_next_track_callback;
3916 ci_voice.mp3_get_filepos = voice_mp3_get_filepos_callback;
3917 ci_voice.seek_buffer = voice_seek_buffer_callback;
3918 ci_voice.seek_complete = voice_do_nothing;
3919 ci_voice.set_elapsed = voice_set_elapsed_callback;
3920 ci_voice.set_offset = voice_set_offset_callback;
3921 ci_voice.configure = voice_configure_callback;
3922 ci_voice.discard_codec = voice_do_nothing;
3923 ci_voice.taginfo_ready = &voicetagtrue;
3924 ci_voice.id3 = &id3_voice;
3925 id3_voice.frequency = 11200;
3926 id3_voice.length = 1000000L;
3927 #endif
3929 /* initialize the buffer */
3930 filebuf = audiobuf;
3932 /* audio_reset_buffer must to know the size of voice buffer so init
3933 talk first */
3934 talk_init();
3936 codec_thread_p = create_thread(
3937 codec_thread, codec_stack, sizeof(codec_stack),
3938 CREATE_THREAD_FROZEN,
3939 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
3940 IF_COP(, CPU));
3942 audio_thread_p = create_thread(audio_thread, audio_stack,
3943 sizeof(audio_stack), CREATE_THREAD_FROZEN,
3944 audio_thread_name IF_PRIO(, PRIORITY_BACKGROUND)
3945 IF_COP(, CPU));
3947 buffering_thread_p = create_thread( buffering_thread, buffering_stack,
3948 sizeof(buffering_stack), CREATE_THREAD_FROZEN,
3949 buffering_thread_name IF_PRIO(, PRIORITY_BUFFERING)
3950 IF_COP(, CPU, true));
3952 #ifdef PLAYBACK_VOICE
3953 /* TODO: Change this around when various speech codecs can be used */
3954 if (talk_voice_required())
3956 logf("Starting voice codec");
3957 queue_init(&voice_queue, true);
3958 voice_thread_p = create_thread(voice_thread, voice_stack,
3959 sizeof(voice_stack), CREATE_THREAD_FROZEN,
3960 voice_thread_name
3961 IF_PRIO(, PRIORITY_PLAYBACK) IF_COP(, CPU));
3963 #endif
3965 /* Set crossfade setting for next buffer init which should be about... */
3966 pcmbuf_crossfade_enable(global_settings.crossfade);
3968 /* ...now! Set up the buffers */
3969 audio_reset_buffer();
3971 buffering_init(filebuf, filebuflen);
3973 /* Probably safe to say */
3974 audio_is_initialized = true;
3976 sound_settings_apply();
3977 #ifdef HAVE_WM8758
3978 eq_hw_enable(global_settings.eq_hw_enabled);
3979 #endif
3980 #ifndef HAVE_FLASH_STORAGE
3981 audio_set_buffer_margin(global_settings.buffer_margin);
3982 #endif
3984 /* it's safe to let the threads run now */
3985 thread_thaw(codec_thread_p);
3986 #ifdef PLAYBACK_VOICE
3987 if (voice_thread_p)
3988 thread_thaw(voice_thread_p);
3989 #endif
3990 thread_thaw(audio_thread_p);
3991 thread_thaw(buffering_thread_p);
3992 } /* audio_init */