1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 Miika Pekkarinen
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 /* TODO: Can use the track changed callback to detect end of track and seek
21 * in the previous track until this happens */
22 /* Design: we have prev_ti already, have a conditional for what type of seek
23 * to do on a seek request, if it is a previous track seek, skip previous,
24 * and in the request_next_track callback set the offset up the same way that
25 * starting from an offset works. */
26 /* TODO: Pause should be handled in here, rather than PCMBUF so that voice can
27 * play whilst audio is paused */
49 #include "buffering.h"
50 #include "mp3_playback.h"
65 #ifdef HAVE_LCD_BITMAP
67 #include "peakmeter.h"
77 #include "ata_idle_notify.h"
80 #include "recording.h"
85 #include "menus/eq_menu.h"
88 #define PLAYBACK_VOICE
91 /* default point to start buffer refill */
92 #define AUDIO_DEFAULT_WATERMARK (1024*512)
93 /* amount of data to read in one read() call */
94 #define AUDIO_DEFAULT_FILECHUNK (1024*32)
95 /* point at which the file buffer will fight for CPU time */
96 #define AUDIO_FILEBUF_CRITICAL (1024*128)
97 /* amount of guess-space to allow for codecs that must hunt and peck
98 * for their correct seeek target, 32k seems a good size */
99 #define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
101 /* Define LOGF_ENABLE to enable logf output in this file */
102 /*#define LOGF_ENABLE*/
105 /* macros to enable logf for queues
106 logging on SYS_TIMEOUT can be disabled */
108 /* Define this for logf output of all queuing except SYS_TIMEOUT */
109 #define PLAYBACK_LOGQUEUES
110 /* Define this to logf SYS_TIMEOUT messages */
111 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
114 #ifdef PLAYBACK_LOGQUEUES
115 #define LOGFQUEUE logf
117 #define LOGFQUEUE(...)
120 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
121 #define LOGFQUEUE_SYS_TIMEOUT logf
123 #define LOGFQUEUE_SYS_TIMEOUT(...)
127 /* Define one constant that includes recording related functionality */
128 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
129 #define AUDIO_HAVE_RECORDING
137 Q_AUDIO_PRE_FF_REWIND
,
139 Q_AUDIO_REBUFFER_SEEK
,
140 Q_AUDIO_CHECK_NEW_TRACK
,
142 Q_AUDIO_TRACK_CHANGED
,
147 Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
,
149 Q_CODEC_REQUEST_COMPLETE
,
150 Q_CODEC_REQUEST_FAILED
,
158 #ifdef AUDIO_HAVE_RECORDING
164 /* As defined in plugins/lib/xxx2wav.h */
166 #define MALLOC_BUFSIZE (512*1024)
167 #define GUARD_BUFSIZE (32*1024)
169 #define MALLOC_BUFSIZE (100*1024)
170 #define GUARD_BUFSIZE (8*1024)
173 /* As defined in plugin.lds */
175 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
176 #define CODEC_IRAM_SIZE ((size_t)0xc000)
177 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
178 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
179 #define CODEC_IRAM_SIZE ((size_t)0x10000)
181 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
182 #define CODEC_IRAM_SIZE ((size_t)0xc000)
185 #ifndef IBSS_ATTR_VOICE_STACK
186 #define IBSS_ATTR_VOICE_STACK IBSS_ATTR
189 bool audio_is_initialized
= false;
191 /* Variables are commented with the threads that use them: *
192 * A=audio, C=codec, V=voice. A suffix of - indicates that *
193 * the variable is read but not updated on that thread. */
194 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
196 /* Main state control */
197 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR
= false; /* Codec loaded? (C/A-) */
198 static volatile bool playing NOCACHEBSS_ATTR
= false; /* Is audio playing? (A) */
199 static volatile bool paused NOCACHEBSS_ATTR
= false; /* Is audio paused? (A/C-) */
200 static volatile bool filling IDATA_ATTR
= false; /* Is file buffer refilling? (A/C-) */
202 /* Ring buffer where compressed audio and codecs are loaded */
203 static unsigned char *filebuf
= NULL
; /* Start of buffer (A/C-) */
204 static unsigned char *malloc_buf
= NULL
; /* Start of malloc buffer (A/C-) */
205 /* FIXME: make filebuflen static */
206 size_t filebuflen
= 0; /* Size of buffer (A/C-) */
207 /* FIXME: make buf_ridx (C/A-) */
209 /* Possible arrangements of the buffer */
210 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
211 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
212 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
213 static int buffer_state
= BUFFER_STATE_TRASHED
; /* Buffer state */
215 struct mp3entry curtrack_id3
;
216 struct mp3entry nexttrack_id3
;
218 /* Track info structure about songs in the file buffer (A/C-) */
220 int audio_hid
; /* The ID for the track's buffer handle */
221 int id3_hid
; /* The ID for the track's metadata handle */
222 int codec_hid
; /* The ID for the track's codec handle */
224 size_t codecsize
; /* Codec length in bytes */
225 size_t filesize
; /* File total length */
227 bool taginfo_ready
; /* Is metadata read */
229 bool event_sent
; /* Was this track's buffered event sent */
232 static struct track_info tracks
[MAX_TRACK
];
233 static volatile int track_ridx
= 0; /* Track being decoded (A/C-) */
234 static int track_widx
= 0; /* Track being buffered (A) */
236 static struct track_info
*prev_ti
= NULL
; /* Previous track info pointer (A/C-) */
237 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
239 /* Set by the audio thread when the current track information has updated
240 * and the WPS may need to update its cached information */
241 static bool track_changed
= false;
243 /* Information used only for filling the buffer */
244 /* Playlist steps from playing track to next track to be buffered (A) */
245 static int last_peek_offset
= 0;
247 /* Scrobbler support */
248 static unsigned long prev_track_elapsed
= 0; /* Previous track elapsed time (C/A-)*/
250 /* Track change controls */
251 static bool automatic_skip
= false; /* Who initiated in-progress skip? (C/A-) */
252 static bool playlist_end
= false; /* Has the current playlist ended? (A) */
253 static bool dir_skip
= false; /* Is a directory skip pending? (A) */
254 static bool new_playlist
= false; /* Are we starting a new playlist? (A) */
255 static int wps_offset
= 0; /* Pending track change offset, to keep WPS responsive (A) */
256 static bool skipped_during_pause
= false; /* Do we need to clear the PCM buffer when playback resumes (A) */
258 /* Callbacks which applications or plugins may set */
259 /* When the playing track has changed from the user's perspective */
260 void (*track_changed_callback
)(struct mp3entry
*id3
) = NULL
;
261 /* When a track has been buffered */
262 void (*track_buffer_callback
)(struct mp3entry
*id3
, bool last_track
) = NULL
;
263 /* When a track's buffer has been overwritten or cleared */
264 void (*track_unbuffer_callback
)(struct mp3entry
*id3
, bool last_track
) = NULL
;
267 static size_t conf_watermark
= 0; /* Level to trigger filebuf fill (A/C) FIXME */
268 static size_t conf_filechunk
= 0; /* Largest chunk the codec accepts (A/C) FIXME */
269 static size_t conf_preseek
= 0; /* Codec pre-seek margin (A/C) FIXME */
270 static size_t buffer_margin
= 0; /* Buffer margin aka anti-skip buffer (A/C-) */
272 static size_t high_watermark
= 0; /* High watermark for rebuffer (A/V/other) */
275 /* Multiple threads */
276 static void set_current_codec(int codec_idx
);
277 /* Set the watermark to trigger buffer fill (A/C) FIXME */
278 static void set_filebuf_watermark(int seconds
);
281 static struct event_queue audio_queue NOCACHEBSS_ATTR
;
282 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR
;
283 static long audio_stack
[(DEFAULT_STACK_SIZE
+ 0x1000)/sizeof(long)];
284 static const char audio_thread_name
[] = "audio";
286 static void audio_thread(void);
287 static void audio_initiate_track_change(long direction
);
288 static bool audio_have_tracks(void);
289 static void audio_reset_buffer(void);
292 extern struct codec_api ci
;
293 static struct event_queue codec_queue NOCACHEBSS_ATTR
;
294 static long codec_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
296 static const char codec_thread_name
[] = "codec";
297 struct thread_entry
*codec_thread_p
; /* For modifying thread priority later. */
299 static volatile int current_codec IDATA_ATTR
; /* Current codec (normal/voice) */
301 /* Buffering thread */
302 void buffering_thread(void);
303 static long buffering_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)];
304 static const char buffering_thread_name
[] = "buffering";
305 struct thread_entry
*buffering_thread_p
;
308 #ifdef PLAYBACK_VOICE
310 extern struct codec_api ci_voice
;
312 static struct thread_entry
*voice_thread_p
= NULL
;
313 static struct event_queue voice_queue NOCACHEBSS_ATTR
;
314 static long voice_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
315 IBSS_ATTR_VOICE_STACK
;
316 static const char voice_thread_name
[] = "voice codec";
318 /* Voice codec swapping control */
319 extern unsigned char codecbuf
[]; /* DRAM codec swap buffer */
322 /* IRAM codec swap buffer for sim*/
323 static unsigned char sim_iram
[CODEC_IRAM_SIZE
];
324 #undef CODEC_IRAM_ORIGIN
325 #define CODEC_IRAM_ORIGIN sim_iram
328 /* iram_buf and dram_buf are either both NULL or both non-NULL */
329 /* Pointer to IRAM buffer for codec swapping */
330 static unsigned char *iram_buf
= NULL
;
331 /* Pointer to DRAM buffer for codec swapping */
332 static unsigned char *dram_buf
= NULL
;
333 /* Parity of swap_codec calls - needed because one codec swapping itself in
334 automatically swaps in the other and the swap when unlocking should not
335 happen if the parity is even.
337 static bool swap_codec_parity NOCACHEBSS_ATTR
= false; /* true=odd, false=even */
338 /* Locking to control which codec (normal/voice) is running */
339 static struct semaphore sem_codecthread NOCACHEBSS_ATTR
;
340 static struct event event_codecthread NOCACHEBSS_ATTR
;
343 static volatile bool voice_thread_start
= false; /* Triggers voice playback (A/V) */
344 static volatile bool voice_is_playing NOCACHEBSS_ATTR
= false; /* Is voice currently playing? (V) */
345 static volatile bool voice_codec_loaded NOCACHEBSS_ATTR
= false; /* Is voice codec loaded (V/A-) */
346 static unsigned char *voicebuf
= NULL
;
347 static size_t voice_remaining
= 0;
350 /* Voice IRAM has been stolen for other use */
351 static bool voice_iram_stolen
= false;
354 static void (*voice_getmore
)(unsigned char** start
, size_t* size
) = NULL
;
357 void (*callback
)(unsigned char **start
, size_t* size
);
361 static void voice_thread(void);
362 static void voice_stop(void);
364 #endif /* PLAYBACK_VOICE */
367 /* --- Helper functions --- */
369 struct mp3entry
*bufgetid3(int handle_id
)
371 struct mp3entry
*id3
;
372 ssize_t ret
= bufgetdata(handle_id
, 0, (unsigned char **)&id3
);
374 if (ret
< 0 || ret
!= sizeof(struct mp3entry
))
380 /* --- External interfaces --- */
382 void mp3_play_data(const unsigned char* start
, int size
,
383 void (*get_more
)(unsigned char** start
, size_t* size
))
385 #ifdef PLAYBACK_VOICE
386 static struct voice_info voice_clip
;
387 voice_clip
.callback
= get_more
;
388 voice_clip
.buf
= (unsigned char*)start
;
389 voice_clip
.size
= size
;
390 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
391 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
392 LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
393 queue_post(&voice_queue
, Q_VOICE_PLAY
, (intptr_t)&voice_clip
);
394 voice_thread_start
= true;
403 void mp3_play_stop(void)
405 #ifdef PLAYBACK_VOICE
406 queue_remove_from_head(&voice_queue
, Q_VOICE_STOP
);
407 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
408 queue_post(&voice_queue
, Q_VOICE_STOP
, 1);
412 void mp3_play_pause(bool play
)
418 bool mp3_is_playing(void)
420 #ifdef PLAYBACK_VOICE
421 return voice_is_playing
;
427 /* If voice could be swapped out - wait for it to return
428 * Used by buffer claming functions.
430 static void wait_for_voice_swap_in(void)
432 #ifdef PLAYBACK_VOICE
433 if (NULL
== iram_buf
)
436 event_wait(&event_codecthread
, STATE_NONSIGNALED
);
437 #endif /* PLAYBACK_VOICE */
440 /* This sends a stop message and the audio thread will dump all it's
441 subsequenct messages */
442 static void audio_hard_stop(void)
445 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
446 queue_send(&audio_queue
, Q_AUDIO_STOP
, 1);
449 unsigned char *audio_get_buffer(bool talk_buf
, size_t *buffer_size
)
451 unsigned char *buf
, *end
;
453 if (audio_is_initialized
)
456 wait_for_voice_swap_in();
457 #ifdef PLAYBACK_VOICE
461 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
463 if (buffer_size
== NULL
)
465 /* Special case for talk_init to use since it already knows it's
467 buffer_state
= BUFFER_STATE_TRASHED
;
471 if (talk_buf
|| buffer_state
== BUFFER_STATE_TRASHED
472 || !talk_voice_required())
474 logf("get buffer: talk, audio");
475 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
476 the talk buffer is not needed because voice isn't being used, or
477 could be BUFFER_STATE_TRASHED already. If state is
478 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
479 without the caller knowing what's going on. Changing certain settings
480 may move it to a worse condition but the memory in use by something
481 else will remain undisturbed.
483 if (buffer_state
!= BUFFER_STATE_TRASHED
)
486 buffer_state
= BUFFER_STATE_TRASHED
;
494 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
495 still BUFFER_STATE_INITIALIZED */
496 /* Skip talk buffer and move pcm buffer to end to maximize available
497 contiguous memory - no audio running means voice will not need the
499 logf("get buffer: audio");
500 buf
= audiobuf
+ talk_get_bufsize();
501 end
= audiobufend
- pcmbuf_init(audiobufend
);
502 buffer_state
= BUFFER_STATE_VOICED_ONLY
;
505 *buffer_size
= end
- buf
;
511 void audio_iram_steal(void)
513 /* We need to stop audio playback in order to use codec IRAM */
516 #ifdef PLAYBACK_VOICE
517 if (NULL
!= iram_buf
)
519 /* Can't already be stolen */
520 if (voice_iram_stolen
)
523 /* Must wait for voice to be current again if it is swapped which
524 would cause the caller's buffer to get clobbered when voice locks
525 and runs - we'll wait for it to lock and yield again then make sure
526 the ride has come to a complete stop */
527 wait_for_voice_swap_in();
530 /* Save voice IRAM but just memcpy - safe to do here since voice
531 is current and no audio codec is loaded */
532 memcpy(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
533 voice_iram_stolen
= true;
537 /* Nothing much to do if no voice */
538 voice_iram_stolen
= false;
542 #endif /* IRAM_STEAL */
544 #ifdef HAVE_RECORDING
545 unsigned char *audio_get_recording_buffer(size_t *buffer_size
)
547 /* Don't allow overwrite of voice swap area or we'll trash the
548 swapped-out voice codec but can use whole thing if none */
551 /* Stop audio and voice. Wait for voice to swap in and be clear
552 of pending events to ensure trouble-free operation of encoders */
554 wait_for_voice_swap_in();
555 #ifdef PLAYBACK_VOICE
560 #ifdef PLAYBACK_VOICE
561 /* If no dram_buf, swap space not used and recording gets more
562 memory. Codec swap areas will remain unaffected by the next init
563 since they're allocated at the end of the buffer and their sizes
564 don't change between calls */
567 #endif /* PLAYBACK_VOICE */
570 buffer_state
= BUFFER_STATE_TRASHED
;
572 *buffer_size
= end
- audiobuf
;
574 return (unsigned char *)audiobuf
;
577 bool audio_load_encoder(int afmt
)
580 const char *enc_fn
= get_codec_filename(afmt
| CODEC_TYPE_ENCODER
);
584 audio_remove_encoder();
585 ci
.enc_codec_loaded
= 0; /* clear any previous error condition */
587 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
588 queue_post(&codec_queue
, Q_ENCODER_LOAD_DISK
, (intptr_t)enc_fn
);
590 while (ci
.enc_codec_loaded
== 0)
593 logf("codec loaded: %d", ci
.enc_codec_loaded
);
595 return ci
.enc_codec_loaded
> 0;
600 } /* audio_load_encoder */
602 void audio_remove_encoder(void)
605 /* force encoder codec unload (if currently loaded) */
606 if (ci
.enc_codec_loaded
<= 0)
609 ci
.stop_encoder
= true;
610 while (ci
.enc_codec_loaded
> 0)
613 } /* audio_remove_encoder */
615 #endif /* HAVE_RECORDING */
617 struct mp3entry
* audio_current_track(void)
619 const char *filename
;
621 static struct mp3entry temp_id3
;
623 int offset
= ci
.new_track
+ wps_offset
;
625 cur_idx
= track_ridx
+ offset
;
626 cur_idx
&= MAX_TRACK_MASK
;
628 if (tracks
[cur_idx
].id3_hid
> 0)
629 return bufgetid3(tracks
[cur_idx
].id3_hid
);
631 memset(&temp_id3
, 0, sizeof(struct mp3entry
));
633 filename
= playlist_peek(0);
635 filename
= "No file!";
637 #ifdef HAVE_TC_RAMCACHE
638 if (tagcache_fill_tags(&temp_id3
, filename
))
642 p
= strrchr(filename
, '/');
648 strncpy(temp_id3
.path
, p
, sizeof(temp_id3
.path
)-1);
649 temp_id3
.title
= &temp_id3
.path
[0];
654 struct mp3entry
* audio_next_track(void)
656 int next_idx
= track_ridx
;
658 if (!audio_have_tracks())
662 next_idx
&= MAX_TRACK_MASK
;
664 if (tracks
[next_idx
].id3_hid
<= 0)
667 return bufgetid3(tracks
[next_idx
].id3_hid
);
670 bool audio_has_changed_track(void)
674 track_changed
= false;
681 void audio_play(long offset
)
685 #ifdef PLAYBACK_VOICE
686 /* Truncate any existing voice output so we don't have spelling
687 * etc. over the first part of the played track */
692 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset
);
693 /* Don't return until playback has actually started */
694 queue_send(&audio_queue
, Q_AUDIO_PLAY
, offset
);
697 void audio_stop(void)
700 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
701 /* Don't return until playback has actually stopped */
702 queue_send(&audio_queue
, Q_AUDIO_STOP
, 0);
705 void audio_pause(void)
707 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
708 /* Don't return until playback has actually paused */
709 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, true);
712 void audio_resume(void)
714 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
715 /* Don't return until playback has actually resumed */
716 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, false);
719 void audio_next(void)
721 if (playlist_check(ci
.new_track
+ wps_offset
+ 1))
723 if (global_settings
.beep
)
724 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
726 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
727 queue_post(&audio_queue
, Q_AUDIO_SKIP
, 1);
728 /* Update wps while our message travels inside deep playback queues. */
730 track_changed
= true;
734 /* No more tracks. */
735 if (global_settings
.beep
)
736 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
740 void audio_prev(void)
742 if (playlist_check(ci
.new_track
+ wps_offset
- 1))
744 if (global_settings
.beep
)
745 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
747 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
748 queue_post(&audio_queue
, Q_AUDIO_SKIP
, -1);
749 /* Update wps while our message travels inside deep playback queues. */
751 track_changed
= true;
755 /* No more tracks. */
756 if (global_settings
.beep
)
757 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
761 void audio_next_dir(void)
763 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
764 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, 1);
767 void audio_prev_dir(void)
769 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
770 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, -1);
773 void audio_pre_ff_rewind(void)
775 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
776 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
779 void audio_ff_rewind(long newpos
)
781 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
782 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, newpos
);
785 void audio_flush_and_reload_tracks(void)
787 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
788 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
791 void audio_error_clear(void)
793 #ifdef AUDIO_HAVE_RECORDING
794 pcm_rec_error_clear();
798 int audio_status(void)
803 ret
|= AUDIO_STATUS_PLAY
;
806 ret
|= AUDIO_STATUS_PAUSE
;
808 #ifdef HAVE_RECORDING
809 /* Do this here for constitency with mpeg.c version */
810 ret
|= pcm_rec_status();
816 int audio_get_file_pos(void)
821 #ifndef HAVE_FLASH_STORAGE
822 void audio_set_buffer_margin(int setting
)
824 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
825 buffer_margin
= lookup
[setting
];
826 logf("buffer margin: %ld", buffer_margin
);
827 set_filebuf_watermark(buffer_margin
);
831 /* Take nescessary steps to enable or disable the crossfade setting */
832 void audio_set_crossfade(int enable
)
838 /* Tell it the next setting to use */
839 pcmbuf_crossfade_enable(enable
);
841 /* Return if size hasn't changed or this is too early to determine
842 which in the second case there's no way we could be playing
844 if (pcmbuf_is_same_size())
846 /* This function is a copout and just syncs some variables -
847 to be removed at a later date */
848 pcmbuf_crossfade_enable_finished();
853 was_playing
= playing
;
855 /* Playback has to be stopped before changing the buffer size */
858 /* Store the track resume position */
859 offset
= curtrack_id3
.offset
;
860 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK
));
863 /* Blast it - audio buffer will have to be setup again next time
865 audio_get_buffer(true, &size
);
867 /* Restart playback if audio was running previously */
872 /* --- Routines called from multiple threads --- */
873 static void set_current_codec(int codec_idx
)
875 current_codec
= codec_idx
;
876 dsp_configure(DSP_SWITCH_CODEC
, codec_idx
);
879 #ifdef PLAYBACK_VOICE
880 static void swap_codec(void)
884 /* Swap nothing if no swap buffers exist */
885 if (dram_buf
== NULL
)
887 logf("swap: no swap buffers");
891 my_codec
= current_codec
;
893 logf("swapping out codec: %d", my_codec
);
895 /* Invert this when a codec thread enters and leaves */
896 swap_codec_parity
= !swap_codec_parity
;
898 /* If this is true, an odd number of calls has occurred and there's
899 no codec thread waiting to swap us out when it locks and runs. This
900 occurs when playback is stopped or when just starting playback and
901 the audio thread is loading a codec; parities should always be even
902 on entry when a thread calls this during playback */
903 if (swap_codec_parity
)
905 /* Save our current IRAM and DRAM */
907 if (voice_iram_stolen
)
909 logf("swap: iram restore");
910 voice_iram_stolen
= false;
911 /* Don't swap trashed data into buffer as the voice IRAM will
912 already be swapped out - should _always_ be the case if
913 voice_iram_stolen is true since the voice has been swapped
915 if (my_codec
== CODEC_IDX_VOICE
)
917 logf("voice iram already swapped");
923 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
929 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
930 /* No cache invalidation needed; it will be done in codec_load_ram
931 or we won't be here otherwise */
934 /* Release my semaphore */
935 semaphore_release(&sem_codecthread
);
936 logf("unlocked: %d", my_codec
);
938 /* Wait for other codec */
939 event_wait(&event_codecthread
,
940 (my_codec
== CODEC_IDX_AUDIO
) ? STATE_NONSIGNALED
: STATE_SIGNALED
);
942 /* Wait for other codec to unlock */
943 logf("waiting for lock: %d", my_codec
);
944 semaphore_wait(&sem_codecthread
);
947 set_current_codec(my_codec
);
948 event_set_state(&event_codecthread
,
949 (my_codec
== CODEC_IDX_AUDIO
) ? STATE_SIGNALED
: STATE_NONSIGNALED
);
951 /* Reload our IRAM and DRAM */
952 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
953 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
956 /* Flip parity again */
957 swap_codec_parity
= !swap_codec_parity
;
959 logf("resuming codec: %d", my_codec
);
962 /* This function is meant to be used by the buffer stealing functions to
963 ensure the codec is no longer active and so voice will be swapped-in
964 before it is called */
965 static void voice_stop(void)
967 /* Must have a voice codec loaded or we'll hang forever here */
968 if (!voice_codec_loaded
)
973 /* Loop until voice empties it's queue, stops and picks up on the new
974 track; the voice thread must be stopped and waiting for messages
976 while (voice_is_playing
|| !queue_empty(&voice_queue
) ||
984 /* Is voice still speaking */
985 /* Unfortunately only reliable when music is not also playing. */
986 static bool is_voice_speaking(void)
988 return is_voice_queued()
990 || (!playing
&& pcm_is_playing());
993 #endif /* PLAYBACK_VOICE */
995 /* Wait for voice to finish speaking. */
996 /* Also only reliable when music is not also playing. */
997 void voice_wait(void)
999 #ifdef PLAYBACK_VOICE
1000 while (is_voice_speaking())
1005 static void set_filebuf_watermark(int seconds
)
1010 return; /* Audio buffers not yet set up */
1012 bytes
= MAX(curtrack_id3
.bitrate
* seconds
* (1000/8), conf_watermark
);
1013 bytes
= MIN(bytes
, filebuflen
/ 2);
1014 conf_watermark
= bytes
;
1017 const char * get_codec_filename(int cod_spec
)
1021 #ifdef HAVE_RECORDING
1022 /* Can choose decoder or encoder if one available */
1023 int type
= cod_spec
& CODEC_TYPE_MASK
;
1024 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
1026 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
1027 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
1029 fname
= (type
== CODEC_TYPE_ENCODER
) ?
1030 audio_formats
[afmt
].codec_enc_root_fn
:
1031 audio_formats
[afmt
].codec_root_fn
;
1034 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
1035 afmt
, fname
? fname
: "<unknown>");
1036 #else /* !HAVE_RECORDING */
1037 /* Always decoder */
1038 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
1039 cod_spec
= AFMT_UNKNOWN
;
1040 fname
= audio_formats
[cod_spec
].codec_root_fn
;
1041 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
1042 #endif /* HAVE_RECORDING */
1045 } /* get_codec_filename */
1048 /* --- Voice thread --- */
1050 #ifdef PLAYBACK_VOICE
1052 static bool voice_pcmbuf_insert_callback(
1053 const void *ch1
, const void *ch2
, int count
)
1055 const char *src
[2] = { ch1
, ch2
};
1059 int out_count
= dsp_output_count(count
);
1063 while ((dest
= pcmbuf_request_voice_buffer(
1064 &out_count
, playing
)) == NULL
)
1066 if (playing
&& audio_codec_loaded
)
1072 /* Get the real input_size for output_size bytes, guarding
1073 * against resampling buffer overflows. */
1074 inp_count
= dsp_input_count(out_count
);
1079 /* Input size has grown, no error, just don't write more than length */
1080 if (inp_count
> count
)
1083 out_count
= dsp_process(dest
, src
, inp_count
);
1090 pcmbuf_mix_voice(out_count
);
1091 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
1096 pcmbuf_write_complete(out_count
);
1102 } /* voice_pcmbuf_insert_callback */
1104 static void* voice_get_memory_callback(size_t *size
)
1106 /* Voice should have no use for this. If it did, we'd have to
1107 swap the malloc buffer as well. */
1112 static void voice_set_elapsed_callback(unsigned int value
)
1117 static void voice_set_offset_callback(size_t value
)
1122 static void voice_configure_callback(int setting
, intptr_t value
)
1124 if (!dsp_configure(setting
, value
))
1126 logf("Illegal key:%d", setting
);
1130 static size_t voice_filebuf_callback(void *ptr
, size_t size
)
1138 /* Handle Q_VOICE_STOP and part of SYS_USB_CONNECTED */
1139 static bool voice_on_voice_stop(bool aborting
, size_t *realsize
)
1141 if (aborting
&& !playing
)
1143 /* Aborting: Slight hack - flush PCM buffer if
1144 only being used for voice */
1148 if (voice_is_playing
)
1150 /* Clear the current buffer */
1151 voice_is_playing
= false;
1152 voice_getmore
= NULL
;
1153 voice_remaining
= 0;
1156 /* Cancel any automatic boost if no more clips requested. */
1157 if (!playing
|| !voice_thread_start
)
1160 /* Force the codec to think it's changing tracks */
1161 ci_voice
.new_track
= 1;
1164 return true; /* Yes, change tracks */
1170 static void* voice_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1172 struct queue_event ev
;
1174 if (ci_voice
.new_track
)
1182 if (voice_is_playing
|| playing
)
1184 queue_wait_w_tmo(&voice_queue
, &ev
, 0);
1185 if (!voice_is_playing
&& ev
.id
== SYS_TIMEOUT
)
1186 ev
.id
= Q_AUDIO_PLAY
;
1190 queue_wait(&voice_queue
, &ev
);
1195 LOGFQUEUE("voice < Q_AUDIO_PLAY");
1198 if (audio_codec_loaded
)
1204 #ifdef AUDIO_HAVE_RECORDING
1205 case Q_ENCODER_RECORD
:
1206 LOGFQUEUE("voice < Q_ENCODER_RECORD");
1212 LOGFQUEUE("voice < Q_VOICE_STOP");
1213 if (voice_on_voice_stop(ev
.data
, realsize
))
1217 case SYS_USB_CONNECTED
:
1219 LOGFQUEUE("voice < SYS_USB_CONNECTED");
1220 bool change_tracks
= voice_on_voice_stop(ev
.data
, realsize
);
1221 /* Voice is obviously current so let us swap ourselves away if
1222 playing so audio may stop itself - audio_codec_loaded can
1223 only be true in this case if we're here even if the codec
1224 is only about to load */
1225 if (audio_codec_loaded
)
1227 /* Playback should be finished by now - ack and wait */
1228 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
1229 usb_wait_for_disconnect(&voice_queue
);
1236 LOGFQUEUE("voice < Q_VOICE_PLAY");
1237 if (!voice_is_playing
)
1239 /* Set up new voice data */
1240 struct voice_info
*voice_data
;
1242 if (voice_iram_stolen
)
1244 /* Voice is the first to run again and is currently
1246 logf("voice: iram restore");
1247 memcpy(CODEC_IRAM_ORIGIN
, iram_buf
, CODEC_IRAM_SIZE
);
1248 voice_iram_stolen
= false;
1251 /* Must reset the buffer before any playback begins if
1253 if (buffer_state
== BUFFER_STATE_TRASHED
)
1254 audio_reset_buffer();
1256 voice_is_playing
= true;
1257 trigger_cpu_boost();
1258 voice_data
= (struct voice_info
*)ev
.data
;
1259 voice_remaining
= voice_data
->size
;
1260 voicebuf
= voice_data
->buf
;
1261 voice_getmore
= voice_data
->callback
;
1263 goto voice_play_clip
; /* To exit both switch and while */
1266 LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
1267 goto voice_play_clip
;
1270 LOGFQUEUE("voice < default");
1276 if (voice_remaining
== 0 || voicebuf
== NULL
)
1279 voice_getmore((unsigned char **)&voicebuf
, &voice_remaining
);
1281 /* If this clip is done */
1282 if (voice_remaining
== 0)
1284 LOGFQUEUE("voice > voice Q_VOICE_STOP");
1285 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
1286 /* Force pcm playback. */
1287 if (!pcm_is_playing())
1288 pcmbuf_play_start();
1292 *realsize
= MIN(voice_remaining
, reqsize
);
1298 } /* voice_request_buffer_callback */
1300 static void voice_advance_buffer_callback(size_t amount
)
1302 amount
= MIN(amount
, voice_remaining
);
1304 voice_remaining
-= amount
;
1307 static void voice_advance_buffer_loc_callback(void *ptr
)
1309 size_t amount
= (size_t)ptr
- (size_t)voicebuf
;
1311 voice_advance_buffer_callback(amount
);
1314 static off_t
voice_mp3_get_filepos_callback(int newtime
)
1321 static void voice_do_nothing(void)
1326 static bool voice_seek_buffer_callback(size_t newpos
)
1333 static bool voice_request_next_track_callback(void)
1335 ci_voice
.new_track
= 0;
1339 static void voice_thread(void)
1341 logf("Loading voice codec");
1342 voice_codec_loaded
= true;
1343 semaphore_wait(&sem_codecthread
);
1344 event_set_state(&event_codecthread
, false);
1345 set_current_codec(CODEC_IDX_VOICE
);
1346 dsp_configure(DSP_RESET
, 0);
1347 voice_remaining
= 0;
1348 voice_getmore
= NULL
;
1350 /* FIXME: If we being starting the voice thread without reboot, the
1351 voice_queue could be full of old stuff and we must flush it. */
1352 codec_load_file(get_codec_filename(AFMT_MPA_L3
), &ci_voice
);
1354 logf("Voice codec finished");
1355 voice_codec_loaded
= false;
1356 voice_thread_p
= NULL
;
1357 semaphore_release(&sem_codecthread
);
1358 } /* voice_thread */
1360 #endif /* PLAYBACK_VOICE */
1362 /* --- Codec thread --- */
1363 static bool codec_pcmbuf_insert_callback(
1364 const void *ch1
, const void *ch2
, int count
)
1366 const char *src
[2] = { ch1
, ch2
};
1370 int out_count
= dsp_output_count(count
);
1374 /* Prevent audio from a previous track from playing */
1375 if (ci
.new_track
|| ci
.stop_codec
)
1378 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
1381 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
1385 /* Get the real input_size for output_size bytes, guarding
1386 * against resampling buffer overflows. */
1387 inp_count
= dsp_input_count(out_count
);
1392 /* Input size has grown, no error, just don't write more than length */
1393 if (inp_count
> count
)
1396 out_count
= dsp_process(dest
, src
, inp_count
);
1401 pcmbuf_write_complete(out_count
);
1403 #ifdef PLAYBACK_VOICE
1404 if ((voice_is_playing
|| voice_thread_start
)
1405 && pcm_is_playing() && voice_codec_loaded
&&
1406 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1408 voice_thread_start
= false;
1417 } /* codec_pcmbuf_insert_callback */
1419 static void* codec_get_memory_callback(size_t *size
)
1421 *size
= MALLOC_BUFSIZE
;
1425 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
1426 static void codec_pcmbuf_position_callback(size_t size
)
1428 /* This is called from an ISR, so be quick */
1429 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
1430 prev_ti
->id3
.elapsed
;
1432 if (time
>= prev_ti
->id3
.length
)
1434 pcmbuf_set_position_callback(NULL
);
1435 prev_ti
->id3
.elapsed
= prev_ti
->id3
.length
;
1438 prev_ti
->id3
.elapsed
= time
;
1441 static void codec_set_elapsed_callback(unsigned int value
)
1443 unsigned int latency
;
1447 #ifdef AB_REPEAT_ENABLE
1448 ab_position_report(value
);
1451 latency
= pcmbuf_get_latency();
1452 if (value
< latency
)
1453 curtrack_id3
.elapsed
= 0;
1454 else if (value
- latency
> curtrack_id3
.elapsed
||
1455 value
- latency
< curtrack_id3
.elapsed
- 2)
1457 curtrack_id3
.elapsed
= value
- latency
;
1461 static void codec_set_offset_callback(size_t value
)
1463 unsigned int latency
;
1468 latency
= pcmbuf_get_latency() * curtrack_id3
.bitrate
/ 8;
1469 if (value
< latency
)
1470 curtrack_id3
.offset
= 0;
1472 curtrack_id3
.offset
= value
- latency
;
1475 static void codec_advance_buffer_counters(size_t amount
)
1477 bufadvance(CUR_TI
->audio_hid
, amount
);
1479 /* Start buffer filling as necessary. */
1480 if (!pcmbuf_is_lowdata() && !filling
)
1482 if (FILEBUFUSED
< conf_watermark
&& playing
&& !playlist_end
)
1484 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1485 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1490 /* copy up-to size bytes into ptr and return the actual size copied */
1491 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
1495 if (ci
.stop_codec
|| !playing
)
1498 copy_n
= bufread(CUR_TI
->audio_hid
, size
, ptr
);
1500 /* Nothing requested OR nothing left */
1504 /* Let the disk buffer catch fill until enough data is available */
1505 while (copy_n
== -2)
1509 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1510 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1514 if (ci
.stop_codec
|| ci
.new_track
)
1518 /* Update read and other position pointers */
1519 codec_advance_buffer_counters(copy_n
);
1521 /* Return the actual amount of data copied to the buffer */
1523 } /* codec_filebuf_callback */
1525 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1527 size_t short_n
, copy_n
, buf_rem
;
1536 copy_n
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, &ret
);
1543 while (copy_n
== -2)
1547 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1548 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1552 if (ci
.stop_codec
|| ci
.new_track
)
1562 } /* codec_request_buffer_callback */
1564 static int get_codec_base_type(int type
)
1576 static void codec_advance_buffer_callback(size_t amount
)
1578 if (amount
> CUR_TI
->available
+ CUR_TI
->filerem
)
1579 amount
= CUR_TI
->available
+ CUR_TI
->filerem
;
1581 while (amount
> CUR_TI
->available
&& filling
)
1584 if (amount
> CUR_TI
->available
)
1586 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1590 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1591 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1592 ci
.curpos
+ amount
);
1597 case Q_CODEC_REQUEST_FAILED
:
1598 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1599 ci
.stop_codec
= true;
1602 case Q_CODEC_REQUEST_COMPLETE
:
1603 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1607 LOGFQUEUE("codec |< default");
1608 ci
.stop_codec
= true;
1613 codec_advance_buffer_counters(amount
);
1615 codec_set_offset_callback(ci
.curpos
);
1618 static void codec_advance_buffer_loc_callback(void *ptr
)
1620 size_t amount
= (size_t)ptr
- (size_t)&filebuf
[buf_ridx
];
1622 codec_advance_buffer_callback(amount
);
1625 /* Copied from mpeg.c. Should be moved somewhere else. */
1626 static int codec_get_file_pos(void)
1629 struct mp3entry
*id3
= audio_current_track();
1635 /* Use the TOC to find the new position */
1636 unsigned int percent
, remainder
;
1637 int curtoc
, nexttoc
, plen
;
1639 percent
= (id3
->elapsed
*100)/id3
->length
;
1643 curtoc
= id3
->toc
[percent
];
1646 nexttoc
= id3
->toc
[percent
+1];
1650 pos
= (id3
->filesize
/256)*curtoc
;
1652 /* Use the remainder to get a more accurate position */
1653 remainder
= (id3
->elapsed
*100)%id3
->length
;
1654 remainder
= (remainder
*100)/id3
->length
;
1655 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1656 pos
+= (plen
/100)*remainder
;
1660 /* No TOC exists, estimate the new position */
1661 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1662 (id3
->elapsed
/ 1000);
1665 else if (id3
->bitrate
)
1666 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1670 pos
+= id3
->first_frame_offset
;
1672 /* Don't seek right to the end of the file so that we can
1673 transition properly to the next song */
1674 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1675 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1680 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1684 curtrack_id3
.elapsed
= newtime
;
1685 newpos
= codec_get_file_pos();
1690 static void codec_seek_complete_callback(void)
1692 logf("seek_complete");
1693 if (pcm_is_paused())
1695 /* If this is not a seamless seek, clear the buffer */
1697 dsp_configure(DSP_FLUSH
, 0);
1699 /* If playback was not 'deliberately' paused, unpause now */
1701 pcmbuf_pause(false);
1706 static bool codec_seek_buffer_callback(size_t newpos
)
1710 logf("codec_seek_buffer_callback");
1712 if (newpos
>= CUR_TI
->filesize
)
1713 newpos
= CUR_TI
->filesize
- 1;
1715 difference
= newpos
- ci
.curpos
;
1716 if (difference
>= 0)
1718 /* Seeking forward */
1719 logf("seek: +%d", difference
);
1720 codec_advance_buffer_callback(difference
);
1724 /* Seeking backward */
1725 difference
= -difference
;
1726 if (ci
.curpos
- difference
< 0)
1727 difference
= ci
.curpos
;
1729 /* We need to reload the song. */
1730 if (newpos
< CUR_TI
->start_pos
)
1732 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1736 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1737 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1743 case Q_CODEC_REQUEST_COMPLETE
:
1744 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1747 case Q_CODEC_REQUEST_FAILED
:
1748 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1749 ci
.stop_codec
= true;
1753 LOGFQUEUE("codec |< default");
1758 /* Seeking inside buffer space. */
1759 logf("seek: -%d", difference
);
1760 CUR_TI
->available
+= difference
;
1761 buf_ridx
= RINGBUF_SUB(buf_ridx
, (unsigned)difference
);
1762 ci
.curpos
-= difference
;
1767 static void codec_configure_callback(int setting
, intptr_t value
)
1770 case CODEC_SET_FILEBUF_WATERMARK
:
1771 conf_watermark
= value
;
1772 set_filebuf_watermark(buffer_margin
);
1775 case CODEC_SET_FILEBUF_CHUNKSIZE
:
1776 conf_filechunk
= value
;
1779 case CODEC_SET_FILEBUF_PRESEEK
:
1780 conf_preseek
= value
;
1784 if (!dsp_configure(setting
, value
)) { logf("Illegal key:%d", setting
); }
1788 static void codec_track_changed(void)
1790 automatic_skip
= false;
1791 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1792 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1795 static void codec_pcmbuf_track_changed_callback(void)
1797 pcmbuf_set_position_callback(NULL
);
1798 codec_track_changed();
1801 static void codec_discard_codec_callback(void)
1803 if (CUR_TI
->has_codec
)
1805 CUR_TI
->has_codec
= false;
1806 if (CUR_TI
->codec_hid
> 0)
1808 bufclose(CUR_TI
->codec_hid
);
1809 CUR_TI
->codec_hid
= 0;
1814 /* Check if a buffer desync has happened, log it and stop playback. */
1815 if (buf_ridx
!= CUR_TI
->buf_idx
)
1817 int offset
= CUR_TI
->buf_idx
- buf_ridx
;
1818 size_t new_used
= FILEBUFUSED
- offset
;
1820 logf("Buf off :%d=%d-%d", offset
, CUR_TI
->buf_idx
, buf_ridx
);
1821 logf("Used off:%d",FILEBUFUSED
- new_used
);
1823 /* This is a fatal internal error and it's not safe to
1824 * continue playback. */
1825 ci
.stop_codec
= true;
1826 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1831 static inline void codec_gapless_track_change(void) {
1832 /* callback keeps the progress bar moving while the pcmbuf empties */
1833 pcmbuf_set_position_callback(codec_pcmbuf_position_callback
);
1834 /* set the pcmbuf callback for when the track really changes */
1835 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1838 static inline void codec_crossfade_track_change(void) {
1839 /* Initiate automatic crossfade mode */
1840 pcmbuf_crossfade_init(false);
1841 /* Notify the wps that the track change starts now */
1842 codec_track_changed();
1845 static void codec_track_skip_done(bool was_manual
)
1847 int crossfade_mode
= global_settings
.crossfade
;
1849 /* Manual track change (always crossfade or flush audio). */
1852 pcmbuf_crossfade_init(true);
1853 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1854 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1856 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1857 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1858 && crossfade_mode
!= CROSSFADE_ENABLE_TRACKSKIP
)
1860 if (crossfade_mode
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1862 if (global_settings
.playlist_shuffle
)
1863 /* shuffle mode is on, so crossfade: */
1864 codec_crossfade_track_change();
1866 /* shuffle mode is off, so do a gapless track change */
1867 codec_gapless_track_change();
1870 /* normal crossfade: */
1871 codec_crossfade_track_change();
1874 /* normal gapless playback. */
1875 codec_gapless_track_change();
1878 static bool codec_load_next_track(void)
1880 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1882 prev_track_elapsed
= curtrack_id3
.elapsed
;
1885 codec_seek_complete_callback();
1887 #ifdef AB_REPEAT_ENABLE
1888 ab_end_of_track_report();
1891 logf("Request new track");
1893 if (ci
.new_track
== 0)
1896 automatic_skip
= true;
1901 trigger_cpu_boost();
1902 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1903 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1908 case Q_CODEC_REQUEST_COMPLETE
:
1909 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1910 codec_track_skip_done(!automatic_skip
);
1913 case Q_CODEC_REQUEST_FAILED
:
1914 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1916 ci
.stop_codec
= true;
1920 LOGFQUEUE("codec |< default");
1921 ci
.stop_codec
= true;
1926 static bool codec_request_next_track_callback(void)
1930 if (ci
.stop_codec
|| !playing
)
1933 prev_codectype
= get_codec_base_type(curtrack_id3
.codectype
);
1935 if (!codec_load_next_track())
1938 /* Check if the next codec is the same file. */
1939 if (prev_codectype
== get_codec_base_type(curtrack_id3
.codectype
))
1941 logf("New track loaded");
1942 codec_discard_codec_callback();
1947 logf("New codec:%d/%d", curtrack_id3
.codectype
, prev_codectype
);
1952 static void codec_thread(void)
1954 struct queue_event ev
;
1960 queue_wait(&codec_queue
, &ev
);
1963 case Q_CODEC_LOAD_DISK
:
1964 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1965 audio_codec_loaded
= true;
1966 #ifdef PLAYBACK_VOICE
1967 /* Don't sent messages to voice codec if it's already swapped
1968 out or it will never get this */
1969 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1971 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1972 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1974 semaphore_wait(&sem_codecthread
);
1975 event_set_state(&event_codecthread
, true);
1977 set_current_codec(CODEC_IDX_AUDIO
);
1978 ci
.stop_codec
= false;
1979 status
= codec_load_file((const char *)ev
.data
, &ci
);
1980 #ifdef PLAYBACK_VOICE
1981 semaphore_release(&sem_codecthread
);
1986 LOGFQUEUE("codec < Q_CODEC_LOAD");
1987 if (!CUR_TI
->has_codec
) {
1988 logf("Codec slot is empty!");
1989 /* Wait for the pcm buffer to go empty */
1990 while (pcm_is_playing())
1992 /* This must be set to prevent an infinite loop */
1993 ci
.stop_codec
= true;
1994 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1995 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
1999 audio_codec_loaded
= true;
2000 #ifdef PLAYBACK_VOICE
2001 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2003 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
2004 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
2006 semaphore_wait(&sem_codecthread
);
2007 event_set_state(&event_codecthread
, true);
2009 set_current_codec(CODEC_IDX_AUDIO
);
2010 ci
.stop_codec
= false;
2011 wrap
= (size_t)&filebuf
[filebuflen
] - (size_t)CUR_TI
->codecbuf
;
2012 status
= codec_load_ram(CUR_TI
->codecbuf
, CUR_TI
->codecsize
,
2013 &filebuf
[0], wrap
, &ci
);
2014 #ifdef PLAYBACK_VOICE
2015 semaphore_release(&sem_codecthread
);
2019 #ifdef AUDIO_HAVE_RECORDING
2020 case Q_ENCODER_LOAD_DISK
:
2021 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2022 audio_codec_loaded
= false; /* Not audio codec! */
2023 #ifdef PLAYBACK_VOICE
2024 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2026 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
2027 queue_post(&voice_queue
, Q_ENCODER_RECORD
, 0);
2029 semaphore_wait(&sem_codecthread
);
2030 event_set_state(&event_codecthread
, true);
2032 logf("loading encoder");
2033 set_current_codec(CODEC_IDX_AUDIO
);
2034 ci
.stop_encoder
= false;
2035 status
= codec_load_file((const char *)ev
.data
, &ci
);
2036 #ifdef PLAYBACK_VOICE
2037 semaphore_release(&sem_codecthread
);
2039 logf("encoder stopped");
2041 #endif /* AUDIO_HAVE_RECORDING */
2044 case SYS_USB_CONNECTED
:
2045 LOGFQUEUE("codec < SYS_USB_CONNECTED");
2046 queue_clear(&codec_queue
);
2047 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
2048 usb_wait_for_disconnect(&codec_queue
);
2053 LOGFQUEUE("codec < default");
2056 if (audio_codec_loaded
)
2065 audio_codec_loaded
= false;
2069 case Q_CODEC_LOAD_DISK
:
2071 LOGFQUEUE("codec < Q_CODEC_LOAD");
2074 if (ci
.new_track
|| status
!= CODEC_OK
)
2078 logf("Codec failure");
2079 gui_syncsplash(HZ
*2, "Codec failure");
2082 if (!codec_load_next_track())
2084 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2085 /* End of playlist */
2086 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2092 logf("Codec finished");
2095 /* Wait for the audio to stop playing before
2096 * triggering the WPS exit */
2097 while(pcm_is_playing())
2099 curtrack_id3
.elapsed
=
2100 curtrack_id3
.length
- pcmbuf_get_latency();
2103 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2104 /* End of playlist */
2105 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2110 if (CUR_TI
->has_codec
)
2112 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2113 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
2117 const char *codec_fn
=
2118 get_codec_filename(curtrack_id3
.codectype
);
2119 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2120 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
2121 (intptr_t)codec_fn
);
2126 #ifdef AUDIO_HAVE_RECORDING
2127 case Q_ENCODER_LOAD_DISK
:
2128 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2130 if (status
== CODEC_OK
)
2133 logf("Encoder failure");
2134 gui_syncsplash(HZ
*2, "Encoder failure");
2136 if (ci
.enc_codec_loaded
< 0)
2139 logf("Encoder failed to load");
2140 ci
.enc_codec_loaded
= -1;
2142 #endif /* AUDIO_HAVE_RECORDING */
2145 LOGFQUEUE("codec < default");
2152 /* --- Audio thread --- */
2154 static bool audio_filebuf_is_lowdata(void)
2156 return FILEBUFUSED
< AUDIO_FILEBUF_CRITICAL
;
2159 static bool audio_have_tracks(void)
2161 return track_ridx
!= track_widx
|| CUR_TI
->filesize
;
2164 static bool audio_have_free_tracks(void)
2166 if (track_widx
< track_ridx
)
2167 return track_widx
+ 1 < track_ridx
;
2168 else if (track_ridx
== 0)
2169 return track_widx
< MAX_TRACK
- 1;
2174 int audio_track_count(void)
2176 if (audio_have_tracks())
2178 int relative_track_widx
= track_widx
;
2180 if (track_ridx
> track_widx
)
2181 relative_track_widx
+= MAX_TRACK
;
2183 return relative_track_widx
- track_ridx
+ 1;
2189 long audio_filebufused(void)
2191 return (long) FILEBUFUSED
;
2194 /* Count the data BETWEEN the selected tracks */
2195 static size_t audio_buffer_count_tracks(int from_track
, int to_track
)
2198 bool need_wrap
= to_track
< from_track
;
2202 if (++from_track
>= MAX_TRACK
)
2204 from_track
-= MAX_TRACK
;
2208 if (from_track
>= to_track
&& !need_wrap
)
2211 amount
+= tracks
[from_track
].codecsize
+ tracks
[from_track
].filesize
;
2216 static bool audio_buffer_wind_forward(int new_track_ridx
, int old_track_ridx
)
2220 /* Start with the remainder of the previously playing track */
2221 amount
= tracks
[old_track_ridx
].filesize
- ci
.curpos
;
2222 /* Then collect all data from tracks in between them */
2223 amount
+= audio_buffer_count_tracks(old_track_ridx
, new_track_ridx
);
2224 logf("bwf:%ldB", (long) amount
);
2226 if (amount
> FILEBUFUSED
)
2229 /* Wind the buffer to the beginning of the target track or its codec */
2230 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
2235 static bool audio_buffer_wind_backward(int new_track_ridx
, int old_track_ridx
)
2237 /* Available buffer data */
2239 /* Start with the previously playing track's data and our data */
2243 buf_back
= RINGBUF_SUB(buf_ridx
, buf_widx
);
2245 /* If we're not just resetting the current track */
2246 if (new_track_ridx
!= old_track_ridx
)
2248 /* Need to wind to before the old track's codec and our filesize */
2249 amount
+= tracks
[old_track_ridx
].codecsize
;
2250 amount
+= tracks
[new_track_ridx
].filesize
;
2252 /* Rewind the old track to its beginning */
2253 tracks
[old_track_ridx
].available
=
2254 tracks
[old_track_ridx
].filesize
- tracks
[old_track_ridx
].filerem
;
2257 /* If the codec was ever buffered */
2258 if (tracks
[new_track_ridx
].codecsize
)
2260 /* Add the codec to the needed size */
2261 amount
+= tracks
[new_track_ridx
].codecsize
;
2262 tracks
[new_track_ridx
].has_codec
= true;
2265 /* Then collect all data from tracks between new and old */
2266 amount
+= audio_buffer_count_tracks(new_track_ridx
, old_track_ridx
);
2268 /* Do we have space to make this skip? */
2269 if (amount
> buf_back
)
2272 logf("bwb:%ldB",amount
);
2274 /* Rewind the buffer to the beginning of the target track or its codec */
2275 buf_ridx
= RINGBUF_SUB(buf_ridx
, amount
);
2277 /* Reset to the beginning of the new track */
2278 tracks
[new_track_ridx
].available
= tracks
[new_track_ridx
].filesize
;
2283 static void audio_update_trackinfo(void)
2285 ci
.filesize
= CUR_TI
->filesize
;
2286 curtrack_id3
.elapsed
= 0;
2287 curtrack_id3
.offset
= 0;
2288 ci
.id3
= &curtrack_id3
;
2290 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2293 /* Yield to codecs for as long as possible if they are in need of data
2294 * return true if the caller should break to let the audio thread process
2296 static bool audio_yield_codecs(void)
2300 if (!queue_empty(&audio_queue
))
2303 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
2304 && !ci
.stop_codec
&& playing
&& !audio_filebuf_is_lowdata())
2311 if (!queue_empty(&audio_queue
))
2318 static void audio_clear_track_entries(bool clear_unbuffered
)
2320 int cur_idx
= track_widx
;
2323 logf("Clearing tracks:%d/%d, %d", track_ridx
, track_widx
, clear_unbuffered
);
2325 /* Loop over all tracks from write-to-read */
2329 cur_idx
&= MAX_TRACK_MASK
;
2331 if (cur_idx
== track_ridx
)
2334 /* If the track is buffered, conditionally clear/notify,
2335 * otherwise clear the track if that option is selected */
2336 if (tracks
[cur_idx
].event_sent
)
2340 /* If there is an unbuffer callback, call it, otherwise,
2341 * just clear the track */
2342 if (track_unbuffer_callback
)
2343 track_unbuffer_callback(&tracks
[last_idx
].id3
, false);
2345 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2349 else if (clear_unbuffered
)
2350 memset(&tracks
[cur_idx
], 0, sizeof(struct track_info
));
2353 /* We clear the previous instance of a buffered track throughout
2354 * the above loop to facilitate 'last' detection. Clear/notify
2355 * the last track here */
2358 if (track_unbuffer_callback
)
2359 track_unbuffer_callback(&tracks
[last_idx
].id3
, true);
2360 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2364 /* FIXME: This code should be made more generic and move to metadata.c */
2365 static void audio_strip_tags(void)
2368 static const unsigned char tag
[] = "TAG";
2369 static const unsigned char apetag
[] = "APETAGEX";
2372 size_t len
, version
;
2374 tag_idx
= RINGBUF_SUB(buf_widx
, 128);
2376 if (FILEBUFUSED
> 128 && tag_idx
> buf_ridx
)
2379 for(i
= 0;i
< 3;i
++)
2381 if(filebuf
[cur_idx
] != tag
[i
])
2384 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2387 /* Skip id3v1 tag */
2388 logf("Skipping ID3v1 tag");
2390 tracks
[track_widx
].available
-= 128;
2391 tracks
[track_widx
].filesize
-= 128;
2395 /* Check for APE tag (look for the APE tag footer) */
2396 tag_idx
= RINGBUF_SUB(buf_widx
, 32);
2398 if (FILEBUFUSED
> 32 && tag_idx
> buf_ridx
)
2401 for(i
= 0;i
< 8;i
++)
2403 if(filebuf
[cur_idx
] != apetag
[i
])
2406 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2409 /* Read the version and length from the footer */
2410 version
= filebuf
[tag_idx
+8] | (filebuf
[tag_idx
+9] << 8) |
2411 (filebuf
[tag_idx
+10] << 16) | (filebuf
[tag_idx
+11] << 24);
2412 len
= filebuf
[tag_idx
+12] | (filebuf
[tag_idx
+13] << 8) |
2413 (filebuf
[tag_idx
+14] << 16) | (filebuf
[tag_idx
+15] << 24);
2414 if (version
== 2000)
2415 len
+= 32; /* APEv2 has a 32 byte header */
2418 if (FILEBUFUSED
> len
)
2420 logf("Skipping APE tag (%ldB)", len
);
2421 buf_widx
= RINGBUF_SUB(buf_widx
, len
);
2422 tracks
[track_widx
].available
-= len
;
2423 tracks
[track_widx
].filesize
-= len
;
2428 /* Returns true if a whole file is read, false otherwise */
2429 static bool audio_read_file(size_t minimum
)
2431 bool ret_val
= false;
2433 /* If we're called and no file is open, this is an error */
2436 logf("Bad fd in arf");
2437 /* Give some hope of miraculous recovery by forcing a track reload */
2438 tracks
[track_widx
].filesize
= 0;
2439 /* Stop this buffering run */
2443 trigger_cpu_boost();
2444 while (tracks
[track_widx
].filerem
> 0)
2450 /* copy_n is the largest chunk that is safe to read */
2451 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2453 /* buf_widx == buf_ridx is defined as buffer empty, not buffer full */
2454 if (RINGBUF_ADD_CROSS(buf_widx
,copy_n
,buf_ridx
) >= 0)
2457 /* rc is the actual amount read */
2458 rc
= read(current_fd
, &filebuf
[buf_widx
], copy_n
);
2462 logf("File ended %ldB early", tracks
[track_widx
].filerem
);
2463 tracks
[track_widx
].filesize
-= tracks
[track_widx
].filerem
;
2464 tracks
[track_widx
].filerem
= 0;
2468 /* How much of the playing track did we overwrite */
2469 if (buf_widx
== CUR_TI
->buf_idx
)
2471 /* Special handling; zero or full overlap? */
2472 if (track_widx
== track_ridx
&& CUR_TI
->available
== 0)
2478 overlap
= RINGBUF_ADD_CROSS(buf_widx
,rc
,CUR_TI
->buf_idx
);
2480 if ((unsigned)rc
> tracks
[track_widx
].filerem
)
2482 logf("Bad: rc-filerem=%ld, fixing", rc
-tracks
[track_widx
].filerem
);
2483 tracks
[track_widx
].filesize
+= rc
- tracks
[track_widx
].filerem
;
2484 tracks
[track_widx
].filerem
= rc
;
2487 /* Advance buffer */
2488 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2489 tracks
[track_widx
].available
+= rc
;
2490 tracks
[track_widx
].filerem
-= rc
;
2492 /* If we write into the playing track, adjust it's buffer info */
2495 CUR_TI
->buf_idx
+= overlap
;
2496 CUR_TI
->start_pos
+= overlap
;
2499 /* For a rebuffer, fill at least this minimum */
2500 if (minimum
> (unsigned)rc
)
2502 /* Let the codec process up to the watermark */
2503 /* Break immediately if this is a quick buffer, or there is an event */
2504 else if (minimum
|| audio_yield_codecs())
2506 /* Exit quickly, but don't stop the overall buffering process */
2512 if (tracks
[track_widx
].filerem
== 0)
2514 logf("Finished buf:%ldB", tracks
[track_widx
].filesize
);
2520 track_widx
&= MAX_TRACK_MASK
;
2522 tracks
[track_widx
].filesize
= 0;
2527 logf("%s buf:%ldB", ret_val
?"Quick":"Partially",
2528 tracks
[track_widx
].filesize
- tracks
[track_widx
].filerem
);
2533 static bool audio_loadcodec(bool start_play
)
2540 char codec_path
[MAX_PATH
]; /* Full path to codec */
2542 const char * codec_fn
=
2543 get_codec_filename(bufgetid3(tracks
[track_widx
].id3_hid
).codectype
);
2544 if (codec_fn
== NULL
)
2547 tracks
[track_widx
].codec_hid
= 0;
2551 /* Load the codec directly from disk and save some memory. */
2552 track_ridx
= track_widx
;
2553 ci
.filesize
= CUR_TI
->filesize
;
2554 ci
.id3
= &curtrack_id3
;
2555 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2557 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2558 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
2563 /* If we already have another track than this one buffered */
2564 if (track_widx
!= track_ridx
)
2566 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
2568 /* If the previous codec is the same as this one, there is no need
2569 * to put another copy of it on the file buffer */
2570 if (get_codec_base_type(
2571 bufgetid3(tracks
[track_widx
].id3_hid
).codectype
) ==
2572 get_codec_base_type(
2573 bufgetid3(tracks
[prev_track
].id3_hid
).codectype
)
2574 && audio_codec_loaded
)
2576 logf("Reusing prev. codec");
2582 codec_get_full_path(codec_path
, codec_fn
);
2584 fd
= open(codec_path
, O_RDONLY
);
2587 logf("Codec doesn't exist!");
2591 tracks
[track_widx
].codecsize
= filesize(fd
);
2593 tracks
[track_widx
].codec_hid
= bufopen(codec_path
, TYPE_CODEC
);
2594 if (tracks
[track_widx
].codec_hid
< 0)
2596 logf("Not enough space");
2601 tracks
[track_widx
].has_codec
= true;
2604 logf("Done: %ldB", size
);
2609 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2610 static void audio_set_elapsed(struct mp3entry
* id3
)
2612 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
2613 id3
->offset
- id3
->first_frame_offset
: 0;
2616 if ( id3
->has_toc
) {
2617 /* calculate elapsed time using TOC */
2619 unsigned int remainder
, plen
, relpos
, nextpos
;
2621 /* find wich percent we're at */
2622 for (i
=0; i
<100; i
++ )
2623 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
2630 relpos
= id3
->toc
[i
];
2633 nextpos
= id3
->toc
[i
+1];
2637 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
2639 /* set time for this percent (divide before multiply to prevent
2640 overflow on long files. loss of precision is negligible on
2642 id3
->elapsed
= i
* (id3
->length
/ 100);
2644 /* calculate remainder time */
2645 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
2646 id3
->elapsed
+= (((remainder
* 100) / plen
) *
2647 (id3
->length
/ 10000));
2650 /* no TOC exists. set a rough estimate using average bitrate */
2651 int tpk
= id3
->length
/
2652 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
2654 id3
->elapsed
= offset
/ 1024 * tpk
;
2659 /* constant bitrate, use exact calculation */
2660 if (id3
->bitrate
!= 0)
2661 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
2665 static bool audio_load_track(int offset
, bool start_play
, bool rebuffer
)
2671 struct mp3entry id3
;
2673 /* Stop buffer filling if there is no free track entries.
2674 Don't fill up the last track entry (we wan't to store next track
2676 if (!audio_have_free_tracks())
2678 logf("No free tracks");
2684 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
2685 /* Get track name from current playlist read position. */
2686 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
2688 /* Handle broken playlists. */
2689 fd
= open(trackname
, O_RDONLY
);
2692 logf("Open failed");
2693 /* Skip invalid entry from playlist. */
2694 playlist_skip_entry(NULL
, last_peek_offset
);
2702 logf("End-of-playlist");
2703 playlist_end
= true;
2707 /* Initialize track entry. */
2708 size
= filesize(fd
);
2709 tracks
[track_widx
].filesize
= size
;
2711 /* Set default values */
2714 int last_codec
= current_codec
;
2716 set_current_codec(CODEC_IDX_AUDIO
);
2717 conf_watermark
= AUDIO_DEFAULT_WATERMARK
;
2718 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
2719 conf_preseek
= AUDIO_REBUFFER_GUESS_SIZE
;
2720 dsp_configure(DSP_RESET
, 0);
2721 set_current_codec(last_codec
);
2724 /* Get track metadata if we don't already have it. */
2725 if (!tracks
[track_widx
].taginfo_ready
)
2727 if (get_metadata(&id3
, fd
, trackname
))
2729 tracks
[track_widx
].taginfo_ready
= true;
2730 tracks
[track_widx
].id3_hid
= bufalloc(&id3
, sizeof(struct mp3entry
),
2734 track_changed
= true;
2735 playlist_update_resume_info(audio_current_track());
2740 logf("mde:%s!",trackname
);
2742 /* Skip invalid entry from playlist. */
2743 playlist_skip_entry(NULL
, last_peek_offset
);
2744 tracks
[track_widx
].taginfo_ready
= false;
2751 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
2753 char cuepath
[MAX_PATH
];
2755 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
2757 if (look_for_cuesheet_file(trackname
, cuepath
) &&
2758 parse_cuesheet(cuepath
, cue
))
2760 strcpy((cue
)->audio_filename
, trackname
);
2762 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
2767 /* Load the codec. */
2768 if (!audio_loadcodec(start_play
))
2770 /* Set filesize to zero to indicate no file was loaded. */
2771 tracks
[track_widx
].filesize
= 0;
2772 tracks
[track_widx
].filerem
= 0;
2776 if (tracks
[track_widx
].codecsize
)
2778 /* No space for codec on buffer, not an error */
2779 tracks
[track_widx
].codecsize
= 0;
2783 /* This is an error condition, either no codec was found, or reading
2784 * the codec file failed part way through, either way, skip the track */
2785 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
2786 /* We should not use gui_syncplash from audio thread! */
2787 gui_syncsplash(HZ
*2, msgbuf
);
2788 /* Skip invalid entry from playlist. */
2789 playlist_skip_entry(NULL
, last_peek_offset
);
2790 tracks
[track_widx
].taginfo_ready
= false;
2794 tracks
[track_widx
].start_pos
= 0;
2795 set_filebuf_watermark(buffer_margin
);
2796 tracks
[track_widx
].id3
.elapsed
= 0;
2800 switch (tracks
[track_widx
].id3
.codectype
) {
2804 lseek(current_fd
, offset
, SEEK_SET
);
2805 tracks
[track_widx
].id3
.offset
= offset
;
2806 audio_set_elapsed(&tracks
[track_widx
].id3
);
2807 tracks
[track_widx
].filerem
= size
- offset
;
2809 tracks
[track_widx
].start_pos
= offset
;
2813 lseek(current_fd
, offset
, SEEK_SET
);
2814 tracks
[track_widx
].id3
.offset
= offset
;
2815 tracks
[track_widx
].id3
.elapsed
=
2816 tracks
[track_widx
].id3
.length
/ 2;
2817 tracks
[track_widx
].filerem
= size
- offset
;
2819 tracks
[track_widx
].start_pos
= offset
;
2822 case AFMT_OGG_VORBIS
:
2830 tracks
[track_widx
].id3
.offset
= offset
;
2835 logf("alt:%s", trackname
);
2836 tracks
[track_widx
].buf_idx
= buf_widx
;
2838 return audio_read_file(rebuffer
);
2841 static bool audio_read_next_metadata(void)
2848 next_idx
= track_widx
;
2849 if (tracks
[next_idx
].taginfo_ready
)
2852 next_idx
&= MAX_TRACK_MASK
;
2854 if (tracks
[next_idx
].taginfo_ready
)
2858 trackname
= playlist_peek(last_peek_offset
+ 1);
2862 fd
= open(trackname
, O_RDONLY
);
2866 status
= get_metadata(&(tracks
[next_idx
].id3
),fd
,trackname
);
2867 /* Preload the glyphs in the tags */
2870 tracks
[next_idx
].taginfo_ready
= true;
2871 if (tracks
[next_idx
].id3
.title
)
2872 lcd_getstringsize(tracks
[next_idx
].id3
.title
, NULL
, NULL
);
2873 if (tracks
[next_idx
].id3
.artist
)
2874 lcd_getstringsize(tracks
[next_idx
].id3
.artist
, NULL
, NULL
);
2875 if (tracks
[next_idx
].id3
.album
)
2876 lcd_getstringsize(tracks
[next_idx
].id3
.album
, NULL
, NULL
);
2883 /* Send callback events to notify about new tracks. */
2884 static void audio_generate_postbuffer_events(void)
2889 logf("Postbuffer:%d/%d",track_ridx
,track_widx
);
2891 if (audio_have_tracks())
2893 cur_idx
= track_ridx
;
2896 if (!tracks
[cur_idx
].event_sent
)
2898 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2900 /* Mark the event 'sent' even if we don't really send one */
2901 tracks
[last_idx
].event_sent
= true;
2902 if (track_buffer_callback
)
2903 track_buffer_callback(&tracks
[last_idx
].id3
, false);
2907 if (cur_idx
== track_widx
)
2910 cur_idx
&= MAX_TRACK_MASK
;
2913 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2915 tracks
[last_idx
].event_sent
= true;
2916 if (track_buffer_callback
)
2917 track_buffer_callback(&tracks
[last_idx
].id3
, true);
2922 static bool audio_initialize_buffer_fill(bool clear_tracks
)
2924 /* Don't initialize if we're already initialized */
2928 logf("Starting buffer fill");
2930 /* Set the filling flag true before calling audio_clear_tracks as that
2931 * function can yield and we start looping. */
2935 audio_clear_track_entries(false);
2937 /* Save the current resume position once. */
2938 playlist_update_resume_info(audio_current_track());
2943 static void audio_fill_file_buffer(
2944 bool start_play
, bool rebuffer
, size_t offset
)
2946 bool had_next_track
= audio_next_track() != NULL
;
2947 bool continue_buffering
;
2949 /* Must reset the buffer before use if trashed or voice only - voice
2950 file size shouldn't have changed so we can go straight from
2951 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
2952 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
2953 audio_reset_buffer();
2955 if (!audio_initialize_buffer_fill(!start_play
))
2958 /* If we have a partially buffered track, continue loading,
2959 * otherwise load a new track */
2960 if (tracks
[track_widx
].filesize
> 0)
2961 continue_buffering
= audio_read_file(rebuffer
);
2963 continue_buffering
= audio_load_track(offset
, start_play
, rebuffer
);
2965 if (!had_next_track
&& audio_next_track())
2966 track_changed
= true;
2968 /* If we're done buffering */
2969 if (!continue_buffering
)
2971 audio_read_next_metadata();
2973 audio_generate_postbuffer_events();
2982 static void audio_rebuffer(void)
2984 logf("Forcing rebuffer");
2986 /* Stop in progress fill, and clear open file descriptor */
2987 if (current_fd
>= 0)
2994 /* Reset buffer and track pointers */
2995 CUR_TI
->buf_idx
= buf_ridx
= buf_widx
= 0;
2996 track_widx
= track_ridx
;
2997 audio_clear_track_entries(true);
2998 CUR_TI
->available
= 0;
3000 /* Fill the buffer */
3001 last_peek_offset
= -1;
3002 CUR_TI
->filesize
= 0;
3003 CUR_TI
->start_pos
= 0;
3006 if (!CUR_TI
->taginfo_ready
)
3007 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
3009 audio_fill_file_buffer(false, true, 0);
3012 static int audio_check_new_track(void)
3014 int track_count
= audio_track_count();
3015 int old_track_ridx
= track_ridx
;
3021 if (playlist_next_dir(ci
.new_track
))
3024 CUR_TI
->taginfo_ready
= false;
3030 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3031 return Q_CODEC_REQUEST_FAILED
;
3038 /* If the playlist isn't that big */
3039 if (!playlist_check(ci
.new_track
))
3041 if (ci
.new_track
>= 0)
3043 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3044 return Q_CODEC_REQUEST_FAILED
;
3046 /* Find the beginning backward if the user over-skips it */
3047 while (!playlist_check(++ci
.new_track
))
3048 if (ci
.new_track
>= 0)
3050 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3051 return Q_CODEC_REQUEST_FAILED
;
3054 /* Update the playlist */
3055 last_peek_offset
-= ci
.new_track
;
3057 if (playlist_next(ci
.new_track
) < 0)
3059 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3060 return Q_CODEC_REQUEST_FAILED
;
3066 new_playlist
= false;
3069 /* Save the old track */
3072 /* Move to the new track */
3073 track_ridx
+= ci
.new_track
;
3074 track_ridx
&= MAX_TRACK_MASK
;
3077 playlist_end
= false;
3079 track_changed
= !automatic_skip
;
3081 /* If it is not safe to even skip this many track entries */
3082 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
3085 CUR_TI
->taginfo_ready
= false;
3090 forward
= ci
.new_track
> 0;
3093 /* If the target track is clearly not in memory */
3094 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
3100 /* The track may be in memory, see if it really is */
3103 if (!audio_buffer_wind_forward(track_ridx
, old_track_ridx
))
3108 int cur_idx
= track_ridx
;
3109 bool taginfo_ready
= true;
3110 bool wrap
= track_ridx
> old_track_ridx
;
3115 cur_idx
&= MAX_TRACK_MASK
;
3116 if (!(wrap
|| cur_idx
< old_track_ridx
))
3119 /* If we hit a track in between without valid tag info, bail */
3120 if (!tracks
[cur_idx
].taginfo_ready
)
3122 taginfo_ready
= false;
3126 tracks
[cur_idx
].available
= tracks
[cur_idx
].filesize
;
3127 if (tracks
[cur_idx
].codecsize
)
3128 tracks
[cur_idx
].has_codec
= true;
3132 if (!audio_buffer_wind_backward(track_ridx
, old_track_ridx
))
3137 CUR_TI
->taginfo_ready
= false;
3143 audio_update_trackinfo();
3144 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3145 return Q_CODEC_REQUEST_COMPLETE
;
3148 static int audio_rebuffer_and_seek(size_t newpos
)
3150 size_t real_preseek
;
3154 /* (Re-)open current track's file handle. */
3155 trackname
= playlist_peek(0);
3156 fd
= open(trackname
, O_RDONLY
);
3159 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3160 return Q_CODEC_REQUEST_FAILED
;
3163 if (current_fd
>= 0)
3167 playlist_end
= false;
3171 /* Clear codec buffer. */
3172 track_widx
= track_ridx
;
3173 tracks
[track_widx
].buf_idx
= buf_widx
= buf_ridx
= 0;
3175 last_peek_offset
= 0;
3177 audio_initialize_buffer_fill(true);
3179 /* This may have been tweaked by the id3v1 code */
3180 CUR_TI
->filesize
=filesize(fd
);
3181 if (newpos
> conf_preseek
)
3183 CUR_TI
->start_pos
= newpos
- conf_preseek
;
3184 lseek(current_fd
, CUR_TI
->start_pos
, SEEK_SET
);
3185 CUR_TI
->filerem
= CUR_TI
->filesize
- CUR_TI
->start_pos
;
3186 real_preseek
= conf_preseek
;
3190 CUR_TI
->start_pos
= 0;
3191 CUR_TI
->filerem
= CUR_TI
->filesize
;
3192 real_preseek
= newpos
;
3195 CUR_TI
->available
= 0;
3197 audio_read_file(real_preseek
);
3199 /* Account for the data we just read that is 'behind' us now */
3200 CUR_TI
->available
-= real_preseek
;
3202 buf_ridx
= RINGBUF_ADD(buf_ridx
, real_preseek
);
3204 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3205 return Q_CODEC_REQUEST_COMPLETE
;
3208 void audio_set_track_buffer_event(void (*handler
)(struct mp3entry
*id3
,
3211 track_buffer_callback
= handler
;
3214 void audio_set_track_unbuffer_event(void (*handler
)(struct mp3entry
*id3
,
3217 track_unbuffer_callback
= handler
;
3220 void audio_set_track_changed_event(void (*handler
)(struct mp3entry
*id3
))
3222 track_changed_callback
= handler
;
3225 unsigned long audio_prev_elapsed(void)
3227 return prev_track_elapsed
;
3230 static void audio_stop_codec_flush(void)
3232 ci
.stop_codec
= true;
3235 while (audio_codec_loaded
)
3238 /* If the audio codec is not loaded any more, and the audio is still
3239 * playing, it is now and _only_ now safe to call this function from the
3241 if (pcm_is_playing())
3243 pcmbuf_pause(paused
);
3246 static void audio_stop_playback(void)
3248 /* If we were playing, save resume information */
3251 struct mp3entry
*id3
= NULL
;
3253 if (!playlist_end
|| !ci
.stop_codec
)
3255 /* Set this early, the outside code yields and may allow the codec
3256 to try to wait for a reply on a buffer wait */
3257 ci
.stop_codec
= true;
3258 id3
= audio_current_track();
3261 /* Save the current playing spot, or NULL if the playlist has ended */
3262 playlist_update_resume_info(id3
);
3264 prev_track_elapsed
= curtrack_id3
.elapsed
;
3266 /* Increment index so runtime info is saved in audio_clear_track_entries().
3267 * Done here, as audio_stop_playback() may be called more than once.
3268 * Don't update runtime unless playback is stopped because of end of playlist.
3269 * Updating runtime when manually stopping a tracks, can destroy autoscores
3275 track_ridx
&= MAX_TRACK_MASK
;
3281 audio_stop_codec_flush();
3284 if (current_fd
>= 0)
3290 /* Mark all entries null. */
3291 audio_clear_track_entries(false);
3294 static void audio_play_start(size_t offset
)
3296 #if INPUT_SRC_CAPS != 0
3297 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
3298 audio_set_output_source(AUDIO_SRC_PLAYBACK
);
3301 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
3303 audio_stop_codec_flush();
3305 track_changed
= true;
3306 playlist_end
= false;
3314 if (current_fd
>= 0)
3320 sound_set_volume(global_settings
.volume
);
3321 track_widx
= track_ridx
= 0;
3323 /* Mark all entries null. */
3324 memset(tracks
, 0, sizeof(struct track_info
) * MAX_TRACK
);
3326 last_peek_offset
= -1;
3328 /* Officially playing */
3329 queue_reply(&audio_queue
, 1);
3331 audio_fill_file_buffer(true, false, offset
);
3333 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
3334 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
3338 /* Invalidates all but currently playing track. */
3339 static void audio_invalidate_tracks(void)
3341 if (audio_have_tracks())
3343 last_peek_offset
= 0;
3344 playlist_end
= false;
3345 track_widx
= track_ridx
;
3347 /* Mark all other entries null (also buffered wrong metadata). */
3348 audio_clear_track_entries(true);
3350 /* If the current track is fully buffered, advance the write pointer */
3351 if (tracks
[track_widx
].filerem
== 0)
3352 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
3354 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3356 audio_read_next_metadata();
3360 static void audio_new_playlist(void)
3362 /* Prepare to start a new fill from the beginning of the playlist */
3363 last_peek_offset
= -1;
3364 if (audio_have_tracks())
3367 skipped_during_pause
= true;
3368 playlist_end
= false;
3369 track_widx
= track_ridx
;
3370 audio_clear_track_entries(true);
3373 track_widx
&= MAX_TRACK_MASK
;
3375 /* Stop reading the current track */
3376 CUR_TI
->filerem
= 0;
3380 /* Mark the current track as invalid to prevent skipping back to it */
3381 CUR_TI
->taginfo_ready
= false;
3383 /* Invalidate the buffer other than the playing track */
3384 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3387 /* Signal the codec to initiate a track change forward */
3388 new_playlist
= true;
3391 /* Officially playing */
3392 queue_reply(&audio_queue
, 1);
3394 audio_fill_file_buffer(false, true, 0);
3397 static void audio_initiate_track_change(long direction
)
3399 playlist_end
= false;
3400 ci
.new_track
+= direction
;
3401 wps_offset
-= direction
;
3403 skipped_during_pause
= true;
3406 static void audio_initiate_dir_change(long direction
)
3408 playlist_end
= false;
3410 ci
.new_track
= direction
;
3412 skipped_during_pause
= true;
3416 * Layout audio buffer as follows - iram buffer depends on target:
3417 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
3419 static void audio_reset_buffer(void)
3421 /* see audio_get_recording_buffer if this is modified */
3422 logf("audio_reset_buffer");
3424 /* If the setup of anything allocated before the file buffer is
3425 changed, do check the adjustments after the buffer_alloc call
3426 as it will likely be affected and need sliding over */
3428 /* Initially set up file buffer as all space available */
3429 malloc_buf
= audiobuf
+ talk_get_bufsize();
3430 /* Align the malloc buf to line size. Especially important to cf
3431 targets that do line reads/writes. */
3432 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
3433 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
3434 filebuflen
= audiobufend
- filebuf
;
3436 /* Allow for codec swap space at end of audio buffer */
3437 if (talk_voice_required())
3439 /* Layout of swap buffer:
3440 * #ifdef IRAM_STEAL (dedicated iram_buf):
3441 * |iram_buf|...audiobuf...|dram_buf|audiobufend
3443 * audiobuf...|dram_buf|iram_buf|audiobufend
3445 #ifdef PLAYBACK_VOICE
3446 /* Check for an absolutely nasty situation which should never,
3447 ever happen - frankly should just panic */
3448 if (voice_codec_loaded
&& current_codec
!= CODEC_IDX_VOICE
)
3450 logf("buffer reset with voice swapped");
3452 /* line align length which line aligns the calculations below since
3453 all sizes are also at least line aligned - needed for memswap128 */
3456 filebuflen
-= CODEC_SIZE
;
3458 filebuflen
-= CODEC_SIZE
+ CODEC_IRAM_SIZE
;
3460 /* Allocate buffers for swapping voice <=> audio */
3461 /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
3462 and out of the way of buffer usage or else a call to audio_get_buffer
3463 and subsequent buffer use might trash the swap space. A plugin
3464 initializing IRAM after getting the full buffer would present similar
3465 problem. Options include: failing the request if the other buffer
3466 has been obtained already or never allowing use of the voice IRAM
3467 buffer within the audio buffer. Using buffer_alloc basically
3468 implements the second in a more convenient way. */
3469 dram_buf
= filebuf
+ filebuflen
;
3472 /* Allocate voice IRAM swap buffer once */
3473 if (iram_buf
== NULL
)
3475 iram_buf
= buffer_alloc(CODEC_IRAM_SIZE
);
3476 /* buffer_alloc moves audiobuf; this is safe because only the end
3477 * has been touched so far in this function and the address of
3478 * filebuf + filebuflen is not changed */
3479 malloc_buf
+= CODEC_IRAM_SIZE
;
3480 filebuf
+= CODEC_IRAM_SIZE
;
3481 filebuflen
-= CODEC_IRAM_SIZE
;
3484 /* Allocate iram_buf after dram_buf */
3485 iram_buf
= dram_buf
+ CODEC_SIZE
;
3486 #endif /* IRAM_STEAL */
3487 #endif /* PLAYBACK_VOICE */
3491 #ifdef PLAYBACK_VOICE
3492 /* No swap buffers needed */
3498 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
3499 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
3501 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
3502 will already be line aligned */
3505 /* Set the high watermark as 75% full...or 25% empty :) */
3507 high_watermark
= 3*filebuflen
/ 4;
3510 /* Clear any references to the file buffer */
3511 buffer_state
= BUFFER_STATE_INITIALIZED
;
3513 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
3514 /* Make sure everything adds up - yes, some info is a bit redundant but
3515 aids viewing and the sumation of certain variables should add up to
3516 the location of others. */
3519 unsigned char * pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
3520 logf("mabuf: %08X", (unsigned)malloc_buf
);
3521 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
3522 logf("fbuf: %08X", (unsigned)filebuf
);
3523 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
3524 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
3525 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
3526 logf("pcmb: %08X", (unsigned)pcmbuf
);
3527 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
3530 logf("dramb: %08X", (unsigned)dram_buf
);
3531 logf("drambe: %08X", (unsigned)(dram_buf
+ CODEC_SIZE
));
3535 logf("iramb: %08X", (unsigned)iram_buf
);
3536 logf("irambe: %08X", (unsigned)(iram_buf
+ CODEC_IRAM_SIZE
));
3543 /* we dont want this rebuffering on targets with little ram
3544 because the disk may never spin down */
3545 static bool ata_fillbuffer_callback(void)
3547 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
, 0);
3552 static void audio_thread(void)
3554 struct queue_event ev
;
3558 #ifdef PLAYBACK_VOICE
3559 /* Unlock semaphore that init stage locks before creating this thread */
3560 semaphore_release(&sem_codecthread
);
3562 /* Buffers must be set up by now - should panic - really */
3563 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
3565 logf("audio_thread start: no buffer");
3568 /* Have to wait for voice to load up or else the codec swap will be
3569 invalid when an audio codec is loaded */
3570 wait_for_voice_swap_in();
3577 queue_wait_w_tmo(&audio_queue
, &ev
, 0);
3578 if (ev
.id
== SYS_TIMEOUT
)
3579 ev
.id
= Q_AUDIO_FILL_BUFFER
;
3583 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
3585 if (playing
&& (ev
.id
== SYS_TIMEOUT
) &&
3586 (FILEBUFUSED
< high_watermark
))
3587 register_ata_idle_func(ata_fillbuffer_callback
);
3593 case Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
:
3594 /* only fill if the disk is still spining */
3596 if (!ata_disk_is_active())
3599 #endif /* MEM > 8 */
3600 /* else fall through to Q_AUDIO_FILL_BUFFER */
3601 case Q_AUDIO_FILL_BUFFER
:
3602 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3604 if (!playing
|| playlist_end
|| ci
.stop_codec
)
3606 audio_fill_file_buffer(false, false, 0);
3610 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3611 if (playing
&& ev
.data
<= 0)
3612 audio_new_playlist();
3615 audio_stop_playback();
3616 audio_play_start((size_t)ev
.data
);
3621 LOGFQUEUE("audio < Q_AUDIO_STOP");
3623 audio_stop_playback();
3625 queue_clear(&audio_queue
);
3629 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3630 if (!(bool) ev
.data
&& skipped_during_pause
&& !pcmbuf_is_crossfade_active())
3631 pcmbuf_play_stop(); /* Flush old track on resume after skip */
3632 skipped_during_pause
= false;
3635 pcmbuf_pause((bool)ev
.data
);
3636 paused
= (bool)ev
.data
;
3640 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3641 audio_initiate_track_change((long)ev
.data
);
3644 case Q_AUDIO_PRE_FF_REWIND
:
3645 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3651 case Q_AUDIO_FF_REWIND
:
3652 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3655 ci
.seek_time
= (long)ev
.data
+1;
3658 case Q_AUDIO_REBUFFER_SEEK
:
3659 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
3660 queue_reply(&audio_queue
, audio_rebuffer_and_seek(ev
.data
));
3663 case Q_AUDIO_CHECK_NEW_TRACK
:
3664 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3665 queue_reply(&audio_queue
, audio_check_new_track());
3668 case Q_AUDIO_DIR_SKIP
:
3669 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3670 playlist_end
= false;
3671 audio_initiate_dir_change(ev
.data
);
3675 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3676 audio_invalidate_tracks();
3679 case Q_AUDIO_TRACK_CHANGED
:
3680 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3681 if (track_changed_callback
)
3682 track_changed_callback(&curtrack_id3
);
3683 track_changed
= true;
3684 playlist_update_resume_info(audio_current_track());
3688 case SYS_USB_CONNECTED
:
3689 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3691 audio_stop_playback();
3692 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
3693 usb_wait_for_disconnect(&audio_queue
);
3698 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3702 LOGFQUEUE("audio < default");
3707 #ifdef ROCKBOX_HAS_LOGF
3708 static void audio_test_track_changed_event(struct mp3entry
*id3
)
3712 logf("tce:%s", id3
->path
);
3716 /* Initialize the audio system - called from init() in main.c.
3717 * Last function because of all the references to internal symbols
3719 void audio_init(void)
3721 #ifdef PLAYBACK_VOICE
3722 static bool voicetagtrue
= true;
3723 static struct mp3entry id3_voice
;
3724 struct thread_entry
*voice_thread_p
= NULL
;
3726 struct thread_entry
*audio_thread_p
;
3728 /* Can never do this twice */
3729 if (audio_is_initialized
)
3731 logf("audio: already initialized");
3735 logf("audio: initializing");
3737 /* Initialize queues before giving control elsewhere in case it likes
3738 to send messages. Thread creation will be delayed however so nothing
3739 starts running until ready if something yields such as talk_init. */
3740 #ifdef PLAYBACK_VOICE
3741 /* Take ownership of lock to prevent playback of anything before audio
3742 hardware is initialized - audio thread unlocks it after final init
3744 semaphore_init(&sem_codecthread
, 1, 0);
3745 event_init(&event_codecthread
, EVENT_MANUAL
| STATE_SIGNALED
);
3747 queue_init(&audio_queue
, true);
3748 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
3749 queue_init(&codec_queue
, true);
3753 #ifdef ROCKBOX_HAS_LOGF
3754 audio_set_track_changed_event(audio_test_track_changed_event
);
3757 /* Initialize codec api. */
3758 ci
.read_filebuf
= codec_filebuf_callback
;
3759 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
3760 ci
.get_codec_memory
= codec_get_memory_callback
;
3761 ci
.request_buffer
= codec_request_buffer_callback
;
3762 ci
.advance_buffer
= codec_advance_buffer_callback
;
3763 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
3764 ci
.request_next_track
= codec_request_next_track_callback
;
3765 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
3766 ci
.seek_buffer
= codec_seek_buffer_callback
;
3767 ci
.seek_complete
= codec_seek_complete_callback
;
3768 ci
.set_elapsed
= codec_set_elapsed_callback
;
3769 ci
.set_offset
= codec_set_offset_callback
;
3770 ci
.configure
= codec_configure_callback
;
3771 ci
.discard_codec
= codec_discard_codec_callback
;
3773 /* Initialize voice codec api. */
3774 #ifdef PLAYBACK_VOICE
3775 memcpy(&ci_voice
, &ci
, sizeof(ci_voice
));
3776 memset(&id3_voice
, 0, sizeof(id3_voice
));
3777 ci_voice
.read_filebuf
= voice_filebuf_callback
;
3778 ci_voice
.pcmbuf_insert
= voice_pcmbuf_insert_callback
;
3779 ci_voice
.get_codec_memory
= voice_get_memory_callback
;
3780 ci_voice
.request_buffer
= voice_request_buffer_callback
;
3781 ci_voice
.advance_buffer
= voice_advance_buffer_callback
;
3782 ci_voice
.advance_buffer_loc
= voice_advance_buffer_loc_callback
;
3783 ci_voice
.request_next_track
= voice_request_next_track_callback
;
3784 ci_voice
.mp3_get_filepos
= voice_mp3_get_filepos_callback
;
3785 ci_voice
.seek_buffer
= voice_seek_buffer_callback
;
3786 ci_voice
.seek_complete
= voice_do_nothing
;
3787 ci_voice
.set_elapsed
= voice_set_elapsed_callback
;
3788 ci_voice
.set_offset
= voice_set_offset_callback
;
3789 ci_voice
.configure
= voice_configure_callback
;
3790 ci_voice
.discard_codec
= voice_do_nothing
;
3791 ci_voice
.taginfo_ready
= &voicetagtrue
;
3792 ci_voice
.id3
= &id3_voice
;
3793 id3_voice
.frequency
= 11200;
3794 id3_voice
.length
= 1000000L;
3797 /* initialize the buffer */
3800 /* audio_reset_buffer must to know the size of voice buffer so init
3804 codec_thread_p
= create_thread(
3805 codec_thread
, codec_stack
, sizeof(codec_stack
),
3806 CREATE_THREAD_FROZEN
,
3807 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
3810 audio_thread_p
= create_thread(audio_thread
, audio_stack
,
3811 sizeof(audio_stack
), CREATE_THREAD_FROZEN
,
3812 audio_thread_name
IF_PRIO(, PRIORITY_BUFFERING
)
3815 buffering_thread_p
= create_thread( buffering_thread
, buffering_stack
,
3816 sizeof(buffering_stack
), CREATE_THREAD_FROZEN
,
3817 buffering_thread_name
IF_PRIO(, PRIORITY_BUFFERING
)
3818 IF_COP(, CPU
, true));
3820 #ifdef PLAYBACK_VOICE
3821 /* TODO: Change this around when various speech codecs can be used */
3822 if (talk_voice_required())
3824 logf("Starting voice codec");
3825 queue_init(&voice_queue
, true);
3826 voice_thread_p
= create_thread(voice_thread
, voice_stack
,
3827 sizeof(voice_stack
), CREATE_THREAD_FROZEN
,
3829 IF_PRIO(, PRIORITY_PLAYBACK
) IF_COP(, CPU
));
3833 /* Set crossfade setting for next buffer init which should be about... */
3834 pcmbuf_crossfade_enable(global_settings
.crossfade
);
3836 /* ...now! Set up the buffers */
3837 audio_reset_buffer();
3839 buffering_init(filebuf
, filebuflen
);
3841 /* Probably safe to say */
3842 audio_is_initialized
= true;
3844 sound_settings_apply();
3846 eq_hw_enable(global_settings
.eq_hw_enabled
);
3848 #ifndef HAVE_FLASH_STORAGE
3849 audio_set_buffer_margin(global_settings
.buffer_margin
);
3852 /* it's safe to let the threads run now */
3853 thread_thaw(codec_thread_p
);
3854 #ifdef PLAYBACK_VOICE
3856 thread_thaw(voice_thread_p
);
3858 thread_thaw(audio_thread_p
);
3859 thread_thaw(buffering_thread_p
);