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