Make TTS name conversion functions static members.
[Rockbox.git] / apps / playback.c
blob87773f89ef916cc9a5dec569a1dab903882a1e5d
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 Miika Pekkarinen
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 /* TODO: Pause should be handled in here, rather than PCMBUF so that voice can
21 * play whilst audio is paused */
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <ctype.h>
28 #include "system.h"
29 #include "thread.h"
30 #include "file.h"
31 #include "panic.h"
32 #include "memory.h"
33 #include "lcd.h"
34 #include "font.h"
35 #include "button.h"
36 #include "kernel.h"
37 #include "tree.h"
38 #include "debug.h"
39 #include "sprintf.h"
40 #include "settings.h"
41 #include "codecs.h"
42 #include "audio.h"
43 #include "buffering.h"
44 #include "voice_thread.h"
45 #include "mp3_playback.h"
46 #include "usb.h"
47 #include "status.h"
48 #include "ata.h"
49 #include "screens.h"
50 #include "playlist.h"
51 #include "playback.h"
52 #include "pcmbuf.h"
53 #include "buffer.h"
54 #include "dsp.h"
55 #include "abrepeat.h"
56 #include "cuesheet.h"
57 #ifdef HAVE_TAGCACHE
58 #include "tagcache.h"
59 #endif
60 #ifdef HAVE_LCD_BITMAP
61 #include "icons.h"
62 #include "peakmeter.h"
63 #include "action.h"
64 #include "albumart.h"
65 #endif
66 #include "lang.h"
67 #include "bookmark.h"
68 #include "misc.h"
69 #include "sound.h"
70 #include "metadata.h"
71 #include "splash.h"
72 #include "talk.h"
73 #include "ata_idle_notify.h"
75 #ifdef HAVE_RECORDING
76 #include "recording.h"
77 #include "talk.h"
78 #endif
80 #define PLAYBACK_VOICE
82 /* default point to start buffer refill */
83 #define AUDIO_DEFAULT_WATERMARK (1024*512)
84 /* amount of guess-space to allow for codecs that must hunt and peck
85 * for their correct seeek target, 32k seems a good size */
86 #define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
88 /* Define LOGF_ENABLE to enable logf output in this file */
89 /*#define LOGF_ENABLE*/
90 #include "logf.h"
92 /* macros to enable logf for queues
93 logging on SYS_TIMEOUT can be disabled */
94 #ifdef SIMULATOR
95 /* Define this for logf output of all queuing except SYS_TIMEOUT */
96 #define PLAYBACK_LOGQUEUES
97 /* Define this to logf SYS_TIMEOUT messages */
98 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
99 #endif
101 #ifdef PLAYBACK_LOGQUEUES
102 #define LOGFQUEUE logf
103 #else
104 #define LOGFQUEUE(...)
105 #endif
107 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
108 #define LOGFQUEUE_SYS_TIMEOUT logf
109 #else
110 #define LOGFQUEUE_SYS_TIMEOUT(...)
111 #endif
114 /* Define one constant that includes recording related functionality */
115 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
116 #define AUDIO_HAVE_RECORDING
117 #endif
119 enum {
120 Q_NULL = 0,
121 Q_AUDIO_PLAY = 1,
122 Q_AUDIO_STOP,
123 Q_AUDIO_PAUSE,
124 Q_AUDIO_SKIP,
125 Q_AUDIO_PRE_FF_REWIND,
126 Q_AUDIO_FF_REWIND,
127 Q_AUDIO_CHECK_NEW_TRACK,
128 Q_AUDIO_FLUSH,
129 Q_AUDIO_TRACK_CHANGED,
130 Q_AUDIO_DIR_SKIP,
131 Q_AUDIO_POSTINIT,
132 Q_AUDIO_FILL_BUFFER,
133 Q_CODEC_REQUEST_COMPLETE,
134 Q_CODEC_REQUEST_FAILED,
136 Q_CODEC_LOAD,
137 Q_CODEC_LOAD_DISK,
139 #ifdef AUDIO_HAVE_RECORDING
140 Q_ENCODER_LOAD_DISK,
141 Q_ENCODER_RECORD,
142 #endif
145 /* As defined in plugins/lib/xxx2wav.h */
146 #if MEM > 1
147 #define MALLOC_BUFSIZE (512*1024)
148 #define GUARD_BUFSIZE (32*1024)
149 #else
150 #define MALLOC_BUFSIZE (100*1024)
151 #define GUARD_BUFSIZE (8*1024)
152 #endif
154 /* As defined in plugin.lds */
155 #if defined(CPU_PP)
156 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
157 #define CODEC_IRAM_SIZE ((size_t)0xc000)
158 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
159 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
160 #define CODEC_IRAM_SIZE ((size_t)0x10000)
161 #else
162 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
163 #define CODEC_IRAM_SIZE ((size_t)0xc000)
164 #endif
166 bool audio_is_initialized = false;
167 static bool audio_thread_ready NOCACHEBSS_ATTR = false;
169 /* Variables are commented with the threads that use them: *
170 * A=audio, C=codec, V=voice. A suffix of - indicates that *
171 * the variable is read but not updated on that thread. */
172 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
174 /* Main state control */
175 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR = false; /* Codec loaded? (C/A-) */
176 static volatile bool playing NOCACHEBSS_ATTR = false; /* Is audio playing? (A) */
177 static volatile bool paused NOCACHEBSS_ATTR = false; /* Is audio paused? (A/C-) */
179 /* Ring buffer where compressed audio and codecs are loaded */
180 static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */
181 static unsigned char *malloc_buf = NULL; /* Start of malloc buffer (A/C-) */
182 /* FIXME: make filebuflen static */
183 size_t filebuflen = 0; /* Size of buffer (A/C-) */
184 /* FIXME: make buf_ridx (C/A-) */
186 /* Possible arrangements of the buffer */
187 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
188 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
189 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
190 static int buffer_state = BUFFER_STATE_TRASHED; /* Buffer state */
192 /* Used to keep the WPS up-to-date during track transtition */
193 static struct mp3entry prevtrack_id3;
195 /* Used to provide the codec with a pointer */
196 static struct mp3entry curtrack_id3;
198 /* Used to make next track info available while playing last track on buffer */
199 static struct mp3entry lasttrack_id3;
201 /* Track info structure about songs in the file buffer (A/C-) */
202 struct track_info {
203 int audio_hid; /* The ID for the track's buffer handle */
204 int id3_hid; /* The ID for the track's metadata handle */
205 int codec_hid; /* The ID for the track's codec handle */
206 #ifdef HAVE_ALBUMART
207 int aa_hid; /* The ID for the track's album art handle */
208 #endif
210 size_t filesize; /* File total length */
212 bool taginfo_ready; /* Is metadata read */
214 bool event_sent; /* Was this track's buffered event sent */
217 static struct track_info tracks[MAX_TRACK];
218 static volatile int track_ridx = 0; /* Track being decoded (A/C-) */
219 static int track_widx = 0; /* Track being buffered (A) */
221 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
222 static struct track_info *prev_ti = NULL; /* Pointer to the previously played
223 track */
225 /* Set by the audio thread when the current track information has updated
226 * and the WPS may need to update its cached information */
227 static bool track_changed = false;
229 /* Information used only for filling the buffer */
230 /* Playlist steps from playing track to next track to be buffered (A) */
231 static int last_peek_offset = 0;
233 /* Scrobbler support */
234 static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/
236 /* Track change controls */
237 static bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */
238 static bool playlist_end = false; /* Has the current playlist ended? (A) */
239 static bool auto_dir_skip = false; /* Have we changed dirs automatically? */
240 static bool dir_skip = false; /* Is a directory skip pending? (A) */
241 static bool new_playlist = false; /* Are we starting a new playlist? (A) */
242 static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */
243 static bool skipped_during_pause = false; /* Do we need to clear the PCM buffer when playback resumes (A) */
245 /* Callbacks which applications or plugins may set */
246 /* When the playing track has changed from the user's perspective */
247 void (*track_changed_callback)(struct mp3entry *id3) = NULL;
248 /* When a track has been buffered */
249 void (*track_buffer_callback)(struct mp3entry *id3) = NULL;
250 /* When a track's buffer has been overwritten or cleared */
251 void (*track_unbuffer_callback)(struct mp3entry *id3) = NULL;
253 static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */
255 /* Multiple threads */
256 /* Set the watermark to trigger buffer fill (A/C) FIXME */
257 static void set_filebuf_watermark(int seconds, size_t max);
259 /* Audio thread */
260 static struct event_queue audio_queue NOCACHEBSS_ATTR;
261 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR;
262 static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
263 static const char audio_thread_name[] = "audio";
265 static void audio_thread(void);
266 static void audio_initiate_track_change(long direction);
267 static bool audio_have_tracks(void);
268 static void audio_reset_buffer(void);
270 /* Codec thread */
271 extern struct codec_api ci;
272 static struct event_queue codec_queue NOCACHEBSS_ATTR;
273 static struct queue_sender_list codec_queue_sender_list;
274 static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
275 IBSS_ATTR;
276 static const char codec_thread_name[] = "codec";
277 struct thread_entry *codec_thread_p; /* For modifying thread priority later. */
279 /* --- Helper functions --- */
281 static struct mp3entry *bufgetid3(int handle_id)
283 if (handle_id < 0)
284 return NULL;
286 struct mp3entry *id3;
287 ssize_t ret = bufgetdata(handle_id, 0, (void *)&id3);
289 if (ret < 0 || ret != sizeof(struct mp3entry))
290 return NULL;
292 return id3;
295 static bool clear_track_info(struct track_info *track)
297 /* bufclose returns true if the handle is not found, or if it is closed
298 * successfully, so these checks are safe on non-existant handles */
299 if (!track)
300 return false;
302 if (track->codec_hid >= 0) {
303 if (bufclose(track->codec_hid))
304 track->codec_hid = -1;
305 else
306 return false;
309 if (track->id3_hid >= 0) {
310 if (track->event_sent && track_unbuffer_callback) {
311 /* If there is an unbuffer callback, call it */
312 track_unbuffer_callback(bufgetid3(track->id3_hid));
315 if (bufclose(track->id3_hid))
316 track->id3_hid = -1;
317 else
318 return false;
321 if (track->audio_hid >= 0) {
322 if (bufclose(track->audio_hid))
323 track->audio_hid = -1;
324 else
325 return false;
328 #ifdef HAVE_ALBUMART
329 if (track->aa_hid >= 0) {
330 if (bufclose(track->aa_hid))
331 track->aa_hid = -1;
332 else
333 return false;
335 #endif
337 track->filesize = 0;
338 track->taginfo_ready = false;
339 track->event_sent = false;
341 return true;
344 /* --- External interfaces --- */
346 /* This sends a stop message and the audio thread will dump all it's
347 subsequenct messages */
348 void audio_hard_stop(void)
350 /* Stop playback */
351 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
352 queue_send(&audio_queue, Q_AUDIO_STOP, 1);
353 #ifdef PLAYBACK_VOICE
354 voice_stop();
355 #endif
358 bool audio_restore_playback(int type)
360 switch (type)
362 case AUDIO_WANT_PLAYBACK:
363 if (buffer_state != BUFFER_STATE_INITIALIZED)
364 audio_reset_buffer();
365 return true;
366 case AUDIO_WANT_VOICE:
367 if (buffer_state == BUFFER_STATE_TRASHED)
368 audio_reset_buffer();
369 return true;
370 default:
371 return false;
375 unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
377 unsigned char *buf, *end;
379 if (audio_is_initialized)
381 audio_hard_stop();
383 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
385 if (buffer_size == NULL)
387 /* Special case for talk_init to use since it already knows it's
388 trashed */
389 buffer_state = BUFFER_STATE_TRASHED;
390 return NULL;
393 if (talk_buf || buffer_state == BUFFER_STATE_TRASHED
394 || !talk_voice_required())
396 logf("get buffer: talk, audio");
397 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
398 the talk buffer is not needed because voice isn't being used, or
399 could be BUFFER_STATE_TRASHED already. If state is
400 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
401 without the caller knowing what's going on. Changing certain settings
402 may move it to a worse condition but the memory in use by something
403 else will remain undisturbed.
405 if (buffer_state != BUFFER_STATE_TRASHED)
407 talk_buffer_steal();
408 buffer_state = BUFFER_STATE_TRASHED;
411 buf = audiobuf;
412 end = audiobufend;
414 else
416 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
417 still BUFFER_STATE_INITIALIZED */
418 /* Skip talk buffer and move pcm buffer to end to maximize available
419 contiguous memory - no audio running means voice will not need the
420 swap space */
421 logf("get buffer: audio");
422 buf = audiobuf + talk_get_bufsize();
423 end = audiobufend - pcmbuf_init(audiobufend);
424 buffer_state = BUFFER_STATE_VOICED_ONLY;
427 *buffer_size = end - buf;
429 return buf;
432 #ifdef HAVE_RECORDING
433 unsigned char *audio_get_recording_buffer(size_t *buffer_size)
435 /* Stop audio, voice and obtain all available buffer space */
436 audio_hard_stop();
437 talk_buffer_steal();
439 unsigned char *end = audiobufend;
440 buffer_state = BUFFER_STATE_TRASHED;
441 *buffer_size = end - audiobuf;
443 return (unsigned char *)audiobuf;
446 bool audio_load_encoder(int afmt)
448 #ifndef SIMULATOR
449 const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER);
450 if (!enc_fn)
451 return false;
453 audio_remove_encoder();
454 ci.enc_codec_loaded = 0; /* clear any previous error condition */
456 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
457 queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (intptr_t)enc_fn);
459 while (ci.enc_codec_loaded == 0)
460 yield();
462 logf("codec loaded: %d", ci.enc_codec_loaded);
464 return ci.enc_codec_loaded > 0;
465 #else
466 (void)afmt;
467 return true;
468 #endif
469 } /* audio_load_encoder */
471 void audio_remove_encoder(void)
473 #ifndef SIMULATOR
474 /* force encoder codec unload (if currently loaded) */
475 if (ci.enc_codec_loaded <= 0)
476 return;
478 ci.stop_encoder = true;
479 while (ci.enc_codec_loaded > 0)
480 yield();
481 #endif
482 } /* audio_remove_encoder */
484 #endif /* HAVE_RECORDING */
486 #ifdef HAVE_ALBUMART
487 int audio_current_aa_hid(void)
489 int cur_idx;
490 int offset = ci.new_track + wps_offset;
492 cur_idx = track_ridx + offset;
493 cur_idx &= MAX_TRACK_MASK;
495 return tracks[cur_idx].aa_hid;
497 #endif
499 struct mp3entry* audio_current_track(void)
501 const char *filename;
502 const char *p;
503 static struct mp3entry temp_id3;
504 int cur_idx;
505 int offset = ci.new_track + wps_offset;
507 cur_idx = (track_ridx + offset) & MAX_TRACK_MASK;
509 if (cur_idx == track_ridx && *curtrack_id3.path)
511 /* The usual case */
512 return &curtrack_id3;
514 else if (offset == -1 && *prevtrack_id3.path)
516 /* We're in a track transition. The codec has moved on to the nex track,
517 but the audio being played is still the same (now previous) track.
518 prevtrack_id3.elapsed is being updated in an ISR by
519 codec_pcmbuf_position_callback */
520 return &prevtrack_id3;
522 else if (tracks[cur_idx].id3_hid >= 0)
524 /* Get the ID3 metadata from the main buffer */
525 return bufgetid3(tracks[cur_idx].id3_hid);
528 /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info
529 we have and return that. */
531 memset(&temp_id3, 0, sizeof(struct mp3entry));
533 filename = playlist_peek(0);
534 if (!filename)
535 filename = "No file!";
537 #ifdef HAVE_TC_RAMCACHE
538 if (tagcache_fill_tags(&temp_id3, filename))
539 return &temp_id3;
540 #endif
542 p = strrchr(filename, '/');
543 if (!p)
544 p = filename;
545 else
546 p++;
548 strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1);
549 temp_id3.title = &temp_id3.path[0];
551 return &temp_id3;
554 struct mp3entry* audio_next_track(void)
556 int next_idx = track_ridx;
558 if (!audio_have_tracks())
559 return NULL;
561 if (wps_offset == -1 && *prevtrack_id3.path)
563 /* We're in a track transition. The next track for the WPS is the one
564 currently being decoded. */
565 return &curtrack_id3;
568 next_idx = (next_idx + 1) & MAX_TRACK_MASK;
570 if (next_idx == track_widx)
572 /* The next track hasn't been buffered yet, so we return the static
573 version of its metadata. */
574 return &lasttrack_id3;
577 if (tracks[next_idx].id3_hid < 0)
578 return NULL;
579 else
580 return bufgetid3(tracks[next_idx].id3_hid);
583 bool audio_has_changed_track(void)
585 if (track_changed)
587 track_changed = false;
588 return true;
591 return false;
594 void audio_play(long offset)
596 logf("audio_play");
598 #ifdef PLAYBACK_VOICE
599 /* Truncate any existing voice output so we don't have spelling
600 * etc. over the first part of the played track */
601 talk_force_shutup();
602 #endif
604 /* Start playback */
605 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset);
606 /* Don't return until playback has actually started */
607 queue_send(&audio_queue, Q_AUDIO_PLAY, offset);
610 void audio_stop(void)
612 /* Stop playback */
613 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
614 /* Don't return until playback has actually stopped */
615 queue_send(&audio_queue, Q_AUDIO_STOP, 0);
618 void audio_pause(void)
620 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
621 /* Don't return until playback has actually paused */
622 queue_send(&audio_queue, Q_AUDIO_PAUSE, true);
625 void audio_resume(void)
627 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
628 /* Don't return until playback has actually resumed */
629 queue_send(&audio_queue, Q_AUDIO_PAUSE, false);
632 void audio_next(void)
634 if (playlist_check(ci.new_track + wps_offset + 1))
636 if (global_settings.beep)
637 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
639 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
640 queue_post(&audio_queue, Q_AUDIO_SKIP, 1);
641 /* Update wps while our message travels inside deep playback queues. */
642 wps_offset++;
643 track_changed = true;
645 else
647 /* No more tracks. */
648 if (global_settings.beep)
649 pcmbuf_beep(1000, 100, 1000*global_settings.beep);
653 void audio_prev(void)
655 if (playlist_check(ci.new_track + wps_offset - 1))
657 if (global_settings.beep)
658 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
660 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
661 queue_post(&audio_queue, Q_AUDIO_SKIP, -1);
662 /* Update wps while our message travels inside deep playback queues. */
663 wps_offset--;
664 track_changed = true;
666 else
668 /* No more tracks. */
669 if (global_settings.beep)
670 pcmbuf_beep(1000, 100, 1000*global_settings.beep);
674 void audio_next_dir(void)
676 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
677 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, 1);
680 void audio_prev_dir(void)
682 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
683 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, -1);
686 void audio_pre_ff_rewind(void)
688 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
689 queue_post(&audio_queue, Q_AUDIO_PRE_FF_REWIND, 0);
692 void audio_ff_rewind(long newpos)
694 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
695 queue_post(&audio_queue, Q_AUDIO_FF_REWIND, newpos);
698 void audio_flush_and_reload_tracks(void)
700 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
701 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0);
704 void audio_error_clear(void)
706 #ifdef AUDIO_HAVE_RECORDING
707 pcm_rec_error_clear();
708 #endif
711 int audio_status(void)
713 int ret = 0;
715 if (playing)
716 ret |= AUDIO_STATUS_PLAY;
718 if (paused)
719 ret |= AUDIO_STATUS_PAUSE;
721 #ifdef HAVE_RECORDING
722 /* Do this here for constitency with mpeg.c version */
723 ret |= pcm_rec_status();
724 #endif
726 return ret;
729 int audio_get_file_pos(void)
731 return 0;
734 #ifndef HAVE_FLASH_STORAGE
735 void audio_set_buffer_margin(int setting)
737 static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
738 buffer_margin = lookup[setting];
739 logf("buffer margin: %ld", (long)buffer_margin);
740 set_filebuf_watermark(buffer_margin, 0);
742 #endif
744 /* Take nescessary steps to enable or disable the crossfade setting */
745 void audio_set_crossfade(int enable)
747 size_t offset;
748 bool was_playing;
749 size_t size;
751 /* Tell it the next setting to use */
752 pcmbuf_crossfade_enable(enable);
754 /* Return if size hasn't changed or this is too early to determine
755 which in the second case there's no way we could be playing
756 anything at all */
757 if (pcmbuf_is_same_size())
759 /* This function is a copout and just syncs some variables -
760 to be removed at a later date */
761 pcmbuf_crossfade_enable_finished();
762 return;
765 offset = 0;
766 was_playing = playing;
768 /* Playback has to be stopped before changing the buffer size */
769 if (was_playing)
771 /* Store the track resume position */
772 offset = curtrack_id3.offset;
773 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK));
776 /* Blast it - audio buffer will have to be setup again next time
777 something plays */
778 audio_get_buffer(true, &size);
780 /* Restart playback if audio was running previously */
781 if (was_playing)
782 audio_play(offset);
785 /* --- Routines called from multiple threads --- */
787 static void set_filebuf_watermark(int seconds, size_t max)
789 size_t bytes;
791 if (!filebuf)
792 return; /* Audio buffers not yet set up */
794 bytes = seconds?MAX(curtrack_id3.bitrate * seconds * (1000/8), max):max;
795 bytes = MIN(bytes, filebuflen / 2);
796 buf_set_watermark(bytes);
799 const char * get_codec_filename(int cod_spec)
801 const char *fname;
803 #ifdef HAVE_RECORDING
804 /* Can choose decoder or encoder if one available */
805 int type = cod_spec & CODEC_TYPE_MASK;
806 int afmt = cod_spec & CODEC_AFMT_MASK;
808 if ((unsigned)afmt >= AFMT_NUM_CODECS)
809 type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
811 fname = (type == CODEC_TYPE_ENCODER) ?
812 audio_formats[afmt].codec_enc_root_fn :
813 audio_formats[afmt].codec_root_fn;
815 logf("%s: %d - %s",
816 (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
817 afmt, fname ? fname : "<unknown>");
818 #else /* !HAVE_RECORDING */
819 /* Always decoder */
820 if ((unsigned)cod_spec >= AFMT_NUM_CODECS)
821 cod_spec = AFMT_UNKNOWN;
822 fname = audio_formats[cod_spec].codec_root_fn;
823 logf("Codec: %d - %s", cod_spec, fname ? fname : "<unknown>");
824 #endif /* HAVE_RECORDING */
826 return fname;
827 } /* get_codec_filename */
829 /* --- Codec thread --- */
830 static bool codec_pcmbuf_insert_callback(
831 const void *ch1, const void *ch2, int count)
833 const char *src[2] = { ch1, ch2 };
835 while (count > 0)
837 int out_count = dsp_output_count(ci.dsp, count);
838 int inp_count;
839 char *dest;
841 /* Prevent audio from a previous track from playing */
842 if (ci.new_track || ci.stop_codec)
843 return true;
845 while ((dest = pcmbuf_request_buffer(&out_count)) == NULL)
847 cancel_cpu_boost();
848 sleep(1);
849 if (ci.seek_time || ci.new_track || ci.stop_codec)
850 return true;
853 /* Get the real input_size for output_size bytes, guarding
854 * against resampling buffer overflows. */
855 inp_count = dsp_input_count(ci.dsp, out_count);
857 if (inp_count <= 0)
858 return true;
860 /* Input size has grown, no error, just don't write more than length */
861 if (inp_count > count)
862 inp_count = count;
864 out_count = dsp_process(ci.dsp, dest, src, inp_count);
866 if (out_count <= 0)
867 return true;
869 pcmbuf_write_complete(out_count);
871 count -= inp_count;
874 return true;
875 } /* codec_pcmbuf_insert_callback */
877 static void* codec_get_memory_callback(size_t *size)
879 *size = MALLOC_BUFSIZE;
880 return malloc_buf;
883 /* Between the codec and PCM track change, we need to keep updating the
884 "elapsed" value of the previous (to the codec, but current to the
885 user/PCM/WPS) track, so that the progressbar reaches the end.
886 During that transition, the WPS will display prevtrack_id3. */
887 static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
888 static void codec_pcmbuf_position_callback(size_t size)
890 /* This is called from an ISR, so be quick */
891 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
892 prevtrack_id3.elapsed;
894 if (time >= prevtrack_id3.length)
896 pcmbuf_set_position_callback(NULL);
897 prevtrack_id3.elapsed = prevtrack_id3.length;
899 else
900 prevtrack_id3.elapsed = time;
903 static void codec_set_elapsed_callback(unsigned int value)
905 unsigned int latency;
906 if (ci.seek_time)
907 return;
909 #ifdef AB_REPEAT_ENABLE
910 ab_position_report(value);
911 #endif
913 latency = pcmbuf_get_latency();
914 if (value < latency)
915 curtrack_id3.elapsed = 0;
916 else if (value - latency > curtrack_id3.elapsed ||
917 value - latency < curtrack_id3.elapsed - 2)
919 curtrack_id3.elapsed = value - latency;
923 static void codec_set_offset_callback(size_t value)
925 unsigned int latency;
927 if (ci.seek_time)
928 return;
930 latency = pcmbuf_get_latency() * curtrack_id3.bitrate / 8;
931 if (value < latency)
932 curtrack_id3.offset = 0;
933 else
934 curtrack_id3.offset = value - latency;
937 static void codec_advance_buffer_counters(size_t amount)
939 bufadvance(CUR_TI->audio_hid, amount);
940 ci.curpos += amount;
943 /* copy up-to size bytes into ptr and return the actual size copied */
944 static size_t codec_filebuf_callback(void *ptr, size_t size)
946 ssize_t copy_n;
948 if (ci.stop_codec || !playing)
949 return 0;
951 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
953 /* Nothing requested OR nothing left */
954 if (copy_n == 0)
955 return 0;
957 /* Update read and other position pointers */
958 codec_advance_buffer_counters(copy_n);
960 /* Return the actual amount of data copied to the buffer */
961 return copy_n;
962 } /* codec_filebuf_callback */
964 static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
966 size_t copy_n = reqsize;
967 ssize_t ret;
968 void *ptr;
970 if (!playing)
972 *realsize = 0;
973 return NULL;
976 ret = bufgetdata(CUR_TI->audio_hid, reqsize, &ptr);
977 if (ret >= 0)
978 copy_n = MIN((size_t)ret, reqsize);
980 if (copy_n == 0)
982 *realsize = 0;
983 return NULL;
986 *realsize = copy_n;
988 return ptr;
989 } /* codec_request_buffer_callback */
991 static int get_codec_base_type(int type)
993 switch (type) {
994 case AFMT_MPA_L1:
995 case AFMT_MPA_L2:
996 case AFMT_MPA_L3:
997 return AFMT_MPA_L3;
1000 return type;
1003 static void codec_advance_buffer_callback(size_t amount)
1005 codec_advance_buffer_counters(amount);
1006 codec_set_offset_callback(ci.curpos);
1009 static void codec_advance_buffer_loc_callback(void *ptr)
1011 size_t amount = buf_get_offset(CUR_TI->audio_hid, ptr);
1012 codec_advance_buffer_callback(amount);
1015 /* Copied from mpeg.c. Should be moved somewhere else. */
1016 static int codec_get_file_pos(void)
1018 int pos = -1;
1019 struct mp3entry *id3 = audio_current_track();
1021 if (id3->vbr)
1023 if (id3->has_toc)
1025 /* Use the TOC to find the new position */
1026 unsigned int percent, remainder;
1027 int curtoc, nexttoc, plen;
1029 percent = (id3->elapsed*100)/id3->length;
1030 if (percent > 99)
1031 percent = 99;
1033 curtoc = id3->toc[percent];
1035 if (percent < 99)
1036 nexttoc = id3->toc[percent+1];
1037 else
1038 nexttoc = 256;
1040 pos = (id3->filesize/256)*curtoc;
1042 /* Use the remainder to get a more accurate position */
1043 remainder = (id3->elapsed*100)%id3->length;
1044 remainder = (remainder*100)/id3->length;
1045 plen = (nexttoc - curtoc)*(id3->filesize/256);
1046 pos += (plen/100)*remainder;
1048 else
1050 /* No TOC exists, estimate the new position */
1051 pos = (id3->filesize / (id3->length / 1000)) *
1052 (id3->elapsed / 1000);
1055 else if (id3->bitrate)
1056 pos = id3->elapsed * (id3->bitrate / 8);
1057 else
1058 return -1;
1060 pos += id3->first_frame_offset;
1062 /* Don't seek right to the end of the file so that we can
1063 transition properly to the next song */
1064 if (pos >= (int)(id3->filesize - id3->id3v1len))
1065 pos = id3->filesize - id3->id3v1len - 1;
1067 return pos;
1070 static off_t codec_mp3_get_filepos_callback(int newtime)
1072 off_t newpos;
1074 curtrack_id3.elapsed = newtime;
1075 newpos = codec_get_file_pos();
1077 return newpos;
1080 static void codec_seek_complete_callback(void)
1082 logf("seek_complete");
1083 if (pcm_is_paused())
1085 /* If this is not a seamless seek, clear the buffer */
1086 pcmbuf_play_stop();
1087 dsp_configure(ci.dsp, DSP_FLUSH, 0);
1089 /* If playback was not 'deliberately' paused, unpause now */
1090 if (!paused)
1091 pcmbuf_pause(false);
1093 ci.seek_time = 0;
1096 static bool codec_seek_buffer_callback(size_t newpos)
1098 logf("codec_seek_buffer_callback");
1100 int ret = bufseek(CUR_TI->audio_hid, newpos);
1101 if (ret == 0) {
1102 ci.curpos = newpos;
1103 return true;
1105 else {
1106 return false;
1110 static void codec_configure_callback(int setting, intptr_t value)
1112 switch (setting) {
1113 case CODEC_SET_FILEBUF_WATERMARK:
1114 set_filebuf_watermark(buffer_margin, value);
1115 break;
1117 default:
1118 if (!dsp_configure(ci.dsp, setting, value))
1119 { logf("Illegal key:%d", setting); }
1123 static void codec_track_changed(void)
1125 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1126 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1129 static void codec_pcmbuf_track_changed_callback(void)
1131 pcmbuf_set_position_callback(NULL);
1132 codec_track_changed();
1135 static void codec_discard_codec_callback(void)
1137 if (CUR_TI->codec_hid >= 0)
1139 bufclose(CUR_TI->codec_hid);
1140 CUR_TI->codec_hid = -1;
1144 static inline void codec_gapless_track_change(void)
1146 /* callback keeps the progress bar moving while the pcmbuf empties */
1147 pcmbuf_set_position_callback(codec_pcmbuf_position_callback);
1148 /* set the pcmbuf callback for when the track really changes */
1149 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
1152 static inline void codec_crossfade_track_change(void)
1154 /* Initiate automatic crossfade mode */
1155 pcmbuf_crossfade_init(false);
1156 /* Notify the wps that the track change starts now */
1157 codec_track_changed();
1160 static void codec_track_skip_done(bool was_manual)
1162 /* Manual track change (always crossfade or flush audio). */
1163 if (was_manual)
1165 pcmbuf_crossfade_init(true);
1166 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1167 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1169 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1170 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1171 && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP)
1173 if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
1175 if (global_settings.playlist_shuffle)
1176 /* shuffle mode is on, so crossfade: */
1177 codec_crossfade_track_change();
1178 else
1179 /* shuffle mode is off, so do a gapless track change */
1180 codec_gapless_track_change();
1182 else
1183 /* normal crossfade: */
1184 codec_crossfade_track_change();
1186 else
1187 /* normal gapless playback. */
1188 codec_gapless_track_change();
1191 static bool codec_load_next_track(void)
1193 intptr_t result = Q_CODEC_REQUEST_FAILED;
1195 prev_track_elapsed = curtrack_id3.elapsed;
1197 #ifdef AB_REPEAT_ENABLE
1198 ab_end_of_track_report();
1199 #endif
1201 logf("Request new track");
1203 if (ci.new_track == 0)
1205 ci.new_track++;
1206 automatic_skip = true;
1209 if (!ci.stop_codec)
1211 trigger_cpu_boost();
1212 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1213 result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
1216 switch (result)
1218 case Q_CODEC_REQUEST_COMPLETE:
1219 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1220 codec_track_skip_done(!automatic_skip);
1221 return true;
1223 case Q_CODEC_REQUEST_FAILED:
1224 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1225 ci.new_track = 0;
1226 ci.stop_codec = true;
1227 return false;
1229 default:
1230 LOGFQUEUE("codec |< default");
1231 ci.stop_codec = true;
1232 return false;
1236 static bool codec_request_next_track_callback(void)
1238 int prev_codectype;
1240 if (ci.stop_codec || !playing)
1241 return false;
1243 prev_codectype = get_codec_base_type(curtrack_id3.codectype);
1245 if (!codec_load_next_track())
1246 return false;
1248 /* Check if the next codec is the same file. */
1249 if (prev_codectype == get_codec_base_type(curtrack_id3.codectype))
1251 logf("New track loaded");
1252 codec_discard_codec_callback();
1253 return true;
1255 else
1257 logf("New codec:%d/%d", curtrack_id3.codectype, prev_codectype);
1258 return false;
1262 static void codec_thread(void)
1264 struct queue_event ev;
1265 int status;
1267 while (1) {
1268 status = 0;
1269 cancel_cpu_boost();
1270 queue_wait(&codec_queue, &ev);
1272 switch (ev.id) {
1273 case Q_CODEC_LOAD_DISK:
1274 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1275 queue_reply(&codec_queue, 1);
1276 audio_codec_loaded = true;
1277 ci.stop_codec = false;
1278 status = codec_load_file((const char *)ev.data, &ci);
1279 break;
1281 case Q_CODEC_LOAD:
1282 LOGFQUEUE("codec < Q_CODEC_LOAD");
1283 if (CUR_TI->codec_hid < 0) {
1284 logf("Codec slot is empty!");
1285 /* Wait for the pcm buffer to go empty */
1286 while (pcm_is_playing())
1287 yield();
1288 /* This must be set to prevent an infinite loop */
1289 ci.stop_codec = true;
1290 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1291 queue_post(&codec_queue, Q_AUDIO_PLAY, 0);
1292 break;
1295 audio_codec_loaded = true;
1296 ci.stop_codec = false;
1297 status = codec_load_buf(CUR_TI->codec_hid, &ci);
1298 break;
1300 #ifdef AUDIO_HAVE_RECORDING
1301 case Q_ENCODER_LOAD_DISK:
1302 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1303 audio_codec_loaded = false; /* Not audio codec! */
1304 logf("loading encoder");
1305 ci.stop_encoder = false;
1306 status = codec_load_file((const char *)ev.data, &ci);
1307 logf("encoder stopped");
1308 break;
1309 #endif /* AUDIO_HAVE_RECORDING */
1311 default:
1312 LOGFQUEUE("codec < default");
1315 if (audio_codec_loaded)
1317 if (ci.stop_codec)
1319 status = CODEC_OK;
1320 if (!playing)
1321 pcmbuf_play_stop();
1324 audio_codec_loaded = false;
1327 switch (ev.id) {
1328 case Q_CODEC_LOAD_DISK:
1329 case Q_CODEC_LOAD:
1330 LOGFQUEUE("codec < Q_CODEC_LOAD");
1331 if (playing)
1333 if (ci.new_track || status != CODEC_OK)
1335 if (!ci.new_track)
1337 logf("Codec failure");
1338 gui_syncsplash(HZ*2, "Codec failure");
1341 if (!codec_load_next_track())
1343 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1344 /* End of playlist */
1345 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1346 break;
1349 else
1351 logf("Codec finished");
1352 if (ci.stop_codec)
1354 /* Wait for the audio to stop playing before
1355 * triggering the WPS exit */
1356 while(pcm_is_playing())
1358 curtrack_id3.elapsed =
1359 curtrack_id3.length - pcmbuf_get_latency();
1360 sleep(1);
1362 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1363 /* End of playlist */
1364 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1365 break;
1369 if (CUR_TI->codec_hid >= 0)
1371 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1372 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
1374 else
1376 const char *codec_fn =
1377 get_codec_filename(curtrack_id3.codectype);
1378 if (codec_fn)
1380 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1381 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
1382 (intptr_t)codec_fn);
1386 break;
1388 #ifdef AUDIO_HAVE_RECORDING
1389 case Q_ENCODER_LOAD_DISK:
1390 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1392 if (status == CODEC_OK)
1393 break;
1395 logf("Encoder failure");
1396 gui_syncsplash(HZ*2, "Encoder failure");
1398 if (ci.enc_codec_loaded < 0)
1399 break;
1401 logf("Encoder failed to load");
1402 ci.enc_codec_loaded = -1;
1403 break;
1404 #endif /* AUDIO_HAVE_RECORDING */
1406 default:
1407 LOGFQUEUE("codec < default");
1409 } /* end switch */
1414 /* --- Audio thread --- */
1416 static bool audio_have_tracks(void)
1418 return (audio_track_count() != 0);
1421 static int audio_free_track_count(void)
1423 /* Used tracks + free tracks adds up to MAX_TRACK - 1 */
1424 return MAX_TRACK - 1 - audio_track_count();
1427 int audio_track_count(void)
1429 /* Calculate difference from track_ridx to track_widx
1430 * taking into account a possible wrap-around. */
1431 return (MAX_TRACK + track_widx - track_ridx) & MAX_TRACK_MASK;
1434 long audio_filebufused(void)
1436 return (long) buf_used();
1439 /* Update track info after successful a codec track change */
1440 static void audio_update_trackinfo(void)
1442 /* Load the curent track's metadata into curtrack_id3 */
1443 CUR_TI->taginfo_ready = (CUR_TI->id3_hid >= 0);
1444 if (CUR_TI->id3_hid >= 0)
1445 copy_mp3entry(&curtrack_id3, bufgetid3(CUR_TI->id3_hid));
1447 int next_idx = (track_ridx + 1) & MAX_TRACK_MASK;
1448 tracks[next_idx].taginfo_ready = (tracks[next_idx].id3_hid >= 0);
1450 /* Reset current position */
1451 curtrack_id3.elapsed = 0;
1452 curtrack_id3.offset = 0;
1454 /* Update the codec API */
1455 ci.filesize = CUR_TI->filesize;
1456 ci.id3 = &curtrack_id3;
1457 ci.curpos = 0;
1458 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1461 static void buffering_audio_callback(enum callback_event ev, int value)
1463 (void)value;
1464 logf("buffering_audio_callback");
1466 switch (ev)
1468 case EVENT_BUFFER_LOW:
1469 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1470 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1471 break;
1473 case EVENT_HANDLE_REBUFFER:
1474 LOGFQUEUE("audio >| audio Q_AUDIO_FLUSH");
1475 queue_send(&audio_queue, Q_AUDIO_FLUSH, 0);
1476 break;
1478 case EVENT_HANDLE_FINISHED:
1479 strip_tags(value);
1480 break;
1482 default:
1483 break;
1487 /* Clear tracks between write and read, non inclusive */
1488 static void audio_clear_track_entries(bool clear_unbuffered)
1490 int cur_idx = track_widx;
1492 logf("Clearing tracks:%d/%d, %d", track_ridx, track_widx, clear_unbuffered);
1494 /* Loop over all tracks from write-to-read */
1495 while (1)
1497 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
1499 if (cur_idx == track_ridx)
1500 break;
1502 /* If the track is buffered, conditionally clear/notify,
1503 * otherwise clear the track if that option is selected */
1504 if (tracks[cur_idx].event_sent || clear_unbuffered)
1505 clear_track_info(&tracks[cur_idx]);
1509 /* Clear all tracks */
1510 static bool audio_release_tracks(void)
1512 int i, cur_idx;
1514 logf("releasing all tracks");
1516 for(i = 0; i < MAX_TRACK; i++)
1518 cur_idx = (track_ridx + i) & MAX_TRACK_MASK;
1519 if (!clear_track_info(&tracks[cur_idx]))
1520 return false;
1523 return true;
1526 static bool audio_loadcodec(bool start_play)
1528 int prev_track;
1529 char codec_path[MAX_PATH]; /* Full path to codec */
1531 if (tracks[track_widx].id3_hid < 0) {
1532 return false;
1535 const char * codec_fn =
1536 get_codec_filename(bufgetid3(tracks[track_widx].id3_hid)->codectype);
1537 if (codec_fn == NULL)
1538 return false;
1540 tracks[track_widx].codec_hid = -1;
1542 if (start_play)
1544 /* Load the codec directly from disk and save some memory. */
1545 track_ridx = track_widx;
1546 ci.filesize = CUR_TI->filesize;
1547 ci.id3 = &curtrack_id3;
1548 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1549 ci.curpos = 0;
1550 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1551 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (intptr_t)codec_fn);
1552 return true;
1554 else
1556 /* If we already have another track than this one buffered */
1557 if (track_widx != track_ridx)
1559 prev_track = (track_widx - 1) & MAX_TRACK_MASK;
1561 /* If the previous codec is the same as this one, there is no need
1562 * to put another copy of it on the file buffer */
1563 if (get_codec_base_type(
1564 bufgetid3(tracks[track_widx].id3_hid)->codectype) ==
1565 get_codec_base_type(
1566 bufgetid3(tracks[prev_track].id3_hid)->codectype)
1567 && audio_codec_loaded)
1569 logf("Reusing prev. codec");
1570 return true;
1575 codec_get_full_path(codec_path, codec_fn);
1577 tracks[track_widx].codec_hid = bufopen(codec_path, 0, TYPE_CODEC);
1578 if (tracks[track_widx].codec_hid < 0)
1579 return false;
1581 logf("Loaded codec");
1583 return true;
1586 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
1587 static void audio_set_elapsed(struct mp3entry* id3)
1589 unsigned long offset = id3->offset > id3->first_frame_offset ?
1590 id3->offset - id3->first_frame_offset : 0;
1592 if ( id3->vbr ) {
1593 if ( id3->has_toc ) {
1594 /* calculate elapsed time using TOC */
1595 int i;
1596 unsigned int remainder, plen, relpos, nextpos;
1598 /* find wich percent we're at */
1599 for (i=0; i<100; i++ )
1600 if ( offset < id3->toc[i] * (id3->filesize / 256) )
1601 break;
1603 i--;
1604 if (i < 0)
1605 i = 0;
1607 relpos = id3->toc[i];
1609 if (i < 99)
1610 nextpos = id3->toc[i+1];
1611 else
1612 nextpos = 256;
1614 remainder = offset - (relpos * (id3->filesize / 256));
1616 /* set time for this percent (divide before multiply to prevent
1617 overflow on long files. loss of precision is negligible on
1618 short files) */
1619 id3->elapsed = i * (id3->length / 100);
1621 /* calculate remainder time */
1622 plen = (nextpos - relpos) * (id3->filesize / 256);
1623 id3->elapsed += (((remainder * 100) / plen) *
1624 (id3->length / 10000));
1626 else {
1627 /* no TOC exists. set a rough estimate using average bitrate */
1628 int tpk = id3->length /
1629 ((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
1630 1024);
1631 id3->elapsed = offset / 1024 * tpk;
1634 else
1636 /* constant bitrate, use exact calculation */
1637 if (id3->bitrate != 0)
1638 id3->elapsed = offset / (id3->bitrate / 8);
1642 /* Load one track by making the appropriate bufopen calls. Return true if
1643 everything required was loaded correctly, false if not. */
1644 static bool audio_load_track(int offset, bool start_play)
1646 char *trackname;
1647 char msgbuf[80];
1648 int fd = -1;
1649 int file_offset = 0;
1650 struct mp3entry id3;
1652 /* Stop buffer filling if there is no free track entries.
1653 Don't fill up the last track entry (we wan't to store next track
1654 metadata there). */
1655 if (!audio_free_track_count())
1657 logf("No free tracks");
1658 return false;
1661 last_peek_offset++;
1662 peek_again:
1663 logf("Buffering track:%d/%d", track_widx, track_ridx);
1664 /* Get track name from current playlist read position. */
1665 while ((trackname = playlist_peek(last_peek_offset)) != NULL)
1667 /* Handle broken playlists. */
1668 fd = open(trackname, O_RDONLY);
1669 if (fd < 0)
1671 logf("Open failed");
1672 /* Skip invalid entry from playlist. */
1673 playlist_skip_entry(NULL, last_peek_offset);
1675 else
1676 break;
1679 if (!trackname)
1681 logf("End-of-playlist");
1682 playlist_end = true;
1683 memset(&lasttrack_id3, 0, sizeof(struct mp3entry));
1684 return false;
1687 tracks[track_widx].filesize = filesize(fd);
1689 if ((unsigned)offset > tracks[track_widx].filesize)
1690 offset = 0;
1692 /* Set default values */
1693 if (start_play)
1695 buf_set_watermark(AUDIO_DEFAULT_WATERMARK);
1696 dsp_configure(ci.dsp, DSP_RESET, 0);
1697 track_changed = true;
1698 playlist_update_resume_info(audio_current_track());
1701 /* Get track metadata if we don't already have it. */
1702 if (tracks[track_widx].id3_hid < 0)
1704 if (get_metadata(&id3, fd, trackname))
1706 if (track_buffer_callback)
1707 track_buffer_callback(&id3);
1709 tracks[track_widx].id3_hid =
1710 bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3);
1711 tracks[track_widx].taginfo_ready = (tracks[track_widx].id3_hid >= 0);
1713 if (tracks[track_widx].id3_hid < 0)
1715 last_peek_offset--;
1716 close(fd);
1717 copy_mp3entry(&lasttrack_id3, &id3);
1718 return false;
1721 if (track_widx == track_ridx)
1722 copy_mp3entry(&curtrack_id3, &id3);
1724 if (start_play)
1726 track_changed = true;
1727 playlist_update_resume_info(audio_current_track());
1730 else
1732 logf("mde:%s!",trackname);
1734 /* Skip invalid entry from playlist. */
1735 playlist_skip_entry(NULL, last_peek_offset);
1736 tracks[track_widx].taginfo_ready = false;
1737 close(fd);
1738 goto peek_again;
1743 close(fd);
1745 #if 0
1746 if (cuesheet_is_enabled() && tracks[track_widx].id3.cuesheet_type == 1)
1748 char cuepath[MAX_PATH];
1750 struct cuesheet *cue = start_play ? curr_cue : temp_cue;
1752 if (look_for_cuesheet_file(trackname, cuepath) &&
1753 parse_cuesheet(cuepath, cue))
1755 strcpy((cue)->audio_filename, trackname);
1756 if (start_play)
1757 cue_spoof_id3(curr_cue, &tracks[track_widx].id3);
1760 #endif
1762 struct mp3entry *track_id3;
1764 if (track_widx == track_ridx)
1765 track_id3 = &curtrack_id3;
1766 else
1767 track_id3 = bufgetid3(tracks[track_widx].id3_hid);
1769 #ifdef HAVE_ALBUMART
1770 if (tracks[track_widx].aa_hid < 0 && gui_sync_wps_uses_albumart())
1772 char aa_path[MAX_PATH];
1773 if (find_albumart(track_id3, aa_path, sizeof(aa_path)))
1774 tracks[track_widx].aa_hid = bufopen(aa_path, 0, TYPE_BITMAP);
1776 #endif
1778 /* Load the codec. */
1779 if (!audio_loadcodec(start_play))
1781 if (tracks[track_widx].codec_hid == ERR_BUFFER_FULL)
1783 /* No space for codec on buffer, not an error */
1784 return false;
1787 /* This is an error condition, either no codec was found, or reading
1788 * the codec file failed part way through, either way, skip the track */
1789 snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname);
1790 /* We should not use gui_syncplash from audio thread! */
1791 gui_syncsplash(HZ*2, msgbuf);
1792 /* Skip invalid entry from playlist. */
1793 playlist_skip_entry(NULL, last_peek_offset);
1794 tracks[track_widx].taginfo_ready = false;
1795 goto peek_again;
1798 track_id3->elapsed = 0;
1800 enum data_type type = TYPE_PACKET_AUDIO;
1802 switch (track_id3->codectype) {
1803 case AFMT_MPA_L1:
1804 case AFMT_MPA_L2:
1805 case AFMT_MPA_L3:
1806 if (offset > 0) {
1807 file_offset = offset;
1808 track_id3->offset = offset;
1809 audio_set_elapsed(track_id3);
1811 break;
1813 case AFMT_WAVPACK:
1814 if (offset > 0) {
1815 file_offset = offset;
1816 track_id3->offset = offset;
1817 track_id3->elapsed = track_id3->length / 2;
1819 break;
1821 case AFMT_OGG_VORBIS:
1822 case AFMT_SPEEX:
1823 case AFMT_FLAC:
1824 case AFMT_PCM_WAV:
1825 case AFMT_A52:
1826 case AFMT_AAC:
1827 case AFMT_MPC:
1828 case AFMT_APE:
1829 if (offset > 0)
1830 track_id3->offset = offset;
1831 break;
1833 case AFMT_NSF:
1834 case AFMT_SPC:
1835 case AFMT_SID:
1836 logf("Loading atomic %d",track_id3->codectype);
1837 type = TYPE_ATOMIC_AUDIO;
1838 break;
1841 logf("alt:%s", trackname);
1843 if (file_offset > AUDIO_REBUFFER_GUESS_SIZE)
1844 file_offset -= AUDIO_REBUFFER_GUESS_SIZE;
1845 else if (track_id3->first_frame_offset)
1846 file_offset = track_id3->first_frame_offset;
1847 else
1848 file_offset = 0;
1850 tracks[track_widx].audio_hid = bufopen(trackname, file_offset, type);
1852 if (tracks[track_widx].audio_hid < 0)
1853 return false;
1855 if (start_play)
1857 ci.curpos=file_offset;
1858 buf_request_buffer_handle(tracks[track_widx].audio_hid);
1861 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
1863 return true;
1866 /* Send callback events to notify about new tracks. */
1867 static void audio_generate_postbuffer_events(void)
1869 int cur_idx;
1871 logf("Postbuffer:%d/%d",track_ridx,track_widx);
1873 if (audio_have_tracks())
1875 cur_idx = track_ridx;
1877 while (1) {
1878 if (!tracks[cur_idx].event_sent)
1880 /* Mark the event 'sent' even if we don't really send one */
1881 tracks[cur_idx].event_sent = true;
1883 if (cur_idx == track_widx)
1884 break;
1885 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
1890 static void audio_fill_file_buffer(bool start_play, size_t offset)
1892 struct queue_event ev;
1893 bool had_next_track = audio_next_track() != NULL;
1894 bool continue_buffering;
1896 /* Must reset the buffer before use if trashed or voice only - voice
1897 file size shouldn't have changed so we can go straight from
1898 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
1899 if (buffer_state != BUFFER_STATE_INITIALIZED)
1900 audio_reset_buffer();
1902 logf("Starting buffer fill");
1904 if (!start_play)
1905 audio_clear_track_entries(false);
1907 /* Save the current resume position once. */
1908 playlist_update_resume_info(audio_current_track());
1910 do {
1911 continue_buffering = audio_load_track(offset, start_play);
1912 start_play = false;
1913 offset = 0;
1914 sleep(1);
1915 if (queue_peek(&audio_queue, &ev)) {
1916 if (ev.id != Q_AUDIO_FILL_BUFFER)
1918 /* There's a message in the queue. break the loop to treat it,
1919 and go back to filling after that. */
1920 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1921 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1923 break;
1925 } while (continue_buffering);
1927 if (!had_next_track && audio_next_track())
1928 track_changed = true;
1930 audio_generate_postbuffer_events();
1933 static void audio_rebuffer(void)
1935 logf("Forcing rebuffer");
1937 clear_track_info(CUR_TI);
1939 /* Reset track pointers */
1940 track_widx = track_ridx;
1941 audio_clear_track_entries(true);
1943 /* Fill the buffer */
1944 last_peek_offset = -1;
1945 ci.curpos = 0;
1947 if (!CUR_TI->taginfo_ready)
1948 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
1950 audio_fill_file_buffer(false, 0);
1953 /* Called on request from the codec to get a new track. This is the codec part
1954 of the track transition. */
1955 static int audio_check_new_track(void)
1957 int track_count = audio_track_count();
1958 int old_track_ridx = track_ridx;
1959 int i, idx;
1960 int next_playlist_index;
1961 bool forward;
1962 bool end_of_playlist; /* Temporary flag, not the same as playlist_end */
1964 if (dir_skip)
1966 dir_skip = false;
1967 if (playlist_next_dir(ci.new_track))
1969 ci.new_track = 0;
1970 audio_rebuffer();
1971 goto skip_done;
1973 else
1975 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1976 return Q_CODEC_REQUEST_FAILED;
1980 if (new_playlist)
1981 ci.new_track = 0;
1983 end_of_playlist = playlist_peek(ci.new_track) == NULL;
1984 auto_dir_skip = end_of_playlist && global_settings.next_folder;
1986 /* If the playlist isn't that big */
1987 if (!playlist_check(ci.new_track))
1989 if (ci.new_track >= 0)
1991 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1992 return Q_CODEC_REQUEST_FAILED;
1994 /* Find the beginning backward if the user over-skips it */
1995 while (!playlist_check(++ci.new_track))
1996 if (ci.new_track >= 0)
1998 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1999 return Q_CODEC_REQUEST_FAILED;
2002 /* Update the playlist */
2003 last_peek_offset -= ci.new_track;
2005 if (auto_dir_skip || !automatic_skip)
2007 /* If the track change was manual or the result of an auto dir skip,
2008 we need to update the playlist now */
2009 next_playlist_index = playlist_next(ci.new_track);
2011 if (next_playlist_index < 0)
2013 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2014 return Q_CODEC_REQUEST_FAILED;
2018 if (new_playlist)
2020 ci.new_track = 1;
2021 new_playlist = false;
2024 /* Save the track metadata to allow the WPS to display it
2025 while PCM finishes playing that track */
2026 copy_mp3entry(&prevtrack_id3, &curtrack_id3);
2028 /* Update the main buffer copy of the track metadata with the one
2029 the codec has been using (for the unbuffer callbacks) */
2030 if (CUR_TI->id3_hid >= 0)
2031 copy_mp3entry(bufgetid3(CUR_TI->id3_hid), &curtrack_id3);
2033 /* Save a pointer to the old track to allow later clearing */
2034 prev_ti = CUR_TI;
2036 for (i = 0; i < ci.new_track; i++)
2038 idx = (track_ridx + i) & MAX_TRACK_MASK;
2039 struct mp3entry *id3 = bufgetid3(tracks[idx].id3_hid);
2040 ssize_t offset = buf_handle_offset(tracks[idx].audio_hid);
2041 if (!id3 || offset < 0 || (unsigned)offset > id3->first_frame_offset)
2043 /* We don't have all the audio data for that track, so clear it,
2044 but keep the metadata. */
2045 if (tracks[idx].audio_hid >= 0 && bufclose(tracks[idx].audio_hid))
2047 tracks[idx].audio_hid = -1;
2048 tracks[idx].filesize = 0;
2053 /* Move to the new track */
2054 track_ridx = (track_ridx + ci.new_track) & MAX_TRACK_MASK;
2056 buf_set_base_handle(CUR_TI->audio_hid);
2058 if (automatic_skip)
2060 playlist_end = false;
2061 wps_offset = -ci.new_track;
2064 track_changed = true;
2066 /* If it is not safe to even skip this many track entries */
2067 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
2069 ci.new_track = 0;
2070 audio_rebuffer();
2071 goto skip_done;
2074 forward = ci.new_track > 0;
2075 ci.new_track = 0;
2077 /* If the target track is clearly not in memory */
2078 if (CUR_TI->filesize == 0 || !CUR_TI->taginfo_ready)
2080 audio_rebuffer();
2081 goto skip_done;
2084 /* When skipping backwards, it is possible that we've found a track that's
2085 * buffered, but which is around the track-wrap and therefor not the track
2086 * we are looking for */
2087 if (!forward)
2089 int cur_idx = track_ridx;
2090 bool taginfo_ready = true;
2091 /* We've wrapped the buffer backwards if new > old */
2092 bool wrap = track_ridx > old_track_ridx;
2094 while (1)
2096 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
2098 /* if we've advanced past the wrap when cur_idx is zeroed */
2099 if (!cur_idx)
2100 wrap = false;
2102 /* if we aren't still on the wrap and we've caught the old track */
2103 if (!(wrap || cur_idx < old_track_ridx))
2104 break;
2106 /* If we hit a track in between without valid tag info, bail */
2107 if (!tracks[cur_idx].taginfo_ready)
2109 taginfo_ready = false;
2110 break;
2113 if (!taginfo_ready)
2115 audio_rebuffer();
2119 skip_done:
2120 audio_update_trackinfo();
2121 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2122 return Q_CODEC_REQUEST_COMPLETE;
2125 void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3))
2127 track_buffer_callback = handler;
2130 void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3))
2132 track_unbuffer_callback = handler;
2135 void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3))
2137 track_changed_callback = handler;
2140 unsigned long audio_prev_elapsed(void)
2142 return prev_track_elapsed;
2145 static void audio_stop_codec_flush(void)
2147 ci.stop_codec = true;
2148 pcmbuf_pause(true);
2150 while (audio_codec_loaded)
2151 yield();
2153 /* If the audio codec is not loaded any more, and the audio is still
2154 * playing, it is now and _only_ now safe to call this function from the
2155 * audio thread */
2156 if (pcm_is_playing())
2157 pcmbuf_play_stop();
2158 pcmbuf_pause(paused);
2161 static void audio_stop_playback(void)
2163 /* If we were playing, save resume information */
2164 if (playing)
2166 struct mp3entry *id3 = NULL;
2168 if (!playlist_end || !ci.stop_codec)
2170 /* Set this early, the outside code yields and may allow the codec
2171 to try to wait for a reply on a buffer wait */
2172 ci.stop_codec = true;
2173 id3 = audio_current_track();
2176 /* Save the current playing spot, or NULL if the playlist has ended */
2177 playlist_update_resume_info(id3);
2179 prev_track_elapsed = curtrack_id3.elapsed;
2181 /* At end of playlist save current id3 (id3.elapsed!) to buffer and
2182 * Increment index so runtime info is saved in audio_clear_track_entries().
2184 if ((playlist_end) && (tracks[track_ridx].id3_hid >= 0)) {
2185 copy_mp3entry(bufgetid3(tracks[track_ridx].id3_hid), &curtrack_id3);
2186 track_ridx = (track_ridx + 1) & MAX_TRACK_MASK;
2190 paused = false;
2191 audio_stop_codec_flush();
2192 playing = false;
2194 /* Mark all entries null. */
2195 audio_clear_track_entries(false);
2197 /* Close all tracks */
2198 audio_release_tracks();
2200 unregister_buffering_callback(buffering_audio_callback);
2202 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
2205 static void audio_play_start(size_t offset)
2207 int i;
2209 #if INPUT_SRC_CAPS != 0
2210 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2211 audio_set_output_source(AUDIO_SRC_PLAYBACK);
2212 #endif
2214 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2215 paused = false;
2216 audio_stop_codec_flush();
2218 track_changed = true;
2219 playlist_end = false;
2221 playing = true;
2223 ci.new_track = 0;
2224 ci.seek_time = 0;
2225 wps_offset = 0;
2227 sound_set_volume(global_settings.volume);
2228 track_widx = track_ridx = 0;
2230 /* Clear all track entries. */
2231 for (i = 0; i < MAX_TRACK; i++) {
2232 clear_track_info(&tracks[i]);
2235 last_peek_offset = -1;
2237 /* Officially playing */
2238 queue_reply(&audio_queue, 1);
2240 #ifndef HAVE_FLASH_STORAGE
2241 set_filebuf_watermark(buffer_margin, 0);
2242 #endif
2243 audio_fill_file_buffer(true, offset);
2244 register_buffering_callback(buffering_audio_callback);
2246 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2247 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
2251 /* Invalidates all but currently playing track. */
2252 static void audio_invalidate_tracks(void)
2254 if (audio_have_tracks())
2256 last_peek_offset = 0;
2257 playlist_end = false;
2258 track_widx = track_ridx;
2260 /* Mark all other entries null (also buffered wrong metadata). */
2261 audio_clear_track_entries(true);
2263 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2265 audio_fill_file_buffer(false, 0);
2269 static void audio_new_playlist(void)
2271 /* Prepare to start a new fill from the beginning of the playlist */
2272 last_peek_offset = -1;
2273 if (audio_have_tracks())
2275 if (paused)
2276 skipped_during_pause = true;
2277 playlist_end = false;
2278 track_widx = track_ridx;
2279 audio_clear_track_entries(true);
2281 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2283 /* Mark the current track as invalid to prevent skipping back to it */
2284 CUR_TI->taginfo_ready = false;
2287 /* Signal the codec to initiate a track change forward */
2288 new_playlist = true;
2289 ci.new_track = 1;
2291 /* Officially playing */
2292 queue_reply(&audio_queue, 1);
2294 audio_fill_file_buffer(false, 0);
2297 static void audio_initiate_track_change(long direction)
2299 playlist_end = false;
2300 ci.new_track += direction;
2301 wps_offset -= direction;
2302 if (paused)
2303 skipped_during_pause = true;
2306 static void audio_initiate_dir_change(long direction)
2308 playlist_end = false;
2309 dir_skip = true;
2310 ci.new_track = direction;
2311 if (paused)
2312 skipped_during_pause = true;
2315 /* Called when PCM track change is complete */
2316 static void audio_finalise_track_change(void)
2318 logf("audio_finalise_track_change");
2320 if (automatic_skip)
2322 if (!auto_dir_skip)
2323 playlist_next(-wps_offset);
2325 wps_offset = 0;
2326 automatic_skip = false;
2329 auto_dir_skip = false;
2331 /* Invalidate prevtrack_id3 */
2332 prevtrack_id3.path[0] = 0;
2334 if (prev_ti && prev_ti->audio_hid < 0)
2336 /* No audio left so we clear all the track info. */
2337 clear_track_info(prev_ti);
2340 if (prev_ti && prev_ti->id3_hid >= 0)
2342 /* Reset the elapsed time to force the progressbar to be empty if
2343 the user skips back to this track */
2344 bufgetid3(prev_ti->id3_hid)->elapsed = 0;
2347 if (track_changed_callback)
2348 track_changed_callback(&curtrack_id3);
2350 track_changed = true;
2351 playlist_update_resume_info(audio_current_track());
2355 * Layout audio buffer as follows - iram buffer depends on target:
2356 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
2358 static void audio_reset_buffer(void)
2360 /* see audio_get_recording_buffer if this is modified */
2361 logf("audio_reset_buffer");
2363 /* If the setup of anything allocated before the file buffer is
2364 changed, do check the adjustments after the buffer_alloc call
2365 as it will likely be affected and need sliding over */
2367 /* Initially set up file buffer as all space available */
2368 malloc_buf = audiobuf + talk_get_bufsize();
2369 /* Align the malloc buf to line size. Especially important to cf
2370 targets that do line reads/writes. */
2371 malloc_buf = (unsigned char *)(((uintptr_t)malloc_buf + 15) & ~15);
2372 filebuf = malloc_buf + MALLOC_BUFSIZE; /* filebuf line align implied */
2373 filebuflen = audiobufend - filebuf;
2375 filebuflen &= ~15;
2377 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
2378 filebuflen -= pcmbuf_init(filebuf + filebuflen) + GUARD_BUFSIZE;
2380 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
2381 will already be line aligned */
2382 filebuflen &= ~3;
2384 buffering_reset(filebuf, filebuflen);
2386 /* Clear any references to the file buffer */
2387 buffer_state = BUFFER_STATE_INITIALIZED;
2389 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
2390 /* Make sure everything adds up - yes, some info is a bit redundant but
2391 aids viewing and the sumation of certain variables should add up to
2392 the location of others. */
2394 size_t pcmbufsize;
2395 unsigned char * pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
2396 logf("mabuf: %08X", (unsigned)malloc_buf);
2397 logf("mabufe: %08X", (unsigned)(malloc_buf + MALLOC_BUFSIZE));
2398 logf("fbuf: %08X", (unsigned)filebuf);
2399 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
2400 logf("gbuf: %08X", (unsigned)(filebuf + filebuflen));
2401 logf("gbufe: %08X", (unsigned)(filebuf + filebuflen + GUARD_BUFSIZE));
2402 logf("pcmb: %08X", (unsigned)pcmbuf);
2403 logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
2405 #endif
2408 static void audio_thread(void)
2410 struct queue_event ev;
2412 pcm_postinit();
2414 audio_thread_ready = true;
2416 while (1)
2418 cancel_cpu_boost();
2419 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
2421 switch (ev.id) {
2422 case Q_AUDIO_FILL_BUFFER:
2423 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
2424 if (!playing || playlist_end || ci.stop_codec)
2425 break;
2426 audio_fill_file_buffer(false, 0);
2427 break;
2429 case Q_AUDIO_PLAY:
2430 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2431 if (playing && ev.data <= 0)
2432 audio_new_playlist();
2433 else
2435 audio_stop_playback();
2436 audio_play_start((size_t)ev.data);
2438 break;
2440 case Q_AUDIO_STOP:
2441 LOGFQUEUE("audio < Q_AUDIO_STOP");
2442 if (playing)
2443 audio_stop_playback();
2444 if (ev.data != 0)
2445 queue_clear(&audio_queue);
2446 break;
2448 case Q_AUDIO_PAUSE:
2449 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
2450 if (!(bool) ev.data && skipped_during_pause && !pcmbuf_is_crossfade_active())
2451 pcmbuf_play_stop(); /* Flush old track on resume after skip */
2452 skipped_during_pause = false;
2453 if (!playing)
2454 break;
2455 pcmbuf_pause((bool)ev.data);
2456 paused = (bool)ev.data;
2457 break;
2459 case Q_AUDIO_SKIP:
2460 LOGFQUEUE("audio < Q_AUDIO_SKIP");
2461 audio_initiate_track_change((long)ev.data);
2462 break;
2464 case Q_AUDIO_PRE_FF_REWIND:
2465 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
2466 if (!playing)
2467 break;
2468 pcmbuf_pause(true);
2469 break;
2471 case Q_AUDIO_FF_REWIND:
2472 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
2473 if (!playing)
2474 break;
2475 if (automatic_skip)
2477 /* An automatic track skip is in progress. Finalize it,
2478 then go back to the previous track */
2479 audio_finalise_track_change();
2480 ci.new_track = -1;
2482 ci.seek_time = (long)ev.data+1;
2483 break;
2485 case Q_AUDIO_CHECK_NEW_TRACK:
2486 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
2487 queue_reply(&audio_queue, audio_check_new_track());
2488 break;
2490 case Q_AUDIO_DIR_SKIP:
2491 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2492 playlist_end = false;
2493 audio_initiate_dir_change(ev.data);
2494 break;
2496 case Q_AUDIO_FLUSH:
2497 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
2498 audio_invalidate_tracks();
2499 break;
2501 case Q_AUDIO_TRACK_CHANGED:
2502 /* PCM track change done */
2503 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2504 audio_finalise_track_change();
2505 break;
2507 #ifndef SIMULATOR
2508 case SYS_USB_CONNECTED:
2509 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2510 if (playing)
2511 audio_stop_playback();
2512 #ifdef PLAYBACK_VOICE
2513 voice_stop();
2514 #endif
2515 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2516 usb_wait_for_disconnect(&audio_queue);
2518 /* Mark all entries null. */
2519 audio_clear_track_entries(false);
2521 /* release tracks to make sure all handles are closed */
2522 audio_release_tracks();
2523 break;
2524 #endif
2526 case SYS_TIMEOUT:
2527 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
2528 break;
2530 default:
2531 LOGFQUEUE("audio < default");
2532 break;
2533 } /* end switch */
2534 } /* end while */
2537 #ifdef ROCKBOX_HAS_LOGF
2538 static void audio_test_track_changed_event(struct mp3entry *id3)
2540 (void)id3;
2542 logf("tce:%s", id3->path);
2544 #endif
2546 /* Initialize the audio system - called from init() in main.c.
2547 * Last function because of all the references to internal symbols
2549 void audio_init(void)
2551 struct thread_entry *audio_thread_p;
2553 /* Can never do this twice */
2554 if (audio_is_initialized)
2556 logf("audio: already initialized");
2557 return;
2560 logf("audio: initializing");
2562 /* Initialize queues before giving control elsewhere in case it likes
2563 to send messages. Thread creation will be delayed however so nothing
2564 starts running until ready if something yields such as talk_init. */
2565 queue_init(&audio_queue, true);
2566 queue_enable_queue_send(&audio_queue, &audio_queue_sender_list);
2567 queue_init(&codec_queue, false);
2568 queue_enable_queue_send(&codec_queue, &codec_queue_sender_list);
2570 pcm_init();
2572 #ifdef ROCKBOX_HAS_LOGF
2573 audio_set_track_changed_event(audio_test_track_changed_event);
2574 #endif
2576 /* Initialize codec api. */
2577 ci.read_filebuf = codec_filebuf_callback;
2578 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
2579 ci.get_codec_memory = codec_get_memory_callback;
2580 ci.request_buffer = codec_request_buffer_callback;
2581 ci.advance_buffer = codec_advance_buffer_callback;
2582 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
2583 ci.request_next_track = codec_request_next_track_callback;
2584 ci.mp3_get_filepos = codec_mp3_get_filepos_callback;
2585 ci.seek_buffer = codec_seek_buffer_callback;
2586 ci.seek_complete = codec_seek_complete_callback;
2587 ci.set_elapsed = codec_set_elapsed_callback;
2588 ci.set_offset = codec_set_offset_callback;
2589 ci.configure = codec_configure_callback;
2590 ci.discard_codec = codec_discard_codec_callback;
2591 ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP,
2592 CODEC_IDX_AUDIO);
2594 /* initialize the buffer */
2595 filebuf = audiobuf;
2597 /* audio_reset_buffer must to know the size of voice buffer so init
2598 talk first */
2599 talk_init();
2601 codec_thread_p = create_thread(
2602 codec_thread, codec_stack, sizeof(codec_stack),
2603 CREATE_THREAD_FROZEN,
2604 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
2605 IF_COP(, CPU));
2607 audio_thread_p = create_thread(audio_thread, audio_stack,
2608 sizeof(audio_stack), CREATE_THREAD_FROZEN,
2609 audio_thread_name IF_PRIO(, PRIORITY_SYSTEM)
2610 IF_COP(, CPU));
2612 #ifdef PLAYBACK_VOICE
2613 voice_thread_init();
2614 #endif
2616 /* Set crossfade setting for next buffer init which should be about... */
2617 pcmbuf_crossfade_enable(global_settings.crossfade);
2619 /* initialize the buffering system */
2621 buffering_init();
2622 /* ...now! Set up the buffers */
2623 audio_reset_buffer();
2625 int i;
2626 for(i = 0; i < MAX_TRACK; i++)
2628 tracks[i].audio_hid = -1;
2629 tracks[i].id3_hid = -1;
2630 tracks[i].codec_hid = -1;
2631 #ifdef HAVE_ALBUMART
2632 tracks[i].aa_hid = -1;
2633 #endif
2636 /* Probably safe to say */
2637 audio_is_initialized = true;
2639 sound_settings_apply();
2640 #ifndef HAVE_FLASH_STORAGE
2641 audio_set_buffer_margin(global_settings.buffer_margin);
2642 #endif
2644 /* it's safe to let the threads run now */
2645 #ifdef PLAYBACK_VOICE
2646 voice_thread_resume();
2647 #endif
2648 thread_thaw(codec_thread_p);
2649 thread_thaw(audio_thread_p);
2651 } /* audio_init */
2653 void audio_wait_for_init(void)
2655 /* audio thread will only set this once after it finished the final
2656 * audio hardware init so this little construct is safe - even
2657 * cross-core. */
2658 while (!audio_thread_ready)
2660 sleep(0);