D2: Fix inverted USB detection.
[Rockbox.git] / apps / playback.c
blob7eecd23e35b7cb0859bef30d9b01da717391a96f
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 */
215 static struct track_info tracks[MAX_TRACK];
216 static volatile int track_ridx = 0; /* Track being decoded (A/C-) */
217 static int track_widx = 0; /* Track being buffered (A) */
219 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
220 static struct track_info *prev_ti = NULL; /* Pointer to the previously played
221 track */
223 /* Set by the audio thread when the current track information has updated
224 * and the WPS may need to update its cached information */
225 static bool track_changed = false;
227 /* Information used only for filling the buffer */
228 /* Playlist steps from playing track to next track to be buffered (A) */
229 static int last_peek_offset = 0;
231 /* Scrobbler support */
232 static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/
234 /* Track change controls */
235 static bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */
236 static bool playlist_end = false; /* Has the current playlist ended? (A) */
237 static bool auto_dir_skip = false; /* Have we changed dirs automatically? */
238 static bool dir_skip = false; /* Is a directory skip pending? (A) */
239 static bool new_playlist = false; /* Are we starting a new playlist? (A) */
240 static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */
241 static bool skipped_during_pause = false; /* Do we need to clear the PCM buffer when playback resumes (A) */
243 /* Set to true if the codec thread should send an audio stop request
244 * (typically because the end of the playlist has been reached).
246 static bool codec_requested_stop = false;
248 static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */
250 /* Multiple threads */
251 /* Set the watermark to trigger buffer fill (A/C) FIXME */
252 static void set_filebuf_watermark(int seconds, size_t max);
254 /* Audio thread */
255 static struct event_queue audio_queue NOCACHEBSS_ATTR;
256 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR;
257 static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
258 static const char audio_thread_name[] = "audio";
260 static void audio_thread(void);
261 static void audio_initiate_track_change(long direction);
262 static bool audio_have_tracks(void);
263 static void audio_reset_buffer(void);
265 /* Codec thread */
266 extern struct codec_api ci;
267 static struct event_queue codec_queue NOCACHEBSS_ATTR;
268 static struct queue_sender_list codec_queue_sender_list;
269 static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
270 IBSS_ATTR;
271 static const char codec_thread_name[] = "codec";
272 struct thread_entry *codec_thread_p; /* For modifying thread priority later. */
274 /* PCM buffer messaging */
275 static struct event_queue pcmbuf_queue NOCACHEBSS_ATTR;
277 /* Function to be called by pcm buffer callbacks.
278 * Permissible Context(s): Audio interrupt
280 static void pcmbuf_callback_queue_post(long id, intptr_t data)
282 /* No lock since we're already in audio interrupt context */
283 queue_post(&pcmbuf_queue, id, data);
286 /* Scan the pcmbuf queue and return true if a message pulled.
287 * Permissible Context(s): Thread
289 static bool pcmbuf_queue_scan(struct queue_event *ev)
291 if (!queue_empty(&pcmbuf_queue))
293 /* Transfer message to audio queue */
294 pcm_play_lock();
295 /* Pull message - never, ever any blocking call! */
296 queue_wait_w_tmo(&pcmbuf_queue, ev, 0);
297 pcm_play_unlock();
298 return true;
301 return false;
304 /* Clear the pcmbuf queue of messages
305 * Permissible Context(s): Thread
307 static void pcmbuf_queue_clear(void)
309 pcm_play_lock();
310 queue_clear(&pcmbuf_queue);
311 pcm_play_unlock();
314 /* --- Helper functions --- */
316 static struct mp3entry *bufgetid3(int handle_id)
318 if (handle_id < 0)
319 return NULL;
321 struct mp3entry *id3;
322 ssize_t ret = bufgetdata(handle_id, 0, (void *)&id3);
324 if (ret < 0 || ret != sizeof(struct mp3entry))
325 return NULL;
327 return id3;
330 static bool clear_track_info(struct track_info *track)
332 /* bufclose returns true if the handle is not found, or if it is closed
333 * successfully, so these checks are safe on non-existant handles */
334 if (!track)
335 return false;
337 if (track->codec_hid >= 0) {
338 if (bufclose(track->codec_hid))
339 track->codec_hid = -1;
340 else
341 return false;
344 if (track->id3_hid >= 0) {
345 if (bufclose(track->id3_hid))
346 track->id3_hid = -1;
347 else
348 return false;
351 if (track->audio_hid >= 0) {
352 if (bufclose(track->audio_hid))
353 track->audio_hid = -1;
354 else
355 return false;
358 #ifdef HAVE_ALBUMART
359 if (track->aa_hid >= 0) {
360 if (bufclose(track->aa_hid))
361 track->aa_hid = -1;
362 else
363 return false;
365 #endif
367 track->filesize = 0;
368 track->taginfo_ready = false;
370 return true;
373 /* --- External interfaces --- */
375 /* This sends a stop message and the audio thread will dump all it's
376 subsequenct messages */
377 void audio_hard_stop(void)
379 /* Stop playback */
380 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
381 queue_send(&audio_queue, Q_AUDIO_STOP, 1);
382 #ifdef PLAYBACK_VOICE
383 voice_stop();
384 #endif
387 bool audio_restore_playback(int type)
389 switch (type)
391 case AUDIO_WANT_PLAYBACK:
392 if (buffer_state != BUFFER_STATE_INITIALIZED)
393 audio_reset_buffer();
394 return true;
395 case AUDIO_WANT_VOICE:
396 if (buffer_state == BUFFER_STATE_TRASHED)
397 audio_reset_buffer();
398 return true;
399 default:
400 return false;
404 unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
406 unsigned char *buf, *end;
408 if (audio_is_initialized)
410 audio_hard_stop();
412 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
414 if (buffer_size == NULL)
416 /* Special case for talk_init to use since it already knows it's
417 trashed */
418 buffer_state = BUFFER_STATE_TRASHED;
419 return NULL;
422 if (talk_buf || buffer_state == BUFFER_STATE_TRASHED
423 || !talk_voice_required())
425 logf("get buffer: talk, audio");
426 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
427 the talk buffer is not needed because voice isn't being used, or
428 could be BUFFER_STATE_TRASHED already. If state is
429 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
430 without the caller knowing what's going on. Changing certain settings
431 may move it to a worse condition but the memory in use by something
432 else will remain undisturbed.
434 if (buffer_state != BUFFER_STATE_TRASHED)
436 talk_buffer_steal();
437 buffer_state = BUFFER_STATE_TRASHED;
440 buf = audiobuf;
441 end = audiobufend;
443 else
445 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
446 still BUFFER_STATE_INITIALIZED */
447 /* Skip talk buffer and move pcm buffer to end to maximize available
448 contiguous memory - no audio running means voice will not need the
449 swap space */
450 logf("get buffer: audio");
451 buf = audiobuf + talk_get_bufsize();
452 end = audiobufend - pcmbuf_init(audiobufend);
453 buffer_state = BUFFER_STATE_VOICED_ONLY;
456 *buffer_size = end - buf;
458 return buf;
461 #ifdef HAVE_RECORDING
462 unsigned char *audio_get_recording_buffer(size_t *buffer_size)
464 /* Stop audio, voice and obtain all available buffer space */
465 audio_hard_stop();
466 talk_buffer_steal();
468 unsigned char *end = audiobufend;
469 buffer_state = BUFFER_STATE_TRASHED;
470 *buffer_size = end - audiobuf;
472 return (unsigned char *)audiobuf;
475 bool audio_load_encoder(int afmt)
477 #ifndef SIMULATOR
478 const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER);
479 if (!enc_fn)
480 return false;
482 audio_remove_encoder();
483 ci.enc_codec_loaded = 0; /* clear any previous error condition */
485 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
486 queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (intptr_t)enc_fn);
488 while (ci.enc_codec_loaded == 0)
489 yield();
491 logf("codec loaded: %d", ci.enc_codec_loaded);
493 return ci.enc_codec_loaded > 0;
494 #else
495 (void)afmt;
496 return true;
497 #endif
498 } /* audio_load_encoder */
500 void audio_remove_encoder(void)
502 #ifndef SIMULATOR
503 /* force encoder codec unload (if currently loaded) */
504 if (ci.enc_codec_loaded <= 0)
505 return;
507 ci.stop_encoder = true;
508 while (ci.enc_codec_loaded > 0)
509 yield();
510 #endif
511 } /* audio_remove_encoder */
513 #endif /* HAVE_RECORDING */
515 #ifdef HAVE_ALBUMART
516 int audio_current_aa_hid(void)
518 int cur_idx;
519 int offset = ci.new_track + wps_offset;
521 cur_idx = track_ridx + offset;
522 cur_idx &= MAX_TRACK_MASK;
524 return tracks[cur_idx].aa_hid;
526 #endif
528 struct mp3entry* audio_current_track(void)
530 const char *filename;
531 const char *p;
532 static struct mp3entry temp_id3;
533 int cur_idx;
534 int offset = ci.new_track + wps_offset;
536 cur_idx = (track_ridx + offset) & MAX_TRACK_MASK;
538 if (cur_idx == track_ridx && *curtrack_id3.path)
540 /* The usual case */
541 return &curtrack_id3;
543 else if (offset == -1 && *prevtrack_id3.path)
545 /* We're in a track transition. The codec has moved on to the nex track,
546 but the audio being played is still the same (now previous) track.
547 prevtrack_id3.elapsed is being updated in an ISR by
548 codec_pcmbuf_position_callback */
549 return &prevtrack_id3;
551 else if (tracks[cur_idx].id3_hid >= 0)
553 /* Get the ID3 metadata from the main buffer */
554 return bufgetid3(tracks[cur_idx].id3_hid);
557 /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info
558 we have and return that. */
560 memset(&temp_id3, 0, sizeof(struct mp3entry));
562 filename = playlist_peek(0);
563 if (!filename)
564 filename = "No file!";
566 #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
567 if (tagcache_fill_tags(&temp_id3, filename))
568 return &temp_id3;
569 #endif
571 p = strrchr(filename, '/');
572 if (!p)
573 p = filename;
574 else
575 p++;
577 strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1);
578 temp_id3.title = &temp_id3.path[0];
580 return &temp_id3;
583 struct mp3entry* audio_next_track(void)
585 int next_idx;
586 int offset = ci.new_track + wps_offset;
588 if (!audio_have_tracks())
589 return NULL;
591 if (wps_offset == -1 && *prevtrack_id3.path)
593 /* We're in a track transition. The next track for the WPS is the one
594 currently being decoded. */
595 return &curtrack_id3;
598 next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK;
600 if (next_idx == track_widx)
602 /* The next track hasn't been buffered yet, so we return the static
603 version of its metadata. */
604 return &lasttrack_id3;
607 if (tracks[next_idx].id3_hid < 0)
608 return NULL;
609 else
610 return bufgetid3(tracks[next_idx].id3_hid);
613 bool audio_has_changed_track(void)
615 if (track_changed)
617 track_changed = false;
618 return true;
621 return false;
624 void audio_play(long offset)
626 logf("audio_play");
628 #ifdef PLAYBACK_VOICE
629 /* Truncate any existing voice output so we don't have spelling
630 * etc. over the first part of the played track */
631 talk_force_shutup();
632 #endif
634 /* Start playback */
635 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset);
636 /* Don't return until playback has actually started */
637 queue_send(&audio_queue, Q_AUDIO_PLAY, offset);
640 void audio_stop(void)
642 /* Stop playback */
643 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
644 /* Don't return until playback has actually stopped */
645 queue_send(&audio_queue, Q_AUDIO_STOP, 0);
648 void audio_pause(void)
650 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
651 /* Don't return until playback has actually paused */
652 queue_send(&audio_queue, Q_AUDIO_PAUSE, true);
655 void audio_resume(void)
657 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
658 /* Don't return until playback has actually resumed */
659 queue_send(&audio_queue, Q_AUDIO_PAUSE, false);
662 static void audio_skip(int direction)
664 if (playlist_check(ci.new_track + wps_offset + direction))
666 if (global_settings.beep)
667 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
669 LOGFQUEUE("audio > audio Q_AUDIO_SKIP %d", direction);
670 queue_post(&audio_queue, Q_AUDIO_SKIP, direction);
671 /* Update wps while our message travels inside deep playback queues. */
672 wps_offset += direction;
673 /* Immediately update the playlist index */
674 playlist_next(direction);
675 track_changed = true;
677 else
679 /* No more tracks. */
680 if (global_settings.beep)
681 pcmbuf_beep(1000, 100, 1000*global_settings.beep);
685 void audio_next(void)
687 audio_skip(1);
690 void audio_prev(void)
692 audio_skip(-1);
695 void audio_next_dir(void)
697 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
698 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, 1);
701 void audio_prev_dir(void)
703 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
704 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, -1);
707 void audio_pre_ff_rewind(void)
709 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
710 queue_post(&audio_queue, Q_AUDIO_PRE_FF_REWIND, 0);
713 void audio_ff_rewind(long newpos)
715 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
716 queue_post(&audio_queue, Q_AUDIO_FF_REWIND, newpos);
719 void audio_flush_and_reload_tracks(void)
721 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
722 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0);
725 void audio_error_clear(void)
727 #ifdef AUDIO_HAVE_RECORDING
728 pcm_rec_error_clear();
729 #endif
732 int audio_status(void)
734 int ret = 0;
736 if (playing)
737 ret |= AUDIO_STATUS_PLAY;
739 if (paused)
740 ret |= AUDIO_STATUS_PAUSE;
742 #ifdef HAVE_RECORDING
743 /* Do this here for constitency with mpeg.c version */
744 ret |= pcm_rec_status();
745 #endif
747 return ret;
750 int audio_get_file_pos(void)
752 return 0;
755 #ifndef HAVE_FLASH_STORAGE
756 void audio_set_buffer_margin(int setting)
758 static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
759 buffer_margin = lookup[setting];
760 logf("buffer margin: %ld", (long)buffer_margin);
761 set_filebuf_watermark(buffer_margin, 0);
763 #endif
765 /* Take nescessary steps to enable or disable the crossfade setting */
766 void audio_set_crossfade(int enable)
768 size_t offset;
769 bool was_playing;
770 size_t size;
772 /* Tell it the next setting to use */
773 pcmbuf_crossfade_enable(enable);
775 /* Return if size hasn't changed or this is too early to determine
776 which in the second case there's no way we could be playing
777 anything at all */
778 if (pcmbuf_is_same_size())
780 /* This function is a copout and just syncs some variables -
781 to be removed at a later date */
782 pcmbuf_crossfade_enable_finished();
783 return;
786 offset = 0;
787 was_playing = playing;
789 /* Playback has to be stopped before changing the buffer size */
790 if (was_playing)
792 /* Store the track resume position */
793 offset = curtrack_id3.offset;
794 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK));
797 /* Blast it - audio buffer will have to be setup again next time
798 something plays */
799 audio_get_buffer(true, &size);
801 /* Restart playback if audio was running previously */
802 if (was_playing)
803 audio_play(offset);
806 /* --- Routines called from multiple threads --- */
808 static void set_filebuf_watermark(int seconds, size_t max)
810 size_t bytes;
812 if (!filebuf)
813 return; /* Audio buffers not yet set up */
815 bytes = seconds?MAX(curtrack_id3.bitrate * seconds * (1000/8), max):max;
816 bytes = MIN(bytes, filebuflen / 2);
817 buf_set_watermark(bytes);
820 const char * get_codec_filename(int cod_spec)
822 const char *fname;
824 #ifdef HAVE_RECORDING
825 /* Can choose decoder or encoder if one available */
826 int type = cod_spec & CODEC_TYPE_MASK;
827 int afmt = cod_spec & CODEC_AFMT_MASK;
829 if ((unsigned)afmt >= AFMT_NUM_CODECS)
830 type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
832 fname = (type == CODEC_TYPE_ENCODER) ?
833 audio_formats[afmt].codec_enc_root_fn :
834 audio_formats[afmt].codec_root_fn;
836 logf("%s: %d - %s",
837 (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
838 afmt, fname ? fname : "<unknown>");
839 #else /* !HAVE_RECORDING */
840 /* Always decoder */
841 if ((unsigned)cod_spec >= AFMT_NUM_CODECS)
842 cod_spec = AFMT_UNKNOWN;
843 fname = audio_formats[cod_spec].codec_root_fn;
844 logf("Codec: %d - %s", cod_spec, fname ? fname : "<unknown>");
845 #endif /* HAVE_RECORDING */
847 return fname;
848 } /* get_codec_filename */
850 /* --- Codec thread --- */
851 static bool codec_pcmbuf_insert_callback(
852 const void *ch1, const void *ch2, int count)
854 const char *src[2] = { ch1, ch2 };
856 while (count > 0)
858 int out_count = dsp_output_count(ci.dsp, count);
859 int inp_count;
860 char *dest;
862 /* Prevent audio from a previous track from playing */
863 if (ci.new_track || ci.stop_codec)
864 return true;
866 while ((dest = pcmbuf_request_buffer(&out_count)) == NULL)
868 cancel_cpu_boost();
869 sleep(1);
870 if (ci.seek_time || ci.new_track || ci.stop_codec)
871 return true;
874 /* Get the real input_size for output_size bytes, guarding
875 * against resampling buffer overflows. */
876 inp_count = dsp_input_count(ci.dsp, out_count);
878 if (inp_count <= 0)
879 return true;
881 /* Input size has grown, no error, just don't write more than length */
882 if (inp_count > count)
883 inp_count = count;
885 out_count = dsp_process(ci.dsp, dest, src, inp_count);
887 if (out_count <= 0)
888 return true;
890 pcmbuf_write_complete(out_count);
892 count -= inp_count;
895 return true;
896 } /* codec_pcmbuf_insert_callback */
898 static void* codec_get_memory_callback(size_t *size)
900 *size = MALLOC_BUFSIZE;
901 return malloc_buf;
904 /* Between the codec and PCM track change, we need to keep updating the
905 "elapsed" value of the previous (to the codec, but current to the
906 user/PCM/WPS) track, so that the progressbar reaches the end.
907 During that transition, the WPS will display prevtrack_id3. */
908 static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
909 static void codec_pcmbuf_position_callback(size_t size)
911 /* This is called from an ISR, so be quick */
912 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
913 prevtrack_id3.elapsed;
915 if (time >= prevtrack_id3.length)
917 pcmbuf_set_position_callback(NULL);
918 prevtrack_id3.elapsed = prevtrack_id3.length;
920 else
921 prevtrack_id3.elapsed = time;
924 static void codec_set_elapsed_callback(unsigned int value)
926 unsigned int latency;
927 if (ci.seek_time)
928 return;
930 #ifdef AB_REPEAT_ENABLE
931 ab_position_report(value);
932 #endif
934 latency = pcmbuf_get_latency();
935 if (value < latency)
936 curtrack_id3.elapsed = 0;
937 else if (value - latency > curtrack_id3.elapsed ||
938 value - latency < curtrack_id3.elapsed - 2)
940 curtrack_id3.elapsed = value - latency;
944 static void codec_set_offset_callback(size_t value)
946 unsigned int latency;
948 if (ci.seek_time)
949 return;
951 latency = pcmbuf_get_latency() * curtrack_id3.bitrate / 8;
952 if (value < latency)
953 curtrack_id3.offset = 0;
954 else
955 curtrack_id3.offset = value - latency;
958 static void codec_advance_buffer_counters(size_t amount)
960 bufadvance(CUR_TI->audio_hid, amount);
961 ci.curpos += amount;
964 /* copy up-to size bytes into ptr and return the actual size copied */
965 static size_t codec_filebuf_callback(void *ptr, size_t size)
967 ssize_t copy_n;
969 if (ci.stop_codec || !playing)
970 return 0;
972 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
974 /* Nothing requested OR nothing left */
975 if (copy_n == 0)
976 return 0;
978 /* Update read and other position pointers */
979 codec_advance_buffer_counters(copy_n);
981 /* Return the actual amount of data copied to the buffer */
982 return copy_n;
983 } /* codec_filebuf_callback */
985 static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
987 size_t copy_n = reqsize;
988 ssize_t ret;
989 void *ptr;
991 if (!playing)
993 *realsize = 0;
994 return NULL;
997 ret = bufgetdata(CUR_TI->audio_hid, reqsize, &ptr);
998 if (ret >= 0)
999 copy_n = MIN((size_t)ret, reqsize);
1001 if (copy_n == 0)
1003 *realsize = 0;
1004 return NULL;
1007 *realsize = copy_n;
1009 return ptr;
1010 } /* codec_request_buffer_callback */
1012 static int get_codec_base_type(int type)
1014 switch (type) {
1015 case AFMT_MPA_L1:
1016 case AFMT_MPA_L2:
1017 case AFMT_MPA_L3:
1018 return AFMT_MPA_L3;
1021 return type;
1024 static void codec_advance_buffer_callback(size_t amount)
1026 codec_advance_buffer_counters(amount);
1027 codec_set_offset_callback(ci.curpos);
1030 static void codec_advance_buffer_loc_callback(void *ptr)
1032 size_t amount = buf_get_offset(CUR_TI->audio_hid, ptr);
1033 codec_advance_buffer_callback(amount);
1036 /* Copied from mpeg.c. Should be moved somewhere else. */
1037 static int codec_get_file_pos(void)
1039 int pos = -1;
1040 struct mp3entry *id3 = audio_current_track();
1042 if (id3->vbr)
1044 if (id3->has_toc)
1046 /* Use the TOC to find the new position */
1047 unsigned int percent, remainder;
1048 int curtoc, nexttoc, plen;
1050 percent = (id3->elapsed*100)/id3->length;
1051 if (percent > 99)
1052 percent = 99;
1054 curtoc = id3->toc[percent];
1056 if (percent < 99)
1057 nexttoc = id3->toc[percent+1];
1058 else
1059 nexttoc = 256;
1061 pos = (id3->filesize/256)*curtoc;
1063 /* Use the remainder to get a more accurate position */
1064 remainder = (id3->elapsed*100)%id3->length;
1065 remainder = (remainder*100)/id3->length;
1066 plen = (nexttoc - curtoc)*(id3->filesize/256);
1067 pos += (plen/100)*remainder;
1069 else
1071 /* No TOC exists, estimate the new position */
1072 pos = (id3->filesize / (id3->length / 1000)) *
1073 (id3->elapsed / 1000);
1076 else if (id3->bitrate)
1077 pos = id3->elapsed * (id3->bitrate / 8);
1078 else
1079 return -1;
1081 pos += id3->first_frame_offset;
1083 /* Don't seek right to the end of the file so that we can
1084 transition properly to the next song */
1085 if (pos >= (int)(id3->filesize - id3->id3v1len))
1086 pos = id3->filesize - id3->id3v1len - 1;
1088 return pos;
1091 static off_t codec_mp3_get_filepos_callback(int newtime)
1093 off_t newpos;
1095 curtrack_id3.elapsed = newtime;
1096 newpos = codec_get_file_pos();
1098 return newpos;
1101 static void codec_seek_complete_callback(void)
1103 logf("seek_complete");
1104 if (pcm_is_paused())
1106 /* If this is not a seamless seek, clear the buffer */
1107 pcmbuf_play_stop();
1108 dsp_configure(ci.dsp, DSP_FLUSH, 0);
1110 /* If playback was not 'deliberately' paused, unpause now */
1111 if (!paused)
1112 pcmbuf_pause(false);
1114 ci.seek_time = 0;
1117 static bool codec_seek_buffer_callback(size_t newpos)
1119 logf("codec_seek_buffer_callback");
1121 int ret = bufseek(CUR_TI->audio_hid, newpos);
1122 if (ret == 0) {
1123 ci.curpos = newpos;
1124 return true;
1126 else {
1127 return false;
1131 static void codec_configure_callback(int setting, intptr_t value)
1133 switch (setting) {
1134 case CODEC_SET_FILEBUF_WATERMARK:
1135 set_filebuf_watermark(buffer_margin, value);
1136 break;
1138 default:
1139 if (!dsp_configure(ci.dsp, setting, value))
1140 { logf("Illegal key:%d", setting); }
1144 static void codec_track_changed(void)
1146 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1147 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1150 static void codec_pcmbuf_track_changed_callback(void)
1152 pcmbuf_set_position_callback(NULL);
1153 pcmbuf_callback_queue_post(Q_AUDIO_TRACK_CHANGED, 0);
1156 static void codec_discard_codec_callback(void)
1158 if (CUR_TI->codec_hid >= 0)
1160 bufclose(CUR_TI->codec_hid);
1161 CUR_TI->codec_hid = -1;
1165 static inline void codec_gapless_track_change(void)
1167 /* callback keeps the progress bar moving while the pcmbuf empties */
1168 pcmbuf_set_position_callback(codec_pcmbuf_position_callback);
1169 /* set the pcmbuf callback for when the track really changes */
1170 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
1173 static inline void codec_crossfade_track_change(void)
1175 /* Initiate automatic crossfade mode */
1176 pcmbuf_crossfade_init(false);
1177 /* Notify the wps that the track change starts now */
1178 codec_track_changed();
1181 static void codec_track_skip_done(bool was_manual)
1183 /* Manual track change (always crossfade or flush audio). */
1184 if (was_manual)
1186 pcmbuf_crossfade_init(true);
1187 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1188 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1190 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1191 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1192 && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP)
1194 if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
1196 if (global_settings.playlist_shuffle)
1197 /* shuffle mode is on, so crossfade: */
1198 codec_crossfade_track_change();
1199 else
1200 /* shuffle mode is off, so do a gapless track change */
1201 codec_gapless_track_change();
1203 else
1204 /* normal crossfade: */
1205 codec_crossfade_track_change();
1207 else
1208 /* normal gapless playback. */
1209 codec_gapless_track_change();
1212 static bool codec_load_next_track(void)
1214 intptr_t result = Q_CODEC_REQUEST_FAILED;
1216 prev_track_elapsed = curtrack_id3.elapsed;
1218 #ifdef AB_REPEAT_ENABLE
1219 ab_end_of_track_report();
1220 #endif
1222 logf("Request new track");
1224 if (ci.new_track == 0)
1226 ci.new_track++;
1227 automatic_skip = true;
1230 if (!ci.stop_codec)
1232 trigger_cpu_boost();
1233 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1234 result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
1237 switch (result)
1239 case Q_CODEC_REQUEST_COMPLETE:
1240 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1241 codec_track_skip_done(!automatic_skip);
1242 return true;
1244 case Q_CODEC_REQUEST_FAILED:
1245 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1246 ci.new_track = 0;
1247 ci.stop_codec = true;
1248 codec_requested_stop = true;
1249 return false;
1251 default:
1252 LOGFQUEUE("codec |< default");
1253 ci.stop_codec = true;
1254 codec_requested_stop = true;
1255 return false;
1259 static bool codec_request_next_track_callback(void)
1261 int prev_codectype;
1263 if (ci.stop_codec || !playing)
1264 return false;
1266 prev_codectype = get_codec_base_type(curtrack_id3.codectype);
1268 if (!codec_load_next_track())
1269 return false;
1271 /* Check if the next codec is the same file. */
1272 if (prev_codectype == get_codec_base_type(curtrack_id3.codectype))
1274 logf("New track loaded");
1275 codec_discard_codec_callback();
1276 return true;
1278 else
1280 logf("New codec:%d/%d", curtrack_id3.codectype, prev_codectype);
1281 return false;
1285 static void codec_thread(void)
1287 struct queue_event ev;
1288 int status;
1290 while (1) {
1291 status = 0;
1292 cancel_cpu_boost();
1293 queue_wait(&codec_queue, &ev);
1294 codec_requested_stop = false;
1296 switch (ev.id) {
1297 case Q_CODEC_LOAD_DISK:
1298 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1299 queue_reply(&codec_queue, 1);
1300 audio_codec_loaded = true;
1301 ci.stop_codec = false;
1302 status = codec_load_file((const char *)ev.data, &ci);
1303 break;
1305 case Q_CODEC_LOAD:
1306 LOGFQUEUE("codec < Q_CODEC_LOAD");
1307 if (CUR_TI->codec_hid < 0) {
1308 logf("Codec slot is empty!");
1309 /* Wait for the pcm buffer to go empty */
1310 while (pcm_is_playing())
1311 yield();
1312 /* This must be set to prevent an infinite loop */
1313 ci.stop_codec = true;
1314 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1315 queue_post(&codec_queue, Q_AUDIO_PLAY, 0);
1316 break;
1319 audio_codec_loaded = true;
1320 ci.stop_codec = false;
1321 status = codec_load_buf(CUR_TI->codec_hid, &ci);
1322 break;
1324 #ifdef AUDIO_HAVE_RECORDING
1325 case Q_ENCODER_LOAD_DISK:
1326 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1327 audio_codec_loaded = false; /* Not audio codec! */
1328 logf("loading encoder");
1329 ci.stop_encoder = false;
1330 status = codec_load_file((const char *)ev.data, &ci);
1331 logf("encoder stopped");
1332 break;
1333 #endif /* AUDIO_HAVE_RECORDING */
1335 default:
1336 LOGFQUEUE("codec < default");
1339 if (audio_codec_loaded)
1341 if (ci.stop_codec)
1343 status = CODEC_OK;
1344 if (!playing)
1345 pcmbuf_play_stop();
1348 audio_codec_loaded = false;
1351 switch (ev.id) {
1352 case Q_CODEC_LOAD_DISK:
1353 case Q_CODEC_LOAD:
1354 LOGFQUEUE("codec < Q_CODEC_LOAD");
1355 if (playing)
1357 if (ci.new_track || status != CODEC_OK)
1359 if (!ci.new_track)
1361 logf("Codec failure");
1362 gui_syncsplash(HZ*2, "Codec failure");
1365 if (!codec_load_next_track())
1367 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1368 /* End of playlist */
1369 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1370 break;
1373 else
1375 logf("Codec finished");
1376 if (ci.stop_codec)
1378 /* Wait for the audio to stop playing before
1379 * triggering the WPS exit */
1380 while(pcm_is_playing())
1382 curtrack_id3.elapsed =
1383 curtrack_id3.length - pcmbuf_get_latency();
1384 sleep(1);
1387 if (codec_requested_stop)
1389 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1390 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1392 break;
1396 if (CUR_TI->codec_hid >= 0)
1398 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1399 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
1401 else
1403 const char *codec_fn =
1404 get_codec_filename(curtrack_id3.codectype);
1405 if (codec_fn)
1407 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1408 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
1409 (intptr_t)codec_fn);
1413 break;
1415 #ifdef AUDIO_HAVE_RECORDING
1416 case Q_ENCODER_LOAD_DISK:
1417 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1419 if (status == CODEC_OK)
1420 break;
1422 logf("Encoder failure");
1423 gui_syncsplash(HZ*2, "Encoder failure");
1425 if (ci.enc_codec_loaded < 0)
1426 break;
1428 logf("Encoder failed to load");
1429 ci.enc_codec_loaded = -1;
1430 break;
1431 #endif /* AUDIO_HAVE_RECORDING */
1433 default:
1434 LOGFQUEUE("codec < default");
1436 } /* end switch */
1441 /* --- Audio thread --- */
1443 static bool audio_have_tracks(void)
1445 return (audio_track_count() != 0);
1448 static int audio_free_track_count(void)
1450 /* Used tracks + free tracks adds up to MAX_TRACK - 1 */
1451 return MAX_TRACK - 1 - audio_track_count();
1454 int audio_track_count(void)
1456 /* Calculate difference from track_ridx to track_widx
1457 * taking into account a possible wrap-around. */
1458 return (MAX_TRACK + track_widx - track_ridx) & MAX_TRACK_MASK;
1461 long audio_filebufused(void)
1463 return (long) buf_used();
1466 /* Update track info after successful a codec track change */
1467 static void audio_update_trackinfo(void)
1469 /* Load the curent track's metadata into curtrack_id3 */
1470 CUR_TI->taginfo_ready = (CUR_TI->id3_hid >= 0);
1471 if (CUR_TI->id3_hid >= 0)
1472 copy_mp3entry(&curtrack_id3, bufgetid3(CUR_TI->id3_hid));
1474 int next_idx = (track_ridx + 1) & MAX_TRACK_MASK;
1475 tracks[next_idx].taginfo_ready = (tracks[next_idx].id3_hid >= 0);
1477 /* Reset current position */
1478 curtrack_id3.elapsed = 0;
1479 curtrack_id3.offset = 0;
1481 /* Update the codec API */
1482 ci.filesize = CUR_TI->filesize;
1483 ci.id3 = &curtrack_id3;
1484 ci.curpos = 0;
1485 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1488 static void buffering_audio_callback(enum callback_event ev, int value)
1490 (void)value;
1491 logf("buffering_audio_callback");
1493 switch (ev)
1495 case EVENT_BUFFER_LOW:
1496 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1497 queue_remove_from_head(&audio_queue, Q_AUDIO_FILL_BUFFER);
1498 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1499 break;
1501 case EVENT_HANDLE_REBUFFER:
1502 LOGFQUEUE("audio >| audio Q_AUDIO_FLUSH");
1503 queue_send(&audio_queue, Q_AUDIO_FLUSH, 0);
1504 break;
1506 case EVENT_HANDLE_FINISHED:
1507 logf("handle %d finished buffering", value);
1508 strip_tags(value);
1509 break;
1511 default:
1512 break;
1516 /* Clear tracks between write and read, non inclusive */
1517 static void audio_clear_track_entries(void)
1519 int cur_idx = track_widx;
1521 logf("Clearing tracks:%d/%d", track_ridx, track_widx);
1523 /* Loop over all tracks from write-to-read */
1524 while (1)
1526 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
1528 if (cur_idx == track_ridx)
1529 break;
1531 clear_track_info(&tracks[cur_idx]);
1535 /* Clear all tracks */
1536 static bool audio_release_tracks(void)
1538 int i, cur_idx;
1540 logf("releasing all tracks");
1542 for(i = 0; i < MAX_TRACK; i++)
1544 cur_idx = (track_ridx + i) & MAX_TRACK_MASK;
1545 if (!clear_track_info(&tracks[cur_idx]))
1546 return false;
1549 return true;
1552 static bool audio_loadcodec(bool start_play)
1554 int prev_track;
1555 char codec_path[MAX_PATH]; /* Full path to codec */
1557 if (tracks[track_widx].id3_hid < 0) {
1558 return false;
1561 const char * codec_fn =
1562 get_codec_filename(bufgetid3(tracks[track_widx].id3_hid)->codectype);
1563 if (codec_fn == NULL)
1564 return false;
1566 tracks[track_widx].codec_hid = -1;
1568 if (start_play)
1570 /* Load the codec directly from disk and save some memory. */
1571 track_ridx = track_widx;
1572 ci.filesize = CUR_TI->filesize;
1573 ci.id3 = &curtrack_id3;
1574 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1575 ci.curpos = 0;
1576 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1577 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (intptr_t)codec_fn);
1578 return true;
1580 else
1582 /* If we already have another track than this one buffered */
1583 if (track_widx != track_ridx)
1585 prev_track = (track_widx - 1) & MAX_TRACK_MASK;
1587 /* If the previous codec is the same as this one, there is no need
1588 * to put another copy of it on the file buffer */
1589 if (get_codec_base_type(
1590 bufgetid3(tracks[track_widx].id3_hid)->codectype) ==
1591 get_codec_base_type(
1592 bufgetid3(tracks[prev_track].id3_hid)->codectype)
1593 && audio_codec_loaded)
1595 logf("Reusing prev. codec");
1596 return true;
1601 codec_get_full_path(codec_path, codec_fn);
1603 tracks[track_widx].codec_hid = bufopen(codec_path, 0, TYPE_CODEC);
1604 if (tracks[track_widx].codec_hid < 0)
1605 return false;
1607 logf("Loaded codec");
1609 return true;
1612 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
1613 static void audio_set_elapsed(struct mp3entry* id3)
1615 unsigned long offset = id3->offset > id3->first_frame_offset ?
1616 id3->offset - id3->first_frame_offset : 0;
1618 if ( id3->vbr ) {
1619 if ( id3->has_toc ) {
1620 /* calculate elapsed time using TOC */
1621 int i;
1622 unsigned int remainder, plen, relpos, nextpos;
1624 /* find wich percent we're at */
1625 for (i=0; i<100; i++ )
1626 if ( offset < id3->toc[i] * (id3->filesize / 256) )
1627 break;
1629 i--;
1630 if (i < 0)
1631 i = 0;
1633 relpos = id3->toc[i];
1635 if (i < 99)
1636 nextpos = id3->toc[i+1];
1637 else
1638 nextpos = 256;
1640 remainder = offset - (relpos * (id3->filesize / 256));
1642 /* set time for this percent (divide before multiply to prevent
1643 overflow on long files. loss of precision is negligible on
1644 short files) */
1645 id3->elapsed = i * (id3->length / 100);
1647 /* calculate remainder time */
1648 plen = (nextpos - relpos) * (id3->filesize / 256);
1649 id3->elapsed += (((remainder * 100) / plen) *
1650 (id3->length / 10000));
1652 else {
1653 /* no TOC exists. set a rough estimate using average bitrate */
1654 int tpk = id3->length /
1655 ((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
1656 1024);
1657 id3->elapsed = offset / 1024 * tpk;
1660 else
1662 /* constant bitrate, use exact calculation */
1663 if (id3->bitrate != 0)
1664 id3->elapsed = offset / (id3->bitrate / 8);
1668 /* Load one track by making the appropriate bufopen calls. Return true if
1669 everything required was loaded correctly, false if not. */
1670 static bool audio_load_track(int offset, bool start_play)
1672 char *trackname;
1673 char msgbuf[80];
1674 int fd = -1;
1675 int file_offset = 0;
1676 struct mp3entry id3;
1678 /* Stop buffer filling if there is no free track entries.
1679 Don't fill up the last track entry (we wan't to store next track
1680 metadata there). */
1681 if (!audio_free_track_count())
1683 logf("No free tracks");
1684 return false;
1687 last_peek_offset++;
1688 tracks[track_widx].taginfo_ready = false;
1690 peek_again:
1691 logf("Buffering track:%d/%d", track_widx, track_ridx);
1692 /* Get track name from current playlist read position. */
1693 while ((trackname = playlist_peek(last_peek_offset)) != NULL)
1695 /* Handle broken playlists. */
1696 fd = open(trackname, O_RDONLY);
1697 if (fd < 0)
1699 logf("Open failed");
1700 /* Skip invalid entry from playlist. */
1701 playlist_skip_entry(NULL, last_peek_offset);
1703 else
1704 break;
1707 if (!trackname)
1709 logf("End-of-playlist");
1710 playlist_end = true;
1711 memset(&lasttrack_id3, 0, sizeof(struct mp3entry));
1712 return false;
1715 tracks[track_widx].filesize = filesize(fd);
1717 if ((unsigned)offset > tracks[track_widx].filesize)
1718 offset = 0;
1720 /* Set default values */
1721 if (start_play)
1723 buf_set_watermark(AUDIO_DEFAULT_WATERMARK);
1724 dsp_configure(ci.dsp, DSP_RESET, 0);
1725 track_changed = true;
1726 playlist_update_resume_info(audio_current_track());
1729 /* Get track metadata if we don't already have it. */
1730 if (tracks[track_widx].id3_hid < 0)
1732 if (get_metadata(&id3, fd, trackname))
1734 send_event(PLAYBACK_EVENT_TRACK_BUFFER, &id3);
1736 tracks[track_widx].id3_hid =
1737 bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3);
1739 if (tracks[track_widx].id3_hid < 0)
1741 last_peek_offset--;
1742 close(fd);
1743 copy_mp3entry(&lasttrack_id3, &id3);
1744 return false;
1747 if (track_widx == track_ridx)
1748 copy_mp3entry(&curtrack_id3, &id3);
1750 if (start_play)
1752 track_changed = true;
1753 playlist_update_resume_info(audio_current_track());
1756 else
1758 logf("mde:%s!",trackname);
1760 /* Skip invalid entry from playlist. */
1761 playlist_skip_entry(NULL, last_peek_offset);
1762 close(fd);
1763 goto peek_again;
1768 close(fd);
1770 #if 0
1771 if (cuesheet_is_enabled() && tracks[track_widx].id3.cuesheet_type == 1)
1773 char cuepath[MAX_PATH];
1775 struct cuesheet *cue = start_play ? curr_cue : temp_cue;
1777 if (look_for_cuesheet_file(trackname, cuepath) &&
1778 parse_cuesheet(cuepath, cue))
1780 strcpy((cue)->audio_filename, trackname);
1781 if (start_play)
1782 cue_spoof_id3(curr_cue, &tracks[track_widx].id3);
1785 #endif
1787 struct mp3entry *track_id3;
1789 if (track_widx == track_ridx)
1790 track_id3 = &curtrack_id3;
1791 else
1792 track_id3 = bufgetid3(tracks[track_widx].id3_hid);
1794 #ifdef HAVE_ALBUMART
1795 if (tracks[track_widx].aa_hid < 0 && gui_sync_wps_uses_albumart())
1797 char aa_path[MAX_PATH];
1798 if (find_albumart(track_id3, aa_path, sizeof(aa_path)))
1799 tracks[track_widx].aa_hid = bufopen(aa_path, 0, TYPE_BITMAP);
1801 #endif
1803 /* Load the codec. */
1804 if (!audio_loadcodec(start_play))
1806 if (tracks[track_widx].codec_hid == ERR_BUFFER_FULL)
1808 /* No space for codec on buffer, not an error */
1809 return false;
1812 /* This is an error condition, either no codec was found, or reading
1813 * the codec file failed part way through, either way, skip the track */
1814 snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname);
1815 /* We should not use gui_syncplash from audio thread! */
1816 gui_syncsplash(HZ*2, msgbuf);
1817 /* Skip invalid entry from playlist. */
1818 playlist_skip_entry(NULL, last_peek_offset);
1819 goto peek_again;
1822 track_id3->elapsed = 0;
1824 enum data_type type = TYPE_PACKET_AUDIO;
1826 switch (track_id3->codectype) {
1827 case AFMT_MPA_L1:
1828 case AFMT_MPA_L2:
1829 case AFMT_MPA_L3:
1830 if (offset > 0) {
1831 file_offset = offset;
1832 track_id3->offset = offset;
1833 audio_set_elapsed(track_id3);
1835 break;
1837 case AFMT_WAVPACK:
1838 if (offset > 0) {
1839 file_offset = offset;
1840 track_id3->offset = offset;
1841 track_id3->elapsed = track_id3->length / 2;
1843 break;
1845 case AFMT_OGG_VORBIS:
1846 case AFMT_SPEEX:
1847 case AFMT_FLAC:
1848 case AFMT_PCM_WAV:
1849 case AFMT_A52:
1850 case AFMT_AAC:
1851 case AFMT_MPC:
1852 case AFMT_APE:
1853 if (offset > 0)
1854 track_id3->offset = offset;
1855 break;
1857 case AFMT_NSF:
1858 case AFMT_SPC:
1859 case AFMT_SID:
1860 logf("Loading atomic %d",track_id3->codectype);
1861 type = TYPE_ATOMIC_AUDIO;
1862 break;
1865 logf("alt:%s", trackname);
1867 if (file_offset > AUDIO_REBUFFER_GUESS_SIZE)
1868 file_offset -= AUDIO_REBUFFER_GUESS_SIZE;
1869 else if (track_id3->first_frame_offset)
1870 file_offset = track_id3->first_frame_offset;
1871 else
1872 file_offset = 0;
1874 tracks[track_widx].audio_hid = bufopen(trackname, file_offset, type);
1876 if (tracks[track_widx].audio_hid < 0)
1877 return false;
1879 /* All required data is now available for the codec. */
1880 tracks[track_widx].taginfo_ready = true;
1882 if (start_play)
1884 ci.curpos=file_offset;
1885 buf_request_buffer_handle(tracks[track_widx].audio_hid);
1888 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
1890 return true;
1893 static void audio_fill_file_buffer(bool start_play, size_t offset)
1895 struct queue_event ev;
1896 bool had_next_track = audio_next_track() != NULL;
1897 bool continue_buffering;
1899 /* No need to rebuffer if there are track skips pending. */
1900 if (ci.new_track != 0)
1901 return;
1903 /* Must reset the buffer before use if trashed or voice only - voice
1904 file size shouldn't have changed so we can go straight from
1905 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
1906 if (buffer_state != BUFFER_STATE_INITIALIZED)
1907 audio_reset_buffer();
1909 logf("Starting buffer fill");
1911 if (!start_play)
1912 audio_clear_track_entries();
1914 /* Save the current resume position once. */
1915 playlist_update_resume_info(audio_current_track());
1917 do {
1918 continue_buffering = audio_load_track(offset, start_play);
1919 start_play = false;
1920 offset = 0;
1921 sleep(1);
1922 if (queue_peek(&audio_queue, &ev)) {
1923 if (ev.id != Q_AUDIO_FILL_BUFFER)
1925 /* There's a message in the queue. break the loop to treat it,
1926 and go back to filling after that. */
1927 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1928 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1930 break;
1932 } while (continue_buffering);
1934 if (!had_next_track && audio_next_track())
1935 track_changed = true;
1939 static void audio_rebuffer(void)
1941 logf("Forcing rebuffer");
1943 clear_track_info(CUR_TI);
1945 /* Reset track pointers */
1946 track_widx = track_ridx;
1947 audio_clear_track_entries();
1949 /* Fill the buffer */
1950 last_peek_offset = -1;
1951 ci.curpos = 0;
1953 if (!CUR_TI->taginfo_ready)
1954 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
1956 audio_fill_file_buffer(false, 0);
1959 /* Called on request from the codec to get a new track. This is the codec part
1960 of the track transition. */
1961 static int audio_check_new_track(void)
1963 int track_count = audio_track_count();
1964 int old_track_ridx = track_ridx;
1965 int i, idx;
1966 int next_playlist_index;
1967 bool forward;
1968 bool end_of_playlist; /* Temporary flag, not the same as playlist_end */
1970 /* Now it's good time to send track unbuffer events. */
1971 send_event(PLAYBACK_EVENT_TRACK_FINISH, &curtrack_id3);
1973 if (dir_skip)
1975 dir_skip = false;
1976 if (playlist_next_dir(ci.new_track))
1978 ci.new_track = 0;
1979 audio_rebuffer();
1980 goto skip_done;
1982 else
1984 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1985 return Q_CODEC_REQUEST_FAILED;
1989 if (new_playlist)
1990 ci.new_track = 0;
1992 end_of_playlist = playlist_peek(automatic_skip ? ci.new_track : 0) == NULL;
1993 auto_dir_skip = end_of_playlist && global_settings.next_folder;
1995 /* If the playlist isn't that big */
1996 if (automatic_skip && !playlist_check(ci.new_track))
1998 if (ci.new_track >= 0)
2000 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2001 return Q_CODEC_REQUEST_FAILED;
2003 /* Find the beginning backward if the user over-skips it */
2004 while (!playlist_check(++ci.new_track))
2005 if (ci.new_track >= 0)
2007 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2008 return Q_CODEC_REQUEST_FAILED;
2012 /* Update the playlist */
2013 last_peek_offset -= ci.new_track;
2015 if (auto_dir_skip)
2017 /* If the track change was the result of an auto dir skip,
2018 we need to update the playlist now */
2019 next_playlist_index = playlist_next(ci.new_track);
2021 if (next_playlist_index < 0)
2023 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2024 return Q_CODEC_REQUEST_FAILED;
2028 if (new_playlist)
2030 ci.new_track = 1;
2031 new_playlist = false;
2034 /* Save the track metadata to allow the WPS to display it
2035 while PCM finishes playing that track */
2036 copy_mp3entry(&prevtrack_id3, &curtrack_id3);
2038 /* Update the main buffer copy of the track metadata with the one
2039 the codec has been using (for the unbuffer callbacks) */
2040 if (CUR_TI->id3_hid >= 0)
2041 copy_mp3entry(bufgetid3(CUR_TI->id3_hid), &curtrack_id3);
2043 /* Save a pointer to the old track to allow later clearing */
2044 prev_ti = CUR_TI;
2046 for (i = 0; i < ci.new_track; i++)
2048 idx = (track_ridx + i) & MAX_TRACK_MASK;
2049 struct mp3entry *id3 = bufgetid3(tracks[idx].id3_hid);
2050 ssize_t offset = buf_handle_offset(tracks[idx].audio_hid);
2051 if (!id3 || offset < 0 || (unsigned)offset > id3->first_frame_offset)
2053 /* We don't have all the audio data for that track, so clear it,
2054 but keep the metadata. */
2055 if (tracks[idx].audio_hid >= 0 && bufclose(tracks[idx].audio_hid))
2057 tracks[idx].audio_hid = -1;
2058 tracks[idx].filesize = 0;
2063 /* Move to the new track */
2064 track_ridx = (track_ridx + ci.new_track) & MAX_TRACK_MASK;
2066 buf_set_base_handle(CUR_TI->audio_hid);
2068 if (automatic_skip)
2070 playlist_end = false;
2071 wps_offset = -ci.new_track;
2072 track_changed = true;
2075 /* If it is not safe to even skip this many track entries */
2076 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
2078 ci.new_track = 0;
2079 audio_rebuffer();
2080 goto skip_done;
2083 forward = ci.new_track > 0;
2084 ci.new_track = 0;
2086 /* If the target track is clearly not in memory */
2087 if (CUR_TI->filesize == 0 || !CUR_TI->taginfo_ready)
2089 audio_rebuffer();
2090 goto skip_done;
2093 /* When skipping backwards, it is possible that we've found a track that's
2094 * buffered, but which is around the track-wrap and therefor not the track
2095 * we are looking for */
2096 if (!forward)
2098 int cur_idx = track_ridx;
2099 bool taginfo_ready = true;
2100 /* We've wrapped the buffer backwards if new > old */
2101 bool wrap = track_ridx > old_track_ridx;
2103 while (1)
2105 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
2107 /* if we've advanced past the wrap when cur_idx is zeroed */
2108 if (!cur_idx)
2109 wrap = false;
2111 /* if we aren't still on the wrap and we've caught the old track */
2112 if (!(wrap || cur_idx < old_track_ridx))
2113 break;
2115 /* If we hit a track in between without valid tag info, bail */
2116 if (!tracks[cur_idx].taginfo_ready)
2118 taginfo_ready = false;
2119 break;
2122 if (!taginfo_ready)
2124 audio_rebuffer();
2128 skip_done:
2129 audio_update_trackinfo();
2130 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2131 return Q_CODEC_REQUEST_COMPLETE;
2134 unsigned long audio_prev_elapsed(void)
2136 return prev_track_elapsed;
2139 static void audio_stop_codec_flush(void)
2141 ci.stop_codec = true;
2142 pcmbuf_pause(true);
2144 while (audio_codec_loaded)
2145 yield();
2147 /* If the audio codec is not loaded any more, and the audio is still
2148 * playing, it is now and _only_ now safe to call this function from the
2149 * audio thread */
2150 if (pcm_is_playing())
2152 pcmbuf_play_stop();
2153 pcmbuf_queue_clear();
2155 pcmbuf_pause(paused);
2158 static void audio_stop_playback(void)
2160 /* If we were playing, save resume information */
2161 if (playing)
2163 struct mp3entry *id3 = NULL;
2165 if (!playlist_end || !ci.stop_codec)
2167 /* Set this early, the outside code yields and may allow the codec
2168 to try to wait for a reply on a buffer wait */
2169 ci.stop_codec = true;
2170 id3 = audio_current_track();
2173 /* Save the current playing spot, or NULL if the playlist has ended */
2174 playlist_update_resume_info(id3);
2176 /* TODO: Create auto bookmark too? */
2178 prev_track_elapsed = curtrack_id3.elapsed;
2181 paused = false;
2182 audio_stop_codec_flush();
2183 playing = false;
2185 /* Mark all entries null. */
2186 audio_clear_track_entries();
2188 /* Close all tracks */
2189 audio_release_tracks();
2191 unregister_buffering_callback(buffering_audio_callback);
2193 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
2196 static void audio_play_start(size_t offset)
2198 int i;
2200 #if INPUT_SRC_CAPS != 0
2201 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2202 audio_set_output_source(AUDIO_SRC_PLAYBACK);
2203 #endif
2205 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2206 paused = false;
2207 audio_stop_codec_flush();
2209 track_changed = true;
2210 playlist_end = false;
2212 playing = true;
2214 ci.new_track = 0;
2215 ci.seek_time = 0;
2216 wps_offset = 0;
2218 sound_set_volume(global_settings.volume);
2219 track_widx = track_ridx = 0;
2221 /* Clear all track entries. */
2222 for (i = 0; i < MAX_TRACK; i++) {
2223 clear_track_info(&tracks[i]);
2226 last_peek_offset = -1;
2228 /* Officially playing */
2229 queue_reply(&audio_queue, 1);
2231 #ifndef HAVE_FLASH_STORAGE
2232 set_filebuf_watermark(buffer_margin, 0);
2233 #endif
2234 audio_fill_file_buffer(true, offset);
2235 register_buffering_callback(buffering_audio_callback);
2237 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2238 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
2242 /* Invalidates all but currently playing track. */
2243 static void audio_invalidate_tracks(void)
2245 if (audio_have_tracks())
2247 last_peek_offset = 0;
2248 playlist_end = false;
2249 track_widx = track_ridx;
2251 /* Mark all other entries null (also buffered wrong metadata). */
2252 audio_clear_track_entries();
2254 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2256 audio_fill_file_buffer(false, 0);
2260 static void audio_new_playlist(void)
2262 /* Prepare to start a new fill from the beginning of the playlist */
2263 last_peek_offset = -1;
2264 if (audio_have_tracks())
2266 if (paused)
2267 skipped_during_pause = true;
2268 playlist_end = false;
2269 track_widx = track_ridx;
2270 audio_clear_track_entries();
2272 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2274 /* Mark the current track as invalid to prevent skipping back to it */
2275 CUR_TI->taginfo_ready = false;
2278 /* Signal the codec to initiate a track change forward */
2279 new_playlist = true;
2280 ci.new_track = 1;
2282 /* Officially playing */
2283 queue_reply(&audio_queue, 1);
2285 audio_fill_file_buffer(false, 0);
2288 /* Called on manual track skip */
2289 static void audio_initiate_track_change(long direction)
2291 logf("audio_initiate_track_change(%ld)", direction);
2293 playlist_end = false;
2294 ci.new_track += direction;
2295 wps_offset -= direction;
2296 if (paused)
2297 skipped_during_pause = true;
2300 /* Called on manual dir skip */
2301 static void audio_initiate_dir_change(long direction)
2303 playlist_end = false;
2304 dir_skip = true;
2305 ci.new_track = direction;
2306 if (paused)
2307 skipped_during_pause = true;
2310 /* Called when PCM track change is complete */
2311 static void audio_finalise_track_change(void)
2313 logf("audio_finalise_track_change");
2315 if (automatic_skip)
2317 if (!auto_dir_skip)
2318 playlist_next(-wps_offset);
2320 wps_offset = 0;
2321 automatic_skip = false;
2324 auto_dir_skip = false;
2326 /* Invalidate prevtrack_id3 */
2327 prevtrack_id3.path[0] = 0;
2329 if (prev_ti && prev_ti->audio_hid < 0)
2331 /* No audio left so we clear all the track info. */
2332 clear_track_info(prev_ti);
2335 if (prev_ti && prev_ti->id3_hid >= 0)
2337 /* Reset the elapsed time to force the progressbar to be empty if
2338 the user skips back to this track */
2339 bufgetid3(prev_ti->id3_hid)->elapsed = 0;
2342 send_event(PLAYBACK_EVENT_TRACK_CHANGE, &curtrack_id3);
2344 track_changed = true;
2345 playlist_update_resume_info(audio_current_track());
2349 * Layout audio buffer as follows - iram buffer depends on target:
2350 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
2352 static void audio_reset_buffer(void)
2354 /* see audio_get_recording_buffer if this is modified */
2355 logf("audio_reset_buffer");
2357 /* If the setup of anything allocated before the file buffer is
2358 changed, do check the adjustments after the buffer_alloc call
2359 as it will likely be affected and need sliding over */
2361 /* Initially set up file buffer as all space available */
2362 malloc_buf = audiobuf + talk_get_bufsize();
2363 /* Align the malloc buf to line size. Especially important to cf
2364 targets that do line reads/writes. */
2365 malloc_buf = (unsigned char *)(((uintptr_t)malloc_buf + 15) & ~15);
2366 filebuf = malloc_buf + MALLOC_BUFSIZE; /* filebuf line align implied */
2367 filebuflen = audiobufend - filebuf;
2369 filebuflen &= ~15;
2371 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
2372 filebuflen -= pcmbuf_init(filebuf + filebuflen) + GUARD_BUFSIZE;
2374 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
2375 will already be line aligned */
2376 filebuflen &= ~3;
2378 buffering_reset(filebuf, filebuflen);
2380 /* Clear any references to the file buffer */
2381 buffer_state = BUFFER_STATE_INITIALIZED;
2383 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
2384 /* Make sure everything adds up - yes, some info is a bit redundant but
2385 aids viewing and the sumation of certain variables should add up to
2386 the location of others. */
2388 size_t pcmbufsize;
2389 unsigned char * pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
2390 logf("mabuf: %08X", (unsigned)malloc_buf);
2391 logf("mabufe: %08X", (unsigned)(malloc_buf + MALLOC_BUFSIZE));
2392 logf("fbuf: %08X", (unsigned)filebuf);
2393 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
2394 logf("gbuf: %08X", (unsigned)(filebuf + filebuflen));
2395 logf("gbufe: %08X", (unsigned)(filebuf + filebuflen + GUARD_BUFSIZE));
2396 logf("pcmb: %08X", (unsigned)pcmbuf);
2397 logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
2399 #endif
2402 static void audio_thread(void)
2404 struct queue_event ev;
2406 pcm_postinit();
2408 audio_thread_ready = true;
2410 while (1)
2412 cancel_cpu_boost();
2413 if (!pcmbuf_queue_scan(&ev))
2414 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
2416 switch (ev.id) {
2417 case Q_AUDIO_FILL_BUFFER:
2418 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
2419 if (!playing || playlist_end || ci.stop_codec)
2420 break;
2421 audio_fill_file_buffer(false, 0);
2422 break;
2424 case Q_AUDIO_PLAY:
2425 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2426 if (playing && ev.data <= 0)
2427 audio_new_playlist();
2428 else
2430 audio_stop_playback();
2431 audio_play_start((size_t)ev.data);
2433 break;
2435 case Q_AUDIO_STOP:
2436 LOGFQUEUE("audio < Q_AUDIO_STOP");
2437 if (playing)
2438 audio_stop_playback();
2439 if (ev.data != 0)
2440 queue_clear(&audio_queue);
2441 break;
2443 case Q_AUDIO_PAUSE:
2444 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
2445 if (!(bool) ev.data && skipped_during_pause && !pcmbuf_is_crossfade_active())
2446 pcmbuf_play_stop(); /* Flush old track on resume after skip */
2447 skipped_during_pause = false;
2448 if (!playing)
2449 break;
2450 pcmbuf_pause((bool)ev.data);
2451 paused = (bool)ev.data;
2452 break;
2454 case Q_AUDIO_SKIP:
2455 LOGFQUEUE("audio < Q_AUDIO_SKIP");
2456 audio_initiate_track_change((long)ev.data);
2457 break;
2459 case Q_AUDIO_PRE_FF_REWIND:
2460 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
2461 if (!playing)
2462 break;
2463 pcmbuf_pause(true);
2464 break;
2466 case Q_AUDIO_FF_REWIND:
2467 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
2468 if (!playing)
2469 break;
2470 if (automatic_skip)
2472 /* An automatic track skip is in progress. Finalize it,
2473 then go back to the previous track */
2474 audio_finalise_track_change();
2475 ci.new_track = -1;
2477 ci.seek_time = (long)ev.data+1;
2478 break;
2480 case Q_AUDIO_CHECK_NEW_TRACK:
2481 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
2482 queue_reply(&audio_queue, audio_check_new_track());
2483 break;
2485 case Q_AUDIO_DIR_SKIP:
2486 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2487 playlist_end = false;
2488 audio_initiate_dir_change(ev.data);
2489 break;
2491 case Q_AUDIO_FLUSH:
2492 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
2493 audio_invalidate_tracks();
2494 break;
2496 case Q_AUDIO_TRACK_CHANGED:
2497 /* PCM track change done */
2498 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2499 audio_finalise_track_change();
2500 break;
2502 #ifndef SIMULATOR
2503 case SYS_USB_CONNECTED:
2504 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2505 if (playing)
2506 audio_stop_playback();
2507 #ifdef PLAYBACK_VOICE
2508 voice_stop();
2509 #endif
2510 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2511 usb_wait_for_disconnect(&audio_queue);
2513 /* Mark all entries null. */
2514 audio_clear_track_entries();
2516 /* release tracks to make sure all handles are closed */
2517 audio_release_tracks();
2518 break;
2519 #endif
2521 case SYS_TIMEOUT:
2522 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
2523 break;
2525 default:
2526 LOGFQUEUE("audio < default");
2527 break;
2528 } /* end switch */
2529 } /* end while */
2532 /* Initialize the audio system - called from init() in main.c.
2533 * Last function because of all the references to internal symbols
2535 void audio_init(void)
2537 struct thread_entry *audio_thread_p;
2539 /* Can never do this twice */
2540 if (audio_is_initialized)
2542 logf("audio: already initialized");
2543 return;
2546 logf("audio: initializing");
2548 /* Initialize queues before giving control elsewhere in case it likes
2549 to send messages. Thread creation will be delayed however so nothing
2550 starts running until ready if something yields such as talk_init. */
2551 queue_init(&audio_queue, true);
2552 queue_enable_queue_send(&audio_queue, &audio_queue_sender_list);
2553 queue_init(&codec_queue, false);
2554 queue_enable_queue_send(&codec_queue, &codec_queue_sender_list);
2555 queue_init(&pcmbuf_queue, false);
2557 pcm_init();
2559 /* Initialize codec api. */
2560 ci.read_filebuf = codec_filebuf_callback;
2561 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
2562 ci.get_codec_memory = codec_get_memory_callback;
2563 ci.request_buffer = codec_request_buffer_callback;
2564 ci.advance_buffer = codec_advance_buffer_callback;
2565 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
2566 ci.request_next_track = codec_request_next_track_callback;
2567 ci.mp3_get_filepos = codec_mp3_get_filepos_callback;
2568 ci.seek_buffer = codec_seek_buffer_callback;
2569 ci.seek_complete = codec_seek_complete_callback;
2570 ci.set_elapsed = codec_set_elapsed_callback;
2571 ci.set_offset = codec_set_offset_callback;
2572 ci.configure = codec_configure_callback;
2573 ci.discard_codec = codec_discard_codec_callback;
2574 ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP,
2575 CODEC_IDX_AUDIO);
2577 /* initialize the buffer */
2578 filebuf = audiobuf;
2580 /* audio_reset_buffer must to know the size of voice buffer so init
2581 talk first */
2582 talk_init();
2584 codec_thread_p = create_thread(
2585 codec_thread, codec_stack, sizeof(codec_stack),
2586 CREATE_THREAD_FROZEN,
2587 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
2588 IF_COP(, CPU));
2590 audio_thread_p = create_thread(audio_thread, audio_stack,
2591 sizeof(audio_stack), CREATE_THREAD_FROZEN,
2592 audio_thread_name IF_PRIO(, PRIORITY_SYSTEM)
2593 IF_COP(, CPU));
2595 #ifdef PLAYBACK_VOICE
2596 voice_thread_init();
2597 #endif
2599 /* Set crossfade setting for next buffer init which should be about... */
2600 pcmbuf_crossfade_enable(global_settings.crossfade);
2602 /* initialize the buffering system */
2604 buffering_init();
2605 /* ...now! Set up the buffers */
2606 audio_reset_buffer();
2608 int i;
2609 for(i = 0; i < MAX_TRACK; i++)
2611 tracks[i].audio_hid = -1;
2612 tracks[i].id3_hid = -1;
2613 tracks[i].codec_hid = -1;
2614 #ifdef HAVE_ALBUMART
2615 tracks[i].aa_hid = -1;
2616 #endif
2619 /* Probably safe to say */
2620 audio_is_initialized = true;
2622 sound_settings_apply();
2623 #ifndef HAVE_FLASH_STORAGE
2624 audio_set_buffer_margin(global_settings.buffer_margin);
2625 #endif
2627 /* it's safe to let the threads run now */
2628 #ifdef PLAYBACK_VOICE
2629 voice_thread_resume();
2630 #endif
2631 thread_thaw(codec_thread_p);
2632 thread_thaw(audio_thread_p);
2634 } /* audio_init */
2636 void audio_wait_for_init(void)
2638 /* audio thread will only set this once after it finished the final
2639 * audio hardware init so this little construct is safe - even
2640 * cross-core. */
2641 while (!audio_thread_ready)
2643 sleep(0);