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
)
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;
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);
1657 ci
.curpos
+= amount
;
1658 codec_set_offset_callback(ci
.curpos
);
1661 static void codec_advance_buffer_loc_callback(void *ptr
)
1663 size_t amount
= get_offset(CUR_TI
->audio_hid
, ptr
);
1665 codec_advance_buffer_callback(amount
);
1668 /* Copied from mpeg.c. Should be moved somewhere else. */
1669 static int codec_get_file_pos(void)
1672 struct mp3entry
*id3
= audio_current_track();
1678 /* Use the TOC to find the new position */
1679 unsigned int percent
, remainder
;
1680 int curtoc
, nexttoc
, plen
;
1682 percent
= (id3
->elapsed
*100)/id3
->length
;
1686 curtoc
= id3
->toc
[percent
];
1689 nexttoc
= id3
->toc
[percent
+1];
1693 pos
= (id3
->filesize
/256)*curtoc
;
1695 /* Use the remainder to get a more accurate position */
1696 remainder
= (id3
->elapsed
*100)%id3
->length
;
1697 remainder
= (remainder
*100)/id3
->length
;
1698 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1699 pos
+= (plen
/100)*remainder
;
1703 /* No TOC exists, estimate the new position */
1704 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1705 (id3
->elapsed
/ 1000);
1708 else if (id3
->bitrate
)
1709 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1713 pos
+= id3
->first_frame_offset
;
1715 /* Don't seek right to the end of the file so that we can
1716 transition properly to the next song */
1717 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1718 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1723 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1727 curtrack_id3
.elapsed
= newtime
;
1728 newpos
= codec_get_file_pos();
1733 static void codec_seek_complete_callback(void)
1735 logf("seek_complete");
1736 if (pcm_is_paused())
1738 /* If this is not a seamless seek, clear the buffer */
1740 dsp_configure(DSP_FLUSH
, 0);
1742 /* If playback was not 'deliberately' paused, unpause now */
1744 pcmbuf_pause(false);
1749 static bool codec_seek_buffer_callback(size_t newpos
)
1753 logf("codec_seek_buffer_callback");
1755 if (newpos
>= CUR_TI
->filesize
)
1756 newpos
= CUR_TI
->filesize
- 1;
1758 difference
= newpos
- ci
.curpos
;
1759 if (difference
>= 0)
1761 /* Seeking forward */
1762 logf("seek: +%d", difference
);
1763 codec_advance_buffer_callback(difference
);
1767 /* Seeking backward */
1768 difference
= -difference
;
1769 if (ci
.curpos
- difference
< 0)
1770 difference
= ci
.curpos
;
1773 /* We need to reload the song. */
1774 if (newpos
< CUR_TI
->start_pos
)
1776 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1780 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1781 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1787 case Q_CODEC_REQUEST_COMPLETE
:
1788 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1791 case Q_CODEC_REQUEST_FAILED
:
1792 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1793 ci
.stop_codec
= true;
1797 LOGFQUEUE("codec |< default");
1803 /* Seeking inside buffer space. */
1804 logf("seek: -%d", difference
);
1805 bufadvance(CUR_TI
->audio_hid
, -difference
);
1806 ci
.curpos
-= difference
;
1811 static void codec_configure_callback(int setting
, intptr_t value
)
1814 case CODEC_SET_FILEBUF_WATERMARK
:
1815 conf_watermark
= value
;
1816 set_filebuf_watermark(buffer_margin
);
1819 case CODEC_SET_FILEBUF_CHUNKSIZE
:
1820 conf_filechunk
= value
;
1823 case CODEC_SET_FILEBUF_PRESEEK
:
1824 conf_preseek
= value
;
1828 if (!dsp_configure(setting
, value
)) { logf("Illegal key:%d", setting
); }
1832 static void codec_track_changed(void)
1834 automatic_skip
= false;
1835 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1836 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1839 static void codec_pcmbuf_track_changed_callback(void)
1841 pcmbuf_set_position_callback(NULL
);
1842 codec_track_changed();
1845 static void codec_discard_codec_callback(void)
1847 if (CUR_TI
->codec_hid
> 0)
1849 bufclose(CUR_TI
->codec_hid
);
1850 CUR_TI
->codec_hid
= 0;
1854 /* Check if a buffer desync has happened, log it and stop playback. */
1855 if (buf_ridx
!= CUR_TI
->buf_idx
)
1857 int offset
= CUR_TI
->buf_idx
- buf_ridx
;
1858 size_t new_used
= bufused() - offset
;
1860 logf("Buf off :%d=%d-%d", offset
, CUR_TI
->buf_idx
, buf_ridx
);
1861 logf("Used off:%d",bufused() - new_used
);
1863 /* This is a fatal internal error and it's not safe to
1864 * continue playback. */
1865 ci
.stop_codec
= true;
1866 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1871 static inline void codec_gapless_track_change(void) {
1872 /* callback keeps the progress bar moving while the pcmbuf empties */
1873 /* pcmbuf_set_position_callback(codec_pcmbuf_position_callback); */
1874 /* set the pcmbuf callback for when the track really changes */
1875 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1878 static inline void codec_crossfade_track_change(void) {
1879 /* Initiate automatic crossfade mode */
1880 pcmbuf_crossfade_init(false);
1881 /* Notify the wps that the track change starts now */
1882 codec_track_changed();
1885 static void codec_track_skip_done(bool was_manual
)
1887 int crossfade_mode
= global_settings
.crossfade
;
1889 /* Manual track change (always crossfade or flush audio). */
1892 pcmbuf_crossfade_init(true);
1893 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1894 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1896 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1897 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1898 && crossfade_mode
!= CROSSFADE_ENABLE_TRACKSKIP
)
1900 if (crossfade_mode
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1902 if (global_settings
.playlist_shuffle
)
1903 /* shuffle mode is on, so crossfade: */
1904 codec_crossfade_track_change();
1906 /* shuffle mode is off, so do a gapless track change */
1907 codec_gapless_track_change();
1910 /* normal crossfade: */
1911 codec_crossfade_track_change();
1914 /* normal gapless playback. */
1915 codec_gapless_track_change();
1918 static bool codec_load_next_track(void)
1920 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1922 prev_track_elapsed
= curtrack_id3
.elapsed
;
1925 codec_seek_complete_callback();
1927 #ifdef AB_REPEAT_ENABLE
1928 ab_end_of_track_report();
1931 logf("Request new track");
1933 if (ci
.new_track
== 0)
1936 automatic_skip
= true;
1941 trigger_cpu_boost();
1942 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1943 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1948 case Q_CODEC_REQUEST_COMPLETE
:
1949 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1950 codec_track_skip_done(!automatic_skip
);
1953 case Q_CODEC_REQUEST_FAILED
:
1954 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1956 ci
.stop_codec
= true;
1960 LOGFQUEUE("codec |< default");
1961 ci
.stop_codec
= true;
1966 static bool codec_request_next_track_callback(void)
1970 if (ci
.stop_codec
|| !playing
)
1973 prev_codectype
= get_codec_base_type(curtrack_id3
.codectype
);
1975 if (!codec_load_next_track())
1978 /* Check if the next codec is the same file. */
1979 if (prev_codectype
== get_codec_base_type(curtrack_id3
.codectype
))
1981 logf("New track loaded");
1982 codec_discard_codec_callback();
1987 logf("New codec:%d/%d", curtrack_id3
.codectype
, prev_codectype
);
1992 static void codec_thread(void)
1994 struct queue_event ev
;
2000 queue_wait(&codec_queue
, &ev
);
2003 case Q_CODEC_LOAD_DISK
:
2004 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
2005 queue_reply(&codec_queue
, 1);
2006 audio_codec_loaded
= true;
2007 #ifdef PLAYBACK_VOICE
2008 /* Don't sent messages to voice codec if it's already swapped
2009 out or it will never get this */
2010 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2012 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
2013 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
2015 semaphore_wait(&sem_codecthread
);
2016 event_set_state(&event_codecthread
, true);
2018 set_current_codec(CODEC_IDX_AUDIO
);
2019 ci
.stop_codec
= false;
2020 status
= codec_load_file((const char *)ev
.data
, &ci
);
2021 DEBUGF("codec_load = %d\n", status
);
2022 #ifdef PLAYBACK_VOICE
2023 semaphore_release(&sem_codecthread
);
2028 LOGFQUEUE("codec < Q_CODEC_LOAD");
2029 if (CUR_TI
->codec_hid
<= 0) {
2030 logf("Codec slot is empty!");
2031 /* Wait for the pcm buffer to go empty */
2032 while (pcm_is_playing())
2034 /* This must be set to prevent an infinite loop */
2035 ci
.stop_codec
= true;
2036 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
2037 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
2041 audio_codec_loaded
= true;
2042 #ifdef PLAYBACK_VOICE
2043 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2045 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
2046 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
2048 semaphore_wait(&sem_codecthread
);
2049 event_set_state(&event_codecthread
, true);
2051 set_current_codec(CODEC_IDX_AUDIO
);
2052 ci
.stop_codec
= false;
2053 wrap
= (size_t)&filebuf
[filebuflen
] - (size_t)getptr(CUR_TI
->codec_hid
);
2054 status
= codec_load_ram(getptr(CUR_TI
->codec_hid
), CUR_TI
->codecsize
,
2055 &filebuf
[0], wrap
, &ci
);
2056 #ifdef PLAYBACK_VOICE
2057 semaphore_release(&sem_codecthread
);
2061 #ifdef AUDIO_HAVE_RECORDING
2062 case Q_ENCODER_LOAD_DISK
:
2063 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2064 audio_codec_loaded
= false; /* Not audio codec! */
2065 #ifdef PLAYBACK_VOICE
2066 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2068 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
2069 queue_post(&voice_queue
, Q_ENCODER_RECORD
, 0);
2071 semaphore_wait(&sem_codecthread
);
2072 event_set_state(&event_codecthread
, true);
2074 logf("loading encoder");
2075 set_current_codec(CODEC_IDX_AUDIO
);
2076 ci
.stop_encoder
= false;
2077 status
= codec_load_file((const char *)ev
.data
, &ci
);
2078 #ifdef PLAYBACK_VOICE
2079 semaphore_release(&sem_codecthread
);
2081 logf("encoder stopped");
2083 #endif /* AUDIO_HAVE_RECORDING */
2086 case SYS_USB_CONNECTED
:
2087 LOGFQUEUE("codec < SYS_USB_CONNECTED");
2088 queue_clear(&codec_queue
);
2089 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
2090 usb_wait_for_disconnect(&codec_queue
);
2095 LOGFQUEUE("codec < default");
2098 if (audio_codec_loaded
)
2107 audio_codec_loaded
= false;
2111 case Q_CODEC_LOAD_DISK
:
2113 LOGFQUEUE("codec < Q_CODEC_LOAD");
2116 if (ci
.new_track
|| status
!= CODEC_OK
)
2120 logf("Codec failure");
2121 gui_syncsplash(HZ
*2, "Codec failure");
2124 if (!codec_load_next_track())
2126 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2127 /* End of playlist */
2128 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2134 logf("Codec finished");
2137 /* Wait for the audio to stop playing before
2138 * triggering the WPS exit */
2139 while(pcm_is_playing())
2141 curtrack_id3
.elapsed
=
2142 curtrack_id3
.length
- pcmbuf_get_latency();
2145 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2146 /* End of playlist */
2147 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2152 if (CUR_TI
->codec_hid
> 0)
2154 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2155 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
2159 const char *codec_fn
=
2160 get_codec_filename(curtrack_id3
.codectype
);
2161 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2162 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
2163 (intptr_t)codec_fn
);
2168 #ifdef AUDIO_HAVE_RECORDING
2169 case Q_ENCODER_LOAD_DISK
:
2170 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2172 if (status
== CODEC_OK
)
2175 logf("Encoder failure");
2176 gui_syncsplash(HZ
*2, "Encoder failure");
2178 if (ci
.enc_codec_loaded
< 0)
2181 logf("Encoder failed to load");
2182 ci
.enc_codec_loaded
= -1;
2184 #endif /* AUDIO_HAVE_RECORDING */
2187 LOGFQUEUE("codec < default");
2194 /* --- Audio thread --- */
2196 static bool audio_filebuf_is_lowdata(void)
2198 return bufused() < AUDIO_FILEBUF_CRITICAL
;
2201 static bool audio_have_tracks(void)
2203 return track_ridx
!= track_widx
|| CUR_TI
->filesize
;
2206 static bool audio_have_free_tracks(void)
2208 if (track_widx
< track_ridx
)
2209 return track_widx
+ 1 < track_ridx
;
2210 else if (track_ridx
== 0)
2211 return track_widx
< MAX_TRACK
- 1;
2216 int audio_track_count(void)
2218 if (audio_have_tracks())
2220 int relative_track_widx
= track_widx
;
2222 if (track_ridx
> track_widx
)
2223 relative_track_widx
+= MAX_TRACK
;
2225 return relative_track_widx
- track_ridx
+ 1;
2231 long audio_filebufused(void)
2233 return (long) bufused();
2236 /* Count the data BETWEEN the selected tracks */
2237 static size_t audio_buffer_count_tracks(int from_track
, int to_track
)
2240 bool need_wrap
= to_track
< from_track
;
2244 if (++from_track
>= MAX_TRACK
)
2246 from_track
-= MAX_TRACK
;
2250 if (from_track
>= to_track
&& !need_wrap
)
2253 amount
+= tracks
[from_track
].codecsize
+ tracks
[from_track
].filesize
;
2258 static bool audio_buffer_wind_forward(int new_track_ridx
, int old_track_ridx
)
2260 (void)new_track_ridx
;
2261 (void)old_track_ridx
;
2265 /* Start with the remainder of the previously playing track */
2266 amount
= tracks
[old_track_ridx
].filesize
- ci
.curpos
;
2267 /* Then collect all data from tracks in between them */
2268 amount
+= audio_buffer_count_tracks(old_track_ridx
, new_track_ridx
);
2269 logf("bwf:%ldB", (long) amount
);
2271 if (amount
> bufused())
2274 /* Wind the buffer to the beginning of the target track or its codec */
2275 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
2280 static bool audio_buffer_wind_backward(int new_track_ridx
, int old_track_ridx
)
2282 (void)new_track_ridx
;
2283 (void)old_track_ridx
;
2285 /* Available buffer data */
2287 /* Start with the previously playing track's data and our data */
2291 buf_back
= RINGBUF_SUB(buf_ridx
, buf_widx
);
2293 /* If we're not just resetting the current track */
2294 if (new_track_ridx
!= old_track_ridx
)
2296 /* Need to wind to before the old track's codec and our filesize */
2297 amount
+= tracks
[old_track_ridx
].codecsize
;
2298 amount
+= tracks
[new_track_ridx
].filesize
;
2300 /* Rewind the old track to its beginning */
2301 tracks
[old_track_ridx
].available
=
2302 tracks
[old_track_ridx
].filesize
- tracks
[old_track_ridx
].filerem
;
2305 /* If the codec was ever buffered */
2306 if (tracks
[new_track_ridx
].codecsize
)
2308 /* Add the codec to the needed size */
2309 amount
+= tracks
[new_track_ridx
].codecsize
;
2310 tracks
[new_track_ridx
].has_codec
= true;
2313 /* Then collect all data from tracks between new and old */
2314 amount
+= audio_buffer_count_tracks(new_track_ridx
, old_track_ridx
);
2316 /* Do we have space to make this skip? */
2317 if (amount
> buf_back
)
2320 logf("bwb:%ldB",amount
);
2322 /* Rewind the buffer to the beginning of the target track or its codec */
2323 buf_ridx
= RINGBUF_SUB(buf_ridx
, amount
);
2325 /* Reset to the beginning of the new track */
2326 tracks
[new_track_ridx
].available
= tracks
[new_track_ridx
].filesize
;
2331 static void audio_update_trackinfo(void)
2333 ci
.filesize
= CUR_TI
->filesize
;
2334 curtrack_id3
.elapsed
= 0;
2335 curtrack_id3
.offset
= 0;
2336 ci
.id3
= &curtrack_id3
;
2338 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2341 /* Yield to codecs for as long as possible if they are in need of data
2342 * return true if the caller should break to let the audio thread process
2344 static bool audio_yield_codecs(void)
2348 if (!queue_empty(&audio_queue
))
2351 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
2352 && !ci
.stop_codec
&& playing
&& !audio_filebuf_is_lowdata())
2359 if (!queue_empty(&audio_queue
))
2366 static void audio_clear_track_entries(bool clear_unbuffered
)
2368 int cur_idx
= track_widx
;
2371 logf("Clearing tracks:%d/%d, %d", track_ridx
, track_widx
, clear_unbuffered
);
2373 /* Loop over all tracks from write-to-read */
2377 cur_idx
&= MAX_TRACK_MASK
;
2379 if (cur_idx
== track_ridx
)
2382 /* If the track is buffered, conditionally clear/notify,
2383 * otherwise clear the track if that option is selected */
2384 if (tracks
[cur_idx
].event_sent
)
2388 /* If there is an unbuffer callback, call it, otherwise,
2389 * just clear the track */
2390 if (track_unbuffer_callback
)
2391 track_unbuffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), false);
2393 close_track_handles(&tracks
[last_idx
]);
2394 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2398 else if (clear_unbuffered
)
2400 close_track_handles(&tracks
[cur_idx
]);
2401 memset(&tracks
[cur_idx
], 0, sizeof(struct track_info
));
2405 /* We clear the previous instance of a buffered track throughout
2406 * the above loop to facilitate 'last' detection. Clear/notify
2407 * the last track here */
2410 if (track_unbuffer_callback
)
2411 track_unbuffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), true);
2412 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2416 static void audio_release_tracks(void)
2418 int cur_idx
= track_ridx
;
2420 logf("releasing all tracks");
2424 close_track_handles(&tracks
[cur_idx
]);
2427 cur_idx
&= MAX_TRACK_MASK
;
2429 if (cur_idx
== track_widx
)
2434 /* FIXME: This code should be made more generic and move to metadata.c */
2435 static void audio_strip_tags(void)
2439 static const unsigned char tag
[] = "TAG";
2440 static const unsigned char apetag
[] = "APETAGEX";
2443 size_t len
, version
;
2445 tag_idx
= RINGBUF_SUB(buf_widx
, 128);
2447 if (bufused() > 128 && tag_idx
> buf_ridx
)
2450 for(i
= 0;i
< 3;i
++)
2452 if(filebuf
[cur_idx
] != tag
[i
])
2455 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2458 /* Skip id3v1 tag */
2459 logf("Skipping ID3v1 tag");
2461 tracks
[track_widx
].available
-= 128;
2462 tracks
[track_widx
].filesize
-= 128;
2466 /* Check for APE tag (look for the APE tag footer) */
2467 tag_idx
= RINGBUF_SUB(buf_widx
, 32);
2469 if (bufused() > 32 && tag_idx
> buf_ridx
)
2472 for(i
= 0;i
< 8;i
++)
2474 if(filebuf
[cur_idx
] != apetag
[i
])
2477 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2480 /* Read the version and length from the footer */
2481 version
= filebuf
[tag_idx
+8] | (filebuf
[tag_idx
+9] << 8) |
2482 (filebuf
[tag_idx
+10] << 16) | (filebuf
[tag_idx
+11] << 24);
2483 len
= filebuf
[tag_idx
+12] | (filebuf
[tag_idx
+13] << 8) |
2484 (filebuf
[tag_idx
+14] << 16) | (filebuf
[tag_idx
+15] << 24);
2485 if (version
== 2000)
2486 len
+= 32; /* APEv2 has a 32 byte header */
2489 if (bufused() > len
)
2491 logf("Skipping APE tag (%ldB)", len
);
2492 buf_widx
= RINGBUF_SUB(buf_widx
, len
);
2493 tracks
[track_widx
].available
-= len
;
2494 tracks
[track_widx
].filesize
-= len
;
2501 /* Returns true if a whole file is read, false otherwise */
2502 static bool audio_read_file(size_t minimum
)
2504 bool ret_val
= false;
2506 /* If we're called and no file is open, this is an error */
2509 logf("Bad fd in arf");
2510 /* Give some hope of miraculous recovery by forcing a track reload */
2511 tracks
[track_widx
].filesize
= 0;
2512 /* Stop this buffering run */
2516 trigger_cpu_boost();
2517 while (tracks
[track_widx
].filerem
> 0)
2523 /* copy_n is the largest chunk that is safe to read */
2524 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2526 /* buf_widx == buf_ridx is defined as buffer empty, not buffer full */
2527 if (RINGBUF_ADD_CROSS(buf_widx
,copy_n
,buf_ridx
) >= 0)
2530 /* rc is the actual amount read */
2531 rc
= read(current_fd
, &filebuf
[buf_widx
], copy_n
);
2535 logf("File ended %ldB early", tracks
[track_widx
].filerem
);
2536 tracks
[track_widx
].filesize
-= tracks
[track_widx
].filerem
;
2537 tracks
[track_widx
].filerem
= 0;
2541 /* How much of the playing track did we overwrite */
2542 if (buf_widx
== CUR_TI
->buf_idx
)
2544 /* Special handling; zero or full overlap? */
2545 if (track_widx
== track_ridx
&& CUR_TI
->available
== 0)
2551 overlap
= RINGBUF_ADD_CROSS(buf_widx
,rc
,CUR_TI
->buf_idx
);
2553 if ((unsigned)rc
> tracks
[track_widx
].filerem
)
2555 logf("Bad: rc-filerem=%ld, fixing", rc
-tracks
[track_widx
].filerem
);
2556 tracks
[track_widx
].filesize
+= rc
- tracks
[track_widx
].filerem
;
2557 tracks
[track_widx
].filerem
= rc
;
2560 /* Advance buffer */
2561 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2562 tracks
[track_widx
].available
+= rc
;
2563 tracks
[track_widx
].filerem
-= rc
;
2565 /* If we write into the playing track, adjust it's buffer info */
2568 CUR_TI
->buf_idx
+= overlap
;
2569 CUR_TI
->start_pos
+= overlap
;
2572 /* For a rebuffer, fill at least this minimum */
2573 if (minimum
> (unsigned)rc
)
2575 /* Let the codec process up to the watermark */
2576 /* Break immediately if this is a quick buffer, or there is an event */
2577 else if (minimum
|| audio_yield_codecs())
2579 /* Exit quickly, but don't stop the overall buffering process */
2585 if (tracks
[track_widx
].filerem
== 0)
2587 logf("Finished buf:%ldB", tracks
[track_widx
].filesize
);
2593 track_widx
&= MAX_TRACK_MASK
;
2595 tracks
[track_widx
].filesize
= 0;
2600 logf("%s buf:%ldB", ret_val
?"Quick":"Partially",
2601 tracks
[track_widx
].filesize
- tracks
[track_widx
].filerem
);
2607 static bool audio_loadcodec(bool start_play
)
2612 char codec_path
[MAX_PATH
]; /* Full path to codec */
2614 DEBUGF("audio_loadcodec(start_play = %s)\n", start_play
? "true" : "false");
2616 if (tracks
[track_widx
].id3_hid
<= 0) {
2617 DEBUGF("track ID3 info not ready\n");
2621 const char * codec_fn
=
2622 get_codec_filename(bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
);
2623 if (codec_fn
== NULL
)
2626 tracks
[track_widx
].codec_hid
= 0;
2630 /* Load the codec directly from disk and save some memory. */
2631 track_ridx
= track_widx
;
2632 ci
.filesize
= CUR_TI
->filesize
;
2633 ci
.id3
= &curtrack_id3
;
2634 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2636 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2637 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
2642 /* If we already have another track than this one buffered */
2643 if (track_widx
!= track_ridx
)
2645 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
2647 /* If the previous codec is the same as this one, there is no need
2648 * to put another copy of it on the file buffer */
2649 if (get_codec_base_type(
2650 bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
) ==
2651 get_codec_base_type(
2652 bufgetid3(tracks
[prev_track
].id3_hid
)->codectype
)
2653 && audio_codec_loaded
)
2655 logf("Reusing prev. codec");
2661 codec_get_full_path(codec_path
, codec_fn
);
2663 fd
= open(codec_path
, O_RDONLY
);
2666 logf("Codec doesn't exist!");
2670 tracks
[track_widx
].codecsize
= filesize(fd
);
2672 tracks
[track_widx
].codec_hid
= bufopen(codec_path
, 0, TYPE_CODEC
);
2673 if (tracks
[track_widx
].codec_hid
< 0)
2675 logf("Not enough space");
2681 logf("Done: %ldB", (long)size
);
2686 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2687 static void audio_set_elapsed(struct mp3entry
* id3
)
2689 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
2690 id3
->offset
- id3
->first_frame_offset
: 0;
2693 if ( id3
->has_toc
) {
2694 /* calculate elapsed time using TOC */
2696 unsigned int remainder
, plen
, relpos
, nextpos
;
2698 /* find wich percent we're at */
2699 for (i
=0; i
<100; i
++ )
2700 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
2707 relpos
= id3
->toc
[i
];
2710 nextpos
= id3
->toc
[i
+1];
2714 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
2716 /* set time for this percent (divide before multiply to prevent
2717 overflow on long files. loss of precision is negligible on
2719 id3
->elapsed
= i
* (id3
->length
/ 100);
2721 /* calculate remainder time */
2722 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
2723 id3
->elapsed
+= (((remainder
* 100) / plen
) *
2724 (id3
->length
/ 10000));
2727 /* no TOC exists. set a rough estimate using average bitrate */
2728 int tpk
= id3
->length
/
2729 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
2731 id3
->elapsed
= offset
/ 1024 * tpk
;
2736 /* constant bitrate, use exact calculation */
2737 if (id3
->bitrate
!= 0)
2738 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
2742 /* Load one track by making the appropriate bufopen calls. Return true if
2743 everything required was loaded correctly, false if not. */
2744 static bool audio_load_track(int offset
, bool start_play
, bool rebuffer
)
2750 struct mp3entry id3
;
2752 /* Stop buffer filling if there is no free track entries.
2753 Don't fill up the last track entry (we wan't to store next track
2755 if (!audio_have_free_tracks())
2757 logf("No free tracks");
2763 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
2764 /* Get track name from current playlist read position. */
2765 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
2767 /* Handle broken playlists. */
2768 fd
= open(trackname
, O_RDONLY
);
2771 logf("Open failed");
2772 /* Skip invalid entry from playlist. */
2773 playlist_skip_entry(NULL
, last_peek_offset
);
2781 logf("End-of-playlist");
2782 playlist_end
= true;
2786 tracks
[track_widx
].filesize
= filesize(fd
);
2788 /* Get track metadata if we don't already have it. */
2789 if (tracks
[track_widx
].id3_hid
<= 0)
2791 if (get_metadata(&id3
, fd
, trackname
))
2793 tracks
[track_widx
].id3_hid
= bufalloc(&id3
, sizeof(struct mp3entry
),
2795 tracks
[track_widx
].taginfo_ready
= (tracks
[track_widx
].id3_hid
> 0);
2797 if (track_widx
== track_ridx
)
2798 copy_mp3entry(&curtrack_id3
, &id3
);
2799 else if (track_widx
== (track_ridx
+ 1) & MAX_TRACK_MASK
)
2800 copy_mp3entry(&nexttrack_id3
, &id3
);
2802 if (tracks
[track_widx
].id3_hid
<= 0)
2804 DEBUGF("failed to allocate space for metadata\n");
2810 track_changed
= true;
2811 playlist_update_resume_info(audio_current_track());
2816 logf("mde:%s!",trackname
);
2818 /* Skip invalid entry from playlist. */
2819 playlist_skip_entry(NULL
, last_peek_offset
);
2820 tracks
[track_widx
].taginfo_ready
= false;
2828 /* Set default values */
2831 int last_codec
= current_codec
;
2833 set_current_codec(CODEC_IDX_AUDIO
);
2834 conf_watermark
= AUDIO_DEFAULT_WATERMARK
;
2835 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
2836 conf_preseek
= AUDIO_REBUFFER_GUESS_SIZE
;
2837 dsp_configure(DSP_RESET
, 0);
2838 set_current_codec(last_codec
);
2840 track_changed
= true;
2841 playlist_update_resume_info(audio_current_track());
2845 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
2847 char cuepath
[MAX_PATH
];
2849 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
2851 if (look_for_cuesheet_file(trackname
, cuepath
) &&
2852 parse_cuesheet(cuepath
, cue
))
2854 strcpy((cue
)->audio_filename
, trackname
);
2856 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
2861 /* Load the codec. */
2862 if (!audio_loadcodec(start_play
))
2865 /* Set filesize to zero to indicate no file was loaded. */
2866 /* tracks[track_widx].filesize = 0;
2867 tracks[track_widx].filerem = 0;
2871 if (tracks
[track_widx
].codecsize
)
2873 /* No space for codec on buffer, not an error */
2874 tracks
[track_widx
].codecsize
= 0;
2878 /* This is an error condition, either no codec was found, or reading
2879 * the codec file failed part way through, either way, skip the track */
2880 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
2881 /* We should not use gui_syncplash from audio thread! */
2882 gui_syncsplash(HZ
*2, msgbuf
);
2883 /* Skip invalid entry from playlist. */
2884 playlist_skip_entry(NULL
, last_peek_offset
);
2885 tracks
[track_widx
].taginfo_ready
= false;
2891 struct mp3entry
*track_id3
= bufgetid3(tracks
[track_widx
].id3_hid
);
2893 /* tracks[track_widx].start_pos = 0; */
2894 set_filebuf_watermark(buffer_margin
);
2895 track_id3
->elapsed
= 0;
2900 switch (id3
.codectype
) {
2904 track_id3
->offset
= offset
;
2905 audio_set_elapsed(&id3
);
2910 track_id3
->offset
= offset
;
2911 track_id3
->elapsed
= id3
.length
/ 2;
2915 case AFMT_OGG_VORBIS
:
2923 track_id3
->offset
= offset
;
2928 logf("alt:%s", trackname
);
2929 /* tracks[track_widx].buf_idx = buf_widx; */
2931 //return audio_read_file(rebuffer);
2933 tracks
[track_widx
].audio_hid
= bufopen(trackname
, offset
, TYPE_AUDIO
);
2935 if (tracks
[track_widx
].audio_hid
<= 0)
2940 LOGFQUEUE("audio >| buffering Q_BUFFER_HANDLE");
2941 queue_send(&buffering_queue
, Q_BUFFER_HANDLE
, tracks
[track_widx
].audio_hid
);
2945 LOGFQUEUE("audio > buffering Q_BUFFER_HANDLE");
2946 queue_post(&buffering_queue
, Q_BUFFER_HANDLE
, tracks
[track_widx
].audio_hid
);
2950 track_widx
&= MAX_TRACK_MASK
;
2955 static bool audio_read_next_metadata(void)
2962 next_idx
= track_widx
;
2963 if (tracks
[next_idx
].id3_hid
> 0)
2966 next_idx
&= MAX_TRACK_MASK
;
2968 if (tracks
[next_idx
].id3_hid
> 0)
2972 trackname
= playlist_peek(last_peek_offset
+ 1);
2976 fd
= open(trackname
, O_RDONLY
);
2980 struct mp3entry id3
;
2982 status
= get_metadata(&id3
, fd
, trackname
);
2983 /* Preload the glyphs in the tags */
2986 tracks
[next_idx
].id3_hid
= bufalloc(&id3
, sizeof(struct mp3entry
), TYPE_ID3
);
2988 if (tracks
[next_idx
].id3_hid
> 0)
2990 tracks
[next_idx
].taginfo_ready
= true;
2992 lcd_getstringsize(id3
.title
, NULL
, NULL
);
2994 lcd_getstringsize(id3
.artist
, NULL
, NULL
);
2996 lcd_getstringsize(id3
.album
, NULL
, NULL
);
3006 /* Send callback events to notify about new tracks. */
3007 static void audio_generate_postbuffer_events(void)
3012 logf("Postbuffer:%d/%d",track_ridx
,track_widx
);
3014 if (audio_have_tracks())
3016 cur_idx
= track_ridx
;
3019 if (!tracks
[cur_idx
].event_sent
)
3021 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
3023 /* Mark the event 'sent' even if we don't really send one */
3024 tracks
[last_idx
].event_sent
= true;
3025 if (track_buffer_callback
)
3026 track_buffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), false);
3030 if (cur_idx
== track_widx
)
3033 cur_idx
&= MAX_TRACK_MASK
;
3036 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
3038 tracks
[last_idx
].event_sent
= true;
3039 if (track_buffer_callback
)
3040 track_buffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), true);
3045 static bool audio_initialize_buffer_fill(bool clear_tracks
)
3047 /* Don't initialize if we're already initialized */
3051 logf("Starting buffer fill");
3053 /* Set the filling flag true before calling audio_clear_tracks as that
3054 * function can yield and we start looping. */
3058 audio_clear_track_entries(false);
3060 /* Save the current resume position once. */
3061 playlist_update_resume_info(audio_current_track());
3066 static void audio_fill_file_buffer(
3067 bool start_play
, bool rebuffer
, size_t offset
)
3069 bool had_next_track
= audio_next_track() != NULL
;
3070 bool continue_buffering
;
3072 /* Must reset the buffer before use if trashed or voice only - voice
3073 file size shouldn't have changed so we can go straight from
3074 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
3075 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
3076 audio_reset_buffer();
3078 if (!audio_initialize_buffer_fill(!start_play
))
3081 continue_buffering
= audio_load_track(offset
, start_play
, rebuffer
);
3083 if (!had_next_track
&& audio_next_track())
3084 track_changed
= true;
3086 /* If we're done buffering */
3087 if (!continue_buffering
)
3089 audio_read_next_metadata();
3091 audio_generate_postbuffer_events();
3100 static void audio_rebuffer(void)
3102 logf("Forcing rebuffer");
3105 /* Stop in progress fill, and clear open file descriptor */
3106 if (current_fd
>= 0)
3113 /* Reset buffer and track pointers */
3114 CUR_TI
->buf_idx
= buf_ridx
= buf_widx
= 0;
3115 track_widx
= track_ridx
;
3116 audio_clear_track_entries(true);
3117 CUR_TI
->available
= 0;
3119 /* Fill the buffer */
3120 last_peek_offset
= -1;
3121 CUR_TI
->filesize
= 0;
3122 CUR_TI
->start_pos
= 0;
3125 if (!CUR_TI
->taginfo_ready
)
3126 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
3128 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 close_track_handles(&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
;
3287 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
);
3346 DEBUGF("/!\\ not implemented /!\\");
3347 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3348 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 /* Mark all entries null. */
3428 audio_clear_track_entries(false);
3430 /* Close all tracks */
3431 audio_release_tracks();
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;
3786 case Q_AUDIO_REBUFFER_SEEK
:
3787 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
3788 queue_reply(&audio_queue
, audio_rebuffer_and_seek(ev
.data
));
3791 case Q_AUDIO_CHECK_NEW_TRACK
:
3792 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3793 queue_reply(&audio_queue
, audio_check_new_track());
3796 case Q_AUDIO_DIR_SKIP
:
3797 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3798 playlist_end
= false;
3799 audio_initiate_dir_change(ev
.data
);
3803 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3804 audio_invalidate_tracks();
3807 case Q_AUDIO_TRACK_CHANGED
:
3808 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3809 if (track_changed_callback
)
3810 track_changed_callback(&curtrack_id3
);
3811 track_changed
= true;
3812 playlist_update_resume_info(audio_current_track());
3816 case SYS_USB_CONNECTED
:
3817 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3819 audio_stop_playback();
3820 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
3821 usb_wait_for_disconnect(&audio_queue
);
3826 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3830 //LOGFQUEUE("audio < default");
3836 #ifdef ROCKBOX_HAS_LOGF
3837 static void audio_test_track_changed_event(struct mp3entry
*id3
)
3841 logf("tce:%s", id3
->path
);
3845 /* Initialize the audio system - called from init() in main.c.
3846 * Last function because of all the references to internal symbols
3848 void audio_init(void)
3850 #ifdef PLAYBACK_VOICE
3851 static bool voicetagtrue
= true;
3852 static struct mp3entry id3_voice
;
3853 struct thread_entry
*voice_thread_p
= NULL
;
3855 struct thread_entry
*audio_thread_p
;
3857 /* Can never do this twice */
3858 if (audio_is_initialized
)
3860 logf("audio: already initialized");
3864 logf("audio: initializing");
3866 /* Initialize queues before giving control elsewhere in case it likes
3867 to send messages. Thread creation will be delayed however so nothing
3868 starts running until ready if something yields such as talk_init. */
3869 #ifdef PLAYBACK_VOICE
3870 /* Take ownership of lock to prevent playback of anything before audio
3871 hardware is initialized - audio thread unlocks it after final init
3873 semaphore_init(&sem_codecthread
, 1, 0);
3874 event_init(&event_codecthread
, EVENT_MANUAL
| STATE_SIGNALED
);
3876 queue_init(&audio_queue
, true);
3877 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
3878 queue_init(&codec_queue
, true);
3879 queue_enable_queue_send(&codec_queue
, &codec_queue_sender_list
);
3883 #ifdef ROCKBOX_HAS_LOGF
3884 audio_set_track_changed_event(audio_test_track_changed_event
);
3887 /* Initialize codec api. */
3888 ci
.read_filebuf
= codec_filebuf_callback
;
3889 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
3890 ci
.get_codec_memory
= codec_get_memory_callback
;
3891 ci
.request_buffer
= codec_request_buffer_callback
;
3892 ci
.advance_buffer
= codec_advance_buffer_callback
;
3893 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
3894 ci
.request_next_track
= codec_request_next_track_callback
;
3895 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
3896 ci
.seek_buffer
= codec_seek_buffer_callback
;
3897 ci
.seek_complete
= codec_seek_complete_callback
;
3898 ci
.set_elapsed
= codec_set_elapsed_callback
;
3899 ci
.set_offset
= codec_set_offset_callback
;
3900 ci
.configure
= codec_configure_callback
;
3901 ci
.discard_codec
= codec_discard_codec_callback
;
3903 /* Initialize voice codec api. */
3904 #ifdef PLAYBACK_VOICE
3905 memcpy(&ci_voice
, &ci
, sizeof(ci_voice
));
3906 memset(&id3_voice
, 0, sizeof(id3_voice
));
3907 ci_voice
.read_filebuf
= voice_filebuf_callback
;
3908 ci_voice
.pcmbuf_insert
= voice_pcmbuf_insert_callback
;
3909 ci_voice
.get_codec_memory
= voice_get_memory_callback
;
3910 ci_voice
.request_buffer
= voice_request_buffer_callback
;
3911 ci_voice
.advance_buffer
= voice_advance_buffer_callback
;
3912 ci_voice
.advance_buffer_loc
= voice_advance_buffer_loc_callback
;
3913 ci_voice
.request_next_track
= voice_request_next_track_callback
;
3914 ci_voice
.mp3_get_filepos
= voice_mp3_get_filepos_callback
;
3915 ci_voice
.seek_buffer
= voice_seek_buffer_callback
;
3916 ci_voice
.seek_complete
= voice_do_nothing
;
3917 ci_voice
.set_elapsed
= voice_set_elapsed_callback
;
3918 ci_voice
.set_offset
= voice_set_offset_callback
;
3919 ci_voice
.configure
= voice_configure_callback
;
3920 ci_voice
.discard_codec
= voice_do_nothing
;
3921 ci_voice
.taginfo_ready
= &voicetagtrue
;
3922 ci_voice
.id3
= &id3_voice
;
3923 id3_voice
.frequency
= 11200;
3924 id3_voice
.length
= 1000000L;
3927 /* initialize the buffer */
3930 /* audio_reset_buffer must to know the size of voice buffer so init
3934 codec_thread_p
= create_thread(
3935 codec_thread
, codec_stack
, sizeof(codec_stack
),
3936 CREATE_THREAD_FROZEN
,
3937 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
3940 audio_thread_p
= create_thread(audio_thread
, audio_stack
,
3941 sizeof(audio_stack
), CREATE_THREAD_FROZEN
,
3942 audio_thread_name
IF_PRIO(, PRIORITY_BACKGROUND
)
3945 buffering_thread_p
= create_thread( buffering_thread
, buffering_stack
,
3946 sizeof(buffering_stack
), CREATE_THREAD_FROZEN
,
3947 buffering_thread_name
IF_PRIO(, PRIORITY_BUFFERING
)
3948 IF_COP(, CPU
, true));
3950 #ifdef PLAYBACK_VOICE
3951 /* TODO: Change this around when various speech codecs can be used */
3952 if (talk_voice_required())
3954 logf("Starting voice codec");
3955 queue_init(&voice_queue
, true);
3956 voice_thread_p
= create_thread(voice_thread
, voice_stack
,
3957 sizeof(voice_stack
), CREATE_THREAD_FROZEN
,
3959 IF_PRIO(, PRIORITY_PLAYBACK
) IF_COP(, CPU
));
3963 /* Set crossfade setting for next buffer init which should be about... */
3964 pcmbuf_crossfade_enable(global_settings
.crossfade
);
3966 /* ...now! Set up the buffers */
3967 audio_reset_buffer();
3969 buffering_init(filebuf
, filebuflen
);
3971 /* Probably safe to say */
3972 audio_is_initialized
= true;
3974 sound_settings_apply();
3976 eq_hw_enable(global_settings
.eq_hw_enabled
);
3978 #ifndef HAVE_FLASH_STORAGE
3979 audio_set_buffer_margin(global_settings
.buffer_margin
);
3982 /* it's safe to let the threads run now */
3983 thread_thaw(codec_thread_p
);
3984 #ifdef PLAYBACK_VOICE
3986 thread_thaw(voice_thread_p
);
3988 thread_thaw(audio_thread_p
);
3989 thread_thaw(buffering_thread_p
);