httpget class: if a request is cancelled before a response is available give a hint...
[Rockbox.git] / apps / playback.c
blob57fca1c00f8bebf0ee0188fb1163059c49641185
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 track_changed = true;
692 else
694 /* No more tracks. */
695 if (global_settings.beep)
696 pcmbuf_beep(1000, 100, 1000*global_settings.beep);
700 void audio_next(void)
702 audio_skip(1);
705 void audio_prev(void)
707 audio_skip(-1);
710 void audio_next_dir(void)
712 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
713 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, 1);
716 void audio_prev_dir(void)
718 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
719 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, -1);
722 void audio_pre_ff_rewind(void)
724 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
725 queue_post(&audio_queue, Q_AUDIO_PRE_FF_REWIND, 0);
728 void audio_ff_rewind(long newpos)
730 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
731 queue_post(&audio_queue, Q_AUDIO_FF_REWIND, newpos);
734 void audio_flush_and_reload_tracks(void)
736 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
737 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0);
740 void audio_error_clear(void)
742 #ifdef AUDIO_HAVE_RECORDING
743 pcm_rec_error_clear();
744 #endif
747 int audio_status(void)
749 int ret = 0;
751 if (playing)
752 ret |= AUDIO_STATUS_PLAY;
754 if (paused)
755 ret |= AUDIO_STATUS_PAUSE;
757 #ifdef HAVE_RECORDING
758 /* Do this here for constitency with mpeg.c version */
759 ret |= pcm_rec_status();
760 #endif
762 return ret;
765 int audio_get_file_pos(void)
767 return 0;
770 #ifndef HAVE_FLASH_STORAGE
771 void audio_set_buffer_margin(int setting)
773 static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
774 buffer_margin = lookup[setting];
775 logf("buffer margin: %ld", (long)buffer_margin);
776 set_filebuf_watermark(buffer_margin, 0);
778 #endif
780 /* Take nescessary steps to enable or disable the crossfade setting */
781 void audio_set_crossfade(int enable)
783 size_t offset;
784 bool was_playing;
785 size_t size;
787 /* Tell it the next setting to use */
788 pcmbuf_crossfade_enable(enable);
790 /* Return if size hasn't changed or this is too early to determine
791 which in the second case there's no way we could be playing
792 anything at all */
793 if (pcmbuf_is_same_size())
795 /* This function is a copout and just syncs some variables -
796 to be removed at a later date */
797 pcmbuf_crossfade_enable_finished();
798 return;
801 offset = 0;
802 was_playing = playing;
804 /* Playback has to be stopped before changing the buffer size */
805 if (was_playing)
807 /* Store the track resume position */
808 offset = curtrack_id3.offset;
809 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK));
812 /* Blast it - audio buffer will have to be setup again next time
813 something plays */
814 audio_get_buffer(true, &size);
816 /* Restart playback if audio was running previously */
817 if (was_playing)
818 audio_play(offset);
821 /* --- Routines called from multiple threads --- */
823 static void set_filebuf_watermark(int seconds, size_t max)
825 size_t bytes;
827 if (!filebuf)
828 return; /* Audio buffers not yet set up */
830 bytes = seconds?MAX(curtrack_id3.bitrate * seconds * (1000/8), max):max;
831 bytes = MIN(bytes, filebuflen / 2);
832 buf_set_watermark(bytes);
835 const char * get_codec_filename(int cod_spec)
837 const char *fname;
839 #ifdef HAVE_RECORDING
840 /* Can choose decoder or encoder if one available */
841 int type = cod_spec & CODEC_TYPE_MASK;
842 int afmt = cod_spec & CODEC_AFMT_MASK;
844 if ((unsigned)afmt >= AFMT_NUM_CODECS)
845 type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
847 fname = (type == CODEC_TYPE_ENCODER) ?
848 audio_formats[afmt].codec_enc_root_fn :
849 audio_formats[afmt].codec_root_fn;
851 logf("%s: %d - %s",
852 (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
853 afmt, fname ? fname : "<unknown>");
854 #else /* !HAVE_RECORDING */
855 /* Always decoder */
856 if ((unsigned)cod_spec >= AFMT_NUM_CODECS)
857 cod_spec = AFMT_UNKNOWN;
858 fname = audio_formats[cod_spec].codec_root_fn;
859 logf("Codec: %d - %s", cod_spec, fname ? fname : "<unknown>");
860 #endif /* HAVE_RECORDING */
862 return fname;
863 } /* get_codec_filename */
865 /* --- Codec thread --- */
866 static bool codec_pcmbuf_insert_callback(
867 const void *ch1, const void *ch2, int count)
869 const char *src[2] = { ch1, ch2 };
871 while (count > 0)
873 int out_count = dsp_output_count(ci.dsp, count);
874 int inp_count;
875 char *dest;
877 /* Prevent audio from a previous track from playing */
878 if (ci.new_track || ci.stop_codec)
879 return true;
881 while ((dest = pcmbuf_request_buffer(&out_count)) == NULL)
883 cancel_cpu_boost();
884 sleep(1);
885 if (ci.seek_time || ci.new_track || ci.stop_codec)
886 return true;
889 /* Get the real input_size for output_size bytes, guarding
890 * against resampling buffer overflows. */
891 inp_count = dsp_input_count(ci.dsp, out_count);
893 if (inp_count <= 0)
894 return true;
896 /* Input size has grown, no error, just don't write more than length */
897 if (inp_count > count)
898 inp_count = count;
900 out_count = dsp_process(ci.dsp, dest, src, inp_count);
902 if (out_count <= 0)
903 return true;
905 pcmbuf_write_complete(out_count);
907 count -= inp_count;
910 return true;
911 } /* codec_pcmbuf_insert_callback */
913 static void* codec_get_memory_callback(size_t *size)
915 *size = MALLOC_BUFSIZE;
916 return malloc_buf;
919 /* Between the codec and PCM track change, we need to keep updating the
920 "elapsed" value of the previous (to the codec, but current to the
921 user/PCM/WPS) track, so that the progressbar reaches the end.
922 During that transition, the WPS will display prevtrack_id3. */
923 static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
924 static void codec_pcmbuf_position_callback(size_t size)
926 /* This is called from an ISR, so be quick */
927 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
928 prevtrack_id3.elapsed;
930 if (time >= prevtrack_id3.length)
932 pcmbuf_set_position_callback(NULL);
933 prevtrack_id3.elapsed = prevtrack_id3.length;
935 else
936 prevtrack_id3.elapsed = time;
939 static void codec_set_elapsed_callback(unsigned int value)
941 unsigned int latency;
942 if (ci.seek_time)
943 return;
945 #ifdef AB_REPEAT_ENABLE
946 ab_position_report(value);
947 #endif
949 latency = pcmbuf_get_latency();
950 if (value < latency)
951 curtrack_id3.elapsed = 0;
952 else if (value - latency > curtrack_id3.elapsed ||
953 value - latency < curtrack_id3.elapsed - 2)
955 curtrack_id3.elapsed = value - latency;
959 static void codec_set_offset_callback(size_t value)
961 unsigned int latency;
963 if (ci.seek_time)
964 return;
966 latency = pcmbuf_get_latency() * curtrack_id3.bitrate / 8;
967 if (value < latency)
968 curtrack_id3.offset = 0;
969 else
970 curtrack_id3.offset = value - latency;
973 static void codec_advance_buffer_counters(size_t amount)
975 bufadvance(CUR_TI->audio_hid, amount);
976 ci.curpos += amount;
979 /* copy up-to size bytes into ptr and return the actual size copied */
980 static size_t codec_filebuf_callback(void *ptr, size_t size)
982 ssize_t copy_n;
984 if (ci.stop_codec || !playing)
985 return 0;
987 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
989 /* Nothing requested OR nothing left */
990 if (copy_n == 0)
991 return 0;
993 /* Update read and other position pointers */
994 codec_advance_buffer_counters(copy_n);
996 /* Return the actual amount of data copied to the buffer */
997 return copy_n;
998 } /* codec_filebuf_callback */
1000 static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
1002 size_t copy_n = reqsize;
1003 ssize_t ret;
1004 void *ptr;
1006 if (!playing)
1008 *realsize = 0;
1009 return NULL;
1012 ret = bufgetdata(CUR_TI->audio_hid, reqsize, &ptr);
1013 if (ret >= 0)
1014 copy_n = MIN((size_t)ret, reqsize);
1016 if (copy_n == 0)
1018 *realsize = 0;
1019 return NULL;
1022 *realsize = copy_n;
1024 return ptr;
1025 } /* codec_request_buffer_callback */
1027 static int get_codec_base_type(int type)
1029 switch (type) {
1030 case AFMT_MPA_L1:
1031 case AFMT_MPA_L2:
1032 case AFMT_MPA_L3:
1033 return AFMT_MPA_L3;
1036 return type;
1039 static void codec_advance_buffer_callback(size_t amount)
1041 codec_advance_buffer_counters(amount);
1042 codec_set_offset_callback(ci.curpos);
1045 static void codec_advance_buffer_loc_callback(void *ptr)
1047 size_t amount = buf_get_offset(CUR_TI->audio_hid, ptr);
1048 codec_advance_buffer_callback(amount);
1051 /* Copied from mpeg.c. Should be moved somewhere else. */
1052 static int codec_get_file_pos(void)
1054 int pos = -1;
1055 struct mp3entry *id3 = audio_current_track();
1057 if (id3->vbr)
1059 if (id3->has_toc)
1061 /* Use the TOC to find the new position */
1062 unsigned int percent, remainder;
1063 int curtoc, nexttoc, plen;
1065 percent = (id3->elapsed*100)/id3->length;
1066 if (percent > 99)
1067 percent = 99;
1069 curtoc = id3->toc[percent];
1071 if (percent < 99)
1072 nexttoc = id3->toc[percent+1];
1073 else
1074 nexttoc = 256;
1076 pos = (id3->filesize/256)*curtoc;
1078 /* Use the remainder to get a more accurate position */
1079 remainder = (id3->elapsed*100)%id3->length;
1080 remainder = (remainder*100)/id3->length;
1081 plen = (nexttoc - curtoc)*(id3->filesize/256);
1082 pos += (plen/100)*remainder;
1084 else
1086 /* No TOC exists, estimate the new position */
1087 pos = (id3->filesize / (id3->length / 1000)) *
1088 (id3->elapsed / 1000);
1091 else if (id3->bitrate)
1092 pos = id3->elapsed * (id3->bitrate / 8);
1093 else
1094 return -1;
1096 pos += id3->first_frame_offset;
1098 /* Don't seek right to the end of the file so that we can
1099 transition properly to the next song */
1100 if (pos >= (int)(id3->filesize - id3->id3v1len))
1101 pos = id3->filesize - id3->id3v1len - 1;
1103 return pos;
1106 static off_t codec_mp3_get_filepos_callback(int newtime)
1108 off_t newpos;
1110 curtrack_id3.elapsed = newtime;
1111 newpos = codec_get_file_pos();
1113 return newpos;
1116 static void codec_seek_complete_callback(void)
1118 logf("seek_complete");
1119 if (pcm_is_paused())
1121 /* If this is not a seamless seek, clear the buffer */
1122 pcmbuf_play_stop();
1123 dsp_configure(ci.dsp, DSP_FLUSH, 0);
1125 /* If playback was not 'deliberately' paused, unpause now */
1126 if (!paused)
1127 pcmbuf_pause(false);
1129 ci.seek_time = 0;
1132 static bool codec_seek_buffer_callback(size_t newpos)
1134 logf("codec_seek_buffer_callback");
1136 int ret = bufseek(CUR_TI->audio_hid, newpos);
1137 if (ret == 0) {
1138 ci.curpos = newpos;
1139 return true;
1141 else {
1142 return false;
1146 static void codec_configure_callback(int setting, intptr_t value)
1148 switch (setting) {
1149 case CODEC_SET_FILEBUF_WATERMARK:
1150 set_filebuf_watermark(buffer_margin, value);
1151 break;
1153 default:
1154 if (!dsp_configure(ci.dsp, setting, value))
1155 { logf("Illegal key:%d", setting); }
1159 static void codec_track_changed(void)
1161 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1162 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1165 static void codec_pcmbuf_track_changed_callback(void)
1167 pcmbuf_set_position_callback(NULL);
1168 pcmbuf_callback_queue_post(Q_AUDIO_TRACK_CHANGED, 0);
1171 static void codec_discard_codec_callback(void)
1173 if (CUR_TI->codec_hid >= 0)
1175 bufclose(CUR_TI->codec_hid);
1176 CUR_TI->codec_hid = -1;
1180 static inline void codec_gapless_track_change(void)
1182 /* callback keeps the progress bar moving while the pcmbuf empties */
1183 pcmbuf_set_position_callback(codec_pcmbuf_position_callback);
1184 /* set the pcmbuf callback for when the track really changes */
1185 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
1188 static inline void codec_crossfade_track_change(void)
1190 /* Initiate automatic crossfade mode */
1191 pcmbuf_crossfade_init(false);
1192 /* Notify the wps that the track change starts now */
1193 codec_track_changed();
1196 static void codec_track_skip_done(bool was_manual)
1198 /* Manual track change (always crossfade or flush audio). */
1199 if (was_manual)
1201 pcmbuf_crossfade_init(true);
1202 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1203 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1205 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1206 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1207 && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP)
1209 if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
1211 if (global_settings.playlist_shuffle)
1212 /* shuffle mode is on, so crossfade: */
1213 codec_crossfade_track_change();
1214 else
1215 /* shuffle mode is off, so do a gapless track change */
1216 codec_gapless_track_change();
1218 else
1219 /* normal crossfade: */
1220 codec_crossfade_track_change();
1222 else
1223 /* normal gapless playback. */
1224 codec_gapless_track_change();
1227 static bool codec_load_next_track(void)
1229 intptr_t result = Q_CODEC_REQUEST_FAILED;
1231 prev_track_elapsed = curtrack_id3.elapsed;
1233 #ifdef AB_REPEAT_ENABLE
1234 ab_end_of_track_report();
1235 #endif
1237 logf("Request new track");
1239 if (ci.new_track == 0)
1241 ci.new_track++;
1242 automatic_skip = true;
1245 if (!ci.stop_codec)
1247 trigger_cpu_boost();
1248 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1249 result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
1252 switch (result)
1254 case Q_CODEC_REQUEST_COMPLETE:
1255 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1256 codec_track_skip_done(!automatic_skip);
1257 return true;
1259 case Q_CODEC_REQUEST_FAILED:
1260 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1261 ci.new_track = 0;
1262 ci.stop_codec = true;
1263 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1264 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1265 return false;
1267 default:
1268 LOGFQUEUE("codec |< default");
1269 ci.stop_codec = true;
1270 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1271 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1272 return false;
1276 static bool codec_request_next_track_callback(void)
1278 int prev_codectype;
1280 if (ci.stop_codec || !playing)
1281 return false;
1283 prev_codectype = get_codec_base_type(curtrack_id3.codectype);
1285 if (!codec_load_next_track())
1286 return false;
1288 /* Check if the next codec is the same file. */
1289 if (prev_codectype == get_codec_base_type(curtrack_id3.codectype))
1291 logf("New track loaded");
1292 codec_discard_codec_callback();
1293 return true;
1295 else
1297 logf("New codec:%d/%d", curtrack_id3.codectype, prev_codectype);
1298 return false;
1302 static void codec_thread(void)
1304 struct queue_event ev;
1305 int status;
1307 while (1) {
1308 status = 0;
1309 cancel_cpu_boost();
1310 queue_wait(&codec_queue, &ev);
1312 switch (ev.id) {
1313 case Q_CODEC_LOAD_DISK:
1314 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1315 queue_reply(&codec_queue, 1);
1316 audio_codec_loaded = true;
1317 ci.stop_codec = false;
1318 status = codec_load_file((const char *)ev.data, &ci);
1319 break;
1321 case Q_CODEC_LOAD:
1322 LOGFQUEUE("codec < Q_CODEC_LOAD");
1323 if (CUR_TI->codec_hid < 0) {
1324 logf("Codec slot is empty!");
1325 /* Wait for the pcm buffer to go empty */
1326 while (pcm_is_playing())
1327 yield();
1328 /* This must be set to prevent an infinite loop */
1329 ci.stop_codec = true;
1330 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1331 queue_post(&codec_queue, Q_AUDIO_PLAY, 0);
1332 break;
1335 audio_codec_loaded = true;
1336 ci.stop_codec = false;
1337 status = codec_load_buf(CUR_TI->codec_hid, &ci);
1338 break;
1340 #ifdef AUDIO_HAVE_RECORDING
1341 case Q_ENCODER_LOAD_DISK:
1342 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1343 audio_codec_loaded = false; /* Not audio codec! */
1344 logf("loading encoder");
1345 ci.stop_encoder = false;
1346 status = codec_load_file((const char *)ev.data, &ci);
1347 logf("encoder stopped");
1348 break;
1349 #endif /* AUDIO_HAVE_RECORDING */
1351 default:
1352 LOGFQUEUE("codec < default");
1355 if (audio_codec_loaded)
1357 if (ci.stop_codec)
1359 status = CODEC_OK;
1360 if (!playing)
1361 pcmbuf_play_stop();
1364 audio_codec_loaded = false;
1367 switch (ev.id) {
1368 case Q_CODEC_LOAD_DISK:
1369 case Q_CODEC_LOAD:
1370 LOGFQUEUE("codec < Q_CODEC_LOAD");
1371 if (playing)
1373 if (ci.new_track || status != CODEC_OK)
1375 if (!ci.new_track)
1377 logf("Codec failure");
1378 gui_syncsplash(HZ*2, "Codec failure");
1381 if (!codec_load_next_track())
1383 break;
1386 else
1388 logf("Codec finished");
1389 if (ci.stop_codec)
1391 /* Wait for the audio to stop playing before
1392 * triggering the WPS exit */
1393 while(pcm_is_playing())
1395 curtrack_id3.elapsed =
1396 curtrack_id3.length - pcmbuf_get_latency();
1397 sleep(1);
1399 break;
1403 if (CUR_TI->codec_hid >= 0)
1405 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1406 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
1408 else
1410 const char *codec_fn =
1411 get_codec_filename(curtrack_id3.codectype);
1412 if (codec_fn)
1414 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1415 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
1416 (intptr_t)codec_fn);
1420 break;
1422 #ifdef AUDIO_HAVE_RECORDING
1423 case Q_ENCODER_LOAD_DISK:
1424 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1426 if (status == CODEC_OK)
1427 break;
1429 logf("Encoder failure");
1430 gui_syncsplash(HZ*2, "Encoder failure");
1432 if (ci.enc_codec_loaded < 0)
1433 break;
1435 logf("Encoder failed to load");
1436 ci.enc_codec_loaded = -1;
1437 break;
1438 #endif /* AUDIO_HAVE_RECORDING */
1440 default:
1441 LOGFQUEUE("codec < default");
1443 } /* end switch */
1448 /* --- Audio thread --- */
1450 static bool audio_have_tracks(void)
1452 return (audio_track_count() != 0);
1455 static int audio_free_track_count(void)
1457 /* Used tracks + free tracks adds up to MAX_TRACK - 1 */
1458 return MAX_TRACK - 1 - audio_track_count();
1461 int audio_track_count(void)
1463 /* Calculate difference from track_ridx to track_widx
1464 * taking into account a possible wrap-around. */
1465 return (MAX_TRACK + track_widx - track_ridx) & MAX_TRACK_MASK;
1468 long audio_filebufused(void)
1470 return (long) buf_used();
1473 /* Update track info after successful a codec track change */
1474 static void audio_update_trackinfo(void)
1476 /* Load the curent track's metadata into curtrack_id3 */
1477 CUR_TI->taginfo_ready = (CUR_TI->id3_hid >= 0);
1478 if (CUR_TI->id3_hid >= 0)
1479 copy_mp3entry(&curtrack_id3, bufgetid3(CUR_TI->id3_hid));
1481 int next_idx = (track_ridx + 1) & MAX_TRACK_MASK;
1482 tracks[next_idx].taginfo_ready = (tracks[next_idx].id3_hid >= 0);
1484 /* Reset current position */
1485 curtrack_id3.elapsed = 0;
1486 curtrack_id3.offset = 0;
1488 /* Update the codec API */
1489 ci.filesize = CUR_TI->filesize;
1490 ci.id3 = &curtrack_id3;
1491 ci.curpos = 0;
1492 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1495 static void buffering_audio_callback(enum callback_event ev, int value)
1497 (void)value;
1498 logf("buffering_audio_callback");
1500 switch (ev)
1502 case EVENT_BUFFER_LOW:
1503 if (!lowbuffer_event_sent) {
1504 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1505 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1506 lowbuffer_event_sent = true;
1508 break;
1510 case EVENT_HANDLE_REBUFFER:
1511 LOGFQUEUE("audio >| audio Q_AUDIO_FLUSH");
1512 queue_send(&audio_queue, Q_AUDIO_FLUSH, 0);
1513 break;
1515 case EVENT_HANDLE_FINISHED:
1516 logf("handle %d finished buffering", value);
1517 strip_tags(value);
1518 break;
1520 default:
1521 break;
1525 /* Clear tracks between write and read, non inclusive */
1526 static void audio_clear_track_entries(bool clear_unbuffered)
1528 int cur_idx = track_widx;
1530 logf("Clearing tracks:%d/%d, %d", track_ridx, track_widx, clear_unbuffered);
1532 /* Loop over all tracks from write-to-read */
1533 while (1)
1535 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
1537 if (cur_idx == track_ridx)
1538 break;
1540 /* If the track is buffered, conditionally clear/notify,
1541 * otherwise clear the track if that option is selected */
1542 if (tracks[cur_idx].event_sent || clear_unbuffered)
1543 clear_track_info(&tracks[cur_idx]);
1547 /* Clear all tracks */
1548 static bool audio_release_tracks(void)
1550 int i, cur_idx;
1552 logf("releasing all tracks");
1554 for(i = 0; i < MAX_TRACK; i++)
1556 cur_idx = (track_ridx + i) & MAX_TRACK_MASK;
1557 if (!clear_track_info(&tracks[cur_idx]))
1558 return false;
1561 return true;
1564 static bool audio_loadcodec(bool start_play)
1566 int prev_track;
1567 char codec_path[MAX_PATH]; /* Full path to codec */
1569 if (tracks[track_widx].id3_hid < 0) {
1570 return false;
1573 const char * codec_fn =
1574 get_codec_filename(bufgetid3(tracks[track_widx].id3_hid)->codectype);
1575 if (codec_fn == NULL)
1576 return false;
1578 tracks[track_widx].codec_hid = -1;
1580 if (start_play)
1582 /* Load the codec directly from disk and save some memory. */
1583 track_ridx = track_widx;
1584 ci.filesize = CUR_TI->filesize;
1585 ci.id3 = &curtrack_id3;
1586 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1587 ci.curpos = 0;
1588 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1589 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (intptr_t)codec_fn);
1590 return true;
1592 else
1594 /* If we already have another track than this one buffered */
1595 if (track_widx != track_ridx)
1597 prev_track = (track_widx - 1) & MAX_TRACK_MASK;
1599 /* If the previous codec is the same as this one, there is no need
1600 * to put another copy of it on the file buffer */
1601 if (get_codec_base_type(
1602 bufgetid3(tracks[track_widx].id3_hid)->codectype) ==
1603 get_codec_base_type(
1604 bufgetid3(tracks[prev_track].id3_hid)->codectype)
1605 && audio_codec_loaded)
1607 logf("Reusing prev. codec");
1608 return true;
1613 codec_get_full_path(codec_path, codec_fn);
1615 tracks[track_widx].codec_hid = bufopen(codec_path, 0, TYPE_CODEC);
1616 if (tracks[track_widx].codec_hid < 0)
1617 return false;
1619 logf("Loaded codec");
1621 return true;
1624 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
1625 static void audio_set_elapsed(struct mp3entry* id3)
1627 unsigned long offset = id3->offset > id3->first_frame_offset ?
1628 id3->offset - id3->first_frame_offset : 0;
1630 if ( id3->vbr ) {
1631 if ( id3->has_toc ) {
1632 /* calculate elapsed time using TOC */
1633 int i;
1634 unsigned int remainder, plen, relpos, nextpos;
1636 /* find wich percent we're at */
1637 for (i=0; i<100; i++ )
1638 if ( offset < id3->toc[i] * (id3->filesize / 256) )
1639 break;
1641 i--;
1642 if (i < 0)
1643 i = 0;
1645 relpos = id3->toc[i];
1647 if (i < 99)
1648 nextpos = id3->toc[i+1];
1649 else
1650 nextpos = 256;
1652 remainder = offset - (relpos * (id3->filesize / 256));
1654 /* set time for this percent (divide before multiply to prevent
1655 overflow on long files. loss of precision is negligible on
1656 short files) */
1657 id3->elapsed = i * (id3->length / 100);
1659 /* calculate remainder time */
1660 plen = (nextpos - relpos) * (id3->filesize / 256);
1661 id3->elapsed += (((remainder * 100) / plen) *
1662 (id3->length / 10000));
1664 else {
1665 /* no TOC exists. set a rough estimate using average bitrate */
1666 int tpk = id3->length /
1667 ((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
1668 1024);
1669 id3->elapsed = offset / 1024 * tpk;
1672 else
1674 /* constant bitrate, use exact calculation */
1675 if (id3->bitrate != 0)
1676 id3->elapsed = offset / (id3->bitrate / 8);
1680 /* Load one track by making the appropriate bufopen calls. Return true if
1681 everything required was loaded correctly, false if not. */
1682 static bool audio_load_track(int offset, bool start_play)
1684 char *trackname;
1685 char msgbuf[80];
1686 int fd = -1;
1687 int file_offset = 0;
1688 struct mp3entry id3;
1690 /* Stop buffer filling if there is no free track entries.
1691 Don't fill up the last track entry (we wan't to store next track
1692 metadata there). */
1693 if (!audio_free_track_count())
1695 logf("No free tracks");
1696 return false;
1699 last_peek_offset++;
1700 tracks[track_widx].taginfo_ready = false;
1702 peek_again:
1703 logf("Buffering track:%d/%d", track_widx, track_ridx);
1704 /* Get track name from current playlist read position. */
1705 while ((trackname = playlist_peek(last_peek_offset)) != NULL)
1707 /* Handle broken playlists. */
1708 fd = open(trackname, O_RDONLY);
1709 if (fd < 0)
1711 logf("Open failed");
1712 /* Skip invalid entry from playlist. */
1713 playlist_skip_entry(NULL, last_peek_offset);
1715 else
1716 break;
1719 if (!trackname)
1721 logf("End-of-playlist");
1722 playlist_end = true;
1723 memset(&lasttrack_id3, 0, sizeof(struct mp3entry));
1724 return false;
1727 tracks[track_widx].filesize = filesize(fd);
1729 if ((unsigned)offset > tracks[track_widx].filesize)
1730 offset = 0;
1732 /* Set default values */
1733 if (start_play)
1735 buf_set_watermark(AUDIO_DEFAULT_WATERMARK);
1736 dsp_configure(ci.dsp, DSP_RESET, 0);
1737 track_changed = true;
1738 playlist_update_resume_info(audio_current_track());
1741 /* Get track metadata if we don't already have it. */
1742 if (tracks[track_widx].id3_hid < 0)
1744 if (get_metadata(&id3, fd, trackname))
1746 if (track_buffer_callback)
1747 track_buffer_callback(&id3);
1749 tracks[track_widx].id3_hid =
1750 bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3);
1752 if (tracks[track_widx].id3_hid < 0)
1754 last_peek_offset--;
1755 close(fd);
1756 copy_mp3entry(&lasttrack_id3, &id3);
1757 return false;
1760 if (track_widx == track_ridx)
1761 copy_mp3entry(&curtrack_id3, &id3);
1763 if (start_play)
1765 track_changed = true;
1766 playlist_update_resume_info(audio_current_track());
1769 else
1771 logf("mde:%s!",trackname);
1773 /* Skip invalid entry from playlist. */
1774 playlist_skip_entry(NULL, last_peek_offset);
1775 close(fd);
1776 goto peek_again;
1781 close(fd);
1783 #if 0
1784 if (cuesheet_is_enabled() && tracks[track_widx].id3.cuesheet_type == 1)
1786 char cuepath[MAX_PATH];
1788 struct cuesheet *cue = start_play ? curr_cue : temp_cue;
1790 if (look_for_cuesheet_file(trackname, cuepath) &&
1791 parse_cuesheet(cuepath, cue))
1793 strcpy((cue)->audio_filename, trackname);
1794 if (start_play)
1795 cue_spoof_id3(curr_cue, &tracks[track_widx].id3);
1798 #endif
1800 struct mp3entry *track_id3;
1802 if (track_widx == track_ridx)
1803 track_id3 = &curtrack_id3;
1804 else
1805 track_id3 = bufgetid3(tracks[track_widx].id3_hid);
1807 #ifdef HAVE_ALBUMART
1808 if (tracks[track_widx].aa_hid < 0 && gui_sync_wps_uses_albumart())
1810 char aa_path[MAX_PATH];
1811 if (find_albumart(track_id3, aa_path, sizeof(aa_path)))
1812 tracks[track_widx].aa_hid = bufopen(aa_path, 0, TYPE_BITMAP);
1814 #endif
1816 /* Load the codec. */
1817 if (!audio_loadcodec(start_play))
1819 if (tracks[track_widx].codec_hid == ERR_BUFFER_FULL)
1821 /* No space for codec on buffer, not an error */
1822 return false;
1825 /* This is an error condition, either no codec was found, or reading
1826 * the codec file failed part way through, either way, skip the track */
1827 snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname);
1828 /* We should not use gui_syncplash from audio thread! */
1829 gui_syncsplash(HZ*2, msgbuf);
1830 /* Skip invalid entry from playlist. */
1831 playlist_skip_entry(NULL, last_peek_offset);
1832 goto peek_again;
1835 track_id3->elapsed = 0;
1837 enum data_type type = TYPE_PACKET_AUDIO;
1839 switch (track_id3->codectype) {
1840 case AFMT_MPA_L1:
1841 case AFMT_MPA_L2:
1842 case AFMT_MPA_L3:
1843 if (offset > 0) {
1844 file_offset = offset;
1845 track_id3->offset = offset;
1846 audio_set_elapsed(track_id3);
1848 break;
1850 case AFMT_WAVPACK:
1851 if (offset > 0) {
1852 file_offset = offset;
1853 track_id3->offset = offset;
1854 track_id3->elapsed = track_id3->length / 2;
1856 break;
1858 case AFMT_OGG_VORBIS:
1859 case AFMT_SPEEX:
1860 case AFMT_FLAC:
1861 case AFMT_PCM_WAV:
1862 case AFMT_A52:
1863 case AFMT_AAC:
1864 case AFMT_MPC:
1865 case AFMT_APE:
1866 if (offset > 0)
1867 track_id3->offset = offset;
1868 break;
1870 case AFMT_NSF:
1871 case AFMT_SPC:
1872 case AFMT_SID:
1873 logf("Loading atomic %d",track_id3->codectype);
1874 type = TYPE_ATOMIC_AUDIO;
1875 break;
1878 logf("alt:%s", trackname);
1880 if (file_offset > AUDIO_REBUFFER_GUESS_SIZE)
1881 file_offset -= AUDIO_REBUFFER_GUESS_SIZE;
1882 else if (track_id3->first_frame_offset)
1883 file_offset = track_id3->first_frame_offset;
1884 else
1885 file_offset = 0;
1887 tracks[track_widx].audio_hid = bufopen(trackname, file_offset, type);
1889 if (tracks[track_widx].audio_hid < 0)
1890 return false;
1892 /* All required data is now available for the codec. */
1893 tracks[track_widx].taginfo_ready = true;
1895 if (start_play)
1897 ci.curpos=file_offset;
1898 buf_request_buffer_handle(tracks[track_widx].audio_hid);
1901 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
1903 return true;
1906 /* Send callback events to notify about new tracks. */
1907 static void audio_generate_postbuffer_events(void)
1909 int cur_idx;
1911 logf("Postbuffer:%d/%d",track_ridx,track_widx);
1913 if (audio_have_tracks())
1915 cur_idx = track_ridx;
1917 while (1) {
1918 if (!tracks[cur_idx].event_sent)
1920 /* Mark the event 'sent' even if we don't really send one */
1921 tracks[cur_idx].event_sent = true;
1923 if (cur_idx == track_widx)
1924 break;
1925 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
1930 static void audio_fill_file_buffer(bool start_play, size_t offset)
1932 struct queue_event ev;
1933 bool had_next_track = audio_next_track() != NULL;
1934 bool continue_buffering;
1936 /* No need to rebuffer if there are track skips pending. */
1937 if (ci.new_track != 0)
1938 return;
1940 /* Must reset the buffer before use if trashed or voice only - voice
1941 file size shouldn't have changed so we can go straight from
1942 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
1943 if (buffer_state != BUFFER_STATE_INITIALIZED)
1944 audio_reset_buffer();
1946 logf("Starting buffer fill");
1948 if (!start_play)
1949 audio_clear_track_entries(false);
1951 /* Save the current resume position once. */
1952 playlist_update_resume_info(audio_current_track());
1954 do {
1955 continue_buffering = audio_load_track(offset, start_play);
1956 start_play = false;
1957 offset = 0;
1958 sleep(1);
1959 if (queue_peek(&audio_queue, &ev)) {
1960 if (ev.id != Q_AUDIO_FILL_BUFFER)
1962 /* There's a message in the queue. break the loop to treat it,
1963 and go back to filling after that. */
1964 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1965 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1967 break;
1969 } while (continue_buffering);
1971 if (!had_next_track && audio_next_track())
1972 track_changed = true;
1974 audio_generate_postbuffer_events();
1975 lowbuffer_event_sent = false;
1978 static void audio_rebuffer(void)
1980 logf("Forcing rebuffer");
1982 clear_track_info(CUR_TI);
1984 /* Reset track pointers */
1985 track_widx = track_ridx;
1986 audio_clear_track_entries(true);
1988 /* Fill the buffer */
1989 last_peek_offset = -1;
1990 ci.curpos = 0;
1992 if (!CUR_TI->taginfo_ready)
1993 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
1995 audio_fill_file_buffer(false, 0);
1998 /* Called on request from the codec to get a new track. This is the codec part
1999 of the track transition. */
2000 static int audio_check_new_track(void)
2002 int track_count = audio_track_count();
2003 int old_track_ridx = track_ridx;
2004 int i, idx;
2005 int next_playlist_index;
2006 bool forward;
2007 bool end_of_playlist; /* Temporary flag, not the same as playlist_end */
2009 if (dir_skip)
2011 dir_skip = false;
2012 if (playlist_next_dir(ci.new_track))
2014 ci.new_track = 0;
2015 audio_rebuffer();
2016 goto skip_done;
2018 else
2020 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2021 return Q_CODEC_REQUEST_FAILED;
2025 if (new_playlist)
2026 ci.new_track = 0;
2028 end_of_playlist = playlist_peek(automatic_skip ? ci.new_track : 0) == NULL;
2029 auto_dir_skip = end_of_playlist && global_settings.next_folder;
2031 /* If the playlist isn't that big */
2032 if (automatic_skip && !playlist_check(ci.new_track))
2034 if (ci.new_track >= 0)
2036 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2037 return Q_CODEC_REQUEST_FAILED;
2039 /* Find the beginning backward if the user over-skips it */
2040 while (!playlist_check(++ci.new_track))
2041 if (ci.new_track >= 0)
2043 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2044 return Q_CODEC_REQUEST_FAILED;
2048 /* Update the playlist */
2049 last_peek_offset -= ci.new_track;
2051 if (auto_dir_skip)
2053 /* If the track change was the result of an auto dir skip,
2054 we need to update the playlist now */
2055 next_playlist_index = playlist_next(ci.new_track);
2057 if (next_playlist_index < 0)
2059 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2060 return Q_CODEC_REQUEST_FAILED;
2064 if (new_playlist)
2066 ci.new_track = 1;
2067 new_playlist = false;
2070 /* Save the track metadata to allow the WPS to display it
2071 while PCM finishes playing that track */
2072 copy_mp3entry(&prevtrack_id3, &curtrack_id3);
2074 /* Update the main buffer copy of the track metadata with the one
2075 the codec has been using (for the unbuffer callbacks) */
2076 if (CUR_TI->id3_hid >= 0)
2077 copy_mp3entry(bufgetid3(CUR_TI->id3_hid), &curtrack_id3);
2079 /* Save a pointer to the old track to allow later clearing */
2080 prev_ti = CUR_TI;
2082 for (i = 0; i < ci.new_track; i++)
2084 idx = (track_ridx + i) & MAX_TRACK_MASK;
2085 struct mp3entry *id3 = bufgetid3(tracks[idx].id3_hid);
2086 ssize_t offset = buf_handle_offset(tracks[idx].audio_hid);
2087 if (!id3 || offset < 0 || (unsigned)offset > id3->first_frame_offset)
2089 /* We don't have all the audio data for that track, so clear it,
2090 but keep the metadata. */
2091 if (tracks[idx].audio_hid >= 0 && bufclose(tracks[idx].audio_hid))
2093 tracks[idx].audio_hid = -1;
2094 tracks[idx].filesize = 0;
2099 /* Move to the new track */
2100 track_ridx = (track_ridx + ci.new_track) & MAX_TRACK_MASK;
2102 buf_set_base_handle(CUR_TI->audio_hid);
2104 if (automatic_skip)
2106 playlist_end = false;
2107 wps_offset = -ci.new_track;
2108 track_changed = true;
2111 /* If it is not safe to even skip this many track entries */
2112 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
2114 ci.new_track = 0;
2115 audio_rebuffer();
2116 goto skip_done;
2119 forward = ci.new_track > 0;
2120 ci.new_track = 0;
2122 /* If the target track is clearly not in memory */
2123 if (CUR_TI->filesize == 0 || !CUR_TI->taginfo_ready)
2125 audio_rebuffer();
2126 goto skip_done;
2129 /* When skipping backwards, it is possible that we've found a track that's
2130 * buffered, but which is around the track-wrap and therefor not the track
2131 * we are looking for */
2132 if (!forward)
2134 int cur_idx = track_ridx;
2135 bool taginfo_ready = true;
2136 /* We've wrapped the buffer backwards if new > old */
2137 bool wrap = track_ridx > old_track_ridx;
2139 while (1)
2141 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK;
2143 /* if we've advanced past the wrap when cur_idx is zeroed */
2144 if (!cur_idx)
2145 wrap = false;
2147 /* if we aren't still on the wrap and we've caught the old track */
2148 if (!(wrap || cur_idx < old_track_ridx))
2149 break;
2151 /* If we hit a track in between without valid tag info, bail */
2152 if (!tracks[cur_idx].taginfo_ready)
2154 taginfo_ready = false;
2155 break;
2158 if (!taginfo_ready)
2160 audio_rebuffer();
2164 skip_done:
2165 audio_update_trackinfo();
2166 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2167 return Q_CODEC_REQUEST_COMPLETE;
2170 void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3))
2172 track_buffer_callback = handler;
2175 void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3))
2177 track_unbuffer_callback = handler;
2180 void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3))
2182 track_changed_callback = handler;
2185 unsigned long audio_prev_elapsed(void)
2187 return prev_track_elapsed;
2190 static void audio_stop_codec_flush(void)
2192 ci.stop_codec = true;
2193 pcmbuf_pause(true);
2195 while (audio_codec_loaded)
2196 yield();
2198 /* If the audio codec is not loaded any more, and the audio is still
2199 * playing, it is now and _only_ now safe to call this function from the
2200 * audio thread */
2201 if (pcm_is_playing())
2203 pcmbuf_play_stop();
2204 pcmbuf_queue_clear();
2206 pcmbuf_pause(paused);
2209 static void audio_stop_playback(void)
2211 /* If we were playing, save resume information */
2212 if (playing)
2214 struct mp3entry *id3 = NULL;
2216 if (!playlist_end || !ci.stop_codec)
2218 /* Set this early, the outside code yields and may allow the codec
2219 to try to wait for a reply on a buffer wait */
2220 ci.stop_codec = true;
2221 id3 = audio_current_track();
2224 /* Save the current playing spot, or NULL if the playlist has ended */
2225 playlist_update_resume_info(id3);
2227 /* TODO: Create auto bookmark too? */
2229 prev_track_elapsed = curtrack_id3.elapsed;
2231 /* At end of playlist save current id3 (id3.elapsed!) to buffer and
2232 * Increment index so runtime info is saved in audio_clear_track_entries().
2234 if ((playlist_end) && (tracks[track_ridx].id3_hid >= 0)) {
2235 copy_mp3entry(bufgetid3(tracks[track_ridx].id3_hid), &curtrack_id3);
2236 track_ridx = (track_ridx + 1) & MAX_TRACK_MASK;
2240 paused = false;
2241 audio_stop_codec_flush();
2242 playing = false;
2244 /* Mark all entries null. */
2245 audio_clear_track_entries(false);
2247 /* Close all tracks */
2248 audio_release_tracks();
2250 unregister_buffering_callback(buffering_audio_callback);
2252 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
2255 static void audio_play_start(size_t offset)
2257 int i;
2259 #if INPUT_SRC_CAPS != 0
2260 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2261 audio_set_output_source(AUDIO_SRC_PLAYBACK);
2262 #endif
2264 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2265 paused = false;
2266 audio_stop_codec_flush();
2268 track_changed = true;
2269 playlist_end = false;
2271 playing = true;
2273 ci.new_track = 0;
2274 ci.seek_time = 0;
2275 wps_offset = 0;
2277 sound_set_volume(global_settings.volume);
2278 track_widx = track_ridx = 0;
2280 /* Clear all track entries. */
2281 for (i = 0; i < MAX_TRACK; i++) {
2282 clear_track_info(&tracks[i]);
2285 last_peek_offset = -1;
2287 /* Officially playing */
2288 queue_reply(&audio_queue, 1);
2290 #ifndef HAVE_FLASH_STORAGE
2291 set_filebuf_watermark(buffer_margin, 0);
2292 #endif
2293 audio_fill_file_buffer(true, offset);
2294 register_buffering_callback(buffering_audio_callback);
2296 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2297 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
2301 /* Invalidates all but currently playing track. */
2302 static void audio_invalidate_tracks(void)
2304 if (audio_have_tracks())
2306 last_peek_offset = 0;
2307 playlist_end = false;
2308 track_widx = track_ridx;
2310 /* Mark all other entries null (also buffered wrong metadata). */
2311 audio_clear_track_entries(true);
2313 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2315 audio_fill_file_buffer(false, 0);
2319 static void audio_new_playlist(void)
2321 /* Prepare to start a new fill from the beginning of the playlist */
2322 last_peek_offset = -1;
2323 if (audio_have_tracks())
2325 if (paused)
2326 skipped_during_pause = true;
2327 playlist_end = false;
2328 track_widx = track_ridx;
2329 audio_clear_track_entries(true);
2331 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
2333 /* Mark the current track as invalid to prevent skipping back to it */
2334 CUR_TI->taginfo_ready = false;
2337 /* Signal the codec to initiate a track change forward */
2338 new_playlist = true;
2339 ci.new_track = 1;
2341 /* Officially playing */
2342 queue_reply(&audio_queue, 1);
2344 audio_fill_file_buffer(false, 0);
2347 /* Called on manual track skip */
2348 static void audio_initiate_track_change(long direction)
2350 logf("audio_initiate_track_change(%ld)", direction);
2352 playlist_end = false;
2353 ci.new_track += direction;
2354 wps_offset -= direction;
2355 if (paused)
2356 skipped_during_pause = true;
2359 /* Called on manual dir skip */
2360 static void audio_initiate_dir_change(long direction)
2362 playlist_end = false;
2363 dir_skip = true;
2364 ci.new_track = direction;
2365 if (paused)
2366 skipped_during_pause = true;
2369 /* Called when PCM track change is complete */
2370 static void audio_finalise_track_change(void)
2372 logf("audio_finalise_track_change");
2374 if (automatic_skip)
2376 if (!auto_dir_skip)
2377 playlist_next(-wps_offset);
2379 wps_offset = 0;
2380 automatic_skip = false;
2383 auto_dir_skip = false;
2385 /* Invalidate prevtrack_id3 */
2386 prevtrack_id3.path[0] = 0;
2388 if (prev_ti && prev_ti->audio_hid < 0)
2390 /* No audio left so we clear all the track info. */
2391 clear_track_info(prev_ti);
2394 if (prev_ti && prev_ti->id3_hid >= 0)
2396 /* Reset the elapsed time to force the progressbar to be empty if
2397 the user skips back to this track */
2398 bufgetid3(prev_ti->id3_hid)->elapsed = 0;
2401 if (track_changed_callback)
2402 track_changed_callback(&curtrack_id3);
2404 track_changed = true;
2405 playlist_update_resume_info(audio_current_track());
2409 * Layout audio buffer as follows - iram buffer depends on target:
2410 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
2412 static void audio_reset_buffer(void)
2414 /* see audio_get_recording_buffer if this is modified */
2415 logf("audio_reset_buffer");
2417 /* If the setup of anything allocated before the file buffer is
2418 changed, do check the adjustments after the buffer_alloc call
2419 as it will likely be affected and need sliding over */
2421 /* Initially set up file buffer as all space available */
2422 malloc_buf = audiobuf + talk_get_bufsize();
2423 /* Align the malloc buf to line size. Especially important to cf
2424 targets that do line reads/writes. */
2425 malloc_buf = (unsigned char *)(((uintptr_t)malloc_buf + 15) & ~15);
2426 filebuf = malloc_buf + MALLOC_BUFSIZE; /* filebuf line align implied */
2427 filebuflen = audiobufend - filebuf;
2429 filebuflen &= ~15;
2431 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
2432 filebuflen -= pcmbuf_init(filebuf + filebuflen) + GUARD_BUFSIZE;
2434 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
2435 will already be line aligned */
2436 filebuflen &= ~3;
2438 buffering_reset(filebuf, filebuflen);
2440 /* Clear any references to the file buffer */
2441 buffer_state = BUFFER_STATE_INITIALIZED;
2443 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
2444 /* Make sure everything adds up - yes, some info is a bit redundant but
2445 aids viewing and the sumation of certain variables should add up to
2446 the location of others. */
2448 size_t pcmbufsize;
2449 unsigned char * pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
2450 logf("mabuf: %08X", (unsigned)malloc_buf);
2451 logf("mabufe: %08X", (unsigned)(malloc_buf + MALLOC_BUFSIZE));
2452 logf("fbuf: %08X", (unsigned)filebuf);
2453 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
2454 logf("gbuf: %08X", (unsigned)(filebuf + filebuflen));
2455 logf("gbufe: %08X", (unsigned)(filebuf + filebuflen + GUARD_BUFSIZE));
2456 logf("pcmb: %08X", (unsigned)pcmbuf);
2457 logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
2459 #endif
2462 static void audio_thread(void)
2464 struct queue_event ev;
2466 pcm_postinit();
2468 audio_thread_ready = true;
2470 while (1)
2472 cancel_cpu_boost();
2473 if (!pcmbuf_queue_scan(&ev))
2474 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
2476 switch (ev.id) {
2477 case Q_AUDIO_FILL_BUFFER:
2478 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
2479 if (!playing || playlist_end || ci.stop_codec)
2480 break;
2481 audio_fill_file_buffer(false, 0);
2482 break;
2484 case Q_AUDIO_PLAY:
2485 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2486 if (playing && ev.data <= 0)
2487 audio_new_playlist();
2488 else
2490 audio_stop_playback();
2491 audio_play_start((size_t)ev.data);
2493 break;
2495 case Q_AUDIO_STOP:
2496 LOGFQUEUE("audio < Q_AUDIO_STOP");
2497 if (playing)
2498 audio_stop_playback();
2499 if (ev.data != 0)
2500 queue_clear(&audio_queue);
2501 break;
2503 case Q_AUDIO_PAUSE:
2504 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
2505 if (!(bool) ev.data && skipped_during_pause && !pcmbuf_is_crossfade_active())
2506 pcmbuf_play_stop(); /* Flush old track on resume after skip */
2507 skipped_during_pause = false;
2508 if (!playing)
2509 break;
2510 pcmbuf_pause((bool)ev.data);
2511 paused = (bool)ev.data;
2512 break;
2514 case Q_AUDIO_SKIP:
2515 LOGFQUEUE("audio < Q_AUDIO_SKIP");
2516 audio_initiate_track_change((long)ev.data);
2517 break;
2519 case Q_AUDIO_PRE_FF_REWIND:
2520 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
2521 if (!playing)
2522 break;
2523 pcmbuf_pause(true);
2524 break;
2526 case Q_AUDIO_FF_REWIND:
2527 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
2528 if (!playing)
2529 break;
2530 if (automatic_skip)
2532 /* An automatic track skip is in progress. Finalize it,
2533 then go back to the previous track */
2534 audio_finalise_track_change();
2535 ci.new_track = -1;
2537 ci.seek_time = (long)ev.data+1;
2538 break;
2540 case Q_AUDIO_CHECK_NEW_TRACK:
2541 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
2542 queue_reply(&audio_queue, audio_check_new_track());
2543 break;
2545 case Q_AUDIO_DIR_SKIP:
2546 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2547 playlist_end = false;
2548 audio_initiate_dir_change(ev.data);
2549 break;
2551 case Q_AUDIO_FLUSH:
2552 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
2553 audio_invalidate_tracks();
2554 break;
2556 case Q_AUDIO_TRACK_CHANGED:
2557 /* PCM track change done */
2558 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2559 audio_finalise_track_change();
2560 break;
2562 #ifndef SIMULATOR
2563 case SYS_USB_CONNECTED:
2564 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2565 if (playing)
2566 audio_stop_playback();
2567 #ifdef PLAYBACK_VOICE
2568 voice_stop();
2569 #endif
2570 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2571 usb_wait_for_disconnect(&audio_queue);
2573 /* Mark all entries null. */
2574 audio_clear_track_entries(false);
2576 /* release tracks to make sure all handles are closed */
2577 audio_release_tracks();
2578 break;
2579 #endif
2581 case SYS_TIMEOUT:
2582 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
2583 break;
2585 default:
2586 LOGFQUEUE("audio < default");
2587 break;
2588 } /* end switch */
2589 } /* end while */
2592 #ifdef ROCKBOX_HAS_LOGF
2593 static void audio_test_track_changed_event(struct mp3entry *id3)
2595 (void)id3;
2597 logf("tce:%s", id3->path);
2599 #endif
2601 /* Initialize the audio system - called from init() in main.c.
2602 * Last function because of all the references to internal symbols
2604 void audio_init(void)
2606 struct thread_entry *audio_thread_p;
2608 /* Can never do this twice */
2609 if (audio_is_initialized)
2611 logf("audio: already initialized");
2612 return;
2615 logf("audio: initializing");
2617 /* Initialize queues before giving control elsewhere in case it likes
2618 to send messages. Thread creation will be delayed however so nothing
2619 starts running until ready if something yields such as talk_init. */
2620 queue_init(&audio_queue, true);
2621 queue_enable_queue_send(&audio_queue, &audio_queue_sender_list);
2622 queue_init(&codec_queue, false);
2623 queue_enable_queue_send(&codec_queue, &codec_queue_sender_list);
2624 queue_init(&pcmbuf_queue, false);
2626 pcm_init();
2628 #ifdef ROCKBOX_HAS_LOGF
2629 audio_set_track_changed_event(audio_test_track_changed_event);
2630 #endif
2632 /* Initialize codec api. */
2633 ci.read_filebuf = codec_filebuf_callback;
2634 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
2635 ci.get_codec_memory = codec_get_memory_callback;
2636 ci.request_buffer = codec_request_buffer_callback;
2637 ci.advance_buffer = codec_advance_buffer_callback;
2638 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
2639 ci.request_next_track = codec_request_next_track_callback;
2640 ci.mp3_get_filepos = codec_mp3_get_filepos_callback;
2641 ci.seek_buffer = codec_seek_buffer_callback;
2642 ci.seek_complete = codec_seek_complete_callback;
2643 ci.set_elapsed = codec_set_elapsed_callback;
2644 ci.set_offset = codec_set_offset_callback;
2645 ci.configure = codec_configure_callback;
2646 ci.discard_codec = codec_discard_codec_callback;
2647 ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP,
2648 CODEC_IDX_AUDIO);
2650 /* initialize the buffer */
2651 filebuf = audiobuf;
2653 /* audio_reset_buffer must to know the size of voice buffer so init
2654 talk first */
2655 talk_init();
2657 codec_thread_p = create_thread(
2658 codec_thread, codec_stack, sizeof(codec_stack),
2659 CREATE_THREAD_FROZEN,
2660 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
2661 IF_COP(, CPU));
2663 audio_thread_p = create_thread(audio_thread, audio_stack,
2664 sizeof(audio_stack), CREATE_THREAD_FROZEN,
2665 audio_thread_name IF_PRIO(, PRIORITY_SYSTEM)
2666 IF_COP(, CPU));
2668 #ifdef PLAYBACK_VOICE
2669 voice_thread_init();
2670 #endif
2672 /* Set crossfade setting for next buffer init which should be about... */
2673 pcmbuf_crossfade_enable(global_settings.crossfade);
2675 /* initialize the buffering system */
2677 buffering_init();
2678 /* ...now! Set up the buffers */
2679 audio_reset_buffer();
2681 int i;
2682 for(i = 0; i < MAX_TRACK; i++)
2684 tracks[i].audio_hid = -1;
2685 tracks[i].id3_hid = -1;
2686 tracks[i].codec_hid = -1;
2687 #ifdef HAVE_ALBUMART
2688 tracks[i].aa_hid = -1;
2689 #endif
2692 /* Probably safe to say */
2693 audio_is_initialized = true;
2695 sound_settings_apply();
2696 #ifndef HAVE_FLASH_STORAGE
2697 audio_set_buffer_margin(global_settings.buffer_margin);
2698 #endif
2700 /* it's safe to let the threads run now */
2701 #ifdef PLAYBACK_VOICE
2702 voice_thread_resume();
2703 #endif
2704 thread_thaw(codec_thread_p);
2705 thread_thaw(audio_thread_p);
2707 } /* audio_init */
2709 void audio_wait_for_init(void)
2711 /* audio thread will only set this once after it finished the final
2712 * audio hardware init so this little construct is safe - even
2713 * cross-core. */
2714 while (!audio_thread_ready)
2716 sleep(0);