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 close_track_handles(struct track_info
*track
)
393 if (track
->codec_hid
> 0) {
394 bufclose(track
->codec_hid
);
395 track
->codec_hid
= 0;
398 if (track
->id3_hid
> 0) {
399 bufclose(track
->id3_hid
);
403 if (track
->audio_hid
> 0) {
404 bufclose(track
->audio_hid
);
405 track
->audio_hid
= 0;
409 /* --- External interfaces --- */
411 void mp3_play_data(const unsigned char* start
, int size
,
412 void (*get_more
)(unsigned char** start
, size_t* size
))
414 #ifdef PLAYBACK_VOICE
415 static struct voice_info voice_clip
;
416 voice_clip
.callback
= get_more
;
417 voice_clip
.buf
= (unsigned char*)start
;
418 voice_clip
.size
= size
;
419 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
420 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
421 LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
422 queue_post(&voice_queue
, Q_VOICE_PLAY
, (intptr_t)&voice_clip
);
423 voice_thread_start
= true;
432 void mp3_play_stop(void)
434 #ifdef PLAYBACK_VOICE
435 queue_remove_from_head(&voice_queue
, Q_VOICE_STOP
);
436 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
437 queue_post(&voice_queue
, Q_VOICE_STOP
, 1);
441 void mp3_play_pause(bool play
)
447 bool mp3_is_playing(void)
449 #ifdef PLAYBACK_VOICE
450 return voice_is_playing
;
456 /* If voice could be swapped out - wait for it to return
457 * Used by buffer claming functions.
459 static void wait_for_voice_swap_in(void)
461 #ifdef PLAYBACK_VOICE
462 if (NULL
== iram_buf
)
465 event_wait(&event_codecthread
, STATE_NONSIGNALED
);
466 #endif /* PLAYBACK_VOICE */
469 /* This sends a stop message and the audio thread will dump all it's
470 subsequenct messages */
471 static void audio_hard_stop(void)
474 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
475 queue_send(&audio_queue
, Q_AUDIO_STOP
, 1);
478 unsigned char *audio_get_buffer(bool talk_buf
, size_t *buffer_size
)
480 unsigned char *buf
, *end
;
482 if (audio_is_initialized
)
485 wait_for_voice_swap_in();
486 #ifdef PLAYBACK_VOICE
490 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
492 if (buffer_size
== NULL
)
494 /* Special case for talk_init to use since it already knows it's
496 buffer_state
= BUFFER_STATE_TRASHED
;
500 if (talk_buf
|| buffer_state
== BUFFER_STATE_TRASHED
501 || !talk_voice_required())
503 logf("get buffer: talk, audio");
504 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
505 the talk buffer is not needed because voice isn't being used, or
506 could be BUFFER_STATE_TRASHED already. If state is
507 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
508 without the caller knowing what's going on. Changing certain settings
509 may move it to a worse condition but the memory in use by something
510 else will remain undisturbed.
512 if (buffer_state
!= BUFFER_STATE_TRASHED
)
515 buffer_state
= BUFFER_STATE_TRASHED
;
523 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
524 still BUFFER_STATE_INITIALIZED */
525 /* Skip talk buffer and move pcm buffer to end to maximize available
526 contiguous memory - no audio running means voice will not need the
528 logf("get buffer: audio");
529 buf
= audiobuf
+ talk_get_bufsize();
530 end
= audiobufend
- pcmbuf_init(audiobufend
);
531 buffer_state
= BUFFER_STATE_VOICED_ONLY
;
534 *buffer_size
= end
- buf
;
540 void audio_iram_steal(void)
542 /* We need to stop audio playback in order to use codec IRAM */
545 #ifdef PLAYBACK_VOICE
546 if (NULL
!= iram_buf
)
548 /* Can't already be stolen */
549 if (voice_iram_stolen
)
552 /* Must wait for voice to be current again if it is swapped which
553 would cause the caller's buffer to get clobbered when voice locks
554 and runs - we'll wait for it to lock and yield again then make sure
555 the ride has come to a complete stop */
556 wait_for_voice_swap_in();
559 /* Save voice IRAM but just memcpy - safe to do here since voice
560 is current and no audio codec is loaded */
561 memcpy(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
562 voice_iram_stolen
= true;
566 /* Nothing much to do if no voice */
567 voice_iram_stolen
= false;
571 #endif /* IRAM_STEAL */
573 #ifdef HAVE_RECORDING
574 unsigned char *audio_get_recording_buffer(size_t *buffer_size
)
576 /* Don't allow overwrite of voice swap area or we'll trash the
577 swapped-out voice codec but can use whole thing if none */
580 /* Stop audio and voice. Wait for voice to swap in and be clear
581 of pending events to ensure trouble-free operation of encoders */
583 wait_for_voice_swap_in();
584 #ifdef PLAYBACK_VOICE
589 #ifdef PLAYBACK_VOICE
590 /* If no dram_buf, swap space not used and recording gets more
591 memory. Codec swap areas will remain unaffected by the next init
592 since they're allocated at the end of the buffer and their sizes
593 don't change between calls */
596 #endif /* PLAYBACK_VOICE */
599 buffer_state
= BUFFER_STATE_TRASHED
;
601 *buffer_size
= end
- audiobuf
;
603 return (unsigned char *)audiobuf
;
606 bool audio_load_encoder(int afmt
)
609 const char *enc_fn
= get_codec_filename(afmt
| CODEC_TYPE_ENCODER
);
613 audio_remove_encoder();
614 ci
.enc_codec_loaded
= 0; /* clear any previous error condition */
616 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
617 queue_post(&codec_queue
, Q_ENCODER_LOAD_DISK
, (intptr_t)enc_fn
);
619 while (ci
.enc_codec_loaded
== 0)
622 logf("codec loaded: %d", ci
.enc_codec_loaded
);
624 return ci
.enc_codec_loaded
> 0;
629 } /* audio_load_encoder */
631 void audio_remove_encoder(void)
634 /* force encoder codec unload (if currently loaded) */
635 if (ci
.enc_codec_loaded
<= 0)
638 ci
.stop_encoder
= true;
639 while (ci
.enc_codec_loaded
> 0)
642 } /* audio_remove_encoder */
644 #endif /* HAVE_RECORDING */
646 struct mp3entry
* audio_current_track(void)
648 const char *filename
;
650 static struct mp3entry temp_id3
;
652 int offset
= ci
.new_track
+ wps_offset
;
654 cur_idx
= track_ridx
+ offset
;
655 cur_idx
&= MAX_TRACK_MASK
;
657 if (tracks
[cur_idx
].id3_hid
> 0)
658 return &curtrack_id3
;
660 memset(&temp_id3
, 0, sizeof(struct mp3entry
));
662 filename
= playlist_peek(0);
664 filename
= "No file!";
666 #ifdef HAVE_TC_RAMCACHE
667 if (tagcache_fill_tags(&temp_id3
, filename
))
671 p
= strrchr(filename
, '/');
677 strncpy(temp_id3
.path
, p
, sizeof(temp_id3
.path
)-1);
678 temp_id3
.title
= &temp_id3
.path
[0];
683 struct mp3entry
* audio_next_track(void)
685 int next_idx
= track_ridx
;
687 if (!audio_have_tracks())
691 next_idx
&= MAX_TRACK_MASK
;
693 if (tracks
[next_idx
].id3_hid
<= 0)
696 return &nexttrack_id3
;
699 bool audio_has_changed_track(void)
703 track_changed
= false;
710 void audio_play(long offset
)
714 #ifdef PLAYBACK_VOICE
715 /* Truncate any existing voice output so we don't have spelling
716 * etc. over the first part of the played track */
721 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset
);
722 /* Don't return until playback has actually started */
723 queue_send(&audio_queue
, Q_AUDIO_PLAY
, offset
);
726 void audio_stop(void)
729 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
730 /* Don't return until playback has actually stopped */
731 queue_send(&audio_queue
, Q_AUDIO_STOP
, 0);
734 void audio_pause(void)
736 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
737 /* Don't return until playback has actually paused */
738 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, true);
741 void audio_resume(void)
743 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
744 /* Don't return until playback has actually resumed */
745 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, false);
748 void audio_next(void)
750 if (playlist_check(ci
.new_track
+ wps_offset
+ 1))
752 if (global_settings
.beep
)
753 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
755 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
756 queue_post(&audio_queue
, Q_AUDIO_SKIP
, 1);
757 /* Update wps while our message travels inside deep playback queues. */
759 track_changed
= true;
763 /* No more tracks. */
764 if (global_settings
.beep
)
765 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
769 void audio_prev(void)
771 if (playlist_check(ci
.new_track
+ wps_offset
- 1))
773 if (global_settings
.beep
)
774 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
776 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
777 queue_post(&audio_queue
, Q_AUDIO_SKIP
, -1);
778 /* Update wps while our message travels inside deep playback queues. */
780 track_changed
= true;
784 /* No more tracks. */
785 if (global_settings
.beep
)
786 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
790 void audio_next_dir(void)
792 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
793 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, 1);
796 void audio_prev_dir(void)
798 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
799 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, -1);
802 void audio_pre_ff_rewind(void)
804 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
805 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
808 void audio_ff_rewind(long newpos
)
810 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
811 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, newpos
);
814 void audio_flush_and_reload_tracks(void)
816 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
817 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
820 void audio_error_clear(void)
822 #ifdef AUDIO_HAVE_RECORDING
823 pcm_rec_error_clear();
827 int audio_status(void)
832 ret
|= AUDIO_STATUS_PLAY
;
835 ret
|= AUDIO_STATUS_PAUSE
;
837 #ifdef HAVE_RECORDING
838 /* Do this here for constitency with mpeg.c version */
839 ret
|= pcm_rec_status();
845 int audio_get_file_pos(void)
850 #ifndef HAVE_FLASH_STORAGE
851 void audio_set_buffer_margin(int setting
)
853 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
854 buffer_margin
= lookup
[setting
];
855 logf("buffer margin: %d", buffer_margin
);
856 set_filebuf_watermark(buffer_margin
);
860 /* Take nescessary steps to enable or disable the crossfade setting */
861 void audio_set_crossfade(int enable
)
867 /* Tell it the next setting to use */
868 pcmbuf_crossfade_enable(enable
);
870 /* Return if size hasn't changed or this is too early to determine
871 which in the second case there's no way we could be playing
873 if (pcmbuf_is_same_size())
875 /* This function is a copout and just syncs some variables -
876 to be removed at a later date */
877 pcmbuf_crossfade_enable_finished();
882 was_playing
= playing
;
884 /* Playback has to be stopped before changing the buffer size */
887 /* Store the track resume position */
888 offset
= curtrack_id3
.offset
;
889 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK
));
892 /* Blast it - audio buffer will have to be setup again next time
894 audio_get_buffer(true, &size
);
896 /* Restart playback if audio was running previously */
901 /* --- Routines called from multiple threads --- */
902 static void set_current_codec(int codec_idx
)
904 current_codec
= codec_idx
;
905 dsp_configure(DSP_SWITCH_CODEC
, codec_idx
);
908 #ifdef PLAYBACK_VOICE
909 static void swap_codec(void)
913 /* Swap nothing if no swap buffers exist */
914 if (dram_buf
== NULL
)
916 logf("swap: no swap buffers");
920 my_codec
= current_codec
;
922 logf("swapping out codec: %d", my_codec
);
924 /* Invert this when a codec thread enters and leaves */
925 swap_codec_parity
= !swap_codec_parity
;
927 /* If this is true, an odd number of calls has occurred and there's
928 no codec thread waiting to swap us out when it locks and runs. This
929 occurs when playback is stopped or when just starting playback and
930 the audio thread is loading a codec; parities should always be even
931 on entry when a thread calls this during playback */
932 if (swap_codec_parity
)
934 /* Save our current IRAM and DRAM */
936 if (voice_iram_stolen
)
938 logf("swap: iram restore");
939 voice_iram_stolen
= false;
940 /* Don't swap trashed data into buffer as the voice IRAM will
941 already be swapped out - should _always_ be the case if
942 voice_iram_stolen is true since the voice has been swapped
944 if (my_codec
== CODEC_IDX_VOICE
)
946 logf("voice iram already swapped");
952 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
958 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
959 /* No cache invalidation needed; it will be done in codec_load_ram
960 or we won't be here otherwise */
963 /* Release my semaphore */
964 semaphore_release(&sem_codecthread
);
965 logf("unlocked: %d", my_codec
);
967 /* Wait for other codec */
968 event_wait(&event_codecthread
,
969 (my_codec
== CODEC_IDX_AUDIO
) ? STATE_NONSIGNALED
: STATE_SIGNALED
);
971 /* Wait for other codec to unlock */
972 logf("waiting for lock: %d", my_codec
);
973 semaphore_wait(&sem_codecthread
);
976 set_current_codec(my_codec
);
977 event_set_state(&event_codecthread
,
978 (my_codec
== CODEC_IDX_AUDIO
) ? STATE_SIGNALED
: STATE_NONSIGNALED
);
980 /* Reload our IRAM and DRAM */
981 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
982 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
985 /* Flip parity again */
986 swap_codec_parity
= !swap_codec_parity
;
988 logf("resuming codec: %d", my_codec
);
991 /* This function is meant to be used by the buffer stealing functions to
992 ensure the codec is no longer active and so voice will be swapped-in
993 before it is called */
994 static void voice_stop(void)
996 /* Must have a voice codec loaded or we'll hang forever here */
997 if (!voice_codec_loaded
)
1000 talk_force_shutup();
1002 /* Loop until voice empties it's queue, stops and picks up on the new
1003 track; the voice thread must be stopped and waiting for messages
1004 outside the codec */
1005 while (voice_is_playing
|| !queue_empty(&voice_queue
) ||
1013 /* Is voice still speaking */
1014 /* Unfortunately only reliable when music is not also playing. */
1015 static bool is_voice_speaking(void)
1017 return is_voice_queued()
1019 || (!playing
&& pcm_is_playing());
1022 #endif /* PLAYBACK_VOICE */
1024 /* Wait for voice to finish speaking. */
1025 /* Also only reliable when music is not also playing. */
1026 void voice_wait(void)
1028 #ifdef PLAYBACK_VOICE
1029 while (is_voice_speaking())
1034 static void set_filebuf_watermark(int seconds
)
1039 return; /* Audio buffers not yet set up */
1041 bytes
= MAX(curtrack_id3
.bitrate
* seconds
* (1000/8), conf_watermark
);
1042 bytes
= MIN(bytes
, filebuflen
/ 2);
1043 conf_watermark
= bytes
;
1046 const char * get_codec_filename(int cod_spec
)
1050 #ifdef HAVE_RECORDING
1051 /* Can choose decoder or encoder if one available */
1052 int type
= cod_spec
& CODEC_TYPE_MASK
;
1053 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
1055 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
1056 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
1058 fname
= (type
== CODEC_TYPE_ENCODER
) ?
1059 audio_formats
[afmt
].codec_enc_root_fn
:
1060 audio_formats
[afmt
].codec_root_fn
;
1063 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
1064 afmt
, fname
? fname
: "<unknown>");
1065 #else /* !HAVE_RECORDING */
1066 /* Always decoder */
1067 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
1068 cod_spec
= AFMT_UNKNOWN
;
1069 fname
= audio_formats
[cod_spec
].codec_root_fn
;
1070 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
1071 #endif /* HAVE_RECORDING */
1074 } /* get_codec_filename */
1077 /* --- Voice thread --- */
1079 #ifdef PLAYBACK_VOICE
1081 static bool voice_pcmbuf_insert_callback(
1082 const void *ch1
, const void *ch2
, int count
)
1084 const char *src
[2] = { ch1
, ch2
};
1088 int out_count
= dsp_output_count(count
);
1092 while ((dest
= pcmbuf_request_voice_buffer(
1093 &out_count
, playing
)) == NULL
)
1095 if (playing
&& audio_codec_loaded
)
1101 /* Get the real input_size for output_size bytes, guarding
1102 * against resampling buffer overflows. */
1103 inp_count
= dsp_input_count(out_count
);
1108 /* Input size has grown, no error, just don't write more than length */
1109 if (inp_count
> count
)
1112 out_count
= dsp_process(dest
, src
, inp_count
);
1119 pcmbuf_mix_voice(out_count
);
1120 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
1125 pcmbuf_write_complete(out_count
);
1131 } /* voice_pcmbuf_insert_callback */
1133 static void* voice_get_memory_callback(size_t *size
)
1135 /* Voice should have no use for this. If it did, we'd have to
1136 swap the malloc buffer as well. */
1141 static void voice_set_elapsed_callback(unsigned int value
)
1146 static void voice_set_offset_callback(size_t value
)
1151 static void voice_configure_callback(int setting
, intptr_t value
)
1153 if (!dsp_configure(setting
, value
))
1155 logf("Illegal key:%d", setting
);
1159 static size_t voice_filebuf_callback(void *ptr
, size_t size
)
1167 /* Handle Q_VOICE_STOP and part of SYS_USB_CONNECTED */
1168 static bool voice_on_voice_stop(bool aborting
, size_t *realsize
)
1170 if (aborting
&& !playing
)
1172 /* Aborting: Slight hack - flush PCM buffer if
1173 only being used for voice */
1177 if (voice_is_playing
)
1179 /* Clear the current buffer */
1180 voice_is_playing
= false;
1181 voice_getmore
= NULL
;
1182 voice_remaining
= 0;
1185 /* Cancel any automatic boost if no more clips requested. */
1186 if (!playing
|| !voice_thread_start
)
1189 /* Force the codec to think it's changing tracks */
1190 ci_voice
.new_track
= 1;
1193 return true; /* Yes, change tracks */
1199 static void* voice_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1201 struct queue_event ev
;
1203 if (ci_voice
.new_track
)
1211 if (voice_is_playing
|| playing
)
1213 queue_wait_w_tmo(&voice_queue
, &ev
, 0);
1214 if (!voice_is_playing
&& ev
.id
== SYS_TIMEOUT
)
1215 ev
.id
= Q_AUDIO_PLAY
;
1219 queue_wait(&voice_queue
, &ev
);
1224 LOGFQUEUE("voice < Q_AUDIO_PLAY");
1227 if (audio_codec_loaded
)
1233 #ifdef AUDIO_HAVE_RECORDING
1234 case Q_ENCODER_RECORD
:
1235 LOGFQUEUE("voice < Q_ENCODER_RECORD");
1241 LOGFQUEUE("voice < Q_VOICE_STOP");
1242 if (voice_on_voice_stop(ev
.data
, realsize
))
1246 case SYS_USB_CONNECTED
:
1248 LOGFQUEUE("voice < SYS_USB_CONNECTED");
1249 bool change_tracks
= voice_on_voice_stop(ev
.data
, realsize
);
1250 /* Voice is obviously current so let us swap ourselves away if
1251 playing so audio may stop itself - audio_codec_loaded can
1252 only be true in this case if we're here even if the codec
1253 is only about to load */
1254 if (audio_codec_loaded
)
1256 /* Playback should be finished by now - ack and wait */
1257 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
1258 usb_wait_for_disconnect(&voice_queue
);
1265 LOGFQUEUE("voice < Q_VOICE_PLAY");
1266 if (!voice_is_playing
)
1268 /* Set up new voice data */
1269 struct voice_info
*voice_data
;
1271 if (voice_iram_stolen
)
1273 /* Voice is the first to run again and is currently
1275 logf("voice: iram restore");
1276 memcpy(CODEC_IRAM_ORIGIN
, iram_buf
, CODEC_IRAM_SIZE
);
1277 voice_iram_stolen
= false;
1280 /* Must reset the buffer before any playback begins if
1282 if (buffer_state
== BUFFER_STATE_TRASHED
)
1283 audio_reset_buffer();
1285 voice_is_playing
= true;
1286 trigger_cpu_boost();
1287 voice_data
= (struct voice_info
*)ev
.data
;
1288 voice_remaining
= voice_data
->size
;
1289 voicebuf
= voice_data
->buf
;
1290 voice_getmore
= voice_data
->callback
;
1292 goto voice_play_clip
; /* To exit both switch and while */
1295 LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
1296 goto voice_play_clip
;
1299 LOGFQUEUE("voice < default");
1305 if (voice_remaining
== 0 || voicebuf
== NULL
)
1308 voice_getmore((unsigned char **)&voicebuf
, &voice_remaining
);
1310 /* If this clip is done */
1311 if (voice_remaining
== 0)
1313 LOGFQUEUE("voice > voice Q_VOICE_STOP");
1314 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
1315 /* Force pcm playback. */
1316 if (!pcm_is_playing())
1317 pcmbuf_play_start();
1321 *realsize
= MIN(voice_remaining
, reqsize
);
1327 } /* voice_request_buffer_callback */
1329 static void voice_advance_buffer_callback(size_t amount
)
1331 amount
= MIN(amount
, voice_remaining
);
1333 voice_remaining
-= amount
;
1336 static void voice_advance_buffer_loc_callback(void *ptr
)
1338 size_t amount
= (size_t)ptr
- (size_t)voicebuf
;
1340 voice_advance_buffer_callback(amount
);
1343 static off_t
voice_mp3_get_filepos_callback(int newtime
)
1350 static void voice_do_nothing(void)
1355 static bool voice_seek_buffer_callback(size_t newpos
)
1362 static bool voice_request_next_track_callback(void)
1364 ci_voice
.new_track
= 0;
1368 static void voice_thread(void)
1370 logf("Loading voice codec");
1371 voice_codec_loaded
= true;
1372 semaphore_wait(&sem_codecthread
);
1373 event_set_state(&event_codecthread
, false);
1374 set_current_codec(CODEC_IDX_VOICE
);
1375 dsp_configure(DSP_RESET
, 0);
1376 voice_remaining
= 0;
1377 voice_getmore
= NULL
;
1379 /* FIXME: If we being starting the voice thread without reboot, the
1380 voice_queue could be full of old stuff and we must flush it. */
1381 codec_load_file(get_codec_filename(AFMT_MPA_L3
), &ci_voice
);
1383 logf("Voice codec finished");
1384 voice_codec_loaded
= false;
1385 voice_thread_p
= NULL
;
1386 semaphore_release(&sem_codecthread
);
1387 } /* voice_thread */
1389 #endif /* PLAYBACK_VOICE */
1391 /* --- Codec thread --- */
1392 static bool codec_pcmbuf_insert_callback(
1393 const void *ch1
, const void *ch2
, int count
)
1395 const char *src
[2] = { ch1
, ch2
};
1399 int out_count
= dsp_output_count(count
);
1403 /* Prevent audio from a previous track from playing */
1404 if (ci
.new_track
|| ci
.stop_codec
)
1407 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
1410 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
1414 /* Get the real input_size for output_size bytes, guarding
1415 * against resampling buffer overflows. */
1416 inp_count
= dsp_input_count(out_count
);
1421 /* Input size has grown, no error, just don't write more than length */
1422 if (inp_count
> count
)
1425 out_count
= dsp_process(dest
, src
, inp_count
);
1430 pcmbuf_write_complete(out_count
);
1432 #ifdef PLAYBACK_VOICE
1433 if ((voice_is_playing
|| voice_thread_start
)
1434 && pcm_is_playing() && voice_codec_loaded
&&
1435 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1437 voice_thread_start
= false;
1446 } /* codec_pcmbuf_insert_callback */
1448 static void* codec_get_memory_callback(size_t *size
)
1450 *size
= MALLOC_BUFSIZE
;
1455 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
1456 static void codec_pcmbuf_position_callback(size_t size
)
1458 /* This is called from an ISR, so be quick */
1459 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
1460 prev_ti
->id3
.elapsed
;
1462 if (time
>= prev_ti
->id3
.length
)
1464 pcmbuf_set_position_callback(NULL
);
1465 prev_ti
->id3
.elapsed
= prev_ti
->id3
.length
;
1468 prev_ti
->id3
.elapsed
= time
;
1472 static void codec_set_elapsed_callback(unsigned int value
)
1474 unsigned int latency
;
1478 #ifdef AB_REPEAT_ENABLE
1479 ab_position_report(value
);
1482 latency
= pcmbuf_get_latency();
1483 if (value
< latency
)
1484 curtrack_id3
.elapsed
= 0;
1485 else if (value
- latency
> curtrack_id3
.elapsed
||
1486 value
- latency
< curtrack_id3
.elapsed
- 2)
1488 curtrack_id3
.elapsed
= value
- latency
;
1492 static void codec_set_offset_callback(size_t value
)
1494 unsigned int latency
;
1499 latency
= pcmbuf_get_latency() * curtrack_id3
.bitrate
/ 8;
1500 if (value
< latency
)
1501 curtrack_id3
.offset
= 0;
1503 curtrack_id3
.offset
= value
- latency
;
1506 /* copy up-to size bytes into ptr and return the actual size copied */
1507 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
1511 if (ci
.stop_codec
|| !playing
)
1514 copy_n
= bufread(CUR_TI
->audio_hid
, size
, ptr
);
1516 /* Nothing requested OR nothing left */
1520 /* Let the disk buffer catch fill until enough data is available */
1521 while (copy_n
== -2)
1526 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1527 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1531 LOGFQUEUE("codec >| buffering Q_BUFFER_HANDLE");
1532 queue_send(&buffering_queue
, Q_BUFFER_HANDLE
, CUR_TI
->audio_hid
);
1534 if (ci
.stop_codec
|| ci
.new_track
)
1537 copy_n
= bufread(CUR_TI
->audio_hid
, size
, ptr
);
1540 /* Update read and other position pointers */
1541 bufadvance(CUR_TI
->audio_hid
, copy_n
);
1542 ci
.curpos
+= copy_n
;
1544 /* Return the actual amount of data copied to the buffer */
1546 } /* codec_filebuf_callback */
1548 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1550 size_t copy_n
= reqsize
;
1560 ret
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, (unsigned char **)&ptr
);
1562 copy_n
= MIN((size_t)ret
, reqsize
);
1575 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1576 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1580 LOGFQUEUE("codec >| buffering Q_BUFFER_HANDLE");
1581 queue_send(&buffering_queue
, Q_BUFFER_HANDLE
, CUR_TI
->audio_hid
);
1585 if (ci
.stop_codec
|| ci
.new_track
)
1590 ret
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, (unsigned char **)&ptr
);
1592 copy_n
= MIN((size_t)ret
, reqsize
);
1597 } /* codec_request_buffer_callback */
1599 static int get_codec_base_type(int type
)
1611 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;
1648 /* Start buffer filling as necessary. */
1649 if (!pcmbuf_is_lowdata() && !filling
)
1651 if (bufused() < conf_watermark
&& playing
&& !playlist_end
)
1653 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1654 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1659 ci
.curpos
+= amount
;
1660 codec_set_offset_callback(ci
.curpos
);
1663 static void codec_advance_buffer_loc_callback(void *ptr
)
1665 size_t amount
= get_offset(CUR_TI
->audio_hid
, ptr
);
1667 codec_advance_buffer_callback(amount
);
1670 /* Copied from mpeg.c. Should be moved somewhere else. */
1671 static int codec_get_file_pos(void)
1674 struct mp3entry
*id3
= audio_current_track();
1680 /* Use the TOC to find the new position */
1681 unsigned int percent
, remainder
;
1682 int curtoc
, nexttoc
, plen
;
1684 percent
= (id3
->elapsed
*100)/id3
->length
;
1688 curtoc
= id3
->toc
[percent
];
1691 nexttoc
= id3
->toc
[percent
+1];
1695 pos
= (id3
->filesize
/256)*curtoc
;
1697 /* Use the remainder to get a more accurate position */
1698 remainder
= (id3
->elapsed
*100)%id3
->length
;
1699 remainder
= (remainder
*100)/id3
->length
;
1700 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1701 pos
+= (plen
/100)*remainder
;
1705 /* No TOC exists, estimate the new position */
1706 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1707 (id3
->elapsed
/ 1000);
1710 else if (id3
->bitrate
)
1711 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1715 pos
+= id3
->first_frame_offset
;
1717 /* Don't seek right to the end of the file so that we can
1718 transition properly to the next song */
1719 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1720 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1725 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1729 curtrack_id3
.elapsed
= newtime
;
1730 newpos
= codec_get_file_pos();
1735 static void codec_seek_complete_callback(void)
1737 logf("seek_complete");
1738 if (pcm_is_paused())
1740 /* If this is not a seamless seek, clear the buffer */
1742 dsp_configure(DSP_FLUSH
, 0);
1744 /* If playback was not 'deliberately' paused, unpause now */
1746 pcmbuf_pause(false);
1751 static bool codec_seek_buffer_callback(size_t newpos
)
1755 logf("codec_seek_buffer_callback");
1757 if (newpos
>= CUR_TI
->filesize
)
1758 newpos
= CUR_TI
->filesize
- 1;
1760 difference
= newpos
- ci
.curpos
;
1761 if (difference
>= 0)
1763 /* Seeking forward */
1764 logf("seek: +%d", difference
);
1765 codec_advance_buffer_callback(difference
);
1769 /* Seeking backward */
1770 difference
= -difference
;
1771 if (ci
.curpos
- difference
< 0)
1772 difference
= ci
.curpos
;
1775 /* We need to reload the song. */
1776 if (newpos
< CUR_TI
->start_pos
)
1778 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1782 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1783 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1789 case Q_CODEC_REQUEST_COMPLETE
:
1790 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1793 case Q_CODEC_REQUEST_FAILED
:
1794 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1795 ci
.stop_codec
= true;
1799 LOGFQUEUE("codec |< default");
1805 /* Seeking inside buffer space. */
1806 logf("seek: -%d", difference
);
1807 if (bufadvance(CUR_TI
->audio_hid
, -difference
) == 0)
1809 ci
.curpos
-= difference
;
1819 static void codec_configure_callback(int setting
, intptr_t value
)
1822 case CODEC_SET_FILEBUF_WATERMARK
:
1823 conf_watermark
= value
;
1824 set_filebuf_watermark(buffer_margin
);
1827 case CODEC_SET_FILEBUF_CHUNKSIZE
:
1828 conf_filechunk
= value
;
1831 case CODEC_SET_FILEBUF_PRESEEK
:
1832 conf_preseek
= value
;
1836 if (!dsp_configure(setting
, value
)) { logf("Illegal key:%d", setting
); }
1840 static void codec_track_changed(void)
1842 automatic_skip
= false;
1843 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1844 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1847 static void codec_pcmbuf_track_changed_callback(void)
1849 pcmbuf_set_position_callback(NULL
);
1850 codec_track_changed();
1853 static void codec_discard_codec_callback(void)
1855 if (CUR_TI
->codec_hid
> 0)
1857 bufclose(CUR_TI
->codec_hid
);
1858 CUR_TI
->codec_hid
= 0;
1862 /* Check if a buffer desync has happened, log it and stop playback. */
1863 if (buf_ridx
!= CUR_TI
->buf_idx
)
1865 int offset
= CUR_TI
->buf_idx
- buf_ridx
;
1866 size_t new_used
= bufused() - offset
;
1868 logf("Buf off :%d=%d-%d", offset
, CUR_TI
->buf_idx
, buf_ridx
);
1869 logf("Used off:%d",bufused() - new_used
);
1871 /* This is a fatal internal error and it's not safe to
1872 * continue playback. */
1873 ci
.stop_codec
= true;
1874 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1879 static inline void codec_gapless_track_change(void) {
1880 /* callback keeps the progress bar moving while the pcmbuf empties */
1881 /* pcmbuf_set_position_callback(codec_pcmbuf_position_callback); */
1882 /* set the pcmbuf callback for when the track really changes */
1883 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1886 static inline void codec_crossfade_track_change(void) {
1887 /* Initiate automatic crossfade mode */
1888 pcmbuf_crossfade_init(false);
1889 /* Notify the wps that the track change starts now */
1890 codec_track_changed();
1893 static void codec_track_skip_done(bool was_manual
)
1895 int crossfade_mode
= global_settings
.crossfade
;
1897 /* Manual track change (always crossfade or flush audio). */
1900 pcmbuf_crossfade_init(true);
1901 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1902 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1904 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1905 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1906 && crossfade_mode
!= CROSSFADE_ENABLE_TRACKSKIP
)
1908 if (crossfade_mode
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1910 if (global_settings
.playlist_shuffle
)
1911 /* shuffle mode is on, so crossfade: */
1912 codec_crossfade_track_change();
1914 /* shuffle mode is off, so do a gapless track change */
1915 codec_gapless_track_change();
1918 /* normal crossfade: */
1919 codec_crossfade_track_change();
1922 /* normal gapless playback. */
1923 codec_gapless_track_change();
1926 static bool codec_load_next_track(void)
1928 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1930 prev_track_elapsed
= curtrack_id3
.elapsed
;
1933 codec_seek_complete_callback();
1935 #ifdef AB_REPEAT_ENABLE
1936 ab_end_of_track_report();
1939 logf("Request new track");
1941 if (ci
.new_track
== 0)
1944 automatic_skip
= true;
1949 trigger_cpu_boost();
1950 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1951 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1956 case Q_CODEC_REQUEST_COMPLETE
:
1957 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1958 codec_track_skip_done(!automatic_skip
);
1961 case Q_CODEC_REQUEST_FAILED
:
1962 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1964 ci
.stop_codec
= true;
1968 LOGFQUEUE("codec |< default");
1969 ci
.stop_codec
= true;
1974 static bool codec_request_next_track_callback(void)
1978 if (ci
.stop_codec
|| !playing
)
1981 prev_codectype
= get_codec_base_type(curtrack_id3
.codectype
);
1983 if (!codec_load_next_track())
1986 /* Check if the next codec is the same file. */
1987 if (prev_codectype
== get_codec_base_type(curtrack_id3
.codectype
))
1989 logf("New track loaded");
1990 codec_discard_codec_callback();
1995 logf("New codec:%d/%d", curtrack_id3
.codectype
, prev_codectype
);
2000 static void codec_thread(void)
2002 struct queue_event ev
;
2008 queue_wait(&codec_queue
, &ev
);
2011 case Q_CODEC_LOAD_DISK
:
2012 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
2013 queue_reply(&codec_queue
, 1);
2014 audio_codec_loaded
= true;
2015 #ifdef PLAYBACK_VOICE
2016 /* Don't sent messages to voice codec if it's already swapped
2017 out or it will never get this */
2018 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2020 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
2021 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
2023 semaphore_wait(&sem_codecthread
);
2024 event_set_state(&event_codecthread
, true);
2026 set_current_codec(CODEC_IDX_AUDIO
);
2027 ci
.stop_codec
= false;
2028 status
= codec_load_file((const char *)ev
.data
, &ci
);
2029 DEBUGF("codec_load = %d\n", status
);
2030 #ifdef PLAYBACK_VOICE
2031 semaphore_release(&sem_codecthread
);
2036 LOGFQUEUE("codec < Q_CODEC_LOAD");
2037 if (CUR_TI
->codec_hid
<= 0) {
2038 logf("Codec slot is empty!");
2039 /* Wait for the pcm buffer to go empty */
2040 while (pcm_is_playing())
2042 /* This must be set to prevent an infinite loop */
2043 ci
.stop_codec
= true;
2044 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
2045 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
2049 audio_codec_loaded
= true;
2050 #ifdef PLAYBACK_VOICE
2051 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2053 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
2054 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
2056 semaphore_wait(&sem_codecthread
);
2057 event_set_state(&event_codecthread
, true);
2059 set_current_codec(CODEC_IDX_AUDIO
);
2060 ci
.stop_codec
= false;
2061 wrap
= (size_t)&filebuf
[filebuflen
] - (size_t)getptr(CUR_TI
->codec_hid
);
2062 status
= codec_load_ram(getptr(CUR_TI
->codec_hid
), CUR_TI
->codecsize
,
2063 &filebuf
[0], wrap
, &ci
);
2064 #ifdef PLAYBACK_VOICE
2065 semaphore_release(&sem_codecthread
);
2069 #ifdef AUDIO_HAVE_RECORDING
2070 case Q_ENCODER_LOAD_DISK
:
2071 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2072 audio_codec_loaded
= false; /* Not audio codec! */
2073 #ifdef PLAYBACK_VOICE
2074 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2076 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
2077 queue_post(&voice_queue
, Q_ENCODER_RECORD
, 0);
2079 semaphore_wait(&sem_codecthread
);
2080 event_set_state(&event_codecthread
, true);
2082 logf("loading encoder");
2083 set_current_codec(CODEC_IDX_AUDIO
);
2084 ci
.stop_encoder
= false;
2085 status
= codec_load_file((const char *)ev
.data
, &ci
);
2086 #ifdef PLAYBACK_VOICE
2087 semaphore_release(&sem_codecthread
);
2089 logf("encoder stopped");
2091 #endif /* AUDIO_HAVE_RECORDING */
2094 case SYS_USB_CONNECTED
:
2095 LOGFQUEUE("codec < SYS_USB_CONNECTED");
2096 queue_clear(&codec_queue
);
2097 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
2098 usb_wait_for_disconnect(&codec_queue
);
2103 LOGFQUEUE("codec < default");
2106 if (audio_codec_loaded
)
2115 audio_codec_loaded
= false;
2119 case Q_CODEC_LOAD_DISK
:
2121 LOGFQUEUE("codec < Q_CODEC_LOAD");
2124 if (ci
.new_track
|| status
!= CODEC_OK
)
2128 logf("Codec failure");
2129 gui_syncsplash(HZ
*2, "Codec failure");
2132 if (!codec_load_next_track())
2134 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2135 /* End of playlist */
2136 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2142 logf("Codec finished");
2145 /* Wait for the audio to stop playing before
2146 * triggering the WPS exit */
2147 while(pcm_is_playing())
2149 curtrack_id3
.elapsed
=
2150 curtrack_id3
.length
- pcmbuf_get_latency();
2153 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2154 /* End of playlist */
2155 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2160 if (CUR_TI
->codec_hid
> 0)
2162 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2163 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
2167 const char *codec_fn
=
2168 get_codec_filename(curtrack_id3
.codectype
);
2169 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2170 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
2171 (intptr_t)codec_fn
);
2176 #ifdef AUDIO_HAVE_RECORDING
2177 case Q_ENCODER_LOAD_DISK
:
2178 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2180 if (status
== CODEC_OK
)
2183 logf("Encoder failure");
2184 gui_syncsplash(HZ
*2, "Encoder failure");
2186 if (ci
.enc_codec_loaded
< 0)
2189 logf("Encoder failed to load");
2190 ci
.enc_codec_loaded
= -1;
2192 #endif /* AUDIO_HAVE_RECORDING */
2195 LOGFQUEUE("codec < default");
2202 /* --- Audio thread --- */
2204 static bool audio_filebuf_is_lowdata(void)
2206 return bufused() < AUDIO_FILEBUF_CRITICAL
;
2209 static bool audio_have_tracks(void)
2211 return track_ridx
!= track_widx
|| CUR_TI
->filesize
;
2214 static bool audio_have_free_tracks(void)
2216 if (track_widx
< track_ridx
)
2217 return track_widx
+ 1 < track_ridx
;
2218 else if (track_ridx
== 0)
2219 return track_widx
< MAX_TRACK
- 1;
2224 int audio_track_count(void)
2226 if (audio_have_tracks())
2228 int relative_track_widx
= track_widx
;
2230 if (track_ridx
> track_widx
)
2231 relative_track_widx
+= MAX_TRACK
;
2233 return relative_track_widx
- track_ridx
+ 1;
2239 long audio_filebufused(void)
2241 return (long) bufused();
2244 /* Count the data BETWEEN the selected tracks */
2245 static size_t audio_buffer_count_tracks(int from_track
, int to_track
)
2248 bool need_wrap
= to_track
< from_track
;
2252 if (++from_track
>= MAX_TRACK
)
2254 from_track
-= MAX_TRACK
;
2258 if (from_track
>= to_track
&& !need_wrap
)
2261 amount
+= tracks
[from_track
].codecsize
+ tracks
[from_track
].filesize
;
2266 static bool audio_buffer_wind_forward(int new_track_ridx
, int old_track_ridx
)
2268 (void)new_track_ridx
;
2269 (void)old_track_ridx
;
2273 /* Start with the remainder of the previously playing track */
2274 amount
= tracks
[old_track_ridx
].filesize
- ci
.curpos
;
2275 /* Then collect all data from tracks in between them */
2276 amount
+= audio_buffer_count_tracks(old_track_ridx
, new_track_ridx
);
2277 logf("bwf:%ldB", (long) amount
);
2279 if (amount
> bufused())
2282 /* Wind the buffer to the beginning of the target track or its codec */
2283 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
2288 static bool audio_buffer_wind_backward(int new_track_ridx
, int old_track_ridx
)
2290 (void)new_track_ridx
;
2291 (void)old_track_ridx
;
2293 /* Available buffer data */
2295 /* Start with the previously playing track's data and our data */
2299 buf_back
= RINGBUF_SUB(buf_ridx
, buf_widx
);
2301 /* If we're not just resetting the current track */
2302 if (new_track_ridx
!= old_track_ridx
)
2304 /* Need to wind to before the old track's codec and our filesize */
2305 amount
+= tracks
[old_track_ridx
].codecsize
;
2306 amount
+= tracks
[new_track_ridx
].filesize
;
2308 /* Rewind the old track to its beginning */
2309 tracks
[old_track_ridx
].available
=
2310 tracks
[old_track_ridx
].filesize
- tracks
[old_track_ridx
].filerem
;
2313 /* If the codec was ever buffered */
2314 if (tracks
[new_track_ridx
].codecsize
)
2316 /* Add the codec to the needed size */
2317 amount
+= tracks
[new_track_ridx
].codecsize
;
2318 tracks
[new_track_ridx
].has_codec
= true;
2321 /* Then collect all data from tracks between new and old */
2322 amount
+= audio_buffer_count_tracks(new_track_ridx
, old_track_ridx
);
2324 /* Do we have space to make this skip? */
2325 if (amount
> buf_back
)
2328 logf("bwb:%ldB",amount
);
2330 /* Rewind the buffer to the beginning of the target track or its codec */
2331 buf_ridx
= RINGBUF_SUB(buf_ridx
, amount
);
2333 /* Reset to the beginning of the new track */
2334 tracks
[new_track_ridx
].available
= tracks
[new_track_ridx
].filesize
;
2339 static void audio_update_trackinfo(void)
2341 ci
.filesize
= CUR_TI
->filesize
;
2342 curtrack_id3
.elapsed
= 0;
2343 curtrack_id3
.offset
= 0;
2344 ci
.id3
= &curtrack_id3
;
2346 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2349 /* Yield to codecs for as long as possible if they are in need of data
2350 * return true if the caller should break to let the audio thread process
2352 static bool audio_yield_codecs(void)
2356 if (!queue_empty(&audio_queue
))
2359 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
2360 && !ci
.stop_codec
&& playing
&& !audio_filebuf_is_lowdata())
2367 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 close_track_handles(&tracks
[last_idx
]);
2402 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2406 else if (clear_unbuffered
)
2408 close_track_handles(&tracks
[cur_idx
]);
2409 memset(&tracks
[cur_idx
], 0, sizeof(struct track_info
));
2413 /* We clear the previous instance of a buffered track throughout
2414 * the above loop to facilitate 'last' detection. Clear/notify
2415 * the last track here */
2418 if (track_unbuffer_callback
)
2419 track_unbuffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), true);
2420 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2424 static void audio_release_tracks(void)
2426 int cur_idx
= track_ridx
;
2428 logf("releasing all tracks");
2432 close_track_handles(&tracks
[cur_idx
]);
2435 cur_idx
&= MAX_TRACK_MASK
;
2437 if (cur_idx
== track_widx
)
2442 /* FIXME: This code should be made more generic and move to metadata.c */
2443 static void audio_strip_tags(void)
2447 static const unsigned char tag
[] = "TAG";
2448 static const unsigned char apetag
[] = "APETAGEX";
2451 size_t len
, version
;
2453 tag_idx
= RINGBUF_SUB(buf_widx
, 128);
2455 if (bufused() > 128 && tag_idx
> buf_ridx
)
2458 for(i
= 0;i
< 3;i
++)
2460 if(filebuf
[cur_idx
] != tag
[i
])
2463 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2466 /* Skip id3v1 tag */
2467 logf("Skipping ID3v1 tag");
2469 tracks
[track_widx
].available
-= 128;
2470 tracks
[track_widx
].filesize
-= 128;
2474 /* Check for APE tag (look for the APE tag footer) */
2475 tag_idx
= RINGBUF_SUB(buf_widx
, 32);
2477 if (bufused() > 32 && tag_idx
> buf_ridx
)
2480 for(i
= 0;i
< 8;i
++)
2482 if(filebuf
[cur_idx
] != apetag
[i
])
2485 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2488 /* Read the version and length from the footer */
2489 version
= filebuf
[tag_idx
+8] | (filebuf
[tag_idx
+9] << 8) |
2490 (filebuf
[tag_idx
+10] << 16) | (filebuf
[tag_idx
+11] << 24);
2491 len
= filebuf
[tag_idx
+12] | (filebuf
[tag_idx
+13] << 8) |
2492 (filebuf
[tag_idx
+14] << 16) | (filebuf
[tag_idx
+15] << 24);
2493 if (version
== 2000)
2494 len
+= 32; /* APEv2 has a 32 byte header */
2497 if (bufused() > len
)
2499 logf("Skipping APE tag (%ldB)", len
);
2500 buf_widx
= RINGBUF_SUB(buf_widx
, len
);
2501 tracks
[track_widx
].available
-= len
;
2502 tracks
[track_widx
].filesize
-= len
;
2509 /* Returns true if a whole file is read, false otherwise */
2510 static bool audio_read_file(size_t minimum
)
2512 bool ret_val
= false;
2514 /* If we're called and no file is open, this is an error */
2517 logf("Bad fd in arf");
2518 /* Give some hope of miraculous recovery by forcing a track reload */
2519 tracks
[track_widx
].filesize
= 0;
2520 /* Stop this buffering run */
2524 trigger_cpu_boost();
2525 while (tracks
[track_widx
].filerem
> 0)
2531 /* copy_n is the largest chunk that is safe to read */
2532 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2534 /* buf_widx == buf_ridx is defined as buffer empty, not buffer full */
2535 if (RINGBUF_ADD_CROSS(buf_widx
,copy_n
,buf_ridx
) >= 0)
2538 /* rc is the actual amount read */
2539 rc
= read(current_fd
, &filebuf
[buf_widx
], copy_n
);
2543 logf("File ended %ldB early", tracks
[track_widx
].filerem
);
2544 tracks
[track_widx
].filesize
-= tracks
[track_widx
].filerem
;
2545 tracks
[track_widx
].filerem
= 0;
2549 /* How much of the playing track did we overwrite */
2550 if (buf_widx
== CUR_TI
->buf_idx
)
2552 /* Special handling; zero or full overlap? */
2553 if (track_widx
== track_ridx
&& CUR_TI
->available
== 0)
2559 overlap
= RINGBUF_ADD_CROSS(buf_widx
,rc
,CUR_TI
->buf_idx
);
2561 if ((unsigned)rc
> tracks
[track_widx
].filerem
)
2563 logf("Bad: rc-filerem=%ld, fixing", rc
-tracks
[track_widx
].filerem
);
2564 tracks
[track_widx
].filesize
+= rc
- tracks
[track_widx
].filerem
;
2565 tracks
[track_widx
].filerem
= rc
;
2568 /* Advance buffer */
2569 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2570 tracks
[track_widx
].available
+= rc
;
2571 tracks
[track_widx
].filerem
-= rc
;
2573 /* If we write into the playing track, adjust it's buffer info */
2576 CUR_TI
->buf_idx
+= overlap
;
2577 CUR_TI
->start_pos
+= overlap
;
2580 /* For a rebuffer, fill at least this minimum */
2581 if (minimum
> (unsigned)rc
)
2583 /* Let the codec process up to the watermark */
2584 /* Break immediately if this is a quick buffer, or there is an event */
2585 else if (minimum
|| audio_yield_codecs())
2587 /* Exit quickly, but don't stop the overall buffering process */
2593 if (tracks
[track_widx
].filerem
== 0)
2595 logf("Finished buf:%ldB", tracks
[track_widx
].filesize
);
2601 track_widx
&= MAX_TRACK_MASK
;
2603 tracks
[track_widx
].filesize
= 0;
2608 logf("%s buf:%ldB", ret_val
?"Quick":"Partially",
2609 tracks
[track_widx
].filesize
- tracks
[track_widx
].filerem
);
2615 static bool audio_loadcodec(bool start_play
)
2619 char codec_path
[MAX_PATH
]; /* Full path to codec */
2621 DEBUGF("audio_loadcodec(start_play = %s)\n", start_play
? "true" : "false");
2623 if (tracks
[track_widx
].id3_hid
<= 0) {
2624 DEBUGF("track ID3 info not ready\n");
2628 const char * codec_fn
=
2629 get_codec_filename(bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
);
2630 if (codec_fn
== NULL
)
2633 tracks
[track_widx
].codec_hid
= 0;
2637 /* Load the codec directly from disk and save some memory. */
2638 track_ridx
= track_widx
;
2639 ci
.filesize
= CUR_TI
->filesize
;
2640 ci
.id3
= &curtrack_id3
;
2641 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2643 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2644 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
2649 /* If we already have another track than this one buffered */
2650 if (track_widx
!= track_ridx
)
2652 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
2654 /* If the previous codec is the same as this one, there is no need
2655 * to put another copy of it on the file buffer */
2656 if (get_codec_base_type(
2657 bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
) ==
2658 get_codec_base_type(
2659 bufgetid3(tracks
[prev_track
].id3_hid
)->codectype
)
2660 && audio_codec_loaded
)
2662 logf("Reusing prev. codec");
2668 codec_get_full_path(codec_path
, codec_fn
);
2670 fd
= open(codec_path
, O_RDONLY
);
2673 logf("Codec doesn't exist!");
2677 tracks
[track_widx
].codecsize
= filesize(fd
);
2679 tracks
[track_widx
].codec_hid
= bufopen(codec_path
, 0, TYPE_CODEC
);
2680 if (tracks
[track_widx
].codec_hid
< 0)
2682 logf("Not enough space");
2688 logf("Loaded codec");
2693 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2694 static void audio_set_elapsed(struct mp3entry
* id3
)
2696 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
2697 id3
->offset
- id3
->first_frame_offset
: 0;
2700 if ( id3
->has_toc
) {
2701 /* calculate elapsed time using TOC */
2703 unsigned int remainder
, plen
, relpos
, nextpos
;
2705 /* find wich percent we're at */
2706 for (i
=0; i
<100; i
++ )
2707 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
2714 relpos
= id3
->toc
[i
];
2717 nextpos
= id3
->toc
[i
+1];
2721 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
2723 /* set time for this percent (divide before multiply to prevent
2724 overflow on long files. loss of precision is negligible on
2726 id3
->elapsed
= i
* (id3
->length
/ 100);
2728 /* calculate remainder time */
2729 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
2730 id3
->elapsed
+= (((remainder
* 100) / plen
) *
2731 (id3
->length
/ 10000));
2734 /* no TOC exists. set a rough estimate using average bitrate */
2735 int tpk
= id3
->length
/
2736 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
2738 id3
->elapsed
= offset
/ 1024 * tpk
;
2743 /* constant bitrate, use exact calculation */
2744 if (id3
->bitrate
!= 0)
2745 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
2749 /* Load one track by making the appropriate bufopen calls. Return true if
2750 everything required was loaded correctly, false if not. */
2751 static bool audio_load_track(int offset
, bool start_play
, bool rebuffer
)
2755 /* char msgbuf[80]; */
2757 int file_offset
= 0;
2758 struct mp3entry id3
;
2760 /* Stop buffer filling if there is no free track entries.
2761 Don't fill up the last track entry (we wan't to store next track
2763 if (!audio_have_free_tracks())
2765 logf("No free tracks");
2771 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
2772 /* Get track name from current playlist read position. */
2773 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
2775 /* Handle broken playlists. */
2776 fd
= open(trackname
, O_RDONLY
);
2779 logf("Open failed");
2780 /* Skip invalid entry from playlist. */
2781 playlist_skip_entry(NULL
, last_peek_offset
);
2789 logf("End-of-playlist");
2790 playlist_end
= true;
2794 tracks
[track_widx
].filesize
= filesize(fd
);
2796 /* Get track metadata if we don't already have it. */
2797 if (tracks
[track_widx
].id3_hid
<= 0)
2799 if (get_metadata(&id3
, fd
, trackname
))
2801 tracks
[track_widx
].id3_hid
= bufalloc(&id3
, sizeof(struct mp3entry
),
2803 tracks
[track_widx
].taginfo_ready
= (tracks
[track_widx
].id3_hid
> 0);
2805 if (tracks
[track_widx
].id3_hid
<= 0)
2807 DEBUGF("failed to allocate space for metadata\n");
2813 if (track_widx
== track_ridx
)
2814 copy_mp3entry(&curtrack_id3
, &id3
);
2815 else if (track_widx
== ((track_ridx
+ 1) & MAX_TRACK_MASK
))
2816 copy_mp3entry(&nexttrack_id3
, &id3
);
2820 track_changed
= true;
2821 playlist_update_resume_info(audio_current_track());
2826 logf("mde:%s!",trackname
);
2828 /* Skip invalid entry from playlist. */
2829 playlist_skip_entry(NULL
, last_peek_offset
);
2830 tracks
[track_widx
].taginfo_ready
= false;
2838 /* Set default values */
2841 int last_codec
= current_codec
;
2843 set_current_codec(CODEC_IDX_AUDIO
);
2844 conf_watermark
= AUDIO_DEFAULT_WATERMARK
;
2845 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
2846 conf_preseek
= AUDIO_REBUFFER_GUESS_SIZE
;
2847 dsp_configure(DSP_RESET
, 0);
2848 set_current_codec(last_codec
);
2850 track_changed
= true;
2851 playlist_update_resume_info(audio_current_track());
2855 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
2857 char cuepath
[MAX_PATH
];
2859 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
2861 if (look_for_cuesheet_file(trackname
, cuepath
) &&
2862 parse_cuesheet(cuepath
, cue
))
2864 strcpy((cue
)->audio_filename
, trackname
);
2866 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
2871 /* Load the codec. */
2872 if (!audio_loadcodec(start_play
))
2875 /* Set filesize to zero to indicate no file was loaded. */
2876 /* tracks[track_widx].filesize = 0;
2877 tracks[track_widx].filerem = 0;
2881 if (tracks
[track_widx
].codecsize
)
2883 /* No space for codec on buffer, not an error */
2884 tracks
[track_widx
].codecsize
= 0;
2888 /* This is an error condition, either no codec was found, or reading
2889 * the codec file failed part way through, either way, skip the track */
2890 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
2891 /* We should not use gui_syncplash from audio thread! */
2892 gui_syncsplash(HZ
*2, msgbuf
);
2893 /* Skip invalid entry from playlist. */
2894 playlist_skip_entry(NULL
, last_peek_offset
);
2895 tracks
[track_widx
].taginfo_ready
= false;
2901 struct mp3entry
*track_id3
;
2903 if (track_widx
== track_ridx
)
2904 track_id3
= &curtrack_id3
;
2905 else if (track_widx
== ((track_ridx
+ 1) & MAX_TRACK_MASK
))
2906 track_id3
= &nexttrack_id3
;
2908 track_id3
= bufgetid3(tracks
[track_widx
].id3_hid
);
2910 /* tracks[track_widx].start_pos = 0; */
2911 set_filebuf_watermark(buffer_margin
);
2912 track_id3
->elapsed
= 0;
2916 switch (track_id3
->codectype
) {
2920 file_offset
= offset
;
2921 track_id3
->offset
= offset
;
2922 audio_set_elapsed(track_id3
);
2927 file_offset
= offset
;
2928 track_id3
->offset
= offset
;
2929 track_id3
->elapsed
= track_id3
->length
/ 2;
2933 case AFMT_OGG_VORBIS
:
2941 track_id3
->offset
= offset
;
2946 logf("alt:%s", trackname
);
2947 /* tracks[track_widx].buf_idx = buf_widx; */
2949 //return audio_read_file(rebuffer);
2951 tracks
[track_widx
].audio_hid
= bufopen(trackname
, file_offset
, TYPE_AUDIO
);
2953 if (tracks
[track_widx
].audio_hid
<= 0)
2958 LOGFQUEUE("audio >| buffering Q_BUFFER_HANDLE");
2959 queue_send(&buffering_queue
, Q_BUFFER_HANDLE
, tracks
[track_widx
].audio_hid
);
2963 track_widx
&= MAX_TRACK_MASK
;
2968 static bool audio_read_next_metadata(void)
2975 next_idx
= track_widx
;
2976 if (tracks
[next_idx
].id3_hid
> 0)
2979 next_idx
&= MAX_TRACK_MASK
;
2981 if (tracks
[next_idx
].id3_hid
> 0)
2985 trackname
= playlist_peek(last_peek_offset
+ 1);
2989 fd
= open(trackname
, O_RDONLY
);
2993 struct mp3entry id3
;
2995 status
= get_metadata(&id3
, fd
, trackname
);
2996 /* Preload the glyphs in the tags */
2999 tracks
[next_idx
].id3_hid
= bufalloc(&id3
, sizeof(struct mp3entry
), TYPE_ID3
);
3001 if (tracks
[next_idx
].id3_hid
> 0)
3003 tracks
[next_idx
].taginfo_ready
= true;
3005 lcd_getstringsize(id3
.title
, NULL
, NULL
);
3007 lcd_getstringsize(id3
.artist
, NULL
, NULL
);
3009 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");
3118 /* Stop in progress fill, and clear open file descriptor */
3119 if (current_fd
>= 0)
3126 /* Reset buffer and track pointers */
3127 CUR_TI
->buf_idx
= buf_ridx
= buf_widx
= 0;
3128 track_widx
= track_ridx
;
3129 audio_clear_track_entries(true);
3130 CUR_TI
->available
= 0;
3132 /* Fill the buffer */
3133 last_peek_offset
= -1;
3134 CUR_TI
->filesize
= 0;
3135 CUR_TI
->start_pos
= 0;
3139 if (!CUR_TI
->taginfo_ready
)
3140 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
3142 audio_fill_file_buffer(false, true, 0);
3145 static int audio_check_new_track(void)
3147 DEBUGF("audio_check_new_track\n");
3149 int track_count
= audio_track_count();
3150 int old_track_ridx
= track_ridx
;
3157 if (playlist_next_dir(ci
.new_track
))
3160 CUR_TI
->taginfo_ready
= false;
3166 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3167 return Q_CODEC_REQUEST_FAILED
;
3174 /* If the playlist isn't that big */
3175 if (!playlist_check(ci
.new_track
))
3177 if (ci
.new_track
>= 0)
3179 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3180 return Q_CODEC_REQUEST_FAILED
;
3182 /* Find the beginning backward if the user over-skips it */
3183 while (!playlist_check(++ci
.new_track
))
3184 if (ci
.new_track
>= 0)
3186 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3187 return Q_CODEC_REQUEST_FAILED
;
3190 /* Update the playlist */
3191 last_peek_offset
-= ci
.new_track
;
3193 if (playlist_next(ci
.new_track
) < 0)
3195 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3196 return Q_CODEC_REQUEST_FAILED
;
3202 new_playlist
= false;
3205 /* Save the old track */
3206 /* prev_ti = CUR_TI; */
3209 for (i
= 0; i
< ci
.new_track
; i
++)
3211 idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
3212 close_track_handles(&tracks
[idx
]);
3215 /* Move to the new track */
3216 track_ridx
+= ci
.new_track
;
3217 track_ridx
&= MAX_TRACK_MASK
;
3219 if (CUR_TI
->id3_hid
> 0)
3220 copy_mp3entry(&curtrack_id3
, bufgetid3(CUR_TI
->id3_hid
));
3222 next_idx
= track_ridx
+ 1;
3223 next_idx
&= MAX_TRACK_MASK
;
3225 if (tracks
[next_idx
].id3_hid
> 0)
3226 copy_mp3entry(&nexttrack_id3
, bufgetid3(tracks
[next_idx
].id3_hid
));
3229 playlist_end
= false;
3231 track_changed
= !automatic_skip
;
3233 /* If it is not safe to even skip this many track entries */
3234 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
3237 CUR_TI
->taginfo_ready
= false;
3242 forward
= ci
.new_track
> 0;
3245 /* If the target track is clearly not in memory */
3246 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
3252 /* The track may be in memory, see if it really is */
3255 if (!audio_buffer_wind_forward(track_ridx
, old_track_ridx
))
3260 int cur_idx
= track_ridx
;
3261 bool taginfo_ready
= true;
3262 bool wrap
= track_ridx
> old_track_ridx
;
3267 cur_idx
&= MAX_TRACK_MASK
;
3268 if (!(wrap
|| cur_idx
< old_track_ridx
))
3271 /* If we hit a track in between without valid tag info, bail */
3272 if (!tracks
[cur_idx
].taginfo_ready
)
3274 taginfo_ready
= false;
3278 tracks[cur_idx].available = tracks[cur_idx].filesize;
3279 if (tracks[cur_idx].codecsize)
3280 tracks[cur_idx].has_codec = true;*/
3284 if (!audio_buffer_wind_backward(track_ridx
, old_track_ridx
))
3289 CUR_TI
->taginfo_ready
= false;
3295 audio_update_trackinfo();
3296 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3297 return Q_CODEC_REQUEST_COMPLETE
;
3300 static int audio_rebuffer_and_seek(size_t newpos
)
3303 size_t real_preseek
;
3307 /* (Re-)open current track's file handle. */
3308 trackname
= playlist_peek(0);
3309 fd
= open(trackname
, O_RDONLY
);
3312 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3313 return Q_CODEC_REQUEST_FAILED
;
3316 if (current_fd
>= 0)
3320 playlist_end
= false;
3324 /* Clear codec buffer. */
3325 track_widx
= track_ridx
;
3326 tracks
[track_widx
].buf_idx
= buf_widx
= buf_ridx
= 0;
3328 last_peek_offset
= 0;
3330 audio_initialize_buffer_fill(true);
3332 /* This may have been tweaked by the id3v1 code */
3333 CUR_TI
->filesize
=filesize(fd
);
3334 if (newpos
> conf_preseek
)
3336 CUR_TI
->start_pos
= newpos
- conf_preseek
;
3337 lseek(current_fd
, CUR_TI
->start_pos
, SEEK_SET
);
3338 CUR_TI
->filerem
= CUR_TI
->filesize
- CUR_TI
->start_pos
;
3339 real_preseek
= conf_preseek
;
3343 CUR_TI
->start_pos
= 0;
3344 CUR_TI
->filerem
= CUR_TI
->filesize
;
3345 real_preseek
= newpos
;
3348 CUR_TI
->available
= 0;
3350 audio_read_file(real_preseek
);
3352 /* Account for the data we just read that is 'behind' us now */
3353 CUR_TI
->available
-= real_preseek
;
3355 buf_ridx
= RINGBUF_ADD(buf_ridx
, real_preseek
);
3359 DEBUGF("/!\\ not implemented /!\\");
3360 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3361 return Q_CODEC_REQUEST_COMPLETE
;
3364 void audio_set_track_buffer_event(void (*handler
)(struct mp3entry
*id3
,
3367 track_buffer_callback
= handler
;
3370 void audio_set_track_unbuffer_event(void (*handler
)(struct mp3entry
*id3
,
3373 track_unbuffer_callback
= handler
;
3376 void audio_set_track_changed_event(void (*handler
)(struct mp3entry
*id3
))
3378 track_changed_callback
= handler
;
3381 unsigned long audio_prev_elapsed(void)
3383 return prev_track_elapsed
;
3386 static void audio_stop_codec_flush(void)
3388 ci
.stop_codec
= true;
3391 while (audio_codec_loaded
)
3394 /* If the audio codec is not loaded any more, and the audio is still
3395 * playing, it is now and _only_ now safe to call this function from the
3397 if (pcm_is_playing())
3399 pcmbuf_pause(paused
);
3402 static void audio_stop_playback(void)
3404 /* If we were playing, save resume information */
3407 struct mp3entry
*id3
= NULL
;
3409 if (!playlist_end
|| !ci
.stop_codec
)
3411 /* Set this early, the outside code yields and may allow the codec
3412 to try to wait for a reply on a buffer wait */
3413 ci
.stop_codec
= true;
3414 id3
= audio_current_track();
3417 /* Save the current playing spot, or NULL if the playlist has ended */
3418 playlist_update_resume_info(id3
);
3420 prev_track_elapsed
= curtrack_id3
.elapsed
;
3422 /* Increment index so runtime info is saved in audio_clear_track_entries().
3423 * Done here, as audio_stop_playback() may be called more than once.
3424 * Don't update runtime unless playback is stopped because of end of playlist.
3425 * Updating runtime when manually stopping a tracks, can destroy autoscores
3431 track_ridx
&= MAX_TRACK_MASK
;
3437 audio_stop_codec_flush();
3440 /* Mark all entries null. */
3441 audio_clear_track_entries(false);
3443 /* Close all tracks */
3444 audio_release_tracks();
3447 static void audio_play_start(size_t offset
)
3449 #if INPUT_SRC_CAPS != 0
3450 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
3451 audio_set_output_source(AUDIO_SRC_PLAYBACK
);
3454 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
3456 audio_stop_codec_flush();
3458 track_changed
= true;
3459 playlist_end
= false;
3467 sound_set_volume(global_settings
.volume
);
3468 track_widx
= track_ridx
= 0;
3470 /* Mark all entries null. */
3471 memset(tracks
, 0, sizeof(struct track_info
) * MAX_TRACK
);
3473 last_peek_offset
= -1;
3475 /* Officially playing */
3476 queue_reply(&audio_queue
, 1);
3478 audio_fill_file_buffer(true, false, offset
);
3480 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
3481 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
3485 /* Invalidates all but currently playing track. */
3486 static void audio_invalidate_tracks(void)
3489 if (audio_have_tracks())
3491 last_peek_offset
= 0;
3492 playlist_end
= false;
3493 track_widx
= track_ridx
;
3495 /* Mark all other entries null (also buffered wrong metadata). */
3496 audio_clear_track_entries(true);
3498 /* If the current track is fully buffered, advance the write pointer */
3499 if (tracks
[track_widx
].filerem
== 0)
3500 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
3502 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3504 audio_read_next_metadata();
3509 static void audio_new_playlist(void)
3511 /* Prepare to start a new fill from the beginning of the playlist */
3512 last_peek_offset
= -1;
3513 if (audio_have_tracks())
3516 skipped_during_pause
= true;
3517 playlist_end
= false;
3518 track_widx
= track_ridx
;
3519 audio_clear_track_entries(true);
3522 track_widx
&= MAX_TRACK_MASK
;
3524 /* Mark the current track as invalid to prevent skipping back to it */
3525 CUR_TI
->taginfo_ready
= false;
3528 /* Signal the codec to initiate a track change forward */
3529 new_playlist
= true;
3532 /* Officially playing */
3533 queue_reply(&audio_queue
, 1);
3535 audio_fill_file_buffer(false, true, 0);
3538 static void audio_initiate_track_change(long direction
)
3540 playlist_end
= false;
3541 ci
.new_track
+= direction
;
3542 wps_offset
-= direction
;
3544 skipped_during_pause
= true;
3547 static void audio_initiate_dir_change(long direction
)
3549 playlist_end
= false;
3551 ci
.new_track
= direction
;
3553 skipped_during_pause
= true;
3557 * Layout audio buffer as follows - iram buffer depends on target:
3558 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
3560 static void audio_reset_buffer(void)
3562 /* see audio_get_recording_buffer if this is modified */
3563 logf("audio_reset_buffer");
3565 /* If the setup of anything allocated before the file buffer is
3566 changed, do check the adjustments after the buffer_alloc call
3567 as it will likely be affected and need sliding over */
3569 /* Initially set up file buffer as all space available */
3570 malloc_buf
= audiobuf
+ talk_get_bufsize();
3571 /* Align the malloc buf to line size. Especially important to cf
3572 targets that do line reads/writes. */
3573 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
3574 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
3575 filebuflen
= audiobufend
- filebuf
;
3577 /* Allow for codec swap space at end of audio buffer */
3578 if (talk_voice_required())
3580 /* Layout of swap buffer:
3581 * #ifdef IRAM_STEAL (dedicated iram_buf):
3582 * |iram_buf|...audiobuf...|dram_buf|audiobufend
3584 * audiobuf...|dram_buf|iram_buf|audiobufend
3586 #ifdef PLAYBACK_VOICE
3587 /* Check for an absolutely nasty situation which should never,
3588 ever happen - frankly should just panic */
3589 if (voice_codec_loaded
&& current_codec
!= CODEC_IDX_VOICE
)
3591 logf("buffer reset with voice swapped");
3593 /* line align length which line aligns the calculations below since
3594 all sizes are also at least line aligned - needed for memswap128 */
3597 filebuflen
-= CODEC_SIZE
;
3599 filebuflen
-= CODEC_SIZE
+ CODEC_IRAM_SIZE
;
3601 /* Allocate buffers for swapping voice <=> audio */
3602 /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
3603 and out of the way of buffer usage or else a call to audio_get_buffer
3604 and subsequent buffer use might trash the swap space. A plugin
3605 initializing IRAM after getting the full buffer would present similar
3606 problem. Options include: failing the request if the other buffer
3607 has been obtained already or never allowing use of the voice IRAM
3608 buffer within the audio buffer. Using buffer_alloc basically
3609 implements the second in a more convenient way. */
3610 dram_buf
= filebuf
+ filebuflen
;
3613 /* Allocate voice IRAM swap buffer once */
3614 if (iram_buf
== NULL
)
3616 iram_buf
= buffer_alloc(CODEC_IRAM_SIZE
);
3617 /* buffer_alloc moves audiobuf; this is safe because only the end
3618 * has been touched so far in this function and the address of
3619 * filebuf + filebuflen is not changed */
3620 malloc_buf
+= CODEC_IRAM_SIZE
;
3621 filebuf
+= CODEC_IRAM_SIZE
;
3622 filebuflen
-= CODEC_IRAM_SIZE
;
3625 /* Allocate iram_buf after dram_buf */
3626 iram_buf
= dram_buf
+ CODEC_SIZE
;
3627 #endif /* IRAM_STEAL */
3628 #endif /* PLAYBACK_VOICE */
3632 #ifdef PLAYBACK_VOICE
3633 /* No swap buffers needed */
3639 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
3640 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
3642 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
3643 will already be line aligned */
3646 /* Set the high watermark as 75% full...or 25% empty :) */
3648 high_watermark
= 3*filebuflen
/ 4;
3651 /* Clear any references to the file buffer */
3652 buffer_state
= BUFFER_STATE_INITIALIZED
;
3654 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
3655 /* Make sure everything adds up - yes, some info is a bit redundant but
3656 aids viewing and the sumation of certain variables should add up to
3657 the location of others. */
3660 unsigned char * pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
3661 logf("mabuf: %08X", (unsigned)malloc_buf
);
3662 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
3663 logf("fbuf: %08X", (unsigned)filebuf
);
3664 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
3665 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
3666 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
3667 logf("pcmb: %08X", (unsigned)pcmbuf
);
3668 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
3671 logf("dramb: %08X", (unsigned)dram_buf
);
3672 logf("drambe: %08X", (unsigned)(dram_buf
+ CODEC_SIZE
));
3676 logf("iramb: %08X", (unsigned)iram_buf
);
3677 logf("irambe: %08X", (unsigned)(iram_buf
+ CODEC_IRAM_SIZE
));
3684 /* we dont want this rebuffering on targets with little ram
3685 because the disk may never spin down */
3686 static bool ata_fillbuffer_callback(void)
3688 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
, 0);
3693 static void audio_thread(void)
3695 struct queue_event ev
;
3699 #ifdef PLAYBACK_VOICE
3700 /* Unlock semaphore that init stage locks before creating this thread */
3701 semaphore_release(&sem_codecthread
);
3703 /* Buffers must be set up by now - should panic - really */
3704 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
3706 logf("audio_thread start: no buffer");
3709 /* Have to wait for voice to load up or else the codec swap will be
3710 invalid when an audio codec is loaded */
3711 wait_for_voice_swap_in();
3718 queue_wait_w_tmo(&audio_queue
, &ev
, 0);
3719 if (ev
.id
== SYS_TIMEOUT
)
3720 ev
.id
= Q_AUDIO_FILL_BUFFER
;
3724 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
3726 if (playing
&& (ev
.id
== SYS_TIMEOUT
) &&
3727 (bufused() < high_watermark
))
3728 register_ata_idle_func(ata_fillbuffer_callback
);
3734 case Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
:
3735 /* only fill if the disk is still spining */
3737 if (!ata_disk_is_active())
3740 #endif /* MEM > 8 */
3741 /* else fall through to Q_AUDIO_FILL_BUFFER */
3742 case Q_AUDIO_FILL_BUFFER
:
3743 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3745 if (!playing
|| playlist_end
|| ci
.stop_codec
)
3747 audio_fill_file_buffer(false, false, 0);
3751 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3752 if (playing
&& ev
.data
<= 0)
3753 audio_new_playlist();
3756 audio_stop_playback();
3757 audio_play_start((size_t)ev
.data
);
3762 LOGFQUEUE("audio < Q_AUDIO_STOP");
3764 audio_stop_playback();
3766 queue_clear(&audio_queue
);
3770 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3771 if (!(bool) ev
.data
&& skipped_during_pause
&& !pcmbuf_is_crossfade_active())
3772 pcmbuf_play_stop(); /* Flush old track on resume after skip */
3773 skipped_during_pause
= false;
3776 pcmbuf_pause((bool)ev
.data
);
3777 paused
= (bool)ev
.data
;
3781 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3782 audio_initiate_track_change((long)ev
.data
);
3785 case Q_AUDIO_PRE_FF_REWIND
:
3786 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3792 case Q_AUDIO_FF_REWIND
:
3793 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3796 ci
.seek_time
= (long)ev
.data
+1;
3799 case Q_AUDIO_REBUFFER_SEEK
:
3800 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
3801 queue_reply(&audio_queue
, audio_rebuffer_and_seek(ev
.data
));
3804 case Q_AUDIO_CHECK_NEW_TRACK
:
3805 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3806 queue_reply(&audio_queue
, audio_check_new_track());
3809 case Q_AUDIO_DIR_SKIP
:
3810 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3811 playlist_end
= false;
3812 audio_initiate_dir_change(ev
.data
);
3816 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3817 audio_invalidate_tracks();
3820 case Q_AUDIO_TRACK_CHANGED
:
3821 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3822 if (track_changed_callback
)
3823 track_changed_callback(&curtrack_id3
);
3824 track_changed
= true;
3825 playlist_update_resume_info(audio_current_track());
3829 case SYS_USB_CONNECTED
:
3830 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3832 audio_stop_playback();
3833 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
3834 usb_wait_for_disconnect(&audio_queue
);
3839 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3843 //LOGFQUEUE("audio < default");
3849 #ifdef ROCKBOX_HAS_LOGF
3850 static void audio_test_track_changed_event(struct mp3entry
*id3
)
3854 logf("tce:%s", id3
->path
);
3858 /* Initialize the audio system - called from init() in main.c.
3859 * Last function because of all the references to internal symbols
3861 void audio_init(void)
3863 #ifdef PLAYBACK_VOICE
3864 static bool voicetagtrue
= true;
3865 static struct mp3entry id3_voice
;
3866 struct thread_entry
*voice_thread_p
= NULL
;
3868 struct thread_entry
*audio_thread_p
;
3870 /* Can never do this twice */
3871 if (audio_is_initialized
)
3873 logf("audio: already initialized");
3877 logf("audio: initializing");
3879 /* Initialize queues before giving control elsewhere in case it likes
3880 to send messages. Thread creation will be delayed however so nothing
3881 starts running until ready if something yields such as talk_init. */
3882 #ifdef PLAYBACK_VOICE
3883 /* Take ownership of lock to prevent playback of anything before audio
3884 hardware is initialized - audio thread unlocks it after final init
3886 semaphore_init(&sem_codecthread
, 1, 0);
3887 event_init(&event_codecthread
, EVENT_MANUAL
| STATE_SIGNALED
);
3889 queue_init(&audio_queue
, true);
3890 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
3891 queue_init(&codec_queue
, true);
3892 queue_enable_queue_send(&codec_queue
, &codec_queue_sender_list
);
3896 #ifdef ROCKBOX_HAS_LOGF
3897 audio_set_track_changed_event(audio_test_track_changed_event
);
3900 /* Initialize codec api. */
3901 ci
.read_filebuf
= codec_filebuf_callback
;
3902 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
3903 ci
.get_codec_memory
= codec_get_memory_callback
;
3904 ci
.request_buffer
= codec_request_buffer_callback
;
3905 ci
.advance_buffer
= codec_advance_buffer_callback
;
3906 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
3907 ci
.request_next_track
= codec_request_next_track_callback
;
3908 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
3909 ci
.seek_buffer
= codec_seek_buffer_callback
;
3910 ci
.seek_complete
= codec_seek_complete_callback
;
3911 ci
.set_elapsed
= codec_set_elapsed_callback
;
3912 ci
.set_offset
= codec_set_offset_callback
;
3913 ci
.configure
= codec_configure_callback
;
3914 ci
.discard_codec
= codec_discard_codec_callback
;
3916 /* Initialize voice codec api. */
3917 #ifdef PLAYBACK_VOICE
3918 memcpy(&ci_voice
, &ci
, sizeof(ci_voice
));
3919 memset(&id3_voice
, 0, sizeof(id3_voice
));
3920 ci_voice
.read_filebuf
= voice_filebuf_callback
;
3921 ci_voice
.pcmbuf_insert
= voice_pcmbuf_insert_callback
;
3922 ci_voice
.get_codec_memory
= voice_get_memory_callback
;
3923 ci_voice
.request_buffer
= voice_request_buffer_callback
;
3924 ci_voice
.advance_buffer
= voice_advance_buffer_callback
;
3925 ci_voice
.advance_buffer_loc
= voice_advance_buffer_loc_callback
;
3926 ci_voice
.request_next_track
= voice_request_next_track_callback
;
3927 ci_voice
.mp3_get_filepos
= voice_mp3_get_filepos_callback
;
3928 ci_voice
.seek_buffer
= voice_seek_buffer_callback
;
3929 ci_voice
.seek_complete
= voice_do_nothing
;
3930 ci_voice
.set_elapsed
= voice_set_elapsed_callback
;
3931 ci_voice
.set_offset
= voice_set_offset_callback
;
3932 ci_voice
.configure
= voice_configure_callback
;
3933 ci_voice
.discard_codec
= voice_do_nothing
;
3934 ci_voice
.taginfo_ready
= &voicetagtrue
;
3935 ci_voice
.id3
= &id3_voice
;
3936 id3_voice
.frequency
= 11200;
3937 id3_voice
.length
= 1000000L;
3940 /* initialize the buffer */
3943 /* audio_reset_buffer must to know the size of voice buffer so init
3947 codec_thread_p
= create_thread(
3948 codec_thread
, codec_stack
, sizeof(codec_stack
),
3949 CREATE_THREAD_FROZEN
,
3950 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
3953 audio_thread_p
= create_thread(audio_thread
, audio_stack
,
3954 sizeof(audio_stack
), CREATE_THREAD_FROZEN
,
3955 audio_thread_name
IF_PRIO(, PRIORITY_BACKGROUND
)
3958 buffering_thread_p
= create_thread( buffering_thread
, buffering_stack
,
3959 sizeof(buffering_stack
), CREATE_THREAD_FROZEN
,
3960 buffering_thread_name
IF_PRIO(, PRIORITY_BUFFERING
)
3961 IF_COP(, CPU
, true));
3963 #ifdef PLAYBACK_VOICE
3964 /* TODO: Change this around when various speech codecs can be used */
3965 if (talk_voice_required())
3967 logf("Starting voice codec");
3968 queue_init(&voice_queue
, true);
3969 voice_thread_p
= create_thread(voice_thread
, voice_stack
,
3970 sizeof(voice_stack
), CREATE_THREAD_FROZEN
,
3972 IF_PRIO(, PRIORITY_PLAYBACK
) IF_COP(, CPU
));
3976 /* Set crossfade setting for next buffer init which should be about... */
3977 pcmbuf_crossfade_enable(global_settings
.crossfade
);
3979 /* ...now! Set up the buffers */
3980 audio_reset_buffer();
3982 buffering_init(filebuf
, filebuflen
);
3984 /* Probably safe to say */
3985 audio_is_initialized
= true;
3987 sound_settings_apply();
3989 eq_hw_enable(global_settings
.eq_hw_enabled
);
3991 #ifndef HAVE_FLASH_STORAGE
3992 audio_set_buffer_margin(global_settings
.buffer_margin
);
3995 /* it's safe to let the threads run now */
3996 thread_thaw(codec_thread_p
);
3997 #ifdef PLAYBACK_VOICE
3999 thread_thaw(voice_thread_p
);
4001 thread_thaw(audio_thread_p
);
4002 thread_thaw(buffering_thread_p
);