Make sure to create the logger first. Fixes a segfault due to a race with info downlo...
[Rockbox.git] / apps / playback.c
blob198337cd61fbe3f0fbaf6a3fc15e1ecaf315d76b
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 buffering_audio_callback when the low buffer event is received, to
226 avoid flodding the audio queue with fill_file_buffer messages. */
227 static bool lowbuffer_event_sent = false;
229 /* Set by the audio thread when the current track information has updated
230 * and the WPS may need to update its cached information */
231 static bool track_changed = false;
233 /* Information used only for filling the buffer */
234 /* Playlist steps from playing track to next track to be buffered (A) */
235 static int last_peek_offset = 0;
237 /* Scrobbler support */
238 static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/
240 /* Track change controls */
241 static bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */
242 static bool playlist_end = false; /* Has the current playlist ended? (A) */
243 static bool auto_dir_skip = false; /* Have we changed dirs automatically? */
244 static bool dir_skip = false; /* Is a directory skip pending? (A) */
245 static bool new_playlist = false; /* Are we starting a new playlist? (A) */
246 static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */
247 static bool skipped_during_pause = false; /* Do we need to clear the PCM buffer when playback resumes (A) */
249 /* Callbacks which applications or plugins may set */
250 /* When the playing track has changed from the user's perspective */
251 void (*track_changed_callback)(struct mp3entry *id3) = NULL;
252 /* When a track has been buffered */
253 void (*track_buffer_callback)(struct mp3entry *id3) = NULL;
254 /* When a track's buffer has been overwritten or cleared */
255 void (*track_unbuffer_callback)(struct mp3entry *id3) = NULL;
257 static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */
259 /* Multiple threads */
260 /* Set the watermark to trigger buffer fill (A/C) FIXME */
261 static void set_filebuf_watermark(int seconds, size_t max);
263 /* Audio thread */
264 static struct event_queue audio_queue NOCACHEBSS_ATTR;
265 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR;
266 static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
267 static const char audio_thread_name[] = "audio";
269 static void audio_thread(void);
270 static void audio_initiate_track_change(long direction);
271 static bool audio_have_tracks(void);
272 static void audio_reset_buffer(void);
274 /* Codec thread */
275 extern struct codec_api ci;
276 static struct event_queue codec_queue NOCACHEBSS_ATTR;
277 static struct queue_sender_list codec_queue_sender_list;
278 static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
279 IBSS_ATTR;
280 static const char codec_thread_name[] = "codec";
281 struct thread_entry *codec_thread_p; /* For modifying thread priority later. */
283 /* PCM buffer messaging */
284 static struct event_queue pcmbuf_queue NOCACHEBSS_ATTR;
286 /* Function to be called by pcm buffer callbacks.
287 * Permissible Context(s): Audio interrupt
289 static void pcmbuf_callback_queue_post(long id, intptr_t data)
291 /* No lock since we're already in audio interrupt context */
292 queue_post(&pcmbuf_queue, id, data);
295 /* Scan the pcmbuf queue and return true if a message pulled.
296 * Permissible Context(s): Thread
298 static bool pcmbuf_queue_scan(struct queue_event *ev)
300 if (!queue_empty(&pcmbuf_queue))
302 /* Transfer message to audio queue */
303 pcm_play_lock();
304 /* Pull message - never, ever any blocking call! */
305 queue_wait_w_tmo(&pcmbuf_queue, ev, 0);
306 pcm_play_unlock();
307 return true;
310 return false;
313 /* Clear the pcmbuf queue of messages
314 * Permissible Context(s): Thread
316 static void pcmbuf_queue_clear(void)
318 pcm_play_lock();
319 queue_clear(&pcmbuf_queue);
320 pcm_play_unlock();
323 /* --- Helper functions --- */
325 static struct mp3entry *bufgetid3(int handle_id)
327 if (handle_id < 0)
328 return NULL;
330 struct mp3entry *id3;
331 ssize_t ret = bufgetdata(handle_id, 0, (void *)&id3);
333 if (ret < 0 || ret != sizeof(struct mp3entry))
334 return NULL;
336 return id3;
339 static bool clear_track_info(struct track_info *track)
341 /* bufclose returns true if the handle is not found, or if it is closed
342 * successfully, so these checks are safe on non-existant handles */
343 if (!track)
344 return false;
346 if (track->codec_hid >= 0) {
347 if (bufclose(track->codec_hid))
348 track->codec_hid = -1;
349 else
350 return false;
353 if (track->id3_hid >= 0) {
354 if (track->event_sent && track_unbuffer_callback) {
355 /* If there is an unbuffer callback, call it */
356 track_unbuffer_callback(bufgetid3(track->id3_hid));
359 if (bufclose(track->id3_hid))
360 track->id3_hid = -1;
361 else
362 return false;
365 if (track->audio_hid >= 0) {
366 if (bufclose(track->audio_hid))
367 track->audio_hid = -1;
368 else
369 return false;
372 #ifdef HAVE_ALBUMART
373 if (track->aa_hid >= 0) {
374 if (bufclose(track->aa_hid))
375 track->aa_hid = -1;
376 else
377 return false;
379 #endif
381 track->filesize = 0;
382 track->taginfo_ready = false;
383 track->event_sent = false;
385 return true;
388 /* --- External interfaces --- */
390 /* This sends a stop message and the audio thread will dump all it's
391 subsequenct messages */
392 void audio_hard_stop(void)
394 /* Stop playback */
395 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
396 queue_send(&audio_queue, Q_AUDIO_STOP, 1);
397 #ifdef PLAYBACK_VOICE
398 voice_stop();
399 #endif
402 bool audio_restore_playback(int type)
404 switch (type)
406 case AUDIO_WANT_PLAYBACK:
407 if (buffer_state != BUFFER_STATE_INITIALIZED)
408 audio_reset_buffer();
409 return true;
410 case AUDIO_WANT_VOICE:
411 if (buffer_state == BUFFER_STATE_TRASHED)
412 audio_reset_buffer();
413 return true;
414 default:
415 return false;
419 unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
421 unsigned char *buf, *end;
423 if (audio_is_initialized)
425 audio_hard_stop();
427 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
429 if (buffer_size == NULL)
431 /* Special case for talk_init to use since it already knows it's
432 trashed */
433 buffer_state = BUFFER_STATE_TRASHED;
434 return NULL;
437 if (talk_buf || buffer_state == BUFFER_STATE_TRASHED
438 || !talk_voice_required())
440 logf("get buffer: talk, audio");
441 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
442 the talk buffer is not needed because voice isn't being used, or
443 could be BUFFER_STATE_TRASHED already. If state is
444 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
445 without the caller knowing what's going on. Changing certain settings
446 may move it to a worse condition but the memory in use by something
447 else will remain undisturbed.
449 if (buffer_state != BUFFER_STATE_TRASHED)
451 talk_buffer_steal();
452 buffer_state = BUFFER_STATE_TRASHED;
455 buf = audiobuf;
456 end = audiobufend;
458 else
460 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
461 still BUFFER_STATE_INITIALIZED */
462 /* Skip talk buffer and move pcm buffer to end to maximize available
463 contiguous memory - no audio running means voice will not need the
464 swap space */
465 logf("get buffer: audio");
466 buf = audiobuf + talk_get_bufsize();
467 end = audiobufend - pcmbuf_init(audiobufend);
468 buffer_state = BUFFER_STATE_VOICED_ONLY;
471 *buffer_size = end - buf;
473 return buf;
476 #ifdef HAVE_RECORDING
477 unsigned char *audio_get_recording_buffer(size_t *buffer_size)
479 /* Stop audio, voice and obtain all available buffer space */
480 audio_hard_stop();
481 talk_buffer_steal();
483 unsigned char *end = audiobufend;
484 buffer_state = BUFFER_STATE_TRASHED;
485 *buffer_size = end - audiobuf;
487 return (unsigned char *)audiobuf;
490 bool audio_load_encoder(int afmt)
492 #ifndef SIMULATOR
493 const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER);
494 if (!enc_fn)
495 return false;
497 audio_remove_encoder();
498 ci.enc_codec_loaded = 0; /* clear any previous error condition */
500 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
501 queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (intptr_t)enc_fn);
503 while (ci.enc_codec_loaded == 0)
504 yield();
506 logf("codec loaded: %d", ci.enc_codec_loaded);
508 return ci.enc_codec_loaded > 0;
509 #else
510 (void)afmt;
511 return true;
512 #endif
513 } /* audio_load_encoder */
515 void audio_remove_encoder(void)
517 #ifndef SIMULATOR
518 /* force encoder codec unload (if currently loaded) */
519 if (ci.enc_codec_loaded <= 0)
520 return;
522 ci.stop_encoder = true;
523 while (ci.enc_codec_loaded > 0)
524 yield();
525 #endif
526 } /* audio_remove_encoder */
528 #endif /* HAVE_RECORDING */
530 #ifdef HAVE_ALBUMART
531 int audio_current_aa_hid(void)
533 int cur_idx;
534 int offset = ci.new_track + wps_offset;
536 cur_idx = track_ridx + offset;
537 cur_idx &= MAX_TRACK_MASK;
539 return tracks[cur_idx].aa_hid;
541 #endif
543 struct mp3entry* audio_current_track(void)
545 const char *filename;
546 const char *p;
547 static struct mp3entry temp_id3;
548 int cur_idx;
549 int offset = ci.new_track + wps_offset;
551 cur_idx = (track_ridx + offset) & MAX_TRACK_MASK;
553 if (cur_idx == track_ridx && *curtrack_id3.path)
555 /* The usual case */
556 return &curtrack_id3;
558 else if (offset == -1 && *prevtrack_id3.path)
560 /* We're in a track transition. The codec has moved on to the nex track,
561 but the audio being played is still the same (now previous) track.
562 prevtrack_id3.elapsed is being updated in an ISR by
563 codec_pcmbuf_position_callback */
564 return &prevtrack_id3;
566 else if (tracks[cur_idx].id3_hid >= 0)
568 /* Get the ID3 metadata from the main buffer */
569 return bufgetid3(tracks[cur_idx].id3_hid);
572 /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info
573 we have and return that. */
575 memset(&temp_id3, 0, sizeof(struct mp3entry));
577 filename = playlist_peek(0);
578 if (!filename)
579 filename = "No file!";
581 #ifdef HAVE_TC_RAMCACHE
582 if (tagcache_fill_tags(&temp_id3, filename))
583 return &temp_id3;
584 #endif
586 p = strrchr(filename, '/');
587 if (!p)
588 p = filename;
589 else
590 p++;
592 strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1);
593 temp_id3.title = &temp_id3.path[0];
595 return &temp_id3;
598 struct mp3entry* audio_next_track(void)
600 int next_idx;
601 int offset = ci.new_track + wps_offset;
603 if (!audio_have_tracks())
604 return NULL;
606 if (wps_offset == -1 && *prevtrack_id3.path)
608 /* We're in a track transition. The next track for the WPS is the one
609 currently being decoded. */
610 return &curtrack_id3;
613 next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK;
615 if (next_idx == track_widx)
617 /* The next track hasn't been buffered yet, so we return the static
618 version of its metadata. */
619 return &lasttrack_id3;
622 if (tracks[next_idx].id3_hid < 0)
623 return NULL;
624 else
625 return bufgetid3(tracks[next_idx].id3_hid);
628 bool audio_has_changed_track(void)
630 if (track_changed)
632 track_changed = false;
633 return true;
636 return false;
639 void audio_play(long offset)
641 logf("audio_play");
643 #ifdef PLAYBACK_VOICE
644 /* Truncate any existing voice output so we don't have spelling
645 * etc. over the first part of the played track */
646 talk_force_shutup();
647 #endif
649 /* Start playback */
650 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset);
651 /* Don't return until playback has actually started */
652 queue_send(&audio_queue, Q_AUDIO_PLAY, offset);
655 void audio_stop(void)
657 /* Stop playback */
658 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
659 /* Don't return until playback has actually stopped */
660 queue_send(&audio_queue, Q_AUDIO_STOP, 0);
663 void audio_pause(void)
665 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
666 /* Don't return until playback has actually paused */
667 queue_send(&audio_queue, Q_AUDIO_PAUSE, true);
670 void audio_resume(void)
672 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
673 /* Don't return until playback has actually resumed */
674 queue_send(&audio_queue, Q_AUDIO_PAUSE, false);
677 static void audio_skip(int direction)
679 if (playlist_check(ci.new_track + wps_offset + direction))
681 if (global_settings.beep)
682 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
684 LOGFQUEUE("audio > audio Q_AUDIO_SKIP %d", direction);
685 queue_post(&audio_queue, Q_AUDIO_SKIP, direction);
686 /* Update wps while our message travels inside deep playback queues. */
687 wps_offset += direction;
688 /* Immediately update the playlist index */
689 playlist_next(direction);
690 last_peek_offset -= direction;
691 track_changed = true;
693 else
695 /* No more tracks. */
696 if (global_settings.beep)
697 pcmbuf_beep(1000, 100, 1000*global_settings.beep);
701 void audio_next(void)
703 audio_skip(1);
706 void audio_prev(void)
708 audio_skip(-1);
711 void audio_next_dir(void)
713 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
714 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, 1);
717 void audio_prev_dir(void)
719 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
720 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, -1);
723 void audio_pre_ff_rewind(void)
725 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
726 queue_post(&audio_queue, Q_AUDIO_PRE_FF_REWIND, 0);
729 void audio_ff_rewind(long newpos)
731 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
732 queue_post(&audio_queue, Q_AUDIO_FF_REWIND, newpos);
735 void audio_flush_and_reload_tracks(void)
737 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
738 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0);
741 void audio_error_clear(void)
743 #ifdef AUDIO_HAVE_RECORDING
744 pcm_rec_error_clear();
745 #endif
748 int audio_status(void)
750 int ret = 0;
752 if (playing)
753 ret |= AUDIO_STATUS_PLAY;
755 if (paused)
756 ret |= AUDIO_STATUS_PAUSE;
758 #ifdef HAVE_RECORDING
759 /* Do this here for constitency with mpeg.c version */
760 ret |= pcm_rec_status();
761 #endif
763 return ret;
766 int audio_get_file_pos(void)
768 return 0;
771 #ifndef HAVE_FLASH_STORAGE
772 void audio_set_buffer_margin(int setting)
774 static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
775 buffer_margin = lookup[setting];
776 logf("buffer margin: %ld", (long)buffer_margin);
777 set_filebuf_watermark(buffer_margin, 0);
779 #endif
781 /* Take nescessary steps to enable or disable the crossfade setting */
782 void audio_set_crossfade(int enable)
784 size_t offset;
785 bool was_playing;
786 size_t size;
788 /* Tell it the next setting to use */
789 pcmbuf_crossfade_enable(enable);
791 /* Return if size hasn't changed or this is too early to determine
792 which in the second case there's no way we could be playing
793 anything at all */
794 if (pcmbuf_is_same_size())
796 /* This function is a copout and just syncs some variables -
797 to be removed at a later date */
798 pcmbuf_crossfade_enable_finished();
799 return;
802 offset = 0;
803 was_playing = playing;
805 /* Playback has to be stopped before changing the buffer size */
806 if (was_playing)
808 /* Store the track resume position */
809 offset = curtrack_id3.offset;
810 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK));
813 /* Blast it - audio buffer will have to be setup again next time
814 something plays */
815 audio_get_buffer(true, &size);
817 /* Restart playback if audio was running previously */
818 if (was_playing)
819 audio_play(offset);
822 /* --- Routines called from multiple threads --- */
824 static void set_filebuf_watermark(int seconds, size_t max)
826 size_t bytes;
828 if (!filebuf)
829 return; /* Audio buffers not yet set up */
831 bytes = seconds?MAX(curtrack_id3.bitrate * seconds * (1000/8), max):max;
832 bytes = MIN(bytes, filebuflen / 2);
833 buf_set_watermark(bytes);
836 const char * get_codec_filename(int cod_spec)
838 const char *fname;
840 #ifdef HAVE_RECORDING
841 /* Can choose decoder or encoder if one available */
842 int type = cod_spec & CODEC_TYPE_MASK;
843 int afmt = cod_spec & CODEC_AFMT_MASK;
845 if ((unsigned)afmt >= AFMT_NUM_CODECS)
846 type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
848 fname = (type == CODEC_TYPE_ENCODER) ?
849 audio_formats[afmt].codec_enc_root_fn :
850 audio_formats[afmt].codec_root_fn;
852 logf("%s: %d - %s",
853 (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
854 afmt, fname ? fname : "<unknown>");
855 #else /* !HAVE_RECORDING */
856 /* Always decoder */
857 if ((unsigned)cod_spec >= AFMT_NUM_CODECS)
858 cod_spec = AFMT_UNKNOWN;
859 fname = audio_formats[cod_spec].codec_root_fn;
860 logf("Codec: %d - %s", cod_spec, fname ? fname : "<unknown>");
861 #endif /* HAVE_RECORDING */
863 return fname;
864 } /* get_codec_filename */
866 /* --- Codec thread --- */
867 static bool codec_pcmbuf_insert_callback(
868 const void *ch1, const void *ch2, int count)
870 const char *src[2] = { ch1, ch2 };
872 while (count > 0)
874 int out_count = dsp_output_count(ci.dsp, count);
875 int inp_count;
876 char *dest;
878 /* Prevent audio from a previous track from playing */
879 if (ci.new_track || ci.stop_codec)
880 return true;
882 while ((dest = pcmbuf_request_buffer(&out_count)) == NULL)
884 cancel_cpu_boost();
885 sleep(1);
886 if (ci.seek_time || ci.new_track || ci.stop_codec)
887 return true;
890 /* Get the real input_size for output_size bytes, guarding
891 * against resampling buffer overflows. */
892 inp_count = dsp_input_count(ci.dsp, out_count);
894 if (inp_count <= 0)
895 return true;
897 /* Input size has grown, no error, just don't write more than length */
898 if (inp_count > count)
899 inp_count = count;
901 out_count = dsp_process(ci.dsp, dest, src, inp_count);
903 if (out_count <= 0)
904 return true;
906 pcmbuf_write_complete(out_count);
908 count -= inp_count;
911 return true;
912 } /* codec_pcmbuf_insert_callback */
914 static void* codec_get_memory_callback(size_t *size)
916 *size = MALLOC_BUFSIZE;
917 return malloc_buf;
920 /* Between the codec and PCM track change, we need to keep updating the
921 "elapsed" value of the previous (to the codec, but current to the
922 user/PCM/WPS) track, so that the progressbar reaches the end.
923 During that transition, the WPS will display prevtrack_id3. */
924 static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
925 static void codec_pcmbuf_position_callback(size_t size)
927 /* This is called from an ISR, so be quick */
928 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
929 prevtrack_id3.elapsed;
931 if (time >= prevtrack_id3.length)
933 pcmbuf_set_position_callback(NULL);
934 prevtrack_id3.elapsed = prevtrack_id3.length;
936 else
937 prevtrack_id3.elapsed = time;
940 static void codec_set_elapsed_callback(unsigned int value)
942 unsigned int latency;
943 if (ci.seek_time)
944 return;
946 #ifdef AB_REPEAT_ENABLE
947 ab_position_report(value);
948 #endif
950 latency = pcmbuf_get_latency();
951 if (value < latency)
952 curtrack_id3.elapsed = 0;
953 else if (value - latency > curtrack_id3.elapsed ||
954 value - latency < curtrack_id3.elapsed - 2)
956 curtrack_id3.elapsed = value - latency;
960 static void codec_set_offset_callback(size_t value)
962 unsigned int latency;
964 if (ci.seek_time)
965 return;
967 latency = pcmbuf_get_latency() * curtrack_id3.bitrate / 8;
968 if (value < latency)
969 curtrack_id3.offset = 0;
970 else
971 curtrack_id3.offset = value - latency;
974 static void codec_advance_buffer_counters(size_t amount)
976 bufadvance(CUR_TI->audio_hid, amount);
977 ci.curpos += amount;
980 /* copy up-to size bytes into ptr and return the actual size copied */
981 static size_t codec_filebuf_callback(void *ptr, size_t size)
983 ssize_t copy_n;
985 if (ci.stop_codec || !playing)
986 return 0;
988 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
990 /* Nothing requested OR nothing left */
991 if (copy_n == 0)
992 return 0;
994 /* Update read and other position pointers */
995 codec_advance_buffer_counters(copy_n);
997 /* Return the actual amount of data copied to the buffer */
998 return copy_n;
999 } /* codec_filebuf_callback */
1001 static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
1003 size_t copy_n = reqsize;
1004 ssize_t ret;
1005 void *ptr;
1007 if (!playing)
1009 *realsize = 0;
1010 return NULL;
1013 ret = bufgetdata(CUR_TI->audio_hid, reqsize, &ptr);
1014 if (ret >= 0)
1015 copy_n = MIN((size_t)ret, reqsize);
1017 if (copy_n == 0)
1019 *realsize = 0;
1020 return NULL;
1023 *realsize = copy_n;
1025 return ptr;
1026 } /* codec_request_buffer_callback */
1028 static int get_codec_base_type(int type)
1030 switch (type) {
1031 case AFMT_MPA_L1:
1032 case AFMT_MPA_L2:
1033 case AFMT_MPA_L3:
1034 return AFMT_MPA_L3;
1037 return type;
1040 static void codec_advance_buffer_callback(size_t amount)
1042 codec_advance_buffer_counters(amount);
1043 codec_set_offset_callback(ci.curpos);
1046 static void codec_advance_buffer_loc_callback(void *ptr)
1048 size_t amount = buf_get_offset(CUR_TI->audio_hid, ptr);
1049 codec_advance_buffer_callback(amount);
1052 /* Copied from mpeg.c. Should be moved somewhere else. */
1053 static int codec_get_file_pos(void)
1055 int pos = -1;
1056 struct mp3entry *id3 = audio_current_track();
1058 if (id3->vbr)
1060 if (id3->has_toc)
1062 /* Use the TOC to find the new position */
1063 unsigned int percent, remainder;
1064 int curtoc, nexttoc, plen;
1066 percent = (id3->elapsed*100)/id3->length;
1067 if (percent > 99)
1068 percent = 99;
1070 curtoc = id3->toc[percent];
1072 if (percent < 99)
1073 nexttoc = id3->toc[percent+1];
1074 else
1075 nexttoc = 256;
1077 pos = (id3->filesize/256)*curtoc;
1079 /* Use the remainder to get a more accurate position */
1080 remainder = (id3->elapsed*100)%id3->length;
1081 remainder = (remainder*100)/id3->length;
1082 plen = (nexttoc - curtoc)*(id3->filesize/256);
1083 pos += (plen/100)*remainder;
1085 else
1087 /* No TOC exists, estimate the new position */
1088 pos = (id3->filesize / (id3->length / 1000)) *
1089 (id3->elapsed / 1000);
1092 else if (id3->bitrate)
1093 pos = id3->elapsed * (id3->bitrate / 8);
1094 else
1095 return -1;
1097 pos += id3->first_frame_offset;
1099 /* Don't seek right to the end of the file so that we can
1100 transition properly to the next song */
1101 if (pos >= (int)(id3->filesize - id3->id3v1len))
1102 pos = id3->filesize - id3->id3v1len - 1;
1104 return pos;
1107 static off_t codec_mp3_get_filepos_callback(int newtime)
1109 off_t newpos;
1111 curtrack_id3.elapsed = newtime;
1112 newpos = codec_get_file_pos();
1114 return newpos;
1117 static void codec_seek_complete_callback(void)
1119 logf("seek_complete");
1120 if (pcm_is_paused())
1122 /* If this is not a seamless seek, clear the buffer */
1123 pcmbuf_play_stop();
1124 dsp_configure(ci.dsp, DSP_FLUSH, 0);
1126 /* If playback was not 'deliberately' paused, unpause now */
1127 if (!paused)
1128 pcmbuf_pause(false);
1130 ci.seek_time = 0;
1133 static bool codec_seek_buffer_callback(size_t newpos)
1135 logf("codec_seek_buffer_callback");
1137 int ret = bufseek(CUR_TI->audio_hid, newpos);
1138 if (ret == 0) {
1139 ci.curpos = newpos;
1140 return true;
1142 else {
1143 return false;
1147 static void codec_configure_callback(int setting, intptr_t value)
1149 switch (setting) {
1150 case CODEC_SET_FILEBUF_WATERMARK:
1151 set_filebuf_watermark(buffer_margin, value);
1152 break;
1154 default:
1155 if (!dsp_configure(ci.dsp, setting, value))
1156 { logf("Illegal key:%d", setting); }
1160 static void codec_track_changed(void)
1162 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1163 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1166 static void codec_pcmbuf_track_changed_callback(void)
1168 pcmbuf_set_position_callback(NULL);
1169 pcmbuf_callback_queue_post(Q_AUDIO_TRACK_CHANGED, 0);
1172 static void codec_discard_codec_callback(void)
1174 if (CUR_TI->codec_hid >= 0)
1176 bufclose(CUR_TI->codec_hid);
1177 CUR_TI->codec_hid = -1;
1181 static inline void codec_gapless_track_change(void)
1183 /* callback keeps the progress bar moving while the pcmbuf empties */
1184 pcmbuf_set_position_callback(codec_pcmbuf_position_callback);
1185 /* set the pcmbuf callback for when the track really changes */
1186 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
1189 static inline void codec_crossfade_track_change(void)
1191 /* Initiate automatic crossfade mode */
1192 pcmbuf_crossfade_init(false);
1193 /* Notify the wps that the track change starts now */
1194 codec_track_changed();
1197 static void codec_track_skip_done(bool was_manual)
1199 /* Manual track change (always crossfade or flush audio). */
1200 if (was_manual)
1202 pcmbuf_crossfade_init(true);
1203 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1204 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1206 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1207 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1208 && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP)
1210 if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
1212 if (global_settings.playlist_shuffle)
1213 /* shuffle mode is on, so crossfade: */
1214 codec_crossfade_track_change();
1215 else
1216 /* shuffle mode is off, so do a gapless track change */
1217 codec_gapless_track_change();
1219 else
1220 /* normal crossfade: */
1221 codec_crossfade_track_change();
1223 else
1224 /* normal gapless playback. */
1225 codec_gapless_track_change();
1228 static bool codec_load_next_track(void)
1230 intptr_t result = Q_CODEC_REQUEST_FAILED;
1232 prev_track_elapsed = curtrack_id3.elapsed;
1234 #ifdef AB_REPEAT_ENABLE
1235 ab_end_of_track_report();
1236 #endif
1238 logf("Request new track");
1240 if (ci.new_track == 0)
1242 ci.new_track++;
1243 automatic_skip = true;
1246 if (!ci.stop_codec)
1248 trigger_cpu_boost();
1249 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1250 result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
1253 switch (result)
1255 case Q_CODEC_REQUEST_COMPLETE:
1256 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1257 codec_track_skip_done(!automatic_skip);
1258 return true;
1260 case Q_CODEC_REQUEST_FAILED:
1261 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1262 ci.new_track = 0;
1263 ci.stop_codec = true;
1264 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1265 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1266 return false;
1268 default:
1269 LOGFQUEUE("codec |< default");
1270 ci.stop_codec = true;
1271 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1272 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1273 return false;
1277 static bool codec_request_next_track_callback(void)
1279 int prev_codectype;
1281 if (ci.stop_codec || !playing)
1282 return false;
1284 prev_codectype = get_codec_base_type(curtrack_id3.codectype);
1286 if (!codec_load_next_track())
1287 return false;
1289 /* Check if the next codec is the same file. */
1290 if (prev_codectype == get_codec_base_type(curtrack_id3.codectype))
1292 logf("New track loaded");
1293 codec_discard_codec_callback();
1294 return true;
1296 else
1298 logf("New codec:%d/%d", curtrack_id3.codectype, prev_codectype);
1299 return false;
1303 static void codec_thread(void)
1305 struct queue_event ev;
1306 int status;
1308 while (1) {
1309 status = 0;
1310 cancel_cpu_boost();
1311 queue_wait(&codec_queue, &ev);
1313 switch (ev.id) {
1314 case Q_CODEC_LOAD_DISK:
1315 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1316 queue_reply(&codec_queue, 1);
1317 audio_codec_loaded = true;
1318 ci.stop_codec = false;
1319 status = codec_load_file((const char *)ev.data, &ci);
1320 break;
1322 case Q_CODEC_LOAD:
1323 LOGFQUEUE("codec < Q_CODEC_LOAD");
1324 if (CUR_TI->codec_hid < 0) {
1325 logf("Codec slot is empty!");
1326 /* Wait for the pcm buffer to go empty */
1327 while (pcm_is_playing())
1328 yield();
1329 /* This must be set to prevent an infinite loop */
1330 ci.stop_codec = true;
1331 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1332 queue_post(&codec_queue, Q_AUDIO_PLAY, 0);
1333 break;
1336 audio_codec_loaded = true;
1337 ci.stop_codec = false;
1338 status = codec_load_buf(CUR_TI->codec_hid, &ci);
1339 break;
1341 #ifdef AUDIO_HAVE_RECORDING
1342 case Q_ENCODER_LOAD_DISK:
1343 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1344 audio_codec_loaded = false; /* Not audio codec! */
1345 logf("loading encoder");
1346 ci.stop_encoder = false;
1347 status = codec_load_file((const char *)ev.data, &ci);
1348 logf("encoder stopped");
1349 break;
1350 #endif /* AUDIO_HAVE_RECORDING */
1352 default:
1353 LOGFQUEUE("codec < default");
1356 if (audio_codec_loaded)
1358 if (ci.stop_codec)
1360 status = CODEC_OK;
1361 if (!playing)
1362 pcmbuf_play_stop();
1365 audio_codec_loaded = false;
1368 switch (ev.id) {
1369 case Q_CODEC_LOAD_DISK:
1370 case Q_CODEC_LOAD:
1371 LOGFQUEUE("codec < Q_CODEC_LOAD");
1372 if (playing)
1374 if (ci.new_track || status != CODEC_OK)
1376 if (!ci.new_track)
1378 logf("Codec failure");
1379 gui_syncsplash(HZ*2, "Codec failure");
1382 if (!codec_load_next_track())
1384 break;
1387 else
1389 logf("Codec finished");
1390 if (ci.stop_codec)
1392 /* Wait for the audio to stop playing before
1393 * triggering the WPS exit */
1394 while(pcm_is_playing())
1396 curtrack_id3.elapsed =
1397 curtrack_id3.length - pcmbuf_get_latency();
1398 sleep(1);
1400 break;
1404 if (CUR_TI->codec_hid >= 0)
1406 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1407 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
1409 else
1411 const char *codec_fn =
1412 get_codec_filename(curtrack_id3.codectype);
1413 if (codec_fn)
1415 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1416 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
1417 (intptr_t)codec_fn);
1421 break;
1423 #ifdef AUDIO_HAVE_RECORDING
1424 case Q_ENCODER_LOAD_DISK:
1425 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1427 if (status == CODEC_OK)
1428 break;
1430 logf("Encoder failure");
1431 gui_syncsplash(HZ*2, "Encoder failure");
1433 if (ci.enc_codec_loaded < 0)
1434 break;
1436 logf("Encoder failed to load");
1437 ci.enc_codec_loaded = -1;
1438 break;
1439 #endif /* AUDIO_HAVE_RECORDING */
1441 default:
1442 LOGFQUEUE("codec < default");
1444 } /* end switch */
1449 /* --- Audio thread --- */
1451 static bool audio_have_tracks(void)
1453 return (audio_track_count() != 0);
1456 static int audio_free_track_count(void)
1458 /* Used tracks + free tracks adds up to MAX_TRACK - 1 */
1459 return MAX_TRACK - 1 - audio_track_count();
1462 int audio_track_count(void)
1464 /* Calculate difference from track_ridx to track_widx
1465 * taking into account a possible wrap-around. */
1466 return (MAX_TRACK + track_widx - track_ridx) & MAX_TRACK_MASK;
1469 long audio_filebufused(void)
1471 return (long) buf_used();
1474 /* Update track info after successful a codec track change */
1475 static void audio_update_trackinfo(void)
1477 /* Load the curent track's metadata into curtrack_id3 */
1478 CUR_TI->taginfo_ready = (CUR_TI->id3_hid >= 0);
1479 if (CUR_TI->id3_hid >= 0)
1480 copy_mp3entry(&curtrack_id3, bufgetid3(CUR_TI->id3_hid));
1482 int next_idx = (track_ridx + 1) & MAX_TRACK_MASK;
1483 tracks[next_idx].taginfo_ready = (tracks[next_idx].id3_hid >= 0);
1485 /* Reset current position */
1486 curtrack_id3.elapsed = 0;
1487 curtrack_id3.offset = 0;
1489 /* Update the codec API */
1490 ci.filesize = CUR_TI->filesize;
1491 ci.id3 = &curtrack_id3;
1492 ci.curpos = 0;
1493 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1496 static void buffering_audio_callback(enum callback_event ev, int value)
1498 (void)value;
1499 logf("buffering_audio_callback");
1501 switch (ev)
1503 case EVENT_BUFFER_LOW:
1504 if (!lowbuffer_event_sent) {
1505 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1506 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1507 lowbuffer_event_sent = true;
1509 break;
1511 case EVENT_HANDLE_REBUFFER:
1512 LOGFQUEUE("audio >| audio Q_AUDIO_FLUSH");
1513 queue_send(&audio_queue, Q_AUDIO_FLUSH, 0);
1514 break;
1516 case EVENT_HANDLE_FINISHED:
1517 logf("handle %d finished buffering", value);
1518 strip_tags(value);
1519 break;
1521 default:
1522 break;
1526 /* Clear tracks between write and read, non inclusive */
1527 static void audio_clear_track_entries(bool clear_unbuffered)
1529 int cur_idx = track_widx;
1531 logf("Clearing tracks:%d/%d, %d", track_ridx, track_widx, clear_unbuffered);
1533 /* Loop over all tracks from write-to-read */
1534 while (1)
1536 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
1538 if (cur_idx == track_ridx)
1539 break;
1541 /* If the track is buffered, conditionally clear/notify,
1542 * otherwise clear the track if that option is selected */
1543 if (tracks[cur_idx].event_sent || clear_unbuffered)
1544 clear_track_info(&tracks[cur_idx]);
1548 /* Clear all tracks */
1549 static bool audio_release_tracks(void)
1551 int i, cur_idx;
1553 logf("releasing all tracks");
1555 for(i = 0; i < MAX_TRACK; i++)
1557 cur_idx = (track_ridx + i) & MAX_TRACK_MASK;
1558 if (!clear_track_info(&tracks[cur_idx]))
1559 return false;
1562 return true;
1565 static bool audio_loadcodec(bool start_play)
1567 int prev_track;
1568 char codec_path[MAX_PATH]; /* Full path to codec */
1570 if (tracks[track_widx].id3_hid < 0) {
1571 return false;
1574 const char * codec_fn =
1575 get_codec_filename(bufgetid3(tracks[track_widx].id3_hid)->codectype);
1576 if (codec_fn == NULL)
1577 return false;
1579 tracks[track_widx].codec_hid = -1;
1581 if (start_play)
1583 /* Load the codec directly from disk and save some memory. */
1584 track_ridx = track_widx;
1585 ci.filesize = CUR_TI->filesize;
1586 ci.id3 = &curtrack_id3;
1587 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1588 ci.curpos = 0;
1589 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1590 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (intptr_t)codec_fn);
1591 return true;
1593 else
1595 /* If we already have another track than this one buffered */
1596 if (track_widx != track_ridx)
1598 prev_track = (track_widx - 1) & MAX_TRACK_MASK;
1600 /* If the previous codec is the same as this one, there is no need
1601 * to put another copy of it on the file buffer */
1602 if (get_codec_base_type(
1603 bufgetid3(tracks[track_widx].id3_hid)->codectype) ==
1604 get_codec_base_type(
1605 bufgetid3(tracks[prev_track].id3_hid)->codectype)
1606 && audio_codec_loaded)
1608 logf("Reusing prev. codec");
1609 return true;
1614 codec_get_full_path(codec_path, codec_fn);
1616 tracks[track_widx].codec_hid = bufopen(codec_path, 0, TYPE_CODEC);
1617 if (tracks[track_widx].codec_hid < 0)
1618 return false;
1620 logf("Loaded codec");
1622 return true;
1625 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
1626 static void audio_set_elapsed(struct mp3entry* id3)
1628 unsigned long offset = id3->offset > id3->first_frame_offset ?
1629 id3->offset - id3->first_frame_offset : 0;
1631 if ( id3->vbr ) {
1632 if ( id3->has_toc ) {
1633 /* calculate elapsed time using TOC */
1634 int i;
1635 unsigned int remainder, plen, relpos, nextpos;
1637 /* find wich percent we're at */
1638 for (i=0; i<100; i++ )
1639 if ( offset < id3->toc[i] * (id3->filesize / 256) )
1640 break;
1642 i--;
1643 if (i < 0)
1644 i = 0;
1646 relpos = id3->toc[i];
1648 if (i < 99)
1649 nextpos = id3->toc[i+1];
1650 else
1651 nextpos = 256;
1653 remainder = offset - (relpos * (id3->filesize / 256));
1655 /* set time for this percent (divide before multiply to prevent
1656 overflow on long files. loss of precision is negligible on
1657 short files) */
1658 id3->elapsed = i * (id3->length / 100);
1660 /* calculate remainder time */
1661 plen = (nextpos - relpos) * (id3->filesize / 256);
1662 id3->elapsed += (((remainder * 100) / plen) *
1663 (id3->length / 10000));
1665 else {
1666 /* no TOC exists. set a rough estimate using average bitrate */
1667 int tpk = id3->length /
1668 ((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
1669 1024);
1670 id3->elapsed = offset / 1024 * tpk;
1673 else
1675 /* constant bitrate, use exact calculation */
1676 if (id3->bitrate != 0)
1677 id3->elapsed = offset / (id3->bitrate / 8);
1681 /* Load one track by making the appropriate bufopen calls. Return true if
1682 everything required was loaded correctly, false if not. */
1683 static bool audio_load_track(int offset, bool start_play)
1685 char *trackname;
1686 char msgbuf[80];
1687 int fd = -1;
1688 int file_offset = 0;
1689 struct mp3entry id3;
1691 /* Stop buffer filling if there is no free track entries.
1692 Don't fill up the last track entry (we wan't to store next track
1693 metadata there). */
1694 if (!audio_free_track_count())
1696 logf("No free tracks");
1697 return false;
1700 last_peek_offset++;
1701 tracks[track_widx].taginfo_ready = false;
1703 peek_again:
1704 logf("Buffering track:%d/%d", track_widx, track_ridx);
1705 /* Get track name from current playlist read position. */
1706 while ((trackname = playlist_peek(last_peek_offset)) != NULL)
1708 /* Handle broken playlists. */
1709 fd = open(trackname, O_RDONLY);
1710 if (fd < 0)
1712 logf("Open failed");
1713 /* Skip invalid entry from playlist. */
1714 playlist_skip_entry(NULL, last_peek_offset);
1716 else
1717 break;
1720 if (!trackname)
1722 logf("End-of-playlist");
1723 playlist_end = true;
1724 memset(&lasttrack_id3, 0, sizeof(struct mp3entry));
1725 return false;
1728 tracks[track_widx].filesize = filesize(fd);
1730 if ((unsigned)offset > tracks[track_widx].filesize)
1731 offset = 0;
1733 /* Set default values */
1734 if (start_play)
1736 buf_set_watermark(AUDIO_DEFAULT_WATERMARK);
1737 dsp_configure(ci.dsp, DSP_RESET, 0);
1738 track_changed = true;
1739 playlist_update_resume_info(audio_current_track());
1742 /* Get track metadata if we don't already have it. */
1743 if (tracks[track_widx].id3_hid < 0)
1745 if (get_metadata(&id3, fd, trackname))
1747 if (track_buffer_callback)
1748 track_buffer_callback(&id3);
1750 tracks[track_widx].id3_hid =
1751 bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3);
1753 if (tracks[track_widx].id3_hid < 0)
1755 last_peek_offset--;
1756 close(fd);
1757 copy_mp3entry(&lasttrack_id3, &id3);
1758 return false;
1761 if (track_widx == track_ridx)
1762 copy_mp3entry(&curtrack_id3, &id3);
1764 if (start_play)
1766 track_changed = true;
1767 playlist_update_resume_info(audio_current_track());
1770 else
1772 logf("mde:%s!",trackname);
1774 /* Skip invalid entry from playlist. */
1775 playlist_skip_entry(NULL, last_peek_offset);
1776 close(fd);
1777 goto peek_again;
1782 close(fd);
1784 #if 0
1785 if (cuesheet_is_enabled() && tracks[track_widx].id3.cuesheet_type == 1)
1787 char cuepath[MAX_PATH];
1789 struct cuesheet *cue = start_play ? curr_cue : temp_cue;
1791 if (look_for_cuesheet_file(trackname, cuepath) &&
1792 parse_cuesheet(cuepath, cue))
1794 strcpy((cue)->audio_filename, trackname);
1795 if (start_play)
1796 cue_spoof_id3(curr_cue, &tracks[track_widx].id3);
1799 #endif
1801 struct mp3entry *track_id3;
1803 if (track_widx == track_ridx)
1804 track_id3 = &curtrack_id3;
1805 else
1806 track_id3 = bufgetid3(tracks[track_widx].id3_hid);
1808 #ifdef HAVE_ALBUMART
1809 if (tracks[track_widx].aa_hid < 0 && gui_sync_wps_uses_albumart())
1811 char aa_path[MAX_PATH];
1812 if (find_albumart(track_id3, aa_path, sizeof(aa_path)))
1813 tracks[track_widx].aa_hid = bufopen(aa_path, 0, TYPE_BITMAP);
1815 #endif
1817 /* Load the codec. */
1818 if (!audio_loadcodec(start_play))
1820 if (tracks[track_widx].codec_hid == ERR_BUFFER_FULL)
1822 /* No space for codec on buffer, not an error */
1823 return false;
1826 /* This is an error condition, either no codec was found, or reading
1827 * the codec file failed part way through, either way, skip the track */
1828 snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname);
1829 /* We should not use gui_syncplash from audio thread! */
1830 gui_syncsplash(HZ*2, msgbuf);
1831 /* Skip invalid entry from playlist. */
1832 playlist_skip_entry(NULL, last_peek_offset);
1833 goto peek_again;
1836 track_id3->elapsed = 0;
1838 enum data_type type = TYPE_PACKET_AUDIO;
1840 switch (track_id3->codectype) {
1841 case AFMT_MPA_L1:
1842 case AFMT_MPA_L2:
1843 case AFMT_MPA_L3:
1844 if (offset > 0) {
1845 file_offset = offset;
1846 track_id3->offset = offset;
1847 audio_set_elapsed(track_id3);
1849 break;
1851 case AFMT_WAVPACK:
1852 if (offset > 0) {
1853 file_offset = offset;
1854 track_id3->offset = offset;
1855 track_id3->elapsed = track_id3->length / 2;
1857 break;
1859 case AFMT_OGG_VORBIS:
1860 case AFMT_SPEEX:
1861 case AFMT_FLAC:
1862 case AFMT_PCM_WAV:
1863 case AFMT_A52:
1864 case AFMT_AAC:
1865 case AFMT_MPC:
1866 case AFMT_APE:
1867 if (offset > 0)
1868 track_id3->offset = offset;
1869 break;
1871 case AFMT_NSF:
1872 case AFMT_SPC:
1873 case AFMT_SID:
1874 logf("Loading atomic %d",track_id3->codectype);
1875 type = TYPE_ATOMIC_AUDIO;
1876 break;
1879 logf("alt:%s", trackname);
1881 if (file_offset > AUDIO_REBUFFER_GUESS_SIZE)
1882 file_offset -= AUDIO_REBUFFER_GUESS_SIZE;
1883 else if (track_id3->first_frame_offset)
1884 file_offset = track_id3->first_frame_offset;
1885 else
1886 file_offset = 0;
1888 tracks[track_widx].audio_hid = bufopen(trackname, file_offset, type);
1890 if (tracks[track_widx].audio_hid < 0)
1891 return false;
1893 /* All required data is now available for the codec. */
1894 tracks[track_widx].taginfo_ready = true;
1896 if (start_play)
1898 ci.curpos=file_offset;
1899 buf_request_buffer_handle(tracks[track_widx].audio_hid);
1902 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
1904 return true;
1907 /* Send callback events to notify about new tracks. */
1908 static void audio_generate_postbuffer_events(void)
1910 int cur_idx;
1912 logf("Postbuffer:%d/%d",track_ridx,track_widx);
1914 if (audio_have_tracks())
1916 cur_idx = track_ridx;
1918 while (1) {
1919 if (!tracks[cur_idx].event_sent)
1921 /* Mark the event 'sent' even if we don't really send one */
1922 tracks[cur_idx].event_sent = true;
1924 if (cur_idx == track_widx)
1925 break;
1926 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
1931 static void audio_fill_file_buffer(bool start_play, size_t offset)
1933 struct queue_event ev;
1934 bool had_next_track = audio_next_track() != NULL;
1935 bool continue_buffering;
1937 /* No need to rebuffer if there are track skips pending. */
1938 if (ci.new_track != 0)
1939 return;
1941 /* Must reset the buffer before use if trashed or voice only - voice
1942 file size shouldn't have changed so we can go straight from
1943 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
1944 if (buffer_state != BUFFER_STATE_INITIALIZED)
1945 audio_reset_buffer();
1947 logf("Starting buffer fill");
1949 if (!start_play)
1950 audio_clear_track_entries(false);
1952 /* Save the current resume position once. */
1953 playlist_update_resume_info(audio_current_track());
1955 do {
1956 continue_buffering = audio_load_track(offset, start_play);
1957 start_play = false;
1958 offset = 0;
1959 sleep(1);
1960 if (queue_peek(&audio_queue, &ev)) {
1961 if (ev.id != Q_AUDIO_FILL_BUFFER)
1963 /* There's a message in the queue. break the loop to treat it,
1964 and go back to filling after that. */
1965 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1966 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1968 break;
1970 } while (continue_buffering);
1972 if (!had_next_track && audio_next_track())
1973 track_changed = true;
1975 audio_generate_postbuffer_events();
1976 lowbuffer_event_sent = false;
1979 static void audio_rebuffer(void)
1981 logf("Forcing rebuffer");
1983 clear_track_info(CUR_TI);
1985 /* Reset track pointers */
1986 track_widx = track_ridx;
1987 audio_clear_track_entries(true);
1989 /* Fill the buffer */
1990 last_peek_offset = -1;
1991 ci.curpos = 0;
1993 if (!CUR_TI->taginfo_ready)
1994 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
1996 audio_fill_file_buffer(false, 0);
1999 /* Called on request from the codec to get a new track. This is the codec part
2000 of the track transition. */
2001 static int audio_check_new_track(void)
2003 int track_count = audio_track_count();
2004 int old_track_ridx = track_ridx;
2005 int i, idx;
2006 int next_playlist_index;
2007 bool forward;
2008 bool end_of_playlist; /* Temporary flag, not the same as playlist_end */
2010 if (dir_skip)
2012 dir_skip = false;
2013 if (playlist_next_dir(ci.new_track))
2015 ci.new_track = 0;
2016 audio_rebuffer();
2017 goto skip_done;
2019 else
2021 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2022 return Q_CODEC_REQUEST_FAILED;
2026 if (new_playlist)
2027 ci.new_track = 0;
2029 end_of_playlist = playlist_peek(automatic_skip ? ci.new_track : 0) == NULL;
2030 auto_dir_skip = end_of_playlist && global_settings.next_folder;
2032 /* If the playlist isn't that big */
2033 if (automatic_skip && !playlist_check(ci.new_track))
2035 if (ci.new_track >= 0)
2037 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2038 return Q_CODEC_REQUEST_FAILED;
2040 /* Find the beginning backward if the user over-skips it */
2041 while (!playlist_check(++ci.new_track))
2042 if (ci.new_track >= 0)
2044 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2045 return Q_CODEC_REQUEST_FAILED;
2049 if (auto_dir_skip)
2051 /* Update the playlist */
2052 last_peek_offset -= ci.new_track;
2054 /* If the track change was the result of an auto dir skip,
2055 we need to update the playlist now */
2056 next_playlist_index = playlist_next(ci.new_track);
2058 if (next_playlist_index < 0)
2060 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2061 return Q_CODEC_REQUEST_FAILED;
2065 if (new_playlist)
2067 ci.new_track = 1;
2068 new_playlist = false;
2071 /* Save the track metadata to allow the WPS to display it
2072 while PCM finishes playing that track */
2073 copy_mp3entry(&prevtrack_id3, &curtrack_id3);
2075 /* Update the main buffer copy of the track metadata with the one
2076 the codec has been using (for the unbuffer callbacks) */
2077 if (CUR_TI->id3_hid >= 0)
2078 copy_mp3entry(bufgetid3(CUR_TI->id3_hid), &curtrack_id3);
2080 /* Save a pointer to the old track to allow later clearing */
2081 prev_ti = CUR_TI;
2083 for (i = 0; i < ci.new_track; i++)
2085 idx = (track_ridx + i) & MAX_TRACK_MASK;
2086 struct mp3entry *id3 = bufgetid3(tracks[idx].id3_hid);
2087 ssize_t offset = buf_handle_offset(tracks[idx].audio_hid);
2088 if (!id3 || offset < 0 || (unsigned)offset > id3->first_frame_offset)
2090 /* We don't have all the audio data for that track, so clear it,
2091 but keep the metadata. */
2092 if (tracks[idx].audio_hid >= 0 && bufclose(tracks[idx].audio_hid))
2094 tracks[idx].audio_hid = -1;
2095 tracks[idx].filesize = 0;
2100 /* Move to the new track */
2101 track_ridx = (track_ridx + ci.new_track) & MAX_TRACK_MASK;
2103 buf_set_base_handle(CUR_TI->audio_hid);
2105 if (automatic_skip)
2107 playlist_end = false;
2108 wps_offset = -ci.new_track;
2109 track_changed = true;
2112 /* If it is not safe to even skip this many track entries */
2113 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
2115 ci.new_track = 0;
2116 audio_rebuffer();
2117 goto skip_done;
2120 forward = ci.new_track > 0;
2121 ci.new_track = 0;
2123 /* If the target track is clearly not in memory */
2124 if (CUR_TI->filesize == 0 || !CUR_TI->taginfo_ready)
2126 audio_rebuffer();
2127 goto skip_done;
2130 /* When skipping backwards, it is possible that we've found a track that's
2131 * buffered, but which is around the track-wrap and therefor not the track
2132 * we are looking for */
2133 if (!forward)
2135 int cur_idx = track_ridx;
2136 bool taginfo_ready = true;
2137 /* We've wrapped the buffer backwards if new > old */
2138 bool wrap = track_ridx > old_track_ridx;
2140 while (1)
2142 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
2144 /* if we've advanced past the wrap when cur_idx is zeroed */
2145 if (!cur_idx)
2146 wrap = false;
2148 /* if we aren't still on the wrap and we've caught the old track */
2149 if (!(wrap || cur_idx < old_track_ridx))
2150 break;
2152 /* If we hit a track in between without valid tag info, bail */
2153 if (!tracks[cur_idx].taginfo_ready)
2155 taginfo_ready = false;
2156 break;
2159 if (!taginfo_ready)
2161 audio_rebuffer();
2165 skip_done:
2166 audio_update_trackinfo();
2167 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2168 return Q_CODEC_REQUEST_COMPLETE;
2171 void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3))
2173 track_buffer_callback = handler;
2176 void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3))
2178 track_unbuffer_callback = handler;
2181 void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3))
2183 track_changed_callback = handler;
2186 unsigned long audio_prev_elapsed(void)
2188 return prev_track_elapsed;
2191 static void audio_stop_codec_flush(void)
2193 ci.stop_codec = true;
2194 pcmbuf_pause(true);
2196 while (audio_codec_loaded)
2197 yield();
2199 /* If the audio codec is not loaded any more, and the audio is still
2200 * playing, it is now and _only_ now safe to call this function from the
2201 * audio thread */
2202 if (pcm_is_playing())
2204 pcmbuf_play_stop();
2205 pcmbuf_queue_clear();
2207 pcmbuf_pause(paused);
2210 static void audio_stop_playback(void)
2212 /* If we were playing, save resume information */
2213 if (playing)
2215 struct mp3entry *id3 = NULL;
2217 if (!playlist_end || !ci.stop_codec)
2219 /* Set this early, the outside code yields and may allow the codec
2220 to try to wait for a reply on a buffer wait */
2221 ci.stop_codec = true;
2222 id3 = audio_current_track();
2225 /* Save the current playing spot, or NULL if the playlist has ended */
2226 playlist_update_resume_info(id3);
2228 /* TODO: Create auto bookmark too? */
2230 prev_track_elapsed = curtrack_id3.elapsed;
2232 /* At end of playlist save current id3 (id3.elapsed!) to buffer and
2233 * Increment index so runtime info is saved in audio_clear_track_entries().
2235 if ((playlist_end) && (tracks[track_ridx].id3_hid >= 0)) {
2236 copy_mp3entry(bufgetid3(tracks[track_ridx].id3_hid), &curtrack_id3);
2237 track_ridx = (track_ridx + 1) & MAX_TRACK_MASK;
2241 paused = false;
2242 audio_stop_codec_flush();
2243 playing = false;
2245 /* Mark all entries null. */
2246 audio_clear_track_entries(false);
2248 /* Close all tracks */
2249 audio_release_tracks();
2251 unregister_buffering_callback(buffering_audio_callback);
2253 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
2256 static void audio_play_start(size_t offset)
2258 int i;
2260 #if INPUT_SRC_CAPS != 0
2261 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2262 audio_set_output_source(AUDIO_SRC_PLAYBACK);
2263 #endif
2265 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2266 paused = false;
2267 audio_stop_codec_flush();
2269 track_changed = true;
2270 playlist_end = false;
2272 playing = true;
2274 ci.new_track = 0;
2275 ci.seek_time = 0;
2276 wps_offset = 0;
2278 sound_set_volume(global_settings.volume);
2279 track_widx = track_ridx = 0;
2281 /* Clear all track entries. */
2282 for (i = 0; i < MAX_TRACK; i++) {
2283 clear_track_info(&tracks[i]);
2286 last_peek_offset = -1;
2288 /* Officially playing */
2289 queue_reply(&audio_queue, 1);
2291 #ifndef HAVE_FLASH_STORAGE
2292 set_filebuf_watermark(buffer_margin, 0);
2293 #endif
2294 audio_fill_file_buffer(true, offset);
2295 register_buffering_callback(buffering_audio_callback);
2297 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2298 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
2302 /* Invalidates all but currently playing track. */
2303 static void audio_invalidate_tracks(void)
2305 if (audio_have_tracks())
2307 last_peek_offset = 0;
2308 playlist_end = false;
2309 track_widx = track_ridx;
2311 /* Mark all other entries null (also buffered wrong metadata). */
2312 audio_clear_track_entries(true);
2314 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2316 audio_fill_file_buffer(false, 0);
2320 static void audio_new_playlist(void)
2322 /* Prepare to start a new fill from the beginning of the playlist */
2323 last_peek_offset = -1;
2324 if (audio_have_tracks())
2326 if (paused)
2327 skipped_during_pause = true;
2328 playlist_end = false;
2329 track_widx = track_ridx;
2330 audio_clear_track_entries(true);
2332 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2334 /* Mark the current track as invalid to prevent skipping back to it */
2335 CUR_TI->taginfo_ready = false;
2338 /* Signal the codec to initiate a track change forward */
2339 new_playlist = true;
2340 ci.new_track = 1;
2342 /* Officially playing */
2343 queue_reply(&audio_queue, 1);
2345 audio_fill_file_buffer(false, 0);
2348 /* Called on manual track skip */
2349 static void audio_initiate_track_change(long direction)
2351 logf("audio_initiate_track_change(%ld)", direction);
2353 playlist_end = false;
2354 ci.new_track += direction;
2355 wps_offset -= direction;
2356 if (paused)
2357 skipped_during_pause = true;
2360 /* Called on manual dir skip */
2361 static void audio_initiate_dir_change(long direction)
2363 playlist_end = false;
2364 dir_skip = true;
2365 ci.new_track = direction;
2366 if (paused)
2367 skipped_during_pause = true;
2370 /* Called when PCM track change is complete */
2371 static void audio_finalise_track_change(void)
2373 logf("audio_finalise_track_change");
2375 if (automatic_skip)
2377 if (!auto_dir_skip)
2378 playlist_next(-wps_offset);
2380 wps_offset = 0;
2381 automatic_skip = false;
2384 auto_dir_skip = false;
2386 /* Invalidate prevtrack_id3 */
2387 prevtrack_id3.path[0] = 0;
2389 if (prev_ti && prev_ti->audio_hid < 0)
2391 /* No audio left so we clear all the track info. */
2392 clear_track_info(prev_ti);
2395 if (prev_ti && prev_ti->id3_hid >= 0)
2397 /* Reset the elapsed time to force the progressbar to be empty if
2398 the user skips back to this track */
2399 bufgetid3(prev_ti->id3_hid)->elapsed = 0;
2402 if (track_changed_callback)
2403 track_changed_callback(&curtrack_id3);
2405 track_changed = true;
2406 playlist_update_resume_info(audio_current_track());
2410 * Layout audio buffer as follows - iram buffer depends on target:
2411 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
2413 static void audio_reset_buffer(void)
2415 /* see audio_get_recording_buffer if this is modified */
2416 logf("audio_reset_buffer");
2418 /* If the setup of anything allocated before the file buffer is
2419 changed, do check the adjustments after the buffer_alloc call
2420 as it will likely be affected and need sliding over */
2422 /* Initially set up file buffer as all space available */
2423 malloc_buf = audiobuf + talk_get_bufsize();
2424 /* Align the malloc buf to line size. Especially important to cf
2425 targets that do line reads/writes. */
2426 malloc_buf = (unsigned char *)(((uintptr_t)malloc_buf + 15) & ~15);
2427 filebuf = malloc_buf + MALLOC_BUFSIZE; /* filebuf line align implied */
2428 filebuflen = audiobufend - filebuf;
2430 filebuflen &= ~15;
2432 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
2433 filebuflen -= pcmbuf_init(filebuf + filebuflen) + GUARD_BUFSIZE;
2435 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
2436 will already be line aligned */
2437 filebuflen &= ~3;
2439 buffering_reset(filebuf, filebuflen);
2441 /* Clear any references to the file buffer */
2442 buffer_state = BUFFER_STATE_INITIALIZED;
2444 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
2445 /* Make sure everything adds up - yes, some info is a bit redundant but
2446 aids viewing and the sumation of certain variables should add up to
2447 the location of others. */
2449 size_t pcmbufsize;
2450 unsigned char * pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
2451 logf("mabuf: %08X", (unsigned)malloc_buf);
2452 logf("mabufe: %08X", (unsigned)(malloc_buf + MALLOC_BUFSIZE));
2453 logf("fbuf: %08X", (unsigned)filebuf);
2454 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
2455 logf("gbuf: %08X", (unsigned)(filebuf + filebuflen));
2456 logf("gbufe: %08X", (unsigned)(filebuf + filebuflen + GUARD_BUFSIZE));
2457 logf("pcmb: %08X", (unsigned)pcmbuf);
2458 logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
2460 #endif
2463 static void audio_thread(void)
2465 struct queue_event ev;
2467 pcm_postinit();
2469 audio_thread_ready = true;
2471 while (1)
2473 cancel_cpu_boost();
2474 if (!pcmbuf_queue_scan(&ev))
2475 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
2477 switch (ev.id) {
2478 case Q_AUDIO_FILL_BUFFER:
2479 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
2480 if (!playing || playlist_end || ci.stop_codec)
2481 break;
2482 audio_fill_file_buffer(false, 0);
2483 break;
2485 case Q_AUDIO_PLAY:
2486 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2487 if (playing && ev.data <= 0)
2488 audio_new_playlist();
2489 else
2491 audio_stop_playback();
2492 audio_play_start((size_t)ev.data);
2494 break;
2496 case Q_AUDIO_STOP:
2497 LOGFQUEUE("audio < Q_AUDIO_STOP");
2498 if (playing)
2499 audio_stop_playback();
2500 if (ev.data != 0)
2501 queue_clear(&audio_queue);
2502 break;
2504 case Q_AUDIO_PAUSE:
2505 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
2506 if (!(bool) ev.data && skipped_during_pause && !pcmbuf_is_crossfade_active())
2507 pcmbuf_play_stop(); /* Flush old track on resume after skip */
2508 skipped_during_pause = false;
2509 if (!playing)
2510 break;
2511 pcmbuf_pause((bool)ev.data);
2512 paused = (bool)ev.data;
2513 break;
2515 case Q_AUDIO_SKIP:
2516 LOGFQUEUE("audio < Q_AUDIO_SKIP");
2517 audio_initiate_track_change((long)ev.data);
2518 break;
2520 case Q_AUDIO_PRE_FF_REWIND:
2521 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
2522 if (!playing)
2523 break;
2524 pcmbuf_pause(true);
2525 break;
2527 case Q_AUDIO_FF_REWIND:
2528 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
2529 if (!playing)
2530 break;
2531 if (automatic_skip)
2533 /* An automatic track skip is in progress. Finalize it,
2534 then go back to the previous track */
2535 audio_finalise_track_change();
2536 ci.new_track = -1;
2538 ci.seek_time = (long)ev.data+1;
2539 break;
2541 case Q_AUDIO_CHECK_NEW_TRACK:
2542 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
2543 queue_reply(&audio_queue, audio_check_new_track());
2544 break;
2546 case Q_AUDIO_DIR_SKIP:
2547 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2548 playlist_end = false;
2549 audio_initiate_dir_change(ev.data);
2550 break;
2552 case Q_AUDIO_FLUSH:
2553 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
2554 audio_invalidate_tracks();
2555 break;
2557 case Q_AUDIO_TRACK_CHANGED:
2558 /* PCM track change done */
2559 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2560 audio_finalise_track_change();
2561 break;
2563 #ifndef SIMULATOR
2564 case SYS_USB_CONNECTED:
2565 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2566 if (playing)
2567 audio_stop_playback();
2568 #ifdef PLAYBACK_VOICE
2569 voice_stop();
2570 #endif
2571 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2572 usb_wait_for_disconnect(&audio_queue);
2574 /* Mark all entries null. */
2575 audio_clear_track_entries(false);
2577 /* release tracks to make sure all handles are closed */
2578 audio_release_tracks();
2579 break;
2580 #endif
2582 case SYS_TIMEOUT:
2583 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
2584 break;
2586 default:
2587 LOGFQUEUE("audio < default");
2588 break;
2589 } /* end switch */
2590 } /* end while */
2593 #ifdef ROCKBOX_HAS_LOGF
2594 static void audio_test_track_changed_event(struct mp3entry *id3)
2596 (void)id3;
2598 logf("tce:%s", id3->path);
2600 #endif
2602 /* Initialize the audio system - called from init() in main.c.
2603 * Last function because of all the references to internal symbols
2605 void audio_init(void)
2607 struct thread_entry *audio_thread_p;
2609 /* Can never do this twice */
2610 if (audio_is_initialized)
2612 logf("audio: already initialized");
2613 return;
2616 logf("audio: initializing");
2618 /* Initialize queues before giving control elsewhere in case it likes
2619 to send messages. Thread creation will be delayed however so nothing
2620 starts running until ready if something yields such as talk_init. */
2621 queue_init(&audio_queue, true);
2622 queue_enable_queue_send(&audio_queue, &audio_queue_sender_list);
2623 queue_init(&codec_queue, false);
2624 queue_enable_queue_send(&codec_queue, &codec_queue_sender_list);
2625 queue_init(&pcmbuf_queue, false);
2627 pcm_init();
2629 #ifdef ROCKBOX_HAS_LOGF
2630 audio_set_track_changed_event(audio_test_track_changed_event);
2631 #endif
2633 /* Initialize codec api. */
2634 ci.read_filebuf = codec_filebuf_callback;
2635 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
2636 ci.get_codec_memory = codec_get_memory_callback;
2637 ci.request_buffer = codec_request_buffer_callback;
2638 ci.advance_buffer = codec_advance_buffer_callback;
2639 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
2640 ci.request_next_track = codec_request_next_track_callback;
2641 ci.mp3_get_filepos = codec_mp3_get_filepos_callback;
2642 ci.seek_buffer = codec_seek_buffer_callback;
2643 ci.seek_complete = codec_seek_complete_callback;
2644 ci.set_elapsed = codec_set_elapsed_callback;
2645 ci.set_offset = codec_set_offset_callback;
2646 ci.configure = codec_configure_callback;
2647 ci.discard_codec = codec_discard_codec_callback;
2648 ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP,
2649 CODEC_IDX_AUDIO);
2651 /* initialize the buffer */
2652 filebuf = audiobuf;
2654 /* audio_reset_buffer must to know the size of voice buffer so init
2655 talk first */
2656 talk_init();
2658 codec_thread_p = create_thread(
2659 codec_thread, codec_stack, sizeof(codec_stack),
2660 CREATE_THREAD_FROZEN,
2661 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
2662 IF_COP(, CPU));
2664 audio_thread_p = create_thread(audio_thread, audio_stack,
2665 sizeof(audio_stack), CREATE_THREAD_FROZEN,
2666 audio_thread_name IF_PRIO(, PRIORITY_SYSTEM)
2667 IF_COP(, CPU));
2669 #ifdef PLAYBACK_VOICE
2670 voice_thread_init();
2671 #endif
2673 /* Set crossfade setting for next buffer init which should be about... */
2674 pcmbuf_crossfade_enable(global_settings.crossfade);
2676 /* initialize the buffering system */
2678 buffering_init();
2679 /* ...now! Set up the buffers */
2680 audio_reset_buffer();
2682 int i;
2683 for(i = 0; i < MAX_TRACK; i++)
2685 tracks[i].audio_hid = -1;
2686 tracks[i].id3_hid = -1;
2687 tracks[i].codec_hid = -1;
2688 #ifdef HAVE_ALBUMART
2689 tracks[i].aa_hid = -1;
2690 #endif
2693 /* Probably safe to say */
2694 audio_is_initialized = true;
2696 sound_settings_apply();
2697 #ifndef HAVE_FLASH_STORAGE
2698 audio_set_buffer_margin(global_settings.buffer_margin);
2699 #endif
2701 /* it's safe to let the threads run now */
2702 #ifdef PLAYBACK_VOICE
2703 voice_thread_resume();
2704 #endif
2705 thread_thaw(codec_thread_p);
2706 thread_thaw(audio_thread_p);
2708 } /* audio_init */
2710 void audio_wait_for_init(void)
2712 /* audio thread will only set this once after it finished the final
2713 * audio hardware init so this little construct is safe - even
2714 * cross-core. */
2715 while (!audio_thread_ready)
2717 sleep(0);