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 /* Define LOGF_ENABLE to enable logf output in this file */
92 /*#define LOGF_ENABLE*/
95 /* macros to enable logf for queues
96 logging on SYS_TIMEOUT can be disabled */
98 /* Define this for logf output of all queuing except SYS_TIMEOUT */
99 #define PLAYBACK_LOGQUEUES
100 /* Define this to logf SYS_TIMEOUT messages */
101 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
104 #ifdef PLAYBACK_LOGQUEUES
105 #define LOGFQUEUE logf
107 #define LOGFQUEUE(...)
110 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
111 #define LOGFQUEUE_SYS_TIMEOUT logf
113 #define LOGFQUEUE_SYS_TIMEOUT(...)
117 /* Define one constant that includes recording related functionality */
118 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
119 #define AUDIO_HAVE_RECORDING
127 Q_AUDIO_PRE_FF_REWIND
,
129 /* Q_AUDIO_REBUFFER_SEEK, */
130 Q_AUDIO_CHECK_NEW_TRACK
,
132 Q_AUDIO_TRACK_CHANGED
,
137 Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
,
139 Q_CODEC_REQUEST_COMPLETE
,
140 Q_CODEC_REQUEST_FAILED
,
148 #ifdef AUDIO_HAVE_RECORDING
154 /* As defined in plugins/lib/xxx2wav.h */
156 #define MALLOC_BUFSIZE (512*1024)
157 #define GUARD_BUFSIZE (32*1024)
159 #define MALLOC_BUFSIZE (100*1024)
160 #define GUARD_BUFSIZE (8*1024)
163 /* As defined in plugin.lds */
165 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
166 #define CODEC_IRAM_SIZE ((size_t)0xc000)
167 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
168 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
169 #define CODEC_IRAM_SIZE ((size_t)0x10000)
171 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
172 #define CODEC_IRAM_SIZE ((size_t)0xc000)
175 #ifndef IBSS_ATTR_VOICE_STACK
176 #define IBSS_ATTR_VOICE_STACK IBSS_ATTR
179 bool audio_is_initialized
= false;
181 /* Variables are commented with the threads that use them: *
182 * A=audio, C=codec, V=voice. A suffix of - indicates that *
183 * the variable is read but not updated on that thread. */
184 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
186 /* Main state control */
187 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR
= false; /* Codec loaded? (C/A-) */
188 static volatile bool playing NOCACHEBSS_ATTR
= false; /* Is audio playing? (A) */
189 static volatile bool paused NOCACHEBSS_ATTR
= false; /* Is audio paused? (A/C-) */
190 static volatile bool filling IDATA_ATTR
= false; /* Is file buffer refilling? (A/C-) */
192 /* Ring buffer where compressed audio and codecs are loaded */
193 static unsigned char *filebuf
= NULL
; /* Start of buffer (A/C-) */
194 static unsigned char *malloc_buf
= NULL
; /* Start of malloc buffer (A/C-) */
195 /* FIXME: make filebuflen static */
196 size_t filebuflen
= 0; /* Size of buffer (A/C-) */
197 /* FIXME: make buf_ridx (C/A-) */
199 /* Possible arrangements of the buffer */
200 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
201 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
202 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
203 static int buffer_state
= BUFFER_STATE_TRASHED
; /* Buffer state */
205 struct mp3entry curtrack_id3
;
206 struct mp3entry nexttrack_id3
;
208 /* Track info structure about songs in the file buffer (A/C-) */
210 int audio_hid
; /* The ID for the track's buffer handle */
211 int id3_hid
; /* The ID for the track's metadata handle */
212 int codec_hid
; /* The ID for the track's codec handle */
214 size_t codecsize
; /* Codec length in bytes */
215 size_t filesize
; /* File total length */
217 bool taginfo_ready
; /* Is metadata read */
219 bool event_sent
; /* Was this track's buffered event sent */
222 static struct track_info tracks
[MAX_TRACK
];
223 static volatile int track_ridx
= 0; /* Track being decoded (A/C-) */
224 static int track_widx
= 0; /* Track being buffered (A) */
227 static struct track_info
*prev_ti
= NULL
; /* Previous track info pointer (A/C-) */
230 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
232 /* Set by the audio thread when the current track information has updated
233 * and the WPS may need to update its cached information */
234 static bool track_changed
= false;
236 /* Information used only for filling the buffer */
237 /* Playlist steps from playing track to next track to be buffered (A) */
238 static int last_peek_offset
= 0;
240 /* Scrobbler support */
241 static unsigned long prev_track_elapsed
= 0; /* Previous track elapsed time (C/A-)*/
243 /* Track change controls */
244 static bool automatic_skip
= false; /* Who initiated in-progress skip? (C/A-) */
245 static bool playlist_end
= false; /* Has the current playlist ended? (A) */
246 static bool dir_skip
= false; /* Is a directory skip pending? (A) */
247 static bool new_playlist
= false; /* Are we starting a new playlist? (A) */
248 static int wps_offset
= 0; /* Pending track change offset, to keep WPS responsive (A) */
249 static bool skipped_during_pause
= false; /* Do we need to clear the PCM buffer when playback resumes (A) */
251 /* Callbacks which applications or plugins may set */
252 /* When the playing track has changed from the user's perspective */
253 void (*track_changed_callback
)(struct mp3entry
*id3
) = NULL
;
254 /* When a track has been buffered */
255 void (*track_buffer_callback
)(struct mp3entry
*id3
, bool last_track
) = NULL
;
256 /* When a track's buffer has been overwritten or cleared */
257 void (*track_unbuffer_callback
)(struct mp3entry
*id3
, bool last_track
) = NULL
;
260 static size_t conf_watermark
= 0; /* Level to trigger filebuf fill (A/C) FIXME */
261 static size_t conf_filechunk
= 0; /* Largest chunk the codec accepts (A/C) FIXME */
262 static size_t conf_preseek
= 0; /* Codec pre-seek margin (A/C) FIXME */
263 static size_t buffer_margin
= 0; /* Buffer margin aka anti-skip buffer (A/C-) */
265 static size_t high_watermark
= 0; /* High watermark for rebuffer (A/V/other) */
268 /* Multiple threads */
269 static void set_current_codec(int codec_idx
);
270 /* Set the watermark to trigger buffer fill (A/C) FIXME */
271 static void set_filebuf_watermark(int seconds
);
274 static struct event_queue audio_queue NOCACHEBSS_ATTR
;
275 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR
;
276 static long audio_stack
[(DEFAULT_STACK_SIZE
+ 0x1000)/sizeof(long)];
277 static const char audio_thread_name
[] = "audio";
279 static void audio_thread(void);
280 static void audio_initiate_track_change(long direction
);
281 static bool audio_have_tracks(void);
282 static void audio_reset_buffer(void);
285 extern struct codec_api ci
;
286 static struct event_queue codec_queue NOCACHEBSS_ATTR
;
287 static struct queue_sender_list codec_queue_sender_list
;
288 static long codec_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
290 static const char codec_thread_name
[] = "codec";
291 struct thread_entry
*codec_thread_p
; /* For modifying thread priority later. */
293 static volatile int current_codec IDATA_ATTR
; /* Current codec (normal/voice) */
295 /* Buffering thread */
296 void buffering_thread(void);
297 static long buffering_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)];
298 static const char buffering_thread_name
[] = "buffering";
299 struct thread_entry
*buffering_thread_p
;
302 #ifdef PLAYBACK_VOICE
304 extern struct codec_api ci_voice
;
306 static struct thread_entry
*voice_thread_p
= NULL
;
307 static struct event_queue voice_queue NOCACHEBSS_ATTR
;
308 static long voice_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
309 IBSS_ATTR_VOICE_STACK
;
310 static const char voice_thread_name
[] = "voice codec";
312 /* Voice codec swapping control */
313 extern unsigned char codecbuf
[]; /* DRAM codec swap buffer */
316 /* IRAM codec swap buffer for sim*/
317 static unsigned char sim_iram
[CODEC_IRAM_SIZE
];
318 #undef CODEC_IRAM_ORIGIN
319 #define CODEC_IRAM_ORIGIN sim_iram
322 /* iram_buf and dram_buf are either both NULL or both non-NULL */
323 /* Pointer to IRAM buffer for codec swapping */
324 static unsigned char *iram_buf
= NULL
;
325 /* Pointer to DRAM buffer for codec swapping */
326 static unsigned char *dram_buf
= NULL
;
327 /* Parity of swap_codec calls - needed because one codec swapping itself in
328 automatically swaps in the other and the swap when unlocking should not
329 happen if the parity is even.
331 static bool swap_codec_parity NOCACHEBSS_ATTR
= false; /* true=odd, false=even */
332 /* Locking to control which codec (normal/voice) is running */
333 static struct semaphore sem_codecthread NOCACHEBSS_ATTR
;
334 static struct event event_codecthread NOCACHEBSS_ATTR
;
337 static volatile bool voice_thread_start
= false; /* Triggers voice playback (A/V) */
338 static volatile bool voice_is_playing NOCACHEBSS_ATTR
= false; /* Is voice currently playing? (V) */
339 static volatile bool voice_codec_loaded NOCACHEBSS_ATTR
= false; /* Is voice codec loaded (V/A-) */
340 static unsigned char *voicebuf
= NULL
;
341 static size_t voice_remaining
= 0;
344 /* Voice IRAM has been stolen for other use */
345 static bool voice_iram_stolen
= false;
348 static void (*voice_getmore
)(unsigned char** start
, size_t* size
) = NULL
;
351 void (*callback
)(unsigned char **start
, size_t* size
);
355 static void voice_thread(void);
356 static void voice_stop(void);
358 #endif /* PLAYBACK_VOICE */
361 /* --- Helper functions --- */
363 struct mp3entry
*bufgetid3(int handle_id
)
368 struct mp3entry
*id3
;
369 ssize_t ret
= bufgetdata(handle_id
, 0, (unsigned char **)&id3
);
371 if (ret
< 0 || ret
!= sizeof(struct mp3entry
))
377 unsigned char *getptr(int handle_id
)
380 ssize_t ret
= bufgetdata(handle_id
, 0, &ptr
);
388 void clear_track_info(struct track_info
*track
)
393 if (track
->codec_hid
> 0) {
394 bufclose(track
->codec_hid
);
397 if (track
->id3_hid
> 0) {
398 bufclose(track
->id3_hid
);
401 if (track
->audio_hid
> 0) {
402 bufclose(track
->audio_hid
);
405 memset(track
, 0, sizeof(struct track_info
));
408 /* --- External interfaces --- */
410 void mp3_play_data(const unsigned char* start
, int size
,
411 void (*get_more
)(unsigned char** start
, size_t* size
))
413 #ifdef PLAYBACK_VOICE
414 static struct voice_info voice_clip
;
415 voice_clip
.callback
= get_more
;
416 voice_clip
.buf
= (unsigned char*)start
;
417 voice_clip
.size
= size
;
418 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
419 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
420 LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
421 queue_post(&voice_queue
, Q_VOICE_PLAY
, (intptr_t)&voice_clip
);
422 voice_thread_start
= true;
431 void mp3_play_stop(void)
433 #ifdef PLAYBACK_VOICE
434 queue_remove_from_head(&voice_queue
, Q_VOICE_STOP
);
435 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
436 queue_post(&voice_queue
, Q_VOICE_STOP
, 1);
440 void mp3_play_pause(bool play
)
446 bool mp3_is_playing(void)
448 #ifdef PLAYBACK_VOICE
449 return voice_is_playing
;
455 /* If voice could be swapped out - wait for it to return
456 * Used by buffer claming functions.
458 static void wait_for_voice_swap_in(void)
460 #ifdef PLAYBACK_VOICE
461 if (NULL
== iram_buf
)
464 event_wait(&event_codecthread
, STATE_NONSIGNALED
);
465 #endif /* PLAYBACK_VOICE */
468 /* This sends a stop message and the audio thread will dump all it's
469 subsequenct messages */
470 static void audio_hard_stop(void)
473 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
474 queue_send(&audio_queue
, Q_AUDIO_STOP
, 1);
477 unsigned char *audio_get_buffer(bool talk_buf
, size_t *buffer_size
)
479 unsigned char *buf
, *end
;
481 if (audio_is_initialized
)
484 wait_for_voice_swap_in();
485 #ifdef PLAYBACK_VOICE
489 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
491 if (buffer_size
== NULL
)
493 /* Special case for talk_init to use since it already knows it's
495 buffer_state
= BUFFER_STATE_TRASHED
;
499 if (talk_buf
|| buffer_state
== BUFFER_STATE_TRASHED
500 || !talk_voice_required())
502 logf("get buffer: talk, audio");
503 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
504 the talk buffer is not needed because voice isn't being used, or
505 could be BUFFER_STATE_TRASHED already. If state is
506 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
507 without the caller knowing what's going on. Changing certain settings
508 may move it to a worse condition but the memory in use by something
509 else will remain undisturbed.
511 if (buffer_state
!= BUFFER_STATE_TRASHED
)
514 buffer_state
= BUFFER_STATE_TRASHED
;
522 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
523 still BUFFER_STATE_INITIALIZED */
524 /* Skip talk buffer and move pcm buffer to end to maximize available
525 contiguous memory - no audio running means voice will not need the
527 logf("get buffer: audio");
528 buf
= audiobuf
+ talk_get_bufsize();
529 end
= audiobufend
- pcmbuf_init(audiobufend
);
530 buffer_state
= BUFFER_STATE_VOICED_ONLY
;
533 *buffer_size
= end
- buf
;
539 void audio_iram_steal(void)
541 /* We need to stop audio playback in order to use codec IRAM */
544 #ifdef PLAYBACK_VOICE
545 if (NULL
!= iram_buf
)
547 /* Can't already be stolen */
548 if (voice_iram_stolen
)
551 /* Must wait for voice to be current again if it is swapped which
552 would cause the caller's buffer to get clobbered when voice locks
553 and runs - we'll wait for it to lock and yield again then make sure
554 the ride has come to a complete stop */
555 wait_for_voice_swap_in();
558 /* Save voice IRAM but just memcpy - safe to do here since voice
559 is current and no audio codec is loaded */
560 memcpy(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
561 voice_iram_stolen
= true;
565 /* Nothing much to do if no voice */
566 voice_iram_stolen
= false;
570 #endif /* IRAM_STEAL */
572 #ifdef HAVE_RECORDING
573 unsigned char *audio_get_recording_buffer(size_t *buffer_size
)
575 /* Don't allow overwrite of voice swap area or we'll trash the
576 swapped-out voice codec but can use whole thing if none */
579 /* Stop audio and voice. Wait for voice to swap in and be clear
580 of pending events to ensure trouble-free operation of encoders */
582 wait_for_voice_swap_in();
583 #ifdef PLAYBACK_VOICE
588 #ifdef PLAYBACK_VOICE
589 /* If no dram_buf, swap space not used and recording gets more
590 memory. Codec swap areas will remain unaffected by the next init
591 since they're allocated at the end of the buffer and their sizes
592 don't change between calls */
595 #endif /* PLAYBACK_VOICE */
598 buffer_state
= BUFFER_STATE_TRASHED
;
600 *buffer_size
= end
- audiobuf
;
602 return (unsigned char *)audiobuf
;
605 bool audio_load_encoder(int afmt
)
608 const char *enc_fn
= get_codec_filename(afmt
| CODEC_TYPE_ENCODER
);
612 audio_remove_encoder();
613 ci
.enc_codec_loaded
= 0; /* clear any previous error condition */
615 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
616 queue_post(&codec_queue
, Q_ENCODER_LOAD_DISK
, (intptr_t)enc_fn
);
618 while (ci
.enc_codec_loaded
== 0)
621 logf("codec loaded: %d", ci
.enc_codec_loaded
);
623 return ci
.enc_codec_loaded
> 0;
628 } /* audio_load_encoder */
630 void audio_remove_encoder(void)
633 /* force encoder codec unload (if currently loaded) */
634 if (ci
.enc_codec_loaded
<= 0)
637 ci
.stop_encoder
= true;
638 while (ci
.enc_codec_loaded
> 0)
641 } /* audio_remove_encoder */
643 #endif /* HAVE_RECORDING */
645 struct mp3entry
* audio_current_track(void)
647 const char *filename
;
649 static struct mp3entry temp_id3
;
651 int offset
= ci
.new_track
+ wps_offset
;
653 cur_idx
= track_ridx
+ offset
;
654 cur_idx
&= MAX_TRACK_MASK
;
656 if (tracks
[cur_idx
].id3_hid
> 0)
657 return &curtrack_id3
;
659 memset(&temp_id3
, 0, sizeof(struct mp3entry
));
661 filename
= playlist_peek(0);
663 filename
= "No file!";
665 #ifdef HAVE_TC_RAMCACHE
666 if (tagcache_fill_tags(&temp_id3
, filename
))
670 p
= strrchr(filename
, '/');
676 strncpy(temp_id3
.path
, p
, sizeof(temp_id3
.path
)-1);
677 temp_id3
.title
= &temp_id3
.path
[0];
682 struct mp3entry
* audio_next_track(void)
684 int next_idx
= track_ridx
;
686 if (!audio_have_tracks())
690 next_idx
&= MAX_TRACK_MASK
;
692 if (tracks
[next_idx
].id3_hid
<= 0)
695 return &nexttrack_id3
;
698 bool audio_has_changed_track(void)
702 track_changed
= false;
709 void audio_play(long offset
)
713 #ifdef PLAYBACK_VOICE
714 /* Truncate any existing voice output so we don't have spelling
715 * etc. over the first part of the played track */
720 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset
);
721 /* Don't return until playback has actually started */
722 queue_send(&audio_queue
, Q_AUDIO_PLAY
, offset
);
725 void audio_stop(void)
728 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
729 /* Don't return until playback has actually stopped */
730 queue_send(&audio_queue
, Q_AUDIO_STOP
, 0);
733 void audio_pause(void)
735 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
736 /* Don't return until playback has actually paused */
737 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, true);
740 void audio_resume(void)
742 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
743 /* Don't return until playback has actually resumed */
744 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, false);
747 void audio_next(void)
749 if (playlist_check(ci
.new_track
+ wps_offset
+ 1))
751 if (global_settings
.beep
)
752 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
754 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
755 queue_post(&audio_queue
, Q_AUDIO_SKIP
, 1);
756 /* Update wps while our message travels inside deep playback queues. */
758 track_changed
= true;
762 /* No more tracks. */
763 if (global_settings
.beep
)
764 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
768 void audio_prev(void)
770 if (playlist_check(ci
.new_track
+ wps_offset
- 1))
772 if (global_settings
.beep
)
773 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
775 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
776 queue_post(&audio_queue
, Q_AUDIO_SKIP
, -1);
777 /* Update wps while our message travels inside deep playback queues. */
779 track_changed
= true;
783 /* No more tracks. */
784 if (global_settings
.beep
)
785 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
789 void audio_next_dir(void)
791 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
792 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, 1);
795 void audio_prev_dir(void)
797 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
798 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, -1);
801 void audio_pre_ff_rewind(void)
803 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
804 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
807 void audio_ff_rewind(long newpos
)
809 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
810 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, newpos
);
813 void audio_flush_and_reload_tracks(void)
815 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
816 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
819 void audio_error_clear(void)
821 #ifdef AUDIO_HAVE_RECORDING
822 pcm_rec_error_clear();
826 int audio_status(void)
831 ret
|= AUDIO_STATUS_PLAY
;
834 ret
|= AUDIO_STATUS_PAUSE
;
836 #ifdef HAVE_RECORDING
837 /* Do this here for constitency with mpeg.c version */
838 ret
|= pcm_rec_status();
844 int audio_get_file_pos(void)
849 #ifndef HAVE_FLASH_STORAGE
850 void audio_set_buffer_margin(int setting
)
852 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
853 buffer_margin
= lookup
[setting
];
854 logf("buffer margin: %d", buffer_margin
);
855 set_filebuf_watermark(buffer_margin
);
859 /* Take nescessary steps to enable or disable the crossfade setting */
860 void audio_set_crossfade(int enable
)
866 /* Tell it the next setting to use */
867 pcmbuf_crossfade_enable(enable
);
869 /* Return if size hasn't changed or this is too early to determine
870 which in the second case there's no way we could be playing
872 if (pcmbuf_is_same_size())
874 /* This function is a copout and just syncs some variables -
875 to be removed at a later date */
876 pcmbuf_crossfade_enable_finished();
881 was_playing
= playing
;
883 /* Playback has to be stopped before changing the buffer size */
886 /* Store the track resume position */
887 offset
= curtrack_id3
.offset
;
888 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK
));
891 /* Blast it - audio buffer will have to be setup again next time
893 audio_get_buffer(true, &size
);
895 /* Restart playback if audio was running previously */
900 /* --- Routines called from multiple threads --- */
901 static void set_current_codec(int codec_idx
)
903 current_codec
= codec_idx
;
904 dsp_configure(DSP_SWITCH_CODEC
, codec_idx
);
907 #ifdef PLAYBACK_VOICE
908 static void swap_codec(void)
912 /* Swap nothing if no swap buffers exist */
913 if (dram_buf
== NULL
)
915 logf("swap: no swap buffers");
919 my_codec
= current_codec
;
921 logf("swapping out codec: %d", my_codec
);
923 /* Invert this when a codec thread enters and leaves */
924 swap_codec_parity
= !swap_codec_parity
;
926 /* If this is true, an odd number of calls has occurred and there's
927 no codec thread waiting to swap us out when it locks and runs. This
928 occurs when playback is stopped or when just starting playback and
929 the audio thread is loading a codec; parities should always be even
930 on entry when a thread calls this during playback */
931 if (swap_codec_parity
)
933 /* Save our current IRAM and DRAM */
935 if (voice_iram_stolen
)
937 logf("swap: iram restore");
938 voice_iram_stolen
= false;
939 /* Don't swap trashed data into buffer as the voice IRAM will
940 already be swapped out - should _always_ be the case if
941 voice_iram_stolen is true since the voice has been swapped
943 if (my_codec
== CODEC_IDX_VOICE
)
945 logf("voice iram already swapped");
951 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
957 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
958 /* No cache invalidation needed; it will be done in codec_load_ram
959 or we won't be here otherwise */
962 /* Release my semaphore */
963 semaphore_release(&sem_codecthread
);
964 logf("unlocked: %d", my_codec
);
966 /* Wait for other codec */
967 event_wait(&event_codecthread
,
968 (my_codec
== CODEC_IDX_AUDIO
) ? STATE_NONSIGNALED
: STATE_SIGNALED
);
970 /* Wait for other codec to unlock */
971 logf("waiting for lock: %d", my_codec
);
972 semaphore_wait(&sem_codecthread
);
975 set_current_codec(my_codec
);
976 event_set_state(&event_codecthread
,
977 (my_codec
== CODEC_IDX_AUDIO
) ? STATE_SIGNALED
: STATE_NONSIGNALED
);
979 /* Reload our IRAM and DRAM */
980 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
981 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
984 /* Flip parity again */
985 swap_codec_parity
= !swap_codec_parity
;
987 logf("resuming codec: %d", my_codec
);
990 /* This function is meant to be used by the buffer stealing functions to
991 ensure the codec is no longer active and so voice will be swapped-in
992 before it is called */
993 static void voice_stop(void)
995 /* Must have a voice codec loaded or we'll hang forever here */
996 if (!voice_codec_loaded
)
1001 /* Loop until voice empties it's queue, stops and picks up on the new
1002 track; the voice thread must be stopped and waiting for messages
1003 outside the codec */
1004 while (voice_is_playing
|| !queue_empty(&voice_queue
) ||
1012 /* Is voice still speaking */
1013 /* Unfortunately only reliable when music is not also playing. */
1014 static bool is_voice_speaking(void)
1016 return is_voice_queued()
1018 || (!playing
&& pcm_is_playing());
1021 #endif /* PLAYBACK_VOICE */
1023 /* Wait for voice to finish speaking. */
1024 /* Also only reliable when music is not also playing. */
1025 void voice_wait(void)
1027 #ifdef PLAYBACK_VOICE
1028 while (is_voice_speaking())
1033 static void set_filebuf_watermark(int seconds
)
1038 return; /* Audio buffers not yet set up */
1040 bytes
= MAX(curtrack_id3
.bitrate
* seconds
* (1000/8), conf_watermark
);
1041 bytes
= MIN(bytes
, filebuflen
/ 2);
1042 conf_watermark
= bytes
;
1045 const char * get_codec_filename(int cod_spec
)
1049 #ifdef HAVE_RECORDING
1050 /* Can choose decoder or encoder if one available */
1051 int type
= cod_spec
& CODEC_TYPE_MASK
;
1052 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
1054 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
1055 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
1057 fname
= (type
== CODEC_TYPE_ENCODER
) ?
1058 audio_formats
[afmt
].codec_enc_root_fn
:
1059 audio_formats
[afmt
].codec_root_fn
;
1062 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
1063 afmt
, fname
? fname
: "<unknown>");
1064 #else /* !HAVE_RECORDING */
1065 /* Always decoder */
1066 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
1067 cod_spec
= AFMT_UNKNOWN
;
1068 fname
= audio_formats
[cod_spec
].codec_root_fn
;
1069 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
1070 #endif /* HAVE_RECORDING */
1073 } /* get_codec_filename */
1076 /* --- Voice thread --- */
1078 #ifdef PLAYBACK_VOICE
1080 static bool voice_pcmbuf_insert_callback(
1081 const void *ch1
, const void *ch2
, int count
)
1083 const char *src
[2] = { ch1
, ch2
};
1087 int out_count
= dsp_output_count(count
);
1091 while ((dest
= pcmbuf_request_voice_buffer(
1092 &out_count
, playing
)) == NULL
)
1094 if (playing
&& audio_codec_loaded
)
1100 /* Get the real input_size for output_size bytes, guarding
1101 * against resampling buffer overflows. */
1102 inp_count
= dsp_input_count(out_count
);
1107 /* Input size has grown, no error, just don't write more than length */
1108 if (inp_count
> count
)
1111 out_count
= dsp_process(dest
, src
, inp_count
);
1118 pcmbuf_mix_voice(out_count
);
1119 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
1124 pcmbuf_write_complete(out_count
);
1130 } /* voice_pcmbuf_insert_callback */
1132 static void* voice_get_memory_callback(size_t *size
)
1134 /* Voice should have no use for this. If it did, we'd have to
1135 swap the malloc buffer as well. */
1140 static void voice_set_elapsed_callback(unsigned int value
)
1145 static void voice_set_offset_callback(size_t value
)
1150 static void voice_configure_callback(int setting
, intptr_t value
)
1152 if (!dsp_configure(setting
, value
))
1154 logf("Illegal key:%d", setting
);
1158 static size_t voice_filebuf_callback(void *ptr
, size_t size
)
1166 /* Handle Q_VOICE_STOP and part of SYS_USB_CONNECTED */
1167 static bool voice_on_voice_stop(bool aborting
, size_t *realsize
)
1169 if (aborting
&& !playing
)
1171 /* Aborting: Slight hack - flush PCM buffer if
1172 only being used for voice */
1176 if (voice_is_playing
)
1178 /* Clear the current buffer */
1179 voice_is_playing
= false;
1180 voice_getmore
= NULL
;
1181 voice_remaining
= 0;
1184 /* Cancel any automatic boost if no more clips requested. */
1185 if (!playing
|| !voice_thread_start
)
1188 /* Force the codec to think it's changing tracks */
1189 ci_voice
.new_track
= 1;
1192 return true; /* Yes, change tracks */
1198 static void* voice_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1200 struct queue_event ev
;
1202 if (ci_voice
.new_track
)
1210 if (voice_is_playing
|| playing
)
1212 queue_wait_w_tmo(&voice_queue
, &ev
, 0);
1213 if (!voice_is_playing
&& ev
.id
== SYS_TIMEOUT
)
1214 ev
.id
= Q_AUDIO_PLAY
;
1218 queue_wait(&voice_queue
, &ev
);
1223 LOGFQUEUE("voice < Q_AUDIO_PLAY");
1226 if (audio_codec_loaded
)
1232 #ifdef AUDIO_HAVE_RECORDING
1233 case Q_ENCODER_RECORD
:
1234 LOGFQUEUE("voice < Q_ENCODER_RECORD");
1240 LOGFQUEUE("voice < Q_VOICE_STOP");
1241 if (voice_on_voice_stop(ev
.data
, realsize
))
1245 case SYS_USB_CONNECTED
:
1247 LOGFQUEUE("voice < SYS_USB_CONNECTED");
1248 bool change_tracks
= voice_on_voice_stop(ev
.data
, realsize
);
1249 /* Voice is obviously current so let us swap ourselves away if
1250 playing so audio may stop itself - audio_codec_loaded can
1251 only be true in this case if we're here even if the codec
1252 is only about to load */
1253 if (audio_codec_loaded
)
1255 /* Playback should be finished by now - ack and wait */
1256 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
1257 usb_wait_for_disconnect(&voice_queue
);
1264 LOGFQUEUE("voice < Q_VOICE_PLAY");
1265 if (!voice_is_playing
)
1267 /* Set up new voice data */
1268 struct voice_info
*voice_data
;
1270 if (voice_iram_stolen
)
1272 /* Voice is the first to run again and is currently
1274 logf("voice: iram restore");
1275 memcpy(CODEC_IRAM_ORIGIN
, iram_buf
, CODEC_IRAM_SIZE
);
1276 voice_iram_stolen
= false;
1279 /* Must reset the buffer before any playback begins if
1281 if (buffer_state
== BUFFER_STATE_TRASHED
)
1282 audio_reset_buffer();
1284 voice_is_playing
= true;
1285 trigger_cpu_boost();
1286 voice_data
= (struct voice_info
*)ev
.data
;
1287 voice_remaining
= voice_data
->size
;
1288 voicebuf
= voice_data
->buf
;
1289 voice_getmore
= voice_data
->callback
;
1291 goto voice_play_clip
; /* To exit both switch and while */
1294 LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
1295 goto voice_play_clip
;
1298 LOGFQUEUE("voice < default");
1304 if (voice_remaining
== 0 || voicebuf
== NULL
)
1307 voice_getmore((unsigned char **)&voicebuf
, &voice_remaining
);
1309 /* If this clip is done */
1310 if (voice_remaining
== 0)
1312 LOGFQUEUE("voice > voice Q_VOICE_STOP");
1313 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
1314 /* Force pcm playback. */
1315 if (!pcm_is_playing())
1316 pcmbuf_play_start();
1320 *realsize
= MIN(voice_remaining
, reqsize
);
1326 } /* voice_request_buffer_callback */
1328 static void voice_advance_buffer_callback(size_t amount
)
1330 amount
= MIN(amount
, voice_remaining
);
1332 voice_remaining
-= amount
;
1335 static void voice_advance_buffer_loc_callback(void *ptr
)
1337 size_t amount
= (size_t)ptr
- (size_t)voicebuf
;
1339 voice_advance_buffer_callback(amount
);
1342 static off_t
voice_mp3_get_filepos_callback(int newtime
)
1349 static void voice_do_nothing(void)
1354 static bool voice_seek_buffer_callback(size_t newpos
)
1361 static bool voice_request_next_track_callback(void)
1363 ci_voice
.new_track
= 0;
1367 static void voice_thread(void)
1369 logf("Loading voice codec");
1370 voice_codec_loaded
= true;
1371 semaphore_wait(&sem_codecthread
);
1372 event_set_state(&event_codecthread
, false);
1373 set_current_codec(CODEC_IDX_VOICE
);
1374 dsp_configure(DSP_RESET
, 0);
1375 voice_remaining
= 0;
1376 voice_getmore
= NULL
;
1378 /* FIXME: If we being starting the voice thread without reboot, the
1379 voice_queue could be full of old stuff and we must flush it. */
1380 codec_load_file(get_codec_filename(AFMT_MPA_L3
), &ci_voice
);
1382 logf("Voice codec finished");
1383 voice_codec_loaded
= false;
1384 voice_thread_p
= NULL
;
1385 semaphore_release(&sem_codecthread
);
1386 } /* voice_thread */
1388 #endif /* PLAYBACK_VOICE */
1390 /* --- Codec thread --- */
1391 static bool codec_pcmbuf_insert_callback(
1392 const void *ch1
, const void *ch2
, int count
)
1394 const char *src
[2] = { ch1
, ch2
};
1398 int out_count
= dsp_output_count(count
);
1402 /* Prevent audio from a previous track from playing */
1403 if (ci
.new_track
|| ci
.stop_codec
)
1406 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
1409 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
1413 /* Get the real input_size for output_size bytes, guarding
1414 * against resampling buffer overflows. */
1415 inp_count
= dsp_input_count(out_count
);
1420 /* Input size has grown, no error, just don't write more than length */
1421 if (inp_count
> count
)
1424 out_count
= dsp_process(dest
, src
, inp_count
);
1429 pcmbuf_write_complete(out_count
);
1431 #ifdef PLAYBACK_VOICE
1432 if ((voice_is_playing
|| voice_thread_start
)
1433 && pcm_is_playing() && voice_codec_loaded
&&
1434 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1436 voice_thread_start
= false;
1445 } /* codec_pcmbuf_insert_callback */
1447 static void* codec_get_memory_callback(size_t *size
)
1449 *size
= MALLOC_BUFSIZE
;
1454 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
1455 static void codec_pcmbuf_position_callback(size_t size
)
1457 /* This is called from an ISR, so be quick */
1458 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
1459 prev_ti
->id3
.elapsed
;
1461 if (time
>= prev_ti
->id3
.length
)
1463 pcmbuf_set_position_callback(NULL
);
1464 prev_ti
->id3
.elapsed
= prev_ti
->id3
.length
;
1467 prev_ti
->id3
.elapsed
= time
;
1471 static void codec_set_elapsed_callback(unsigned int value
)
1473 unsigned int latency
;
1477 #ifdef AB_REPEAT_ENABLE
1478 ab_position_report(value
);
1481 latency
= pcmbuf_get_latency();
1482 if (value
< latency
)
1483 curtrack_id3
.elapsed
= 0;
1484 else if (value
- latency
> curtrack_id3
.elapsed
||
1485 value
- latency
< curtrack_id3
.elapsed
- 2)
1487 curtrack_id3
.elapsed
= value
- latency
;
1491 static void codec_set_offset_callback(size_t value
)
1493 unsigned int latency
;
1498 latency
= pcmbuf_get_latency() * curtrack_id3
.bitrate
/ 8;
1499 if (value
< latency
)
1500 curtrack_id3
.offset
= 0;
1502 curtrack_id3
.offset
= value
- latency
;
1505 /* copy up-to size bytes into ptr and return the actual size copied */
1506 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
1510 if (ci
.stop_codec
|| !playing
)
1513 copy_n
= bufread(CUR_TI
->audio_hid
, size
, ptr
);
1515 /* Nothing requested OR nothing left */
1519 /* Let the disk buffer catch fill until enough data is available */
1520 while (copy_n
== -2)
1525 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1526 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1530 LOGFQUEUE("codec >| buffering Q_BUFFER_HANDLE");
1531 queue_send(&buffering_queue
, Q_BUFFER_HANDLE
, CUR_TI
->audio_hid
);
1533 if (ci
.stop_codec
|| ci
.new_track
)
1536 copy_n
= bufread(CUR_TI
->audio_hid
, size
, ptr
);
1539 /* Update read and other position pointers */
1540 bufadvance(CUR_TI
->audio_hid
, copy_n
);
1541 ci
.curpos
+= copy_n
;
1543 /* Return the actual amount of data copied to the buffer */
1545 } /* codec_filebuf_callback */
1547 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1549 size_t copy_n
= reqsize
;
1559 ret
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, (unsigned char **)&ptr
);
1561 copy_n
= MIN((size_t)ret
, reqsize
);
1574 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1575 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1579 LOGFQUEUE("codec >| buffering Q_BUFFER_HANDLE");
1580 queue_send(&buffering_queue
, Q_BUFFER_HANDLE
, CUR_TI
->audio_hid
);
1584 if (ci
.stop_codec
|| ci
.new_track
)
1589 ret
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, (unsigned char **)&ptr
);
1591 copy_n
= MIN((size_t)ret
, reqsize
);
1596 } /* codec_request_buffer_callback */
1598 static int get_codec_base_type(int type
)
1610 static void codec_advance_buffer_callback(size_t amount
)
1615 while ((ret
= bufadvance(CUR_TI
->audio_hid
, amount
) == -2) && filling
)
1620 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1624 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1625 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1626 ci
.curpos
+ amount
);
1631 case Q_CODEC_REQUEST_FAILED
:
1632 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1633 ci
.stop_codec
= true;
1636 case Q_CODEC_REQUEST_COMPLETE
:
1637 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1641 LOGFQUEUE("codec |< default");
1642 ci
.stop_codec
= true;
1647 /* Start buffer filling as necessary. */
1648 if (!pcmbuf_is_lowdata() && !filling
)
1650 if (bufused() < conf_watermark
&& playing
&& !playlist_end
)
1652 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1653 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1658 bufadvance(CUR_TI
->audio_hid
, amount
);
1660 ci
.curpos
+= amount
;
1661 codec_set_offset_callback(ci
.curpos
);
1664 static void codec_advance_buffer_loc_callback(void *ptr
)
1666 size_t amount
= get_offset(CUR_TI
->audio_hid
, ptr
);
1668 codec_advance_buffer_callback(amount
);
1671 /* Copied from mpeg.c. Should be moved somewhere else. */
1672 static int codec_get_file_pos(void)
1675 struct mp3entry
*id3
= audio_current_track();
1681 /* Use the TOC to find the new position */
1682 unsigned int percent
, remainder
;
1683 int curtoc
, nexttoc
, plen
;
1685 percent
= (id3
->elapsed
*100)/id3
->length
;
1689 curtoc
= id3
->toc
[percent
];
1692 nexttoc
= id3
->toc
[percent
+1];
1696 pos
= (id3
->filesize
/256)*curtoc
;
1698 /* Use the remainder to get a more accurate position */
1699 remainder
= (id3
->elapsed
*100)%id3
->length
;
1700 remainder
= (remainder
*100)/id3
->length
;
1701 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1702 pos
+= (plen
/100)*remainder
;
1706 /* No TOC exists, estimate the new position */
1707 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1708 (id3
->elapsed
/ 1000);
1711 else if (id3
->bitrate
)
1712 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1716 pos
+= id3
->first_frame_offset
;
1718 /* Don't seek right to the end of the file so that we can
1719 transition properly to the next song */
1720 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1721 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1726 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1730 curtrack_id3
.elapsed
= newtime
;
1731 newpos
= codec_get_file_pos();
1736 static void codec_seek_complete_callback(void)
1738 logf("seek_complete");
1739 if (pcm_is_paused())
1741 /* If this is not a seamless seek, clear the buffer */
1743 dsp_configure(DSP_FLUSH
, 0);
1745 /* If playback was not 'deliberately' paused, unpause now */
1747 pcmbuf_pause(false);
1752 static bool codec_seek_buffer_callback(size_t newpos
)
1756 logf("codec_seek_buffer_callback");
1758 if (newpos
>= CUR_TI
->filesize
)
1759 newpos
= CUR_TI
->filesize
- 1;
1761 difference
= newpos
- ci
.curpos
;
1762 if (difference
>= 0)
1764 /* Seeking forward */
1765 logf("seek: +%d", difference
);
1766 codec_advance_buffer_callback(difference
);
1770 /* Seeking backward */
1771 difference
= -difference
;
1772 if (ci
.curpos
- difference
< 0)
1773 difference
= ci
.curpos
;
1776 /* We need to reload the song. */
1777 if (newpos
< CUR_TI
->start_pos
)
1779 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1783 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1784 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1790 case Q_CODEC_REQUEST_COMPLETE
:
1791 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1794 case Q_CODEC_REQUEST_FAILED
:
1795 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1796 ci
.stop_codec
= true;
1800 LOGFQUEUE("codec |< default");
1806 /* Seeking inside buffer space. */
1807 logf("seek: -%d", difference
);
1808 bufadvance(CUR_TI
->audio_hid
, -difference
);
1809 ci
.curpos
-= difference
;
1813 static void codec_configure_callback(int setting
, intptr_t value
)
1816 case CODEC_SET_FILEBUF_WATERMARK
:
1817 conf_watermark
= value
;
1818 set_filebuf_watermark(buffer_margin
);
1821 case CODEC_SET_FILEBUF_CHUNKSIZE
:
1822 conf_filechunk
= value
;
1825 case CODEC_SET_FILEBUF_PRESEEK
:
1826 conf_preseek
= value
;
1830 if (!dsp_configure(setting
, value
)) { logf("Illegal key:%d", setting
); }
1834 static void codec_track_changed(void)
1836 automatic_skip
= false;
1837 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1838 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1841 static void codec_pcmbuf_track_changed_callback(void)
1843 pcmbuf_set_position_callback(NULL
);
1844 codec_track_changed();
1847 static void codec_discard_codec_callback(void)
1849 if (CUR_TI
->codec_hid
> 0)
1851 bufclose(CUR_TI
->codec_hid
);
1852 CUR_TI
->codec_hid
= 0;
1856 /* Check if a buffer desync has happened, log it and stop playback. */
1857 if (buf_ridx
!= CUR_TI
->buf_idx
)
1859 int offset
= CUR_TI
->buf_idx
- buf_ridx
;
1860 size_t new_used
= bufused() - offset
;
1862 logf("Buf off :%d=%d-%d", offset
, CUR_TI
->buf_idx
, buf_ridx
);
1863 logf("Used off:%d",bufused() - new_used
);
1865 /* This is a fatal internal error and it's not safe to
1866 * continue playback. */
1867 ci
.stop_codec
= true;
1868 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1873 static inline void codec_gapless_track_change(void) {
1874 /* callback keeps the progress bar moving while the pcmbuf empties */
1875 /* pcmbuf_set_position_callback(codec_pcmbuf_position_callback); */
1876 /* set the pcmbuf callback for when the track really changes */
1877 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1880 static inline void codec_crossfade_track_change(void) {
1881 /* Initiate automatic crossfade mode */
1882 pcmbuf_crossfade_init(false);
1883 /* Notify the wps that the track change starts now */
1884 codec_track_changed();
1887 static void codec_track_skip_done(bool was_manual
)
1889 int crossfade_mode
= global_settings
.crossfade
;
1891 /* Manual track change (always crossfade or flush audio). */
1894 pcmbuf_crossfade_init(true);
1895 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1896 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1898 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1899 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1900 && crossfade_mode
!= CROSSFADE_ENABLE_TRACKSKIP
)
1902 if (crossfade_mode
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1904 if (global_settings
.playlist_shuffle
)
1905 /* shuffle mode is on, so crossfade: */
1906 codec_crossfade_track_change();
1908 /* shuffle mode is off, so do a gapless track change */
1909 codec_gapless_track_change();
1912 /* normal crossfade: */
1913 codec_crossfade_track_change();
1916 /* normal gapless playback. */
1917 codec_gapless_track_change();
1920 static bool codec_load_next_track(void)
1922 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1924 prev_track_elapsed
= curtrack_id3
.elapsed
;
1927 codec_seek_complete_callback();
1929 #ifdef AB_REPEAT_ENABLE
1930 ab_end_of_track_report();
1933 logf("Request new track");
1935 if (ci
.new_track
== 0)
1938 automatic_skip
= true;
1943 trigger_cpu_boost();
1944 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1945 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1950 case Q_CODEC_REQUEST_COMPLETE
:
1951 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1952 codec_track_skip_done(!automatic_skip
);
1955 case Q_CODEC_REQUEST_FAILED
:
1956 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1958 ci
.stop_codec
= true;
1962 LOGFQUEUE("codec |< default");
1963 ci
.stop_codec
= true;
1968 static bool codec_request_next_track_callback(void)
1972 if (ci
.stop_codec
|| !playing
)
1975 prev_codectype
= get_codec_base_type(curtrack_id3
.codectype
);
1977 if (!codec_load_next_track())
1980 /* Check if the next codec is the same file. */
1981 if (prev_codectype
== get_codec_base_type(curtrack_id3
.codectype
))
1983 logf("New track loaded");
1984 codec_discard_codec_callback();
1989 logf("New codec:%d/%d", curtrack_id3
.codectype
, prev_codectype
);
1994 static void codec_thread(void)
1996 struct queue_event ev
;
2002 queue_wait(&codec_queue
, &ev
);
2005 case Q_CODEC_LOAD_DISK
:
2006 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
2007 queue_reply(&codec_queue
, 1);
2008 audio_codec_loaded
= true;
2009 #ifdef PLAYBACK_VOICE
2010 /* Don't sent messages to voice codec if it's already swapped
2011 out or it will never get this */
2012 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2014 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
2015 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
2017 semaphore_wait(&sem_codecthread
);
2018 event_set_state(&event_codecthread
, true);
2020 set_current_codec(CODEC_IDX_AUDIO
);
2021 ci
.stop_codec
= false;
2022 status
= codec_load_file((const char *)ev
.data
, &ci
);
2023 DEBUGF("codec_load = %d\n", status
);
2024 #ifdef PLAYBACK_VOICE
2025 semaphore_release(&sem_codecthread
);
2030 LOGFQUEUE("codec < Q_CODEC_LOAD");
2031 if (CUR_TI
->codec_hid
<= 0) {
2032 logf("Codec slot is empty!");
2033 /* Wait for the pcm buffer to go empty */
2034 while (pcm_is_playing())
2036 /* This must be set to prevent an infinite loop */
2037 ci
.stop_codec
= true;
2038 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
2039 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
2043 audio_codec_loaded
= true;
2044 #ifdef PLAYBACK_VOICE
2045 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2047 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
2048 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
2050 semaphore_wait(&sem_codecthread
);
2051 event_set_state(&event_codecthread
, true);
2053 set_current_codec(CODEC_IDX_AUDIO
);
2054 ci
.stop_codec
= false;
2055 wrap
= (size_t)&filebuf
[filebuflen
] - (size_t)getptr(CUR_TI
->codec_hid
);
2056 status
= codec_load_ram(getptr(CUR_TI
->codec_hid
), CUR_TI
->codecsize
,
2057 &filebuf
[0], wrap
, &ci
);
2058 #ifdef PLAYBACK_VOICE
2059 semaphore_release(&sem_codecthread
);
2063 #ifdef AUDIO_HAVE_RECORDING
2064 case Q_ENCODER_LOAD_DISK
:
2065 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2066 audio_codec_loaded
= false; /* Not audio codec! */
2067 #ifdef PLAYBACK_VOICE
2068 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2070 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
2071 queue_post(&voice_queue
, Q_ENCODER_RECORD
, 0);
2073 semaphore_wait(&sem_codecthread
);
2074 event_set_state(&event_codecthread
, true);
2076 logf("loading encoder");
2077 set_current_codec(CODEC_IDX_AUDIO
);
2078 ci
.stop_encoder
= false;
2079 status
= codec_load_file((const char *)ev
.data
, &ci
);
2080 #ifdef PLAYBACK_VOICE
2081 semaphore_release(&sem_codecthread
);
2083 logf("encoder stopped");
2085 #endif /* AUDIO_HAVE_RECORDING */
2088 case SYS_USB_CONNECTED
:
2089 LOGFQUEUE("codec < SYS_USB_CONNECTED");
2090 queue_clear(&codec_queue
);
2091 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
2092 usb_wait_for_disconnect(&codec_queue
);
2097 LOGFQUEUE("codec < default");
2100 if (audio_codec_loaded
)
2109 audio_codec_loaded
= false;
2113 case Q_CODEC_LOAD_DISK
:
2115 LOGFQUEUE("codec < Q_CODEC_LOAD");
2118 if (ci
.new_track
|| status
!= CODEC_OK
)
2122 logf("Codec failure");
2123 gui_syncsplash(HZ
*2, "Codec failure");
2126 if (!codec_load_next_track())
2128 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2129 /* End of playlist */
2130 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2136 logf("Codec finished");
2139 /* Wait for the audio to stop playing before
2140 * triggering the WPS exit */
2141 while(pcm_is_playing())
2143 curtrack_id3
.elapsed
=
2144 curtrack_id3
.length
- pcmbuf_get_latency();
2147 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2148 /* End of playlist */
2149 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2154 if (CUR_TI
->codec_hid
> 0)
2156 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2157 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
2161 const char *codec_fn
=
2162 get_codec_filename(curtrack_id3
.codectype
);
2163 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2164 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
2165 (intptr_t)codec_fn
);
2170 #ifdef AUDIO_HAVE_RECORDING
2171 case Q_ENCODER_LOAD_DISK
:
2172 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2174 if (status
== CODEC_OK
)
2177 logf("Encoder failure");
2178 gui_syncsplash(HZ
*2, "Encoder failure");
2180 if (ci
.enc_codec_loaded
< 0)
2183 logf("Encoder failed to load");
2184 ci
.enc_codec_loaded
= -1;
2186 #endif /* AUDIO_HAVE_RECORDING */
2189 LOGFQUEUE("codec < default");
2196 /* --- Audio thread --- */
2199 static bool audio_filebuf_is_lowdata(void)
2201 return bufused() < AUDIO_FILEBUF_CRITICAL
;
2205 static bool audio_have_tracks(void)
2207 return track_ridx
!= track_widx
|| CUR_TI
->filesize
;
2210 static bool audio_have_free_tracks(void)
2212 if (track_widx
< track_ridx
)
2213 return track_widx
+ 1 < track_ridx
;
2214 else if (track_ridx
== 0)
2215 return track_widx
< MAX_TRACK
- 1;
2220 int audio_track_count(void)
2222 if (audio_have_tracks())
2224 int relative_track_widx
= track_widx
;
2226 if (track_ridx
> track_widx
)
2227 relative_track_widx
+= MAX_TRACK
;
2229 return relative_track_widx
- track_ridx
+ 1;
2235 long audio_filebufused(void)
2237 return (long) bufused();
2241 /* Count the data BETWEEN the selected tracks */
2242 static size_t audio_buffer_count_tracks(int from_track
, int to_track
)
2245 bool need_wrap
= to_track
< from_track
;
2249 if (++from_track
>= MAX_TRACK
)
2251 from_track
-= MAX_TRACK
;
2255 if (from_track
>= to_track
&& !need_wrap
)
2258 amount
+= tracks
[from_track
].codecsize
+ tracks
[from_track
].filesize
;
2264 static bool audio_buffer_wind_forward(int new_track_ridx
, int old_track_ridx
)
2266 (void)new_track_ridx
;
2267 (void)old_track_ridx
;
2271 /* Start with the remainder of the previously playing track */
2272 amount
= tracks
[old_track_ridx
].filesize
- ci
.curpos
;
2273 /* Then collect all data from tracks in between them */
2274 amount
+= audio_buffer_count_tracks(old_track_ridx
, new_track_ridx
);
2275 logf("bwf:%ldB", (long) amount
);
2277 if (amount
> bufused())
2280 /* Wind the buffer to the beginning of the target track or its codec */
2281 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
2286 static bool audio_buffer_wind_backward(int new_track_ridx
, int old_track_ridx
)
2288 (void)new_track_ridx
;
2289 (void)old_track_ridx
;
2291 /* Available buffer data */
2293 /* Start with the previously playing track's data and our data */
2297 buf_back
= RINGBUF_SUB(buf_ridx
, buf_widx
);
2299 /* If we're not just resetting the current track */
2300 if (new_track_ridx
!= old_track_ridx
)
2302 /* Need to wind to before the old track's codec and our filesize */
2303 amount
+= tracks
[old_track_ridx
].codecsize
;
2304 amount
+= tracks
[new_track_ridx
].filesize
;
2306 /* Rewind the old track to its beginning */
2307 tracks
[old_track_ridx
].available
=
2308 tracks
[old_track_ridx
].filesize
- tracks
[old_track_ridx
].filerem
;
2311 /* If the codec was ever buffered */
2312 if (tracks
[new_track_ridx
].codecsize
)
2314 /* Add the codec to the needed size */
2315 amount
+= tracks
[new_track_ridx
].codecsize
;
2316 tracks
[new_track_ridx
].has_codec
= true;
2319 /* Then collect all data from tracks between new and old */
2320 amount
+= audio_buffer_count_tracks(new_track_ridx
, old_track_ridx
);
2322 /* Do we have space to make this skip? */
2323 if (amount
> buf_back
)
2326 logf("bwb:%ldB",amount
);
2328 /* Rewind the buffer to the beginning of the target track or its codec */
2329 buf_ridx
= RINGBUF_SUB(buf_ridx
, amount
);
2331 /* Reset to the beginning of the new track */
2332 tracks
[new_track_ridx
].available
= tracks
[new_track_ridx
].filesize
;
2337 static void audio_update_trackinfo(void)
2339 ci
.filesize
= CUR_TI
->filesize
;
2340 curtrack_id3
.elapsed
= 0;
2341 curtrack_id3
.offset
= 0;
2342 ci
.id3
= &curtrack_id3
;
2344 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2348 /* Yield to codecs for as long as possible if they are in need of data
2349 * return true if the caller should break to let the audio thread process
2351 static bool audio_yield_codecs(void)
2355 if (!queue_empty(&audio_queue
))
2358 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
2359 && !ci
.stop_codec
&& playing
&& !audio_filebuf_is_lowdata())
2366 if (!queue_empty(&audio_queue
))
2374 static void audio_clear_track_entries(bool clear_unbuffered
)
2376 int cur_idx
= track_widx
;
2379 logf("Clearing tracks:%d/%d, %d", track_ridx
, track_widx
, clear_unbuffered
);
2381 /* Loop over all tracks from write-to-read */
2385 cur_idx
&= MAX_TRACK_MASK
;
2387 if (cur_idx
== track_ridx
)
2390 /* If the track is buffered, conditionally clear/notify,
2391 * otherwise clear the track if that option is selected */
2392 if (tracks
[cur_idx
].event_sent
)
2396 /* If there is an unbuffer callback, call it, otherwise,
2397 * just clear the track */
2398 if (track_unbuffer_callback
)
2399 track_unbuffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), false);
2401 clear_track_info(&tracks
[last_idx
]);
2405 else if (clear_unbuffered
)
2407 clear_track_info(&tracks
[cur_idx
]);
2411 /* We clear the previous instance of a buffered track throughout
2412 * the above loop to facilitate 'last' detection. Clear/notify
2413 * the last track here */
2416 if (track_unbuffer_callback
)
2417 track_unbuffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), true);
2418 clear_track_info(&tracks
[last_idx
]);
2422 static void audio_release_tracks(void)
2424 int cur_idx
= track_ridx
;
2426 logf("releasing all tracks");
2430 clear_track_info(&tracks
[cur_idx
]);
2433 cur_idx
&= MAX_TRACK_MASK
;
2435 if (cur_idx
== track_widx
)
2441 /* FIXME: This code should be made more generic and move to metadata.c */
2442 static void audio_strip_tags(void)
2445 static const unsigned char tag
[] = "TAG";
2446 static const unsigned char apetag
[] = "APETAGEX";
2449 size_t len
, version
;
2451 tag_idx
= RINGBUF_SUB(buf_widx
, 128);
2453 if (bufused() > 128 && tag_idx
> buf_ridx
)
2456 for(i
= 0;i
< 3;i
++)
2458 if(filebuf
[cur_idx
] != tag
[i
])
2461 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2464 /* Skip id3v1 tag */
2465 logf("Skipping ID3v1 tag");
2467 tracks
[track_widx
].available
-= 128;
2468 tracks
[track_widx
].filesize
-= 128;
2472 /* Check for APE tag (look for the APE tag footer) */
2473 tag_idx
= RINGBUF_SUB(buf_widx
, 32);
2475 if (bufused() > 32 && tag_idx
> buf_ridx
)
2478 for(i
= 0;i
< 8;i
++)
2480 if(filebuf
[cur_idx
] != apetag
[i
])
2483 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2486 /* Read the version and length from the footer */
2487 version
= filebuf
[tag_idx
+8] | (filebuf
[tag_idx
+9] << 8) |
2488 (filebuf
[tag_idx
+10] << 16) | (filebuf
[tag_idx
+11] << 24);
2489 len
= filebuf
[tag_idx
+12] | (filebuf
[tag_idx
+13] << 8) |
2490 (filebuf
[tag_idx
+14] << 16) | (filebuf
[tag_idx
+15] << 24);
2491 if (version
== 2000)
2492 len
+= 32; /* APEv2 has a 32 byte header */
2495 if (bufused() > len
)
2497 logf("Skipping APE tag (%ldB)", len
);
2498 buf_widx
= RINGBUF_SUB(buf_widx
, len
);
2499 tracks
[track_widx
].available
-= len
;
2500 tracks
[track_widx
].filesize
-= len
;
2507 /* Returns true if a whole file is read, false otherwise */
2508 static bool audio_read_file(size_t minimum
)
2510 bool ret_val
= false;
2512 /* If we're called and no file is open, this is an error */
2515 logf("Bad fd in arf");
2516 /* Give some hope of miraculous recovery by forcing a track reload */
2517 tracks
[track_widx
].filesize
= 0;
2518 /* Stop this buffering run */
2522 trigger_cpu_boost();
2523 while (tracks
[track_widx
].filerem
> 0)
2529 /* copy_n is the largest chunk that is safe to read */
2530 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2532 /* buf_widx == buf_ridx is defined as buffer empty, not buffer full */
2533 if (RINGBUF_ADD_CROSS(buf_widx
,copy_n
,buf_ridx
) >= 0)
2536 /* rc is the actual amount read */
2537 rc
= read(current_fd
, &filebuf
[buf_widx
], copy_n
);
2541 logf("File ended %ldB early", tracks
[track_widx
].filerem
);
2542 tracks
[track_widx
].filesize
-= tracks
[track_widx
].filerem
;
2543 tracks
[track_widx
].filerem
= 0;
2547 /* How much of the playing track did we overwrite */
2548 if (buf_widx
== CUR_TI
->buf_idx
)
2550 /* Special handling; zero or full overlap? */
2551 if (track_widx
== track_ridx
&& CUR_TI
->available
== 0)
2557 overlap
= RINGBUF_ADD_CROSS(buf_widx
,rc
,CUR_TI
->buf_idx
);
2559 if ((unsigned)rc
> tracks
[track_widx
].filerem
)
2561 logf("Bad: rc-filerem=%ld, fixing", rc
-tracks
[track_widx
].filerem
);
2562 tracks
[track_widx
].filesize
+= rc
- tracks
[track_widx
].filerem
;
2563 tracks
[track_widx
].filerem
= rc
;
2566 /* Advance buffer */
2567 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2568 tracks
[track_widx
].available
+= rc
;
2569 tracks
[track_widx
].filerem
-= rc
;
2571 /* If we write into the playing track, adjust it's buffer info */
2574 CUR_TI
->buf_idx
+= overlap
;
2575 CUR_TI
->start_pos
+= overlap
;
2578 /* For a rebuffer, fill at least this minimum */
2579 if (minimum
> (unsigned)rc
)
2581 /* Let the codec process up to the watermark */
2582 /* Break immediately if this is a quick buffer, or there is an event */
2583 else if (minimum
|| audio_yield_codecs())
2585 /* Exit quickly, but don't stop the overall buffering process */
2591 if (tracks
[track_widx
].filerem
== 0)
2593 logf("Finished buf:%ldB", tracks
[track_widx
].filesize
);
2599 track_widx
&= MAX_TRACK_MASK
;
2601 tracks
[track_widx
].filesize
= 0;
2606 logf("%s buf:%ldB", ret_val
?"Quick":"Partially",
2607 tracks
[track_widx
].filesize
- tracks
[track_widx
].filerem
);
2613 static bool audio_loadcodec(bool start_play
)
2617 char codec_path
[MAX_PATH
]; /* Full path to codec */
2619 DEBUGF("audio_loadcodec(start_play = %s)\n", start_play
? "true" : "false");
2621 if (tracks
[track_widx
].id3_hid
<= 0) {
2622 DEBUGF("track ID3 info not ready\n");
2626 const char * codec_fn
=
2627 get_codec_filename(bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
);
2628 if (codec_fn
== NULL
)
2631 tracks
[track_widx
].codec_hid
= 0;
2635 /* Load the codec directly from disk and save some memory. */
2636 track_ridx
= track_widx
;
2637 ci
.filesize
= CUR_TI
->filesize
;
2638 ci
.id3
= &curtrack_id3
;
2639 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2641 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2642 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
2647 /* If we already have another track than this one buffered */
2648 if (track_widx
!= track_ridx
)
2650 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
2652 /* If the previous codec is the same as this one, there is no need
2653 * to put another copy of it on the file buffer */
2654 if (get_codec_base_type(
2655 bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
) ==
2656 get_codec_base_type(
2657 bufgetid3(tracks
[prev_track
].id3_hid
)->codectype
)
2658 && audio_codec_loaded
)
2660 logf("Reusing prev. codec");
2666 codec_get_full_path(codec_path
, codec_fn
);
2668 fd
= open(codec_path
, O_RDONLY
);
2671 logf("Codec doesn't exist!");
2675 tracks
[track_widx
].codecsize
= filesize(fd
);
2677 tracks
[track_widx
].codec_hid
= bufopen(codec_path
, 0, TYPE_CODEC
);
2678 if (tracks
[track_widx
].codec_hid
< 0)
2680 logf("Not enough space");
2686 logf("Loaded codec");
2691 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2692 static void audio_set_elapsed(struct mp3entry
* id3
)
2694 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
2695 id3
->offset
- id3
->first_frame_offset
: 0;
2698 if ( id3
->has_toc
) {
2699 /* calculate elapsed time using TOC */
2701 unsigned int remainder
, plen
, relpos
, nextpos
;
2703 /* find wich percent we're at */
2704 for (i
=0; i
<100; i
++ )
2705 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
2712 relpos
= id3
->toc
[i
];
2715 nextpos
= id3
->toc
[i
+1];
2719 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
2721 /* set time for this percent (divide before multiply to prevent
2722 overflow on long files. loss of precision is negligible on
2724 id3
->elapsed
= i
* (id3
->length
/ 100);
2726 /* calculate remainder time */
2727 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
2728 id3
->elapsed
+= (((remainder
* 100) / plen
) *
2729 (id3
->length
/ 10000));
2732 /* no TOC exists. set a rough estimate using average bitrate */
2733 int tpk
= id3
->length
/
2734 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
2736 id3
->elapsed
= offset
/ 1024 * tpk
;
2741 /* constant bitrate, use exact calculation */
2742 if (id3
->bitrate
!= 0)
2743 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
2747 /* Load one track by making the appropriate bufopen calls. Return true if
2748 everything required was loaded correctly, false if not. */
2749 static bool audio_load_track(int offset
, bool start_play
, bool rebuffer
)
2753 /* char msgbuf[80]; */
2755 int file_offset
= 0;
2756 struct mp3entry id3
;
2758 /* Stop buffer filling if there is no free track entries.
2759 Don't fill up the last track entry (we wan't to store next track
2761 if (!audio_have_free_tracks())
2763 logf("No free tracks");
2769 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
2770 /* Get track name from current playlist read position. */
2771 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
2773 /* Handle broken playlists. */
2774 fd
= open(trackname
, O_RDONLY
);
2777 logf("Open failed");
2778 /* Skip invalid entry from playlist. */
2779 playlist_skip_entry(NULL
, last_peek_offset
);
2787 logf("End-of-playlist");
2788 playlist_end
= true;
2792 tracks
[track_widx
].filesize
= filesize(fd
);
2794 /* Get track metadata if we don't already have it. */
2795 if (tracks
[track_widx
].id3_hid
<= 0)
2797 if (get_metadata(&id3
, fd
, trackname
))
2799 tracks
[track_widx
].id3_hid
= bufalloc(&id3
, sizeof(struct mp3entry
),
2801 tracks
[track_widx
].taginfo_ready
= (tracks
[track_widx
].id3_hid
> 0);
2803 if (tracks
[track_widx
].id3_hid
<= 0)
2805 DEBUGF("failed to allocate space for metadata\n");
2811 if (track_widx
== track_ridx
)
2812 copy_mp3entry(&curtrack_id3
, &id3
);
2813 else if (track_widx
== ((track_ridx
+ 1) & MAX_TRACK_MASK
))
2814 copy_mp3entry(&nexttrack_id3
, &id3
);
2818 track_changed
= true;
2819 playlist_update_resume_info(audio_current_track());
2824 logf("mde:%s!",trackname
);
2826 /* Skip invalid entry from playlist. */
2827 playlist_skip_entry(NULL
, last_peek_offset
);
2828 tracks
[track_widx
].taginfo_ready
= false;
2836 /* Set default values */
2839 int last_codec
= current_codec
;
2841 set_current_codec(CODEC_IDX_AUDIO
);
2842 conf_watermark
= AUDIO_DEFAULT_WATERMARK
;
2843 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
2844 conf_preseek
= AUDIO_REBUFFER_GUESS_SIZE
;
2845 dsp_configure(DSP_RESET
, 0);
2846 set_current_codec(last_codec
);
2848 track_changed
= true;
2849 playlist_update_resume_info(audio_current_track());
2853 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
2855 char cuepath
[MAX_PATH
];
2857 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
2859 if (look_for_cuesheet_file(trackname
, cuepath
) &&
2860 parse_cuesheet(cuepath
, cue
))
2862 strcpy((cue
)->audio_filename
, trackname
);
2864 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
2869 /* Load the codec. */
2870 if (!audio_loadcodec(start_play
))
2873 /* Set filesize to zero to indicate no file was loaded. */
2874 /* tracks[track_widx].filesize = 0;
2875 tracks[track_widx].filerem = 0;
2879 if (tracks
[track_widx
].codecsize
)
2881 /* No space for codec on buffer, not an error */
2882 tracks
[track_widx
].codecsize
= 0;
2886 /* This is an error condition, either no codec was found, or reading
2887 * the codec file failed part way through, either way, skip the track */
2888 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
2889 /* We should not use gui_syncplash from audio thread! */
2890 gui_syncsplash(HZ
*2, msgbuf
);
2891 /* Skip invalid entry from playlist. */
2892 playlist_skip_entry(NULL
, last_peek_offset
);
2893 tracks
[track_widx
].taginfo_ready
= false;
2899 struct mp3entry
*track_id3
;
2901 if (track_widx
== track_ridx
)
2902 track_id3
= &curtrack_id3
;
2903 else if (track_widx
== ((track_ridx
+ 1) & MAX_TRACK_MASK
))
2904 track_id3
= &nexttrack_id3
;
2906 track_id3
= bufgetid3(tracks
[track_widx
].id3_hid
);
2908 /* tracks[track_widx].start_pos = 0; */
2909 set_filebuf_watermark(buffer_margin
);
2910 track_id3
->elapsed
= 0;
2914 switch (track_id3
->codectype
) {
2918 file_offset
= offset
;
2919 track_id3
->offset
= offset
;
2920 audio_set_elapsed(track_id3
);
2925 file_offset
= offset
;
2926 track_id3
->offset
= offset
;
2927 track_id3
->elapsed
= track_id3
->length
/ 2;
2931 case AFMT_OGG_VORBIS
:
2939 track_id3
->offset
= offset
;
2944 logf("alt:%s", trackname
);
2945 /* tracks[track_widx].buf_idx = buf_widx; */
2947 //return audio_read_file(rebuffer);
2949 tracks
[track_widx
].audio_hid
= bufopen(trackname
, file_offset
, TYPE_AUDIO
);
2951 if (tracks
[track_widx
].audio_hid
<= 0)
2956 LOGFQUEUE("audio >| buffering Q_BUFFER_HANDLE");
2957 queue_send(&buffering_queue
, Q_BUFFER_HANDLE
, tracks
[track_widx
].audio_hid
);
2961 track_widx
&= MAX_TRACK_MASK
;
2967 static bool audio_read_next_metadata(void)
2974 next_idx
= track_widx
;
2975 if (tracks
[next_idx
].id3_hid
> 0)
2978 next_idx
&= MAX_TRACK_MASK
;
2980 if (tracks
[next_idx
].id3_hid
> 0)
2984 trackname
= playlist_peek(last_peek_offset
+ 1);
2988 fd
= open(trackname
, O_RDONLY
);
2992 struct mp3entry id3
;
2994 status
= get_metadata(&id3
, fd
, trackname
);
2995 /* Preload the glyphs in the tags */
2998 tracks
[next_idx
].id3_hid
= bufalloc(&id3
, sizeof(struct mp3entry
), TYPE_ID3
);
3000 if (tracks
[next_idx
].id3_hid
> 0)
3002 tracks
[next_idx
].taginfo_ready
= true;
3004 lcd_getstringsize(id3
.title
, NULL
, NULL
);
3006 lcd_getstringsize(id3
.artist
, NULL
, NULL
);
3008 lcd_getstringsize(id3
.album
, NULL
, NULL
);
3019 /* Send callback events to notify about new tracks. */
3020 static void audio_generate_postbuffer_events(void)
3025 logf("Postbuffer:%d/%d",track_ridx
,track_widx
);
3027 if (audio_have_tracks())
3029 cur_idx
= track_ridx
;
3032 if (!tracks
[cur_idx
].event_sent
)
3034 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
3036 /* Mark the event 'sent' even if we don't really send one */
3037 tracks
[last_idx
].event_sent
= true;
3038 if (track_buffer_callback
)
3039 track_buffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), false);
3043 if (cur_idx
== track_widx
)
3046 cur_idx
&= MAX_TRACK_MASK
;
3049 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
3051 tracks
[last_idx
].event_sent
= true;
3052 if (track_buffer_callback
)
3053 track_buffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), true);
3058 static bool audio_initialize_buffer_fill(bool clear_tracks
)
3060 /* Don't initialize if we're already initialized */
3064 logf("Starting buffer fill");
3066 /* Set the filling flag true before calling audio_clear_tracks as that
3067 * function can yield and we start looping. */
3071 audio_clear_track_entries(false);
3073 /* Save the current resume position once. */
3074 playlist_update_resume_info(audio_current_track());
3079 static void audio_fill_file_buffer(
3080 bool start_play
, bool rebuffer
, size_t offset
)
3082 bool had_next_track
= audio_next_track() != NULL
;
3083 bool continue_buffering
;
3085 /* Must reset the buffer before use if trashed or voice only - voice
3086 file size shouldn't have changed so we can go straight from
3087 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
3088 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
3089 audio_reset_buffer();
3091 if (!audio_initialize_buffer_fill(!start_play
))
3094 continue_buffering
= audio_load_track(offset
, start_play
, rebuffer
);
3096 if (!had_next_track
&& audio_next_track())
3097 track_changed
= true;
3099 /* If we're done buffering */
3100 if (!continue_buffering
)
3102 //audio_read_next_metadata();
3104 audio_generate_postbuffer_events();
3113 static void audio_rebuffer(void)
3115 logf("Forcing rebuffer");
3117 /* Reset track pointers */
3118 track_widx
= track_ridx
;
3119 audio_clear_track_entries(true);
3121 /* Fill the buffer */
3122 last_peek_offset
= -1;
3123 CUR_TI
->filesize
= 0;
3126 if (!CUR_TI
->taginfo_ready
)
3127 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
3129 audio_fill_file_buffer(false, true, 0);
3132 static int audio_check_new_track(void)
3134 DEBUGF("audio_check_new_track\n");
3136 int track_count
= audio_track_count();
3137 int old_track_ridx
= track_ridx
;
3144 if (playlist_next_dir(ci
.new_track
))
3147 CUR_TI
->taginfo_ready
= false;
3153 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3154 return Q_CODEC_REQUEST_FAILED
;
3161 /* If the playlist isn't that big */
3162 if (!playlist_check(ci
.new_track
))
3164 if (ci
.new_track
>= 0)
3166 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3167 return Q_CODEC_REQUEST_FAILED
;
3169 /* Find the beginning backward if the user over-skips it */
3170 while (!playlist_check(++ci
.new_track
))
3171 if (ci
.new_track
>= 0)
3173 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3174 return Q_CODEC_REQUEST_FAILED
;
3177 /* Update the playlist */
3178 last_peek_offset
-= ci
.new_track
;
3180 if (playlist_next(ci
.new_track
) < 0)
3182 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3183 return Q_CODEC_REQUEST_FAILED
;
3189 new_playlist
= false;
3192 /* Save the old track */
3193 /* prev_ti = CUR_TI; */
3196 for (i
= 0; i
< ci
.new_track
; i
++)
3198 idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
3199 clear_track_info(&tracks
[idx
]);
3202 /* Move to the new track */
3203 track_ridx
+= ci
.new_track
;
3204 track_ridx
&= MAX_TRACK_MASK
;
3206 if (CUR_TI
->id3_hid
> 0)
3207 copy_mp3entry(&curtrack_id3
, bufgetid3(CUR_TI
->id3_hid
));
3209 next_idx
= track_ridx
+ 1;
3210 next_idx
&= MAX_TRACK_MASK
;
3212 if (tracks
[next_idx
].id3_hid
> 0)
3213 copy_mp3entry(&nexttrack_id3
, bufgetid3(tracks
[next_idx
].id3_hid
));
3216 playlist_end
= false;
3218 track_changed
= !automatic_skip
;
3220 /* If it is not safe to even skip this many track entries */
3221 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
3224 CUR_TI
->taginfo_ready
= false;
3229 forward
= ci
.new_track
> 0;
3232 /* If the target track is clearly not in memory */
3233 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
3239 /* The track may be in memory, see if it really is */
3242 if (!audio_buffer_wind_forward(track_ridx
, old_track_ridx
))
3247 int cur_idx
= track_ridx
;
3248 bool taginfo_ready
= true;
3249 bool wrap
= track_ridx
> old_track_ridx
;
3254 cur_idx
&= MAX_TRACK_MASK
;
3255 if (!(wrap
|| cur_idx
< old_track_ridx
))
3258 /* If we hit a track in between without valid tag info, bail */
3259 if (!tracks
[cur_idx
].taginfo_ready
)
3261 taginfo_ready
= false;
3265 tracks[cur_idx].available = tracks[cur_idx].filesize;
3266 if (tracks[cur_idx].codecsize)
3267 tracks[cur_idx].has_codec = true;*/
3271 if (!audio_buffer_wind_backward(track_ridx
, old_track_ridx
))
3276 CUR_TI
->taginfo_ready
= false;
3282 audio_update_trackinfo();
3283 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3284 return Q_CODEC_REQUEST_COMPLETE
;
3288 static int audio_rebuffer_and_seek(size_t newpos
)
3290 size_t real_preseek
;
3294 /* (Re-)open current track's file handle. */
3295 trackname
= playlist_peek(0);
3296 fd
= open(trackname
, O_RDONLY
);
3299 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3300 return Q_CODEC_REQUEST_FAILED
;
3303 if (current_fd
>= 0)
3307 playlist_end
= false;
3311 /* Clear codec buffer. */
3312 track_widx
= track_ridx
;
3313 tracks
[track_widx
].buf_idx
= buf_widx
= buf_ridx
= 0;
3315 last_peek_offset
= 0;
3317 audio_initialize_buffer_fill(true);
3319 /* This may have been tweaked by the id3v1 code */
3320 CUR_TI
->filesize
=filesize(fd
);
3321 if (newpos
> conf_preseek
)
3323 CUR_TI
->start_pos
= newpos
- conf_preseek
;
3324 lseek(current_fd
, CUR_TI
->start_pos
, SEEK_SET
);
3325 CUR_TI
->filerem
= CUR_TI
->filesize
- CUR_TI
->start_pos
;
3326 real_preseek
= conf_preseek
;
3330 CUR_TI
->start_pos
= 0;
3331 CUR_TI
->filerem
= CUR_TI
->filesize
;
3332 real_preseek
= newpos
;
3335 CUR_TI
->available
= 0;
3337 audio_read_file(real_preseek
);
3339 /* Account for the data we just read that is 'behind' us now */
3340 CUR_TI
->available
-= real_preseek
;
3342 buf_ridx
= RINGBUF_ADD(buf_ridx
, real_preseek
);
3345 DEBUGF("/!\\ not implemented /!\\");
3346 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3347 return Q_CODEC_REQUEST_COMPLETE
;
3351 void audio_set_track_buffer_event(void (*handler
)(struct mp3entry
*id3
,
3354 track_buffer_callback
= handler
;
3357 void audio_set_track_unbuffer_event(void (*handler
)(struct mp3entry
*id3
,
3360 track_unbuffer_callback
= handler
;
3363 void audio_set_track_changed_event(void (*handler
)(struct mp3entry
*id3
))
3365 track_changed_callback
= handler
;
3368 unsigned long audio_prev_elapsed(void)
3370 return prev_track_elapsed
;
3373 static void audio_stop_codec_flush(void)
3375 ci
.stop_codec
= true;
3378 while (audio_codec_loaded
)
3381 /* If the audio codec is not loaded any more, and the audio is still
3382 * playing, it is now and _only_ now safe to call this function from the
3384 if (pcm_is_playing())
3386 pcmbuf_pause(paused
);
3389 static void audio_stop_playback(void)
3391 /* If we were playing, save resume information */
3394 struct mp3entry
*id3
= NULL
;
3396 if (!playlist_end
|| !ci
.stop_codec
)
3398 /* Set this early, the outside code yields and may allow the codec
3399 to try to wait for a reply on a buffer wait */
3400 ci
.stop_codec
= true;
3401 id3
= audio_current_track();
3404 /* Save the current playing spot, or NULL if the playlist has ended */
3405 playlist_update_resume_info(id3
);
3407 prev_track_elapsed
= curtrack_id3
.elapsed
;
3409 /* Increment index so runtime info is saved in audio_clear_track_entries().
3410 * Done here, as audio_stop_playback() may be called more than once.
3411 * Don't update runtime unless playback is stopped because of end of playlist.
3412 * Updating runtime when manually stopping a tracks, can destroy autoscores
3418 track_ridx
&= MAX_TRACK_MASK
;
3424 audio_stop_codec_flush();
3427 /* Close all tracks */
3428 audio_release_tracks();
3430 /* Mark all entries null. */
3431 audio_clear_track_entries(false);
3434 static void audio_play_start(size_t offset
)
3436 #if INPUT_SRC_CAPS != 0
3437 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
3438 audio_set_output_source(AUDIO_SRC_PLAYBACK
);
3441 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
3443 audio_stop_codec_flush();
3445 track_changed
= true;
3446 playlist_end
= false;
3454 sound_set_volume(global_settings
.volume
);
3455 track_widx
= track_ridx
= 0;
3457 /* Mark all entries null. */
3458 memset(tracks
, 0, sizeof(struct track_info
) * MAX_TRACK
);
3460 last_peek_offset
= -1;
3462 /* Officially playing */
3463 queue_reply(&audio_queue
, 1);
3465 audio_fill_file_buffer(true, false, offset
);
3467 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
3468 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
3472 /* Invalidates all but currently playing track. */
3473 static void audio_invalidate_tracks(void)
3476 if (audio_have_tracks())
3478 last_peek_offset
= 0;
3479 playlist_end
= false;
3480 track_widx
= track_ridx
;
3482 /* Mark all other entries null (also buffered wrong metadata). */
3483 audio_clear_track_entries(true);
3485 /* If the current track is fully buffered, advance the write pointer */
3486 if (tracks
[track_widx
].filerem
== 0)
3487 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
3489 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3491 audio_read_next_metadata();
3496 static void audio_new_playlist(void)
3498 /* Prepare to start a new fill from the beginning of the playlist */
3499 last_peek_offset
= -1;
3500 if (audio_have_tracks())
3503 skipped_during_pause
= true;
3504 playlist_end
= false;
3505 track_widx
= track_ridx
;
3506 audio_clear_track_entries(true);
3509 track_widx
&= MAX_TRACK_MASK
;
3511 /* Mark the current track as invalid to prevent skipping back to it */
3512 CUR_TI
->taginfo_ready
= false;
3515 /* Signal the codec to initiate a track change forward */
3516 new_playlist
= true;
3519 /* Officially playing */
3520 queue_reply(&audio_queue
, 1);
3522 audio_fill_file_buffer(false, true, 0);
3525 static void audio_initiate_track_change(long direction
)
3527 playlist_end
= false;
3528 ci
.new_track
+= direction
;
3529 wps_offset
-= direction
;
3531 skipped_during_pause
= true;
3534 static void audio_initiate_dir_change(long direction
)
3536 playlist_end
= false;
3538 ci
.new_track
= direction
;
3540 skipped_during_pause
= true;
3544 * Layout audio buffer as follows - iram buffer depends on target:
3545 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
3547 static void audio_reset_buffer(void)
3549 /* see audio_get_recording_buffer if this is modified */
3550 logf("audio_reset_buffer");
3552 /* If the setup of anything allocated before the file buffer is
3553 changed, do check the adjustments after the buffer_alloc call
3554 as it will likely be affected and need sliding over */
3556 /* Initially set up file buffer as all space available */
3557 malloc_buf
= audiobuf
+ talk_get_bufsize();
3558 /* Align the malloc buf to line size. Especially important to cf
3559 targets that do line reads/writes. */
3560 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
3561 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
3562 filebuflen
= audiobufend
- filebuf
;
3564 /* Allow for codec swap space at end of audio buffer */
3565 if (talk_voice_required())
3567 /* Layout of swap buffer:
3568 * #ifdef IRAM_STEAL (dedicated iram_buf):
3569 * |iram_buf|...audiobuf...|dram_buf|audiobufend
3571 * audiobuf...|dram_buf|iram_buf|audiobufend
3573 #ifdef PLAYBACK_VOICE
3574 /* Check for an absolutely nasty situation which should never,
3575 ever happen - frankly should just panic */
3576 if (voice_codec_loaded
&& current_codec
!= CODEC_IDX_VOICE
)
3578 logf("buffer reset with voice swapped");
3580 /* line align length which line aligns the calculations below since
3581 all sizes are also at least line aligned - needed for memswap128 */
3584 filebuflen
-= CODEC_SIZE
;
3586 filebuflen
-= CODEC_SIZE
+ CODEC_IRAM_SIZE
;
3588 /* Allocate buffers for swapping voice <=> audio */
3589 /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
3590 and out of the way of buffer usage or else a call to audio_get_buffer
3591 and subsequent buffer use might trash the swap space. A plugin
3592 initializing IRAM after getting the full buffer would present similar
3593 problem. Options include: failing the request if the other buffer
3594 has been obtained already or never allowing use of the voice IRAM
3595 buffer within the audio buffer. Using buffer_alloc basically
3596 implements the second in a more convenient way. */
3597 dram_buf
= filebuf
+ filebuflen
;
3600 /* Allocate voice IRAM swap buffer once */
3601 if (iram_buf
== NULL
)
3603 iram_buf
= buffer_alloc(CODEC_IRAM_SIZE
);
3604 /* buffer_alloc moves audiobuf; this is safe because only the end
3605 * has been touched so far in this function and the address of
3606 * filebuf + filebuflen is not changed */
3607 malloc_buf
+= CODEC_IRAM_SIZE
;
3608 filebuf
+= CODEC_IRAM_SIZE
;
3609 filebuflen
-= CODEC_IRAM_SIZE
;
3612 /* Allocate iram_buf after dram_buf */
3613 iram_buf
= dram_buf
+ CODEC_SIZE
;
3614 #endif /* IRAM_STEAL */
3615 #endif /* PLAYBACK_VOICE */
3619 #ifdef PLAYBACK_VOICE
3620 /* No swap buffers needed */
3626 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
3627 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
3629 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
3630 will already be line aligned */
3633 /* Set the high watermark as 75% full...or 25% empty :) */
3635 high_watermark
= 3*filebuflen
/ 4;
3638 /* Clear any references to the file buffer */
3639 buffer_state
= BUFFER_STATE_INITIALIZED
;
3641 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
3642 /* Make sure everything adds up - yes, some info is a bit redundant but
3643 aids viewing and the sumation of certain variables should add up to
3644 the location of others. */
3647 unsigned char * pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
3648 logf("mabuf: %08X", (unsigned)malloc_buf
);
3649 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
3650 logf("fbuf: %08X", (unsigned)filebuf
);
3651 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
3652 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
3653 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
3654 logf("pcmb: %08X", (unsigned)pcmbuf
);
3655 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
3658 logf("dramb: %08X", (unsigned)dram_buf
);
3659 logf("drambe: %08X", (unsigned)(dram_buf
+ CODEC_SIZE
));
3663 logf("iramb: %08X", (unsigned)iram_buf
);
3664 logf("irambe: %08X", (unsigned)(iram_buf
+ CODEC_IRAM_SIZE
));
3671 /* we dont want this rebuffering on targets with little ram
3672 because the disk may never spin down */
3673 static bool ata_fillbuffer_callback(void)
3675 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
, 0);
3680 static void audio_thread(void)
3682 struct queue_event ev
;
3686 #ifdef PLAYBACK_VOICE
3687 /* Unlock semaphore that init stage locks before creating this thread */
3688 semaphore_release(&sem_codecthread
);
3690 /* Buffers must be set up by now - should panic - really */
3691 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
3693 logf("audio_thread start: no buffer");
3696 /* Have to wait for voice to load up or else the codec swap will be
3697 invalid when an audio codec is loaded */
3698 wait_for_voice_swap_in();
3705 queue_wait_w_tmo(&audio_queue
, &ev
, 0);
3706 if (ev
.id
== SYS_TIMEOUT
)
3707 ev
.id
= Q_AUDIO_FILL_BUFFER
;
3711 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
3713 if (playing
&& (ev
.id
== SYS_TIMEOUT
) &&
3714 (bufused() < high_watermark
))
3715 register_ata_idle_func(ata_fillbuffer_callback
);
3721 case Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
:
3722 /* only fill if the disk is still spining */
3724 if (!ata_disk_is_active())
3727 #endif /* MEM > 8 */
3728 /* else fall through to Q_AUDIO_FILL_BUFFER */
3729 case Q_AUDIO_FILL_BUFFER
:
3730 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3732 if (!playing
|| playlist_end
|| ci
.stop_codec
)
3734 audio_fill_file_buffer(false, false, 0);
3738 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3739 if (playing
&& ev
.data
<= 0)
3740 audio_new_playlist();
3743 audio_stop_playback();
3744 audio_play_start((size_t)ev
.data
);
3749 LOGFQUEUE("audio < Q_AUDIO_STOP");
3751 audio_stop_playback();
3753 queue_clear(&audio_queue
);
3757 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3758 if (!(bool) ev
.data
&& skipped_during_pause
&& !pcmbuf_is_crossfade_active())
3759 pcmbuf_play_stop(); /* Flush old track on resume after skip */
3760 skipped_during_pause
= false;
3763 pcmbuf_pause((bool)ev
.data
);
3764 paused
= (bool)ev
.data
;
3768 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3769 audio_initiate_track_change((long)ev
.data
);
3772 case Q_AUDIO_PRE_FF_REWIND
:
3773 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3779 case Q_AUDIO_FF_REWIND
:
3780 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3783 ci
.seek_time
= (long)ev
.data
+1;
3787 case Q_AUDIO_REBUFFER_SEEK
:
3788 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
3789 queue_reply(&audio_queue
, audio_rebuffer_and_seek(ev
.data
));
3793 case Q_AUDIO_CHECK_NEW_TRACK
:
3794 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3795 queue_reply(&audio_queue
, audio_check_new_track());
3798 case Q_AUDIO_DIR_SKIP
:
3799 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3800 playlist_end
= false;
3801 audio_initiate_dir_change(ev
.data
);
3805 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3806 audio_invalidate_tracks();
3809 case Q_AUDIO_TRACK_CHANGED
:
3810 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3811 if (track_changed_callback
)
3812 track_changed_callback(&curtrack_id3
);
3813 track_changed
= true;
3814 playlist_update_resume_info(audio_current_track());
3818 case SYS_USB_CONNECTED
:
3819 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3821 audio_stop_playback();
3822 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
3823 usb_wait_for_disconnect(&audio_queue
);
3828 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3832 //LOGFQUEUE("audio < default");
3838 #ifdef ROCKBOX_HAS_LOGF
3839 static void audio_test_track_changed_event(struct mp3entry
*id3
)
3843 logf("tce:%s", id3
->path
);
3847 /* Initialize the audio system - called from init() in main.c.
3848 * Last function because of all the references to internal symbols
3850 void audio_init(void)
3852 #ifdef PLAYBACK_VOICE
3853 static bool voicetagtrue
= true;
3854 static struct mp3entry id3_voice
;
3855 struct thread_entry
*voice_thread_p
= NULL
;
3857 struct thread_entry
*audio_thread_p
;
3859 /* Can never do this twice */
3860 if (audio_is_initialized
)
3862 logf("audio: already initialized");
3866 logf("audio: initializing");
3868 /* Initialize queues before giving control elsewhere in case it likes
3869 to send messages. Thread creation will be delayed however so nothing
3870 starts running until ready if something yields such as talk_init. */
3871 #ifdef PLAYBACK_VOICE
3872 /* Take ownership of lock to prevent playback of anything before audio
3873 hardware is initialized - audio thread unlocks it after final init
3875 semaphore_init(&sem_codecthread
, 1, 0);
3876 event_init(&event_codecthread
, EVENT_MANUAL
| STATE_SIGNALED
);
3878 queue_init(&audio_queue
, true);
3879 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
3880 queue_init(&codec_queue
, true);
3881 queue_enable_queue_send(&codec_queue
, &codec_queue_sender_list
);
3885 #ifdef ROCKBOX_HAS_LOGF
3886 audio_set_track_changed_event(audio_test_track_changed_event
);
3889 /* Initialize codec api. */
3890 ci
.read_filebuf
= codec_filebuf_callback
;
3891 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
3892 ci
.get_codec_memory
= codec_get_memory_callback
;
3893 ci
.request_buffer
= codec_request_buffer_callback
;
3894 ci
.advance_buffer
= codec_advance_buffer_callback
;
3895 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
3896 ci
.request_next_track
= codec_request_next_track_callback
;
3897 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
3898 ci
.seek_buffer
= codec_seek_buffer_callback
;
3899 ci
.seek_complete
= codec_seek_complete_callback
;
3900 ci
.set_elapsed
= codec_set_elapsed_callback
;
3901 ci
.set_offset
= codec_set_offset_callback
;
3902 ci
.configure
= codec_configure_callback
;
3903 ci
.discard_codec
= codec_discard_codec_callback
;
3905 /* Initialize voice codec api. */
3906 #ifdef PLAYBACK_VOICE
3907 memcpy(&ci_voice
, &ci
, sizeof(ci_voice
));
3908 memset(&id3_voice
, 0, sizeof(id3_voice
));
3909 ci_voice
.read_filebuf
= voice_filebuf_callback
;
3910 ci_voice
.pcmbuf_insert
= voice_pcmbuf_insert_callback
;
3911 ci_voice
.get_codec_memory
= voice_get_memory_callback
;
3912 ci_voice
.request_buffer
= voice_request_buffer_callback
;
3913 ci_voice
.advance_buffer
= voice_advance_buffer_callback
;
3914 ci_voice
.advance_buffer_loc
= voice_advance_buffer_loc_callback
;
3915 ci_voice
.request_next_track
= voice_request_next_track_callback
;
3916 ci_voice
.mp3_get_filepos
= voice_mp3_get_filepos_callback
;
3917 ci_voice
.seek_buffer
= voice_seek_buffer_callback
;
3918 ci_voice
.seek_complete
= voice_do_nothing
;
3919 ci_voice
.set_elapsed
= voice_set_elapsed_callback
;
3920 ci_voice
.set_offset
= voice_set_offset_callback
;
3921 ci_voice
.configure
= voice_configure_callback
;
3922 ci_voice
.discard_codec
= voice_do_nothing
;
3923 ci_voice
.taginfo_ready
= &voicetagtrue
;
3924 ci_voice
.id3
= &id3_voice
;
3925 id3_voice
.frequency
= 11200;
3926 id3_voice
.length
= 1000000L;
3929 /* initialize the buffer */
3932 /* audio_reset_buffer must to know the size of voice buffer so init
3936 codec_thread_p
= create_thread(
3937 codec_thread
, codec_stack
, sizeof(codec_stack
),
3938 CREATE_THREAD_FROZEN
,
3939 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
3942 audio_thread_p
= create_thread(audio_thread
, audio_stack
,
3943 sizeof(audio_stack
), CREATE_THREAD_FROZEN
,
3944 audio_thread_name
IF_PRIO(, PRIORITY_BACKGROUND
)
3947 buffering_thread_p
= create_thread( buffering_thread
, buffering_stack
,
3948 sizeof(buffering_stack
), CREATE_THREAD_FROZEN
,
3949 buffering_thread_name
IF_PRIO(, PRIORITY_BUFFERING
)
3950 IF_COP(, CPU
, true));
3952 #ifdef PLAYBACK_VOICE
3953 /* TODO: Change this around when various speech codecs can be used */
3954 if (talk_voice_required())
3956 logf("Starting voice codec");
3957 queue_init(&voice_queue
, true);
3958 voice_thread_p
= create_thread(voice_thread
, voice_stack
,
3959 sizeof(voice_stack
), CREATE_THREAD_FROZEN
,
3961 IF_PRIO(, PRIORITY_PLAYBACK
) IF_COP(, CPU
));
3965 /* Set crossfade setting for next buffer init which should be about... */
3966 pcmbuf_crossfade_enable(global_settings
.crossfade
);
3968 /* ...now! Set up the buffers */
3969 audio_reset_buffer();
3971 buffering_init(filebuf
, filebuflen
);
3973 /* Probably safe to say */
3974 audio_is_initialized
= true;
3976 sound_settings_apply();
3978 eq_hw_enable(global_settings
.eq_hw_enabled
);
3980 #ifndef HAVE_FLASH_STORAGE
3981 audio_set_buffer_margin(global_settings
.buffer_margin
);
3984 /* it's safe to let the threads run now */
3985 thread_thaw(codec_thread_p
);
3986 #ifdef PLAYBACK_VOICE
3988 thread_thaw(voice_thread_p
);
3990 thread_thaw(audio_thread_p
);
3991 thread_thaw(buffering_thread_p
);