1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 Miika Pekkarinen
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 /* TODO: Can use the track changed callback to detect end of track and seek
21 * in the previous track until this happens */
22 /* Design: we have prev_ti already, have a conditional for what type of seek
23 * to do on a seek request, if it is a previous track seek, skip previous,
24 * and in the request_next_track callback set the offset up the same way that
25 * starting from an offset works. */
26 /* TODO: Pause should be handled in here, rather than PCMBUF so that voice can
27 * play whilst audio is paused */
49 #include "buffering.h"
50 #include "mp3_playback.h"
65 #ifdef HAVE_LCD_BITMAP
67 #include "peakmeter.h"
77 #include "ata_idle_notify.h"
80 #include "recording.h"
85 #include "menus/eq_menu.h"
88 #define PLAYBACK_VOICE
91 /* default point to start buffer refill */
92 #define AUDIO_DEFAULT_WATERMARK (1024*512)
93 /* amount of data to read in one read() call */
94 #define AUDIO_DEFAULT_FILECHUNK (1024*32)
95 /* point at which the file buffer will fight for CPU time */
96 #define AUDIO_FILEBUF_CRITICAL (1024*128)
97 /* amount of guess-space to allow for codecs that must hunt and peck
98 * for their correct seeek target, 32k seems a good size */
99 #define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
101 /* Define LOGF_ENABLE to enable logf output in this file */
102 /*#define LOGF_ENABLE*/
105 /* macros to enable logf for queues
106 logging on SYS_TIMEOUT can be disabled */
108 /* Define this for logf output of all queuing except SYS_TIMEOUT */
109 #define PLAYBACK_LOGQUEUES
110 /* Define this to logf SYS_TIMEOUT messages */
111 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
114 #ifdef PLAYBACK_LOGQUEUES
115 #define LOGFQUEUE logf
117 #define LOGFQUEUE(...)
120 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
121 #define LOGFQUEUE_SYS_TIMEOUT logf
123 #define LOGFQUEUE_SYS_TIMEOUT(...)
127 /* Define one constant that includes recording related functionality */
128 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
129 #define AUDIO_HAVE_RECORDING
137 Q_AUDIO_PRE_FF_REWIND
,
139 Q_AUDIO_REBUFFER_SEEK
,
140 Q_AUDIO_CHECK_NEW_TRACK
,
142 Q_AUDIO_TRACK_CHANGED
,
147 Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
,
149 Q_CODEC_REQUEST_COMPLETE
,
150 Q_CODEC_REQUEST_FAILED
,
158 #ifdef AUDIO_HAVE_RECORDING
164 /* As defined in plugins/lib/xxx2wav.h */
166 #define MALLOC_BUFSIZE (512*1024)
167 #define GUARD_BUFSIZE (32*1024)
169 #define MALLOC_BUFSIZE (100*1024)
170 #define GUARD_BUFSIZE (8*1024)
173 /* As defined in plugin.lds */
175 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
176 #define CODEC_IRAM_SIZE ((size_t)0xc000)
177 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
178 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
179 #define CODEC_IRAM_SIZE ((size_t)0x10000)
181 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
182 #define CODEC_IRAM_SIZE ((size_t)0xc000)
185 #ifndef IBSS_ATTR_VOICE_STACK
186 #define IBSS_ATTR_VOICE_STACK IBSS_ATTR
189 bool audio_is_initialized
= false;
191 /* Variables are commented with the threads that use them: *
192 * A=audio, C=codec, V=voice. A suffix of - indicates that *
193 * the variable is read but not updated on that thread. */
194 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
196 /* Main state control */
197 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR
= false; /* Codec loaded? (C/A-) */
198 static volatile bool playing NOCACHEBSS_ATTR
= false; /* Is audio playing? (A) */
199 static volatile bool paused NOCACHEBSS_ATTR
= false; /* Is audio paused? (A/C-) */
200 static volatile bool filling IDATA_ATTR
= false; /* Is file buffer refilling? (A/C-) */
202 /* Ring buffer where compressed audio and codecs are loaded */
203 static unsigned char *filebuf
= NULL
; /* Start of buffer (A/C-) */
204 static unsigned char *malloc_buf
= NULL
; /* Start of malloc buffer (A/C-) */
205 /* FIXME: make filebuflen static */
206 size_t filebuflen
= 0; /* Size of buffer (A/C-) */
207 /* FIXME: make buf_ridx (C/A-) */
209 /* Possible arrangements of the buffer */
210 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
211 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
212 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
213 static int buffer_state
= BUFFER_STATE_TRASHED
; /* Buffer state */
215 struct mp3entry curtrack_id3
;
216 struct mp3entry nexttrack_id3
;
218 /* Track info structure about songs in the file buffer (A/C-) */
220 int audio_hid
; /* The ID for the track's buffer handle */
221 int id3_hid
; /* The ID for the track's metadata handle */
222 int codec_hid
; /* The ID for the track's codec handle */
224 size_t codecsize
; /* Codec length in bytes */
225 size_t filesize
; /* File total length */
227 bool taginfo_ready
; /* Is metadata read */
229 bool event_sent
; /* Was this track's buffered event sent */
232 static struct track_info tracks
[MAX_TRACK
];
233 static volatile int track_ridx
= 0; /* Track being decoded (A/C-) */
234 static int track_widx
= 0; /* Track being buffered (A) */
237 static struct track_info
*prev_ti
= NULL
; /* Previous track info pointer (A/C-) */
240 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
242 /* Set by the audio thread when the current track information has updated
243 * and the WPS may need to update its cached information */
244 static bool track_changed
= false;
246 /* Information used only for filling the buffer */
247 /* Playlist steps from playing track to next track to be buffered (A) */
248 static int last_peek_offset
= 0;
250 /* Scrobbler support */
251 static unsigned long prev_track_elapsed
= 0; /* Previous track elapsed time (C/A-)*/
253 /* Track change controls */
254 static bool automatic_skip
= false; /* Who initiated in-progress skip? (C/A-) */
255 static bool playlist_end
= false; /* Has the current playlist ended? (A) */
256 static bool dir_skip
= false; /* Is a directory skip pending? (A) */
257 static bool new_playlist
= false; /* Are we starting a new playlist? (A) */
258 static int wps_offset
= 0; /* Pending track change offset, to keep WPS responsive (A) */
259 static bool skipped_during_pause
= false; /* Do we need to clear the PCM buffer when playback resumes (A) */
261 /* Callbacks which applications or plugins may set */
262 /* When the playing track has changed from the user's perspective */
263 void (*track_changed_callback
)(struct mp3entry
*id3
) = NULL
;
264 /* When a track has been buffered */
265 void (*track_buffer_callback
)(struct mp3entry
*id3
, bool last_track
) = NULL
;
266 /* When a track's buffer has been overwritten or cleared */
267 void (*track_unbuffer_callback
)(struct mp3entry
*id3
, bool last_track
) = NULL
;
270 static size_t conf_watermark
= 0; /* Level to trigger filebuf fill (A/C) FIXME */
271 static size_t conf_filechunk
= 0; /* Largest chunk the codec accepts (A/C) FIXME */
272 static size_t conf_preseek
= 0; /* Codec pre-seek margin (A/C) FIXME */
273 static size_t buffer_margin
= 0; /* Buffer margin aka anti-skip buffer (A/C-) */
275 static size_t high_watermark
= 0; /* High watermark for rebuffer (A/V/other) */
278 /* Multiple threads */
279 static void set_current_codec(int codec_idx
);
280 /* Set the watermark to trigger buffer fill (A/C) FIXME */
281 static void set_filebuf_watermark(int seconds
);
284 static struct event_queue audio_queue NOCACHEBSS_ATTR
;
285 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR
;
286 static long audio_stack
[(DEFAULT_STACK_SIZE
+ 0x1000)/sizeof(long)];
287 static const char audio_thread_name
[] = "audio";
289 static void audio_thread(void);
290 static void audio_initiate_track_change(long direction
);
291 static bool audio_have_tracks(void);
292 static void audio_reset_buffer(void);
295 extern struct codec_api ci
;
296 static struct event_queue codec_queue NOCACHEBSS_ATTR
;
297 static long codec_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
299 static const char codec_thread_name
[] = "codec";
300 struct thread_entry
*codec_thread_p
; /* For modifying thread priority later. */
302 static volatile int current_codec IDATA_ATTR
; /* Current codec (normal/voice) */
304 /* Buffering thread */
305 void buffering_thread(void);
306 static long buffering_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)];
307 static const char buffering_thread_name
[] = "buffering";
308 struct thread_entry
*buffering_thread_p
;
311 #ifdef PLAYBACK_VOICE
313 extern struct codec_api ci_voice
;
315 static struct thread_entry
*voice_thread_p
= NULL
;
316 static struct event_queue voice_queue NOCACHEBSS_ATTR
;
317 static long voice_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
318 IBSS_ATTR_VOICE_STACK
;
319 static const char voice_thread_name
[] = "voice codec";
321 /* Voice codec swapping control */
322 extern unsigned char codecbuf
[]; /* DRAM codec swap buffer */
325 /* IRAM codec swap buffer for sim*/
326 static unsigned char sim_iram
[CODEC_IRAM_SIZE
];
327 #undef CODEC_IRAM_ORIGIN
328 #define CODEC_IRAM_ORIGIN sim_iram
331 /* iram_buf and dram_buf are either both NULL or both non-NULL */
332 /* Pointer to IRAM buffer for codec swapping */
333 static unsigned char *iram_buf
= NULL
;
334 /* Pointer to DRAM buffer for codec swapping */
335 static unsigned char *dram_buf
= NULL
;
336 /* Parity of swap_codec calls - needed because one codec swapping itself in
337 automatically swaps in the other and the swap when unlocking should not
338 happen if the parity is even.
340 static bool swap_codec_parity NOCACHEBSS_ATTR
= false; /* true=odd, false=even */
341 /* Locking to control which codec (normal/voice) is running */
342 static struct semaphore sem_codecthread NOCACHEBSS_ATTR
;
343 static struct event event_codecthread NOCACHEBSS_ATTR
;
346 static volatile bool voice_thread_start
= false; /* Triggers voice playback (A/V) */
347 static volatile bool voice_is_playing NOCACHEBSS_ATTR
= false; /* Is voice currently playing? (V) */
348 static volatile bool voice_codec_loaded NOCACHEBSS_ATTR
= false; /* Is voice codec loaded (V/A-) */
349 static unsigned char *voicebuf
= NULL
;
350 static size_t voice_remaining
= 0;
353 /* Voice IRAM has been stolen for other use */
354 static bool voice_iram_stolen
= false;
357 static void (*voice_getmore
)(unsigned char** start
, size_t* size
) = NULL
;
360 void (*callback
)(unsigned char **start
, size_t* size
);
364 static void voice_thread(void);
365 static void voice_stop(void);
367 #endif /* PLAYBACK_VOICE */
370 /* --- Helper functions --- */
372 struct mp3entry
*bufgetid3(int handle_id
)
374 struct mp3entry
*id3
;
375 ssize_t ret
= bufgetdata(handle_id
, 0, (unsigned char **)&id3
);
377 if (ret
< 0 || ret
!= sizeof(struct mp3entry
))
383 unsigned char *getptr(int handle_id
)
386 ssize_t ret
= bufgetdata(handle_id
, 0, &ptr
);
394 /* --- External interfaces --- */
396 void mp3_play_data(const unsigned char* start
, int size
,
397 void (*get_more
)(unsigned char** start
, size_t* size
))
399 #ifdef PLAYBACK_VOICE
400 static struct voice_info voice_clip
;
401 voice_clip
.callback
= get_more
;
402 voice_clip
.buf
= (unsigned char*)start
;
403 voice_clip
.size
= size
;
404 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
405 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
406 LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
407 queue_post(&voice_queue
, Q_VOICE_PLAY
, (intptr_t)&voice_clip
);
408 voice_thread_start
= true;
417 void mp3_play_stop(void)
419 #ifdef PLAYBACK_VOICE
420 queue_remove_from_head(&voice_queue
, Q_VOICE_STOP
);
421 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
422 queue_post(&voice_queue
, Q_VOICE_STOP
, 1);
426 void mp3_play_pause(bool play
)
432 bool mp3_is_playing(void)
434 #ifdef PLAYBACK_VOICE
435 return voice_is_playing
;
441 /* If voice could be swapped out - wait for it to return
442 * Used by buffer claming functions.
444 static void wait_for_voice_swap_in(void)
446 #ifdef PLAYBACK_VOICE
447 if (NULL
== iram_buf
)
450 event_wait(&event_codecthread
, STATE_NONSIGNALED
);
451 #endif /* PLAYBACK_VOICE */
454 /* This sends a stop message and the audio thread will dump all it's
455 subsequenct messages */
456 static void audio_hard_stop(void)
459 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
460 queue_send(&audio_queue
, Q_AUDIO_STOP
, 1);
463 unsigned char *audio_get_buffer(bool talk_buf
, size_t *buffer_size
)
465 unsigned char *buf
, *end
;
467 if (audio_is_initialized
)
470 wait_for_voice_swap_in();
471 #ifdef PLAYBACK_VOICE
475 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
477 if (buffer_size
== NULL
)
479 /* Special case for talk_init to use since it already knows it's
481 buffer_state
= BUFFER_STATE_TRASHED
;
485 if (talk_buf
|| buffer_state
== BUFFER_STATE_TRASHED
486 || !talk_voice_required())
488 logf("get buffer: talk, audio");
489 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
490 the talk buffer is not needed because voice isn't being used, or
491 could be BUFFER_STATE_TRASHED already. If state is
492 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
493 without the caller knowing what's going on. Changing certain settings
494 may move it to a worse condition but the memory in use by something
495 else will remain undisturbed.
497 if (buffer_state
!= BUFFER_STATE_TRASHED
)
500 buffer_state
= BUFFER_STATE_TRASHED
;
508 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
509 still BUFFER_STATE_INITIALIZED */
510 /* Skip talk buffer and move pcm buffer to end to maximize available
511 contiguous memory - no audio running means voice will not need the
513 logf("get buffer: audio");
514 buf
= audiobuf
+ talk_get_bufsize();
515 end
= audiobufend
- pcmbuf_init(audiobufend
);
516 buffer_state
= BUFFER_STATE_VOICED_ONLY
;
519 *buffer_size
= end
- buf
;
525 void audio_iram_steal(void)
527 /* We need to stop audio playback in order to use codec IRAM */
530 #ifdef PLAYBACK_VOICE
531 if (NULL
!= iram_buf
)
533 /* Can't already be stolen */
534 if (voice_iram_stolen
)
537 /* Must wait for voice to be current again if it is swapped which
538 would cause the caller's buffer to get clobbered when voice locks
539 and runs - we'll wait for it to lock and yield again then make sure
540 the ride has come to a complete stop */
541 wait_for_voice_swap_in();
544 /* Save voice IRAM but just memcpy - safe to do here since voice
545 is current and no audio codec is loaded */
546 memcpy(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
547 voice_iram_stolen
= true;
551 /* Nothing much to do if no voice */
552 voice_iram_stolen
= false;
556 #endif /* IRAM_STEAL */
558 #ifdef HAVE_RECORDING
559 unsigned char *audio_get_recording_buffer(size_t *buffer_size
)
561 /* Don't allow overwrite of voice swap area or we'll trash the
562 swapped-out voice codec but can use whole thing if none */
565 /* Stop audio and voice. Wait for voice to swap in and be clear
566 of pending events to ensure trouble-free operation of encoders */
568 wait_for_voice_swap_in();
569 #ifdef PLAYBACK_VOICE
574 #ifdef PLAYBACK_VOICE
575 /* If no dram_buf, swap space not used and recording gets more
576 memory. Codec swap areas will remain unaffected by the next init
577 since they're allocated at the end of the buffer and their sizes
578 don't change between calls */
581 #endif /* PLAYBACK_VOICE */
584 buffer_state
= BUFFER_STATE_TRASHED
;
586 *buffer_size
= end
- audiobuf
;
588 return (unsigned char *)audiobuf
;
591 bool audio_load_encoder(int afmt
)
594 const char *enc_fn
= get_codec_filename(afmt
| CODEC_TYPE_ENCODER
);
598 audio_remove_encoder();
599 ci
.enc_codec_loaded
= 0; /* clear any previous error condition */
601 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
602 queue_post(&codec_queue
, Q_ENCODER_LOAD_DISK
, (intptr_t)enc_fn
);
604 while (ci
.enc_codec_loaded
== 0)
607 logf("codec loaded: %d", ci
.enc_codec_loaded
);
609 return ci
.enc_codec_loaded
> 0;
614 } /* audio_load_encoder */
616 void audio_remove_encoder(void)
619 /* force encoder codec unload (if currently loaded) */
620 if (ci
.enc_codec_loaded
<= 0)
623 ci
.stop_encoder
= true;
624 while (ci
.enc_codec_loaded
> 0)
627 } /* audio_remove_encoder */
629 #endif /* HAVE_RECORDING */
631 struct mp3entry
* audio_current_track(void)
633 const char *filename
;
635 static struct mp3entry temp_id3
;
637 int offset
= ci
.new_track
+ wps_offset
;
639 cur_idx
= track_ridx
+ offset
;
640 cur_idx
&= MAX_TRACK_MASK
;
642 if (tracks
[cur_idx
].id3_hid
> 0)
643 return bufgetid3(tracks
[cur_idx
].id3_hid
);
645 memset(&temp_id3
, 0, sizeof(struct mp3entry
));
647 filename
= playlist_peek(0);
649 filename
= "No file!";
651 #ifdef HAVE_TC_RAMCACHE
652 if (tagcache_fill_tags(&temp_id3
, filename
))
656 p
= strrchr(filename
, '/');
662 strncpy(temp_id3
.path
, p
, sizeof(temp_id3
.path
)-1);
663 temp_id3
.title
= &temp_id3
.path
[0];
668 struct mp3entry
* audio_next_track(void)
670 int next_idx
= track_ridx
;
672 if (!audio_have_tracks())
676 next_idx
&= MAX_TRACK_MASK
;
678 if (tracks
[next_idx
].id3_hid
<= 0)
681 return bufgetid3(tracks
[next_idx
].id3_hid
);
684 bool audio_has_changed_track(void)
688 track_changed
= false;
695 void audio_play(long offset
)
699 #ifdef PLAYBACK_VOICE
700 /* Truncate any existing voice output so we don't have spelling
701 * etc. over the first part of the played track */
706 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset
);
707 /* Don't return until playback has actually started */
708 queue_send(&audio_queue
, Q_AUDIO_PLAY
, offset
);
711 void audio_stop(void)
714 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
715 /* Don't return until playback has actually stopped */
716 queue_send(&audio_queue
, Q_AUDIO_STOP
, 0);
719 void audio_pause(void)
721 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
722 /* Don't return until playback has actually paused */
723 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, true);
726 void audio_resume(void)
728 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
729 /* Don't return until playback has actually resumed */
730 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, false);
733 void audio_next(void)
735 if (playlist_check(ci
.new_track
+ wps_offset
+ 1))
737 if (global_settings
.beep
)
738 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
740 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
741 queue_post(&audio_queue
, Q_AUDIO_SKIP
, 1);
742 /* Update wps while our message travels inside deep playback queues. */
744 track_changed
= true;
748 /* No more tracks. */
749 if (global_settings
.beep
)
750 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
754 void audio_prev(void)
756 if (playlist_check(ci
.new_track
+ wps_offset
- 1))
758 if (global_settings
.beep
)
759 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
761 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
762 queue_post(&audio_queue
, Q_AUDIO_SKIP
, -1);
763 /* Update wps while our message travels inside deep playback queues. */
765 track_changed
= true;
769 /* No more tracks. */
770 if (global_settings
.beep
)
771 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
775 void audio_next_dir(void)
777 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
778 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, 1);
781 void audio_prev_dir(void)
783 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
784 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, -1);
787 void audio_pre_ff_rewind(void)
789 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
790 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
793 void audio_ff_rewind(long newpos
)
795 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
796 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, newpos
);
799 void audio_flush_and_reload_tracks(void)
801 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
802 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
805 void audio_error_clear(void)
807 #ifdef AUDIO_HAVE_RECORDING
808 pcm_rec_error_clear();
812 int audio_status(void)
817 ret
|= AUDIO_STATUS_PLAY
;
820 ret
|= AUDIO_STATUS_PAUSE
;
822 #ifdef HAVE_RECORDING
823 /* Do this here for constitency with mpeg.c version */
824 ret
|= pcm_rec_status();
830 int audio_get_file_pos(void)
835 #ifndef HAVE_FLASH_STORAGE
836 void audio_set_buffer_margin(int setting
)
838 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
839 buffer_margin
= lookup
[setting
];
840 logf("buffer margin: %ld", buffer_margin
);
841 set_filebuf_watermark(buffer_margin
);
845 /* Take nescessary steps to enable or disable the crossfade setting */
846 void audio_set_crossfade(int enable
)
852 /* Tell it the next setting to use */
853 pcmbuf_crossfade_enable(enable
);
855 /* Return if size hasn't changed or this is too early to determine
856 which in the second case there's no way we could be playing
858 if (pcmbuf_is_same_size())
860 /* This function is a copout and just syncs some variables -
861 to be removed at a later date */
862 pcmbuf_crossfade_enable_finished();
867 was_playing
= playing
;
869 /* Playback has to be stopped before changing the buffer size */
872 /* Store the track resume position */
873 offset
= curtrack_id3
.offset
;
874 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK
));
877 /* Blast it - audio buffer will have to be setup again next time
879 audio_get_buffer(true, &size
);
881 /* Restart playback if audio was running previously */
886 /* --- Routines called from multiple threads --- */
887 static void set_current_codec(int codec_idx
)
889 current_codec
= codec_idx
;
890 dsp_configure(DSP_SWITCH_CODEC
, codec_idx
);
893 #ifdef PLAYBACK_VOICE
894 static void swap_codec(void)
898 /* Swap nothing if no swap buffers exist */
899 if (dram_buf
== NULL
)
901 logf("swap: no swap buffers");
905 my_codec
= current_codec
;
907 logf("swapping out codec: %d", my_codec
);
909 /* Invert this when a codec thread enters and leaves */
910 swap_codec_parity
= !swap_codec_parity
;
912 /* If this is true, an odd number of calls has occurred and there's
913 no codec thread waiting to swap us out when it locks and runs. This
914 occurs when playback is stopped or when just starting playback and
915 the audio thread is loading a codec; parities should always be even
916 on entry when a thread calls this during playback */
917 if (swap_codec_parity
)
919 /* Save our current IRAM and DRAM */
921 if (voice_iram_stolen
)
923 logf("swap: iram restore");
924 voice_iram_stolen
= false;
925 /* Don't swap trashed data into buffer as the voice IRAM will
926 already be swapped out - should _always_ be the case if
927 voice_iram_stolen is true since the voice has been swapped
929 if (my_codec
== CODEC_IDX_VOICE
)
931 logf("voice iram already swapped");
937 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
943 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
944 /* No cache invalidation needed; it will be done in codec_load_ram
945 or we won't be here otherwise */
948 /* Release my semaphore */
949 semaphore_release(&sem_codecthread
);
950 logf("unlocked: %d", my_codec
);
952 /* Wait for other codec */
953 event_wait(&event_codecthread
,
954 (my_codec
== CODEC_IDX_AUDIO
) ? STATE_NONSIGNALED
: STATE_SIGNALED
);
956 /* Wait for other codec to unlock */
957 logf("waiting for lock: %d", my_codec
);
958 semaphore_wait(&sem_codecthread
);
961 set_current_codec(my_codec
);
962 event_set_state(&event_codecthread
,
963 (my_codec
== CODEC_IDX_AUDIO
) ? STATE_SIGNALED
: STATE_NONSIGNALED
);
965 /* Reload our IRAM and DRAM */
966 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
967 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
970 /* Flip parity again */
971 swap_codec_parity
= !swap_codec_parity
;
973 logf("resuming codec: %d", my_codec
);
976 /* This function is meant to be used by the buffer stealing functions to
977 ensure the codec is no longer active and so voice will be swapped-in
978 before it is called */
979 static void voice_stop(void)
981 /* Must have a voice codec loaded or we'll hang forever here */
982 if (!voice_codec_loaded
)
987 /* Loop until voice empties it's queue, stops and picks up on the new
988 track; the voice thread must be stopped and waiting for messages
990 while (voice_is_playing
|| !queue_empty(&voice_queue
) ||
998 /* Is voice still speaking */
999 /* Unfortunately only reliable when music is not also playing. */
1000 static bool is_voice_speaking(void)
1002 return is_voice_queued()
1004 || (!playing
&& pcm_is_playing());
1007 #endif /* PLAYBACK_VOICE */
1009 /* Wait for voice to finish speaking. */
1010 /* Also only reliable when music is not also playing. */
1011 void voice_wait(void)
1013 #ifdef PLAYBACK_VOICE
1014 while (is_voice_speaking())
1019 static void set_filebuf_watermark(int seconds
)
1024 return; /* Audio buffers not yet set up */
1026 bytes
= MAX(curtrack_id3
.bitrate
* seconds
* (1000/8), conf_watermark
);
1027 bytes
= MIN(bytes
, filebuflen
/ 2);
1028 conf_watermark
= bytes
;
1031 const char * get_codec_filename(int cod_spec
)
1035 #ifdef HAVE_RECORDING
1036 /* Can choose decoder or encoder if one available */
1037 int type
= cod_spec
& CODEC_TYPE_MASK
;
1038 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
1040 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
1041 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
1043 fname
= (type
== CODEC_TYPE_ENCODER
) ?
1044 audio_formats
[afmt
].codec_enc_root_fn
:
1045 audio_formats
[afmt
].codec_root_fn
;
1048 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
1049 afmt
, fname
? fname
: "<unknown>");
1050 #else /* !HAVE_RECORDING */
1051 /* Always decoder */
1052 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
1053 cod_spec
= AFMT_UNKNOWN
;
1054 fname
= audio_formats
[cod_spec
].codec_root_fn
;
1055 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
1056 #endif /* HAVE_RECORDING */
1059 } /* get_codec_filename */
1062 /* --- Voice thread --- */
1064 #ifdef PLAYBACK_VOICE
1066 static bool voice_pcmbuf_insert_callback(
1067 const void *ch1
, const void *ch2
, int count
)
1069 const char *src
[2] = { ch1
, ch2
};
1073 int out_count
= dsp_output_count(count
);
1077 while ((dest
= pcmbuf_request_voice_buffer(
1078 &out_count
, playing
)) == NULL
)
1080 if (playing
&& audio_codec_loaded
)
1086 /* Get the real input_size for output_size bytes, guarding
1087 * against resampling buffer overflows. */
1088 inp_count
= dsp_input_count(out_count
);
1093 /* Input size has grown, no error, just don't write more than length */
1094 if (inp_count
> count
)
1097 out_count
= dsp_process(dest
, src
, inp_count
);
1104 pcmbuf_mix_voice(out_count
);
1105 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
1110 pcmbuf_write_complete(out_count
);
1116 } /* voice_pcmbuf_insert_callback */
1118 static void* voice_get_memory_callback(size_t *size
)
1120 /* Voice should have no use for this. If it did, we'd have to
1121 swap the malloc buffer as well. */
1126 static void voice_set_elapsed_callback(unsigned int value
)
1131 static void voice_set_offset_callback(size_t value
)
1136 static void voice_configure_callback(int setting
, intptr_t value
)
1138 if (!dsp_configure(setting
, value
))
1140 logf("Illegal key:%d", setting
);
1144 static size_t voice_filebuf_callback(void *ptr
, size_t size
)
1152 /* Handle Q_VOICE_STOP and part of SYS_USB_CONNECTED */
1153 static bool voice_on_voice_stop(bool aborting
, size_t *realsize
)
1155 if (aborting
&& !playing
)
1157 /* Aborting: Slight hack - flush PCM buffer if
1158 only being used for voice */
1162 if (voice_is_playing
)
1164 /* Clear the current buffer */
1165 voice_is_playing
= false;
1166 voice_getmore
= NULL
;
1167 voice_remaining
= 0;
1170 /* Cancel any automatic boost if no more clips requested. */
1171 if (!playing
|| !voice_thread_start
)
1174 /* Force the codec to think it's changing tracks */
1175 ci_voice
.new_track
= 1;
1178 return true; /* Yes, change tracks */
1184 static void* voice_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1186 struct queue_event ev
;
1188 if (ci_voice
.new_track
)
1196 if (voice_is_playing
|| playing
)
1198 queue_wait_w_tmo(&voice_queue
, &ev
, 0);
1199 if (!voice_is_playing
&& ev
.id
== SYS_TIMEOUT
)
1200 ev
.id
= Q_AUDIO_PLAY
;
1204 queue_wait(&voice_queue
, &ev
);
1209 LOGFQUEUE("voice < Q_AUDIO_PLAY");
1212 if (audio_codec_loaded
)
1218 #ifdef AUDIO_HAVE_RECORDING
1219 case Q_ENCODER_RECORD
:
1220 LOGFQUEUE("voice < Q_ENCODER_RECORD");
1226 LOGFQUEUE("voice < Q_VOICE_STOP");
1227 if (voice_on_voice_stop(ev
.data
, realsize
))
1231 case SYS_USB_CONNECTED
:
1233 LOGFQUEUE("voice < SYS_USB_CONNECTED");
1234 bool change_tracks
= voice_on_voice_stop(ev
.data
, realsize
);
1235 /* Voice is obviously current so let us swap ourselves away if
1236 playing so audio may stop itself - audio_codec_loaded can
1237 only be true in this case if we're here even if the codec
1238 is only about to load */
1239 if (audio_codec_loaded
)
1241 /* Playback should be finished by now - ack and wait */
1242 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
1243 usb_wait_for_disconnect(&voice_queue
);
1250 LOGFQUEUE("voice < Q_VOICE_PLAY");
1251 if (!voice_is_playing
)
1253 /* Set up new voice data */
1254 struct voice_info
*voice_data
;
1256 if (voice_iram_stolen
)
1258 /* Voice is the first to run again and is currently
1260 logf("voice: iram restore");
1261 memcpy(CODEC_IRAM_ORIGIN
, iram_buf
, CODEC_IRAM_SIZE
);
1262 voice_iram_stolen
= false;
1265 /* Must reset the buffer before any playback begins if
1267 if (buffer_state
== BUFFER_STATE_TRASHED
)
1268 audio_reset_buffer();
1270 voice_is_playing
= true;
1271 trigger_cpu_boost();
1272 voice_data
= (struct voice_info
*)ev
.data
;
1273 voice_remaining
= voice_data
->size
;
1274 voicebuf
= voice_data
->buf
;
1275 voice_getmore
= voice_data
->callback
;
1277 goto voice_play_clip
; /* To exit both switch and while */
1280 LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
1281 goto voice_play_clip
;
1284 LOGFQUEUE("voice < default");
1290 if (voice_remaining
== 0 || voicebuf
== NULL
)
1293 voice_getmore((unsigned char **)&voicebuf
, &voice_remaining
);
1295 /* If this clip is done */
1296 if (voice_remaining
== 0)
1298 LOGFQUEUE("voice > voice Q_VOICE_STOP");
1299 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
1300 /* Force pcm playback. */
1301 if (!pcm_is_playing())
1302 pcmbuf_play_start();
1306 *realsize
= MIN(voice_remaining
, reqsize
);
1312 } /* voice_request_buffer_callback */
1314 static void voice_advance_buffer_callback(size_t amount
)
1316 amount
= MIN(amount
, voice_remaining
);
1318 voice_remaining
-= amount
;
1321 static void voice_advance_buffer_loc_callback(void *ptr
)
1323 size_t amount
= (size_t)ptr
- (size_t)voicebuf
;
1325 voice_advance_buffer_callback(amount
);
1328 static off_t
voice_mp3_get_filepos_callback(int newtime
)
1335 static void voice_do_nothing(void)
1340 static bool voice_seek_buffer_callback(size_t newpos
)
1347 static bool voice_request_next_track_callback(void)
1349 ci_voice
.new_track
= 0;
1353 static void voice_thread(void)
1355 logf("Loading voice codec");
1356 voice_codec_loaded
= true;
1357 semaphore_wait(&sem_codecthread
);
1358 event_set_state(&event_codecthread
, false);
1359 set_current_codec(CODEC_IDX_VOICE
);
1360 dsp_configure(DSP_RESET
, 0);
1361 voice_remaining
= 0;
1362 voice_getmore
= NULL
;
1364 /* FIXME: If we being starting the voice thread without reboot, the
1365 voice_queue could be full of old stuff and we must flush it. */
1366 codec_load_file(get_codec_filename(AFMT_MPA_L3
), &ci_voice
);
1368 logf("Voice codec finished");
1369 voice_codec_loaded
= false;
1370 voice_thread_p
= NULL
;
1371 semaphore_release(&sem_codecthread
);
1372 } /* voice_thread */
1374 #endif /* PLAYBACK_VOICE */
1376 /* --- Codec thread --- */
1377 static bool codec_pcmbuf_insert_callback(
1378 const void *ch1
, const void *ch2
, int count
)
1380 const char *src
[2] = { ch1
, ch2
};
1384 int out_count
= dsp_output_count(count
);
1388 /* Prevent audio from a previous track from playing */
1389 if (ci
.new_track
|| ci
.stop_codec
)
1392 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
1395 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
1399 /* Get the real input_size for output_size bytes, guarding
1400 * against resampling buffer overflows. */
1401 inp_count
= dsp_input_count(out_count
);
1406 /* Input size has grown, no error, just don't write more than length */
1407 if (inp_count
> count
)
1410 out_count
= dsp_process(dest
, src
, inp_count
);
1415 pcmbuf_write_complete(out_count
);
1417 #ifdef PLAYBACK_VOICE
1418 if ((voice_is_playing
|| voice_thread_start
)
1419 && pcm_is_playing() && voice_codec_loaded
&&
1420 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1422 voice_thread_start
= false;
1431 } /* codec_pcmbuf_insert_callback */
1433 static void* codec_get_memory_callback(size_t *size
)
1435 *size
= MALLOC_BUFSIZE
;
1440 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
1441 static void codec_pcmbuf_position_callback(size_t size
)
1443 /* This is called from an ISR, so be quick */
1444 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
1445 prev_ti
->id3
.elapsed
;
1447 if (time
>= prev_ti
->id3
.length
)
1449 pcmbuf_set_position_callback(NULL
);
1450 prev_ti
->id3
.elapsed
= prev_ti
->id3
.length
;
1453 prev_ti
->id3
.elapsed
= time
;
1457 static void codec_set_elapsed_callback(unsigned int value
)
1459 unsigned int latency
;
1463 #ifdef AB_REPEAT_ENABLE
1464 ab_position_report(value
);
1467 latency
= pcmbuf_get_latency();
1468 if (value
< latency
)
1469 curtrack_id3
.elapsed
= 0;
1470 else if (value
- latency
> curtrack_id3
.elapsed
||
1471 value
- latency
< curtrack_id3
.elapsed
- 2)
1473 curtrack_id3
.elapsed
= value
- latency
;
1477 static void codec_set_offset_callback(size_t value
)
1479 unsigned int latency
;
1484 latency
= pcmbuf_get_latency() * curtrack_id3
.bitrate
/ 8;
1485 if (value
< latency
)
1486 curtrack_id3
.offset
= 0;
1488 curtrack_id3
.offset
= value
- latency
;
1491 static void codec_advance_buffer_counters(size_t amount
)
1493 bufadvance(CUR_TI
->audio_hid
, amount
);
1495 /* Start buffer filling as necessary. */
1496 if (!pcmbuf_is_lowdata() && !filling
)
1498 if (bufused() < conf_watermark
&& playing
&& !playlist_end
)
1500 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1501 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
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)
1525 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1526 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1530 if (ci
.stop_codec
|| ci
.new_track
)
1534 /* Update read and other position pointers */
1535 codec_advance_buffer_counters(copy_n
);
1537 /* Return the actual amount of data copied to the buffer */
1539 } /* codec_filebuf_callback */
1541 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1543 size_t short_n
, copy_n
, buf_rem
;
1552 copy_n
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, (unsigned char **)&ret
);
1559 while (copy_n
== -2)
1563 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1564 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1568 if (ci
.stop_codec
|| ci
.new_track
)
1578 } /* codec_request_buffer_callback */
1580 static int get_codec_base_type(int type
)
1592 static void codec_advance_buffer_callback(size_t amount
)
1596 while (filling
&& (ret
= bufadvance(CUR_TI
->audio_hid
, amount
)) == -2)
1601 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1605 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1606 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1607 ci
.curpos
+ amount
);
1612 case Q_CODEC_REQUEST_FAILED
:
1613 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1614 ci
.stop_codec
= true;
1617 case Q_CODEC_REQUEST_COMPLETE
:
1618 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1622 LOGFQUEUE("codec |< default");
1623 ci
.stop_codec
= true;
1628 //codec_advance_buffer_counters(amount);
1630 codec_set_offset_callback(ci
.curpos
);
1633 static void codec_advance_buffer_loc_callback(void *ptr
)
1635 size_t amount
= get_offset(CUR_TI
->audio_hid
, ptr
);
1637 codec_advance_buffer_callback(amount
);
1640 /* Copied from mpeg.c. Should be moved somewhere else. */
1641 static int codec_get_file_pos(void)
1644 struct mp3entry
*id3
= audio_current_track();
1650 /* Use the TOC to find the new position */
1651 unsigned int percent
, remainder
;
1652 int curtoc
, nexttoc
, plen
;
1654 percent
= (id3
->elapsed
*100)/id3
->length
;
1658 curtoc
= id3
->toc
[percent
];
1661 nexttoc
= id3
->toc
[percent
+1];
1665 pos
= (id3
->filesize
/256)*curtoc
;
1667 /* Use the remainder to get a more accurate position */
1668 remainder
= (id3
->elapsed
*100)%id3
->length
;
1669 remainder
= (remainder
*100)/id3
->length
;
1670 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1671 pos
+= (plen
/100)*remainder
;
1675 /* No TOC exists, estimate the new position */
1676 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1677 (id3
->elapsed
/ 1000);
1680 else if (id3
->bitrate
)
1681 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1685 pos
+= id3
->first_frame_offset
;
1687 /* Don't seek right to the end of the file so that we can
1688 transition properly to the next song */
1689 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1690 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1695 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1699 curtrack_id3
.elapsed
= newtime
;
1700 newpos
= codec_get_file_pos();
1705 static void codec_seek_complete_callback(void)
1707 logf("seek_complete");
1708 if (pcm_is_paused())
1710 /* If this is not a seamless seek, clear the buffer */
1712 dsp_configure(DSP_FLUSH
, 0);
1714 /* If playback was not 'deliberately' paused, unpause now */
1716 pcmbuf_pause(false);
1721 static bool codec_seek_buffer_callback(size_t newpos
)
1726 logf("codec_seek_buffer_callback");
1728 if (newpos
>= CUR_TI
->filesize
)
1729 newpos
= CUR_TI
->filesize
- 1;
1731 difference
= newpos
- ci
.curpos
;
1732 if (difference
>= 0)
1734 /* Seeking forward */
1735 logf("seek: +%d", difference
);
1736 codec_advance_buffer_callback(difference
);
1740 /* Seeking backward */
1741 difference
= -difference
;
1742 if (ci
.curpos
- difference
< 0)
1743 difference
= ci
.curpos
;
1745 /* We need to reload the song. */
1746 if (newpos
< CUR_TI
->start_pos
)
1748 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1752 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1753 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1759 case Q_CODEC_REQUEST_COMPLETE
:
1760 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1763 case Q_CODEC_REQUEST_FAILED
:
1764 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1765 ci
.stop_codec
= true;
1769 LOGFQUEUE("codec |< default");
1774 /* Seeking inside buffer space. */
1775 logf("seek: -%d", difference
);
1776 CUR_TI
->available
+= difference
;
1777 buf_ridx
= RINGBUF_SUB(buf_ridx
, (unsigned)difference
);
1778 ci
.curpos
-= difference
;
1783 static void codec_configure_callback(int setting
, intptr_t value
)
1786 case CODEC_SET_FILEBUF_WATERMARK
:
1787 conf_watermark
= value
;
1788 set_filebuf_watermark(buffer_margin
);
1791 case CODEC_SET_FILEBUF_CHUNKSIZE
:
1792 conf_filechunk
= value
;
1795 case CODEC_SET_FILEBUF_PRESEEK
:
1796 conf_preseek
= value
;
1800 if (!dsp_configure(setting
, value
)) { logf("Illegal key:%d", setting
); }
1804 static void codec_track_changed(void)
1806 automatic_skip
= false;
1807 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1808 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1811 static void codec_pcmbuf_track_changed_callback(void)
1813 pcmbuf_set_position_callback(NULL
);
1814 codec_track_changed();
1817 static void codec_discard_codec_callback(void)
1819 if (CUR_TI
->codec_hid
> 0)
1821 bufclose(CUR_TI
->codec_hid
);
1822 CUR_TI
->codec_hid
= 0;
1826 /* Check if a buffer desync has happened, log it and stop playback. */
1827 if (buf_ridx
!= CUR_TI
->buf_idx
)
1829 int offset
= CUR_TI
->buf_idx
- buf_ridx
;
1830 size_t new_used
= bufused() - offset
;
1832 logf("Buf off :%d=%d-%d", offset
, CUR_TI
->buf_idx
, buf_ridx
);
1833 logf("Used off:%d",bufused() - new_used
);
1835 /* This is a fatal internal error and it's not safe to
1836 * continue playback. */
1837 ci
.stop_codec
= true;
1838 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1843 static inline void codec_gapless_track_change(void) {
1844 /* callback keeps the progress bar moving while the pcmbuf empties */
1845 /* pcmbuf_set_position_callback(codec_pcmbuf_position_callback); */
1846 /* set the pcmbuf callback for when the track really changes */
1847 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1850 static inline void codec_crossfade_track_change(void) {
1851 /* Initiate automatic crossfade mode */
1852 pcmbuf_crossfade_init(false);
1853 /* Notify the wps that the track change starts now */
1854 codec_track_changed();
1857 static void codec_track_skip_done(bool was_manual
)
1859 int crossfade_mode
= global_settings
.crossfade
;
1861 /* Manual track change (always crossfade or flush audio). */
1864 pcmbuf_crossfade_init(true);
1865 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1866 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1868 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1869 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1870 && crossfade_mode
!= CROSSFADE_ENABLE_TRACKSKIP
)
1872 if (crossfade_mode
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1874 if (global_settings
.playlist_shuffle
)
1875 /* shuffle mode is on, so crossfade: */
1876 codec_crossfade_track_change();
1878 /* shuffle mode is off, so do a gapless track change */
1879 codec_gapless_track_change();
1882 /* normal crossfade: */
1883 codec_crossfade_track_change();
1886 /* normal gapless playback. */
1887 codec_gapless_track_change();
1890 static bool codec_load_next_track(void)
1892 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1894 prev_track_elapsed
= curtrack_id3
.elapsed
;
1897 codec_seek_complete_callback();
1899 #ifdef AB_REPEAT_ENABLE
1900 ab_end_of_track_report();
1903 logf("Request new track");
1905 if (ci
.new_track
== 0)
1908 automatic_skip
= true;
1913 trigger_cpu_boost();
1914 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1915 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1920 case Q_CODEC_REQUEST_COMPLETE
:
1921 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1922 codec_track_skip_done(!automatic_skip
);
1925 case Q_CODEC_REQUEST_FAILED
:
1926 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1928 ci
.stop_codec
= true;
1932 LOGFQUEUE("codec |< default");
1933 ci
.stop_codec
= true;
1938 static bool codec_request_next_track_callback(void)
1942 if (ci
.stop_codec
|| !playing
)
1945 prev_codectype
= get_codec_base_type(curtrack_id3
.codectype
);
1947 if (!codec_load_next_track())
1950 /* Check if the next codec is the same file. */
1951 if (prev_codectype
== get_codec_base_type(curtrack_id3
.codectype
))
1953 logf("New track loaded");
1954 codec_discard_codec_callback();
1959 logf("New codec:%d/%d", curtrack_id3
.codectype
, prev_codectype
);
1964 static void codec_thread(void)
1966 struct queue_event ev
;
1972 queue_wait(&codec_queue
, &ev
);
1975 case Q_CODEC_LOAD_DISK
:
1976 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1977 audio_codec_loaded
= true;
1978 #ifdef PLAYBACK_VOICE
1979 /* Don't sent messages to voice codec if it's already swapped
1980 out or it will never get this */
1981 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1983 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1984 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1986 semaphore_wait(&sem_codecthread
);
1987 event_set_state(&event_codecthread
, true);
1989 set_current_codec(CODEC_IDX_AUDIO
);
1990 ci
.stop_codec
= false;
1991 status
= codec_load_file((const char *)ev
.data
, &ci
);
1992 #ifdef PLAYBACK_VOICE
1993 semaphore_release(&sem_codecthread
);
1998 LOGFQUEUE("codec < Q_CODEC_LOAD");
1999 if (CUR_TI
->codec_hid
<= 0) {
2000 logf("Codec slot is empty!");
2001 /* Wait for the pcm buffer to go empty */
2002 while (pcm_is_playing())
2004 /* This must be set to prevent an infinite loop */
2005 ci
.stop_codec
= true;
2006 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
2007 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
2011 audio_codec_loaded
= true;
2012 #ifdef PLAYBACK_VOICE
2013 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2015 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
2016 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
2018 semaphore_wait(&sem_codecthread
);
2019 event_set_state(&event_codecthread
, true);
2021 set_current_codec(CODEC_IDX_AUDIO
);
2022 ci
.stop_codec
= false;
2023 wrap
= (size_t)&filebuf
[filebuflen
] - (size_t)getptr(CUR_TI
->codec_hid
);
2024 status
= codec_load_ram(getptr(CUR_TI
->codec_hid
), CUR_TI
->codecsize
,
2025 &filebuf
[0], wrap
, &ci
);
2026 #ifdef PLAYBACK_VOICE
2027 semaphore_release(&sem_codecthread
);
2031 #ifdef AUDIO_HAVE_RECORDING
2032 case Q_ENCODER_LOAD_DISK
:
2033 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2034 audio_codec_loaded
= false; /* Not audio codec! */
2035 #ifdef PLAYBACK_VOICE
2036 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2038 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
2039 queue_post(&voice_queue
, Q_ENCODER_RECORD
, 0);
2041 semaphore_wait(&sem_codecthread
);
2042 event_set_state(&event_codecthread
, true);
2044 logf("loading encoder");
2045 set_current_codec(CODEC_IDX_AUDIO
);
2046 ci
.stop_encoder
= false;
2047 status
= codec_load_file((const char *)ev
.data
, &ci
);
2048 #ifdef PLAYBACK_VOICE
2049 semaphore_release(&sem_codecthread
);
2051 logf("encoder stopped");
2053 #endif /* AUDIO_HAVE_RECORDING */
2056 case SYS_USB_CONNECTED
:
2057 LOGFQUEUE("codec < SYS_USB_CONNECTED");
2058 queue_clear(&codec_queue
);
2059 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
2060 usb_wait_for_disconnect(&codec_queue
);
2065 LOGFQUEUE("codec < default");
2068 if (audio_codec_loaded
)
2077 audio_codec_loaded
= false;
2081 case Q_CODEC_LOAD_DISK
:
2083 LOGFQUEUE("codec < Q_CODEC_LOAD");
2086 if (ci
.new_track
|| status
!= CODEC_OK
)
2090 logf("Codec failure");
2091 gui_syncsplash(HZ
*2, "Codec failure");
2094 if (!codec_load_next_track())
2096 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2097 /* End of playlist */
2098 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2104 logf("Codec finished");
2107 /* Wait for the audio to stop playing before
2108 * triggering the WPS exit */
2109 while(pcm_is_playing())
2111 curtrack_id3
.elapsed
=
2112 curtrack_id3
.length
- pcmbuf_get_latency();
2115 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2116 /* End of playlist */
2117 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2122 if (CUR_TI
->codec_hid
> 0)
2124 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2125 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
2129 const char *codec_fn
=
2130 get_codec_filename(curtrack_id3
.codectype
);
2131 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2132 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
2133 (intptr_t)codec_fn
);
2138 #ifdef AUDIO_HAVE_RECORDING
2139 case Q_ENCODER_LOAD_DISK
:
2140 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2142 if (status
== CODEC_OK
)
2145 logf("Encoder failure");
2146 gui_syncsplash(HZ
*2, "Encoder failure");
2148 if (ci
.enc_codec_loaded
< 0)
2151 logf("Encoder failed to load");
2152 ci
.enc_codec_loaded
= -1;
2154 #endif /* AUDIO_HAVE_RECORDING */
2157 LOGFQUEUE("codec < default");
2164 /* --- Audio thread --- */
2166 static bool audio_filebuf_is_lowdata(void)
2168 return bufused() < AUDIO_FILEBUF_CRITICAL
;
2171 static bool audio_have_tracks(void)
2173 return track_ridx
!= track_widx
|| CUR_TI
->filesize
;
2176 static bool audio_have_free_tracks(void)
2178 if (track_widx
< track_ridx
)
2179 return track_widx
+ 1 < track_ridx
;
2180 else if (track_ridx
== 0)
2181 return track_widx
< MAX_TRACK
- 1;
2186 int audio_track_count(void)
2188 if (audio_have_tracks())
2190 int relative_track_widx
= track_widx
;
2192 if (track_ridx
> track_widx
)
2193 relative_track_widx
+= MAX_TRACK
;
2195 return relative_track_widx
- track_ridx
+ 1;
2201 long audio_filebufused(void)
2203 return (long) bufused();
2206 /* Count the data BETWEEN the selected tracks */
2207 static size_t audio_buffer_count_tracks(int from_track
, int to_track
)
2210 bool need_wrap
= to_track
< from_track
;
2214 if (++from_track
>= MAX_TRACK
)
2216 from_track
-= MAX_TRACK
;
2220 if (from_track
>= to_track
&& !need_wrap
)
2223 amount
+= tracks
[from_track
].codecsize
+ tracks
[from_track
].filesize
;
2228 static bool audio_buffer_wind_forward(int new_track_ridx
, int old_track_ridx
)
2233 /* Start with the remainder of the previously playing track */
2234 amount
= tracks
[old_track_ridx
].filesize
- ci
.curpos
;
2235 /* Then collect all data from tracks in between them */
2236 amount
+= audio_buffer_count_tracks(old_track_ridx
, new_track_ridx
);
2237 logf("bwf:%ldB", (long) amount
);
2239 if (amount
> bufused())
2242 /* Wind the buffer to the beginning of the target track or its codec */
2243 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
2248 static bool audio_buffer_wind_backward(int new_track_ridx
, int old_track_ridx
)
2251 /* Available buffer data */
2253 /* Start with the previously playing track's data and our data */
2257 buf_back
= RINGBUF_SUB(buf_ridx
, buf_widx
);
2259 /* If we're not just resetting the current track */
2260 if (new_track_ridx
!= old_track_ridx
)
2262 /* Need to wind to before the old track's codec and our filesize */
2263 amount
+= tracks
[old_track_ridx
].codecsize
;
2264 amount
+= tracks
[new_track_ridx
].filesize
;
2266 /* Rewind the old track to its beginning */
2267 tracks
[old_track_ridx
].available
=
2268 tracks
[old_track_ridx
].filesize
- tracks
[old_track_ridx
].filerem
;
2271 /* If the codec was ever buffered */
2272 if (tracks
[new_track_ridx
].codecsize
)
2274 /* Add the codec to the needed size */
2275 amount
+= tracks
[new_track_ridx
].codecsize
;
2276 tracks
[new_track_ridx
].has_codec
= true;
2279 /* Then collect all data from tracks between new and old */
2280 amount
+= audio_buffer_count_tracks(new_track_ridx
, old_track_ridx
);
2282 /* Do we have space to make this skip? */
2283 if (amount
> buf_back
)
2286 logf("bwb:%ldB",amount
);
2288 /* Rewind the buffer to the beginning of the target track or its codec */
2289 buf_ridx
= RINGBUF_SUB(buf_ridx
, amount
);
2291 /* Reset to the beginning of the new track */
2292 tracks
[new_track_ridx
].available
= tracks
[new_track_ridx
].filesize
;
2297 static void audio_update_trackinfo(void)
2299 ci
.filesize
= CUR_TI
->filesize
;
2300 curtrack_id3
.elapsed
= 0;
2301 curtrack_id3
.offset
= 0;
2302 ci
.id3
= &curtrack_id3
;
2304 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2307 /* Yield to codecs for as long as possible if they are in need of data
2308 * return true if the caller should break to let the audio thread process
2310 static bool audio_yield_codecs(void)
2314 if (!queue_empty(&audio_queue
))
2317 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
2318 && !ci
.stop_codec
&& playing
&& !audio_filebuf_is_lowdata())
2325 if (!queue_empty(&audio_queue
))
2332 static void audio_clear_track_entries(bool clear_unbuffered
)
2334 int cur_idx
= track_widx
;
2337 logf("Clearing tracks:%d/%d, %d", track_ridx
, track_widx
, clear_unbuffered
);
2340 /* Loop over all tracks from write-to-read */
2344 cur_idx
&= MAX_TRACK_MASK
;
2346 if (cur_idx
== track_ridx
)
2349 /* If the track is buffered, conditionally clear/notify,
2350 * otherwise clear the track if that option is selected */
2351 if (tracks
[cur_idx
].event_sent
)
2355 /* If there is an unbuffer callback, call it, otherwise,
2356 * just clear the track */
2357 if (track_unbuffer_callback
)
2358 track_unbuffer_callback(&tracks
[last_idx
].id3
, false);
2360 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2364 else if (clear_unbuffered
)
2365 memset(&tracks
[cur_idx
], 0, sizeof(struct track_info
));
2368 /* We clear the previous instance of a buffered track throughout
2369 * the above loop to facilitate 'last' detection. Clear/notify
2370 * the last track here */
2373 if (track_unbuffer_callback
)
2374 track_unbuffer_callback(&tracks
[last_idx
].id3
, true);
2375 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2379 for (cur_idx
= track_widx
; cur_idx
!= track_ridx
;
2380 cur_idx
++, cur_idx
&= MAX_TRACK_MASK
)
2382 bufclose(tracks
[cur_idx
].audio_hid
);
2383 bufclose(tracks
[cur_idx
].id3_hid
);
2384 bufclose(tracks
[cur_idx
].codec_hid
);
2388 /* FIXME: This code should be made more generic and move to metadata.c */
2389 static void audio_strip_tags(void)
2393 static const unsigned char tag
[] = "TAG";
2394 static const unsigned char apetag
[] = "APETAGEX";
2397 size_t len
, version
;
2399 tag_idx
= RINGBUF_SUB(buf_widx
, 128);
2401 if (bufused() > 128 && tag_idx
> buf_ridx
)
2404 for(i
= 0;i
< 3;i
++)
2406 if(filebuf
[cur_idx
] != tag
[i
])
2409 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2412 /* Skip id3v1 tag */
2413 logf("Skipping ID3v1 tag");
2415 tracks
[track_widx
].available
-= 128;
2416 tracks
[track_widx
].filesize
-= 128;
2420 /* Check for APE tag (look for the APE tag footer) */
2421 tag_idx
= RINGBUF_SUB(buf_widx
, 32);
2423 if (bufused() > 32 && tag_idx
> buf_ridx
)
2426 for(i
= 0;i
< 8;i
++)
2428 if(filebuf
[cur_idx
] != apetag
[i
])
2431 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2434 /* Read the version and length from the footer */
2435 version
= filebuf
[tag_idx
+8] | (filebuf
[tag_idx
+9] << 8) |
2436 (filebuf
[tag_idx
+10] << 16) | (filebuf
[tag_idx
+11] << 24);
2437 len
= filebuf
[tag_idx
+12] | (filebuf
[tag_idx
+13] << 8) |
2438 (filebuf
[tag_idx
+14] << 16) | (filebuf
[tag_idx
+15] << 24);
2439 if (version
== 2000)
2440 len
+= 32; /* APEv2 has a 32 byte header */
2443 if (bufused() > len
)
2445 logf("Skipping APE tag (%ldB)", len
);
2446 buf_widx
= RINGBUF_SUB(buf_widx
, len
);
2447 tracks
[track_widx
].available
-= len
;
2448 tracks
[track_widx
].filesize
-= len
;
2454 /* Returns true if a whole file is read, false otherwise */
2455 static bool audio_read_file(size_t minimum
)
2458 bool ret_val
= false;
2460 /* If we're called and no file is open, this is an error */
2463 logf("Bad fd in arf");
2464 /* Give some hope of miraculous recovery by forcing a track reload */
2465 tracks
[track_widx
].filesize
= 0;
2466 /* Stop this buffering run */
2470 trigger_cpu_boost();
2471 while (tracks
[track_widx
].filerem
> 0)
2477 /* copy_n is the largest chunk that is safe to read */
2478 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2480 /* buf_widx == buf_ridx is defined as buffer empty, not buffer full */
2481 if (RINGBUF_ADD_CROSS(buf_widx
,copy_n
,buf_ridx
) >= 0)
2484 /* rc is the actual amount read */
2485 rc
= read(current_fd
, &filebuf
[buf_widx
], copy_n
);
2489 logf("File ended %ldB early", tracks
[track_widx
].filerem
);
2490 tracks
[track_widx
].filesize
-= tracks
[track_widx
].filerem
;
2491 tracks
[track_widx
].filerem
= 0;
2495 /* How much of the playing track did we overwrite */
2496 if (buf_widx
== CUR_TI
->buf_idx
)
2498 /* Special handling; zero or full overlap? */
2499 if (track_widx
== track_ridx
&& CUR_TI
->available
== 0)
2505 overlap
= RINGBUF_ADD_CROSS(buf_widx
,rc
,CUR_TI
->buf_idx
);
2507 if ((unsigned)rc
> tracks
[track_widx
].filerem
)
2509 logf("Bad: rc-filerem=%ld, fixing", rc
-tracks
[track_widx
].filerem
);
2510 tracks
[track_widx
].filesize
+= rc
- tracks
[track_widx
].filerem
;
2511 tracks
[track_widx
].filerem
= rc
;
2514 /* Advance buffer */
2515 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2516 tracks
[track_widx
].available
+= rc
;
2517 tracks
[track_widx
].filerem
-= rc
;
2519 /* If we write into the playing track, adjust it's buffer info */
2522 CUR_TI
->buf_idx
+= overlap
;
2523 CUR_TI
->start_pos
+= overlap
;
2526 /* For a rebuffer, fill at least this minimum */
2527 if (minimum
> (unsigned)rc
)
2529 /* Let the codec process up to the watermark */
2530 /* Break immediately if this is a quick buffer, or there is an event */
2531 else if (minimum
|| audio_yield_codecs())
2533 /* Exit quickly, but don't stop the overall buffering process */
2539 if (tracks
[track_widx
].filerem
== 0)
2541 logf("Finished buf:%ldB", tracks
[track_widx
].filesize
);
2547 track_widx
&= MAX_TRACK_MASK
;
2549 tracks
[track_widx
].filesize
= 0;
2554 logf("%s buf:%ldB", ret_val
?"Quick":"Partially",
2555 tracks
[track_widx
].filesize
- tracks
[track_widx
].filerem
);
2561 static bool audio_loadcodec(bool start_play
)
2568 char codec_path
[MAX_PATH
]; /* Full path to codec */
2570 if (tracks
[track_widx
].id3_hid
<= 0)
2573 const char * codec_fn
=
2574 get_codec_filename(bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
);
2575 if (codec_fn
== NULL
)
2578 tracks
[track_widx
].codec_hid
= 0;
2582 /* Load the codec directly from disk and save some memory. */
2583 track_ridx
= track_widx
;
2584 ci
.filesize
= CUR_TI
->filesize
;
2585 ci
.id3
= &curtrack_id3
;
2586 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2588 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2589 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
2594 /* If we already have another track than this one buffered */
2595 if (track_widx
!= track_ridx
)
2597 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
2599 /* If the previous codec is the same as this one, there is no need
2600 * to put another copy of it on the file buffer */
2601 if (get_codec_base_type(
2602 bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
) ==
2603 get_codec_base_type(
2604 bufgetid3(tracks
[prev_track
].id3_hid
)->codectype
)
2605 && audio_codec_loaded
)
2607 logf("Reusing prev. codec");
2613 codec_get_full_path(codec_path
, codec_fn
);
2615 fd
= open(codec_path
, O_RDONLY
);
2618 logf("Codec doesn't exist!");
2622 tracks
[track_widx
].codecsize
= filesize(fd
);
2624 tracks
[track_widx
].codec_hid
= bufopen(codec_path
, 0, TYPE_CODEC
);
2625 if (tracks
[track_widx
].codec_hid
< 0)
2627 logf("Not enough space");
2633 logf("Done: %ldB", size
);
2638 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2639 static void audio_set_elapsed(struct mp3entry
* id3
)
2641 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
2642 id3
->offset
- id3
->first_frame_offset
: 0;
2645 if ( id3
->has_toc
) {
2646 /* calculate elapsed time using TOC */
2648 unsigned int remainder
, plen
, relpos
, nextpos
;
2650 /* find wich percent we're at */
2651 for (i
=0; i
<100; i
++ )
2652 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
2659 relpos
= id3
->toc
[i
];
2662 nextpos
= id3
->toc
[i
+1];
2666 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
2668 /* set time for this percent (divide before multiply to prevent
2669 overflow on long files. loss of precision is negligible on
2671 id3
->elapsed
= i
* (id3
->length
/ 100);
2673 /* calculate remainder time */
2674 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
2675 id3
->elapsed
+= (((remainder
* 100) / plen
) *
2676 (id3
->length
/ 10000));
2679 /* no TOC exists. set a rough estimate using average bitrate */
2680 int tpk
= id3
->length
/
2681 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
2683 id3
->elapsed
= offset
/ 1024 * tpk
;
2688 /* constant bitrate, use exact calculation */
2689 if (id3
->bitrate
!= 0)
2690 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
2694 static bool audio_load_track(int offset
, bool start_play
, bool rebuffer
)
2700 struct mp3entry id3
;
2702 /* Stop buffer filling if there is no free track entries.
2703 Don't fill up the last track entry (we wan't to store next track
2705 if (!audio_have_free_tracks())
2707 logf("No free tracks");
2713 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
2714 /* Get track name from current playlist read position. */
2715 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
2717 /* Handle broken playlists. */
2718 fd
= open(trackname
, O_RDONLY
);
2721 logf("Open failed");
2722 /* Skip invalid entry from playlist. */
2723 playlist_skip_entry(NULL
, last_peek_offset
);
2731 logf("End-of-playlist");
2732 playlist_end
= true;
2736 tracks
[track_widx
].audio_hid
= bufopen(trackname
, offset
, TYPE_AUDIO
);
2738 if (tracks
[track_widx
].audio_hid
<= 0)
2741 /* Set default values */
2744 int last_codec
= current_codec
;
2746 set_current_codec(CODEC_IDX_AUDIO
);
2747 conf_watermark
= AUDIO_DEFAULT_WATERMARK
;
2748 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
2749 conf_preseek
= AUDIO_REBUFFER_GUESS_SIZE
;
2750 dsp_configure(DSP_RESET
, 0);
2751 set_current_codec(last_codec
);
2754 /* Get track metadata if we don't already have it. */
2755 if (!tracks
[track_widx
].taginfo_ready
)
2757 if (get_metadata(&id3
, fd
, trackname
))
2759 tracks
[track_widx
].taginfo_ready
= true;
2760 tracks
[track_widx
].id3_hid
= bufalloc(&id3
, sizeof(struct mp3entry
),
2764 track_changed
= true;
2765 playlist_update_resume_info(audio_current_track());
2770 logf("mde:%s!",trackname
);
2772 /* Skip invalid entry from playlist. */
2773 playlist_skip_entry(NULL
, last_peek_offset
);
2774 tracks
[track_widx
].taginfo_ready
= false;
2781 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
2783 char cuepath
[MAX_PATH
];
2785 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
2787 if (look_for_cuesheet_file(trackname
, cuepath
) &&
2788 parse_cuesheet(cuepath
, cue
))
2790 strcpy((cue
)->audio_filename
, trackname
);
2792 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
2797 /* Load the codec. */
2798 if (!audio_loadcodec(start_play
))
2800 /* Set filesize to zero to indicate no file was loaded. */
2801 /* tracks[track_widx].filesize = 0;
2802 tracks[track_widx].filerem = 0;
2806 if (tracks
[track_widx
].codecsize
)
2808 /* No space for codec on buffer, not an error */
2809 tracks
[track_widx
].codecsize
= 0;
2813 /* This is an error condition, either no codec was found, or reading
2814 * the codec file failed part way through, either way, skip the track */
2815 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
2816 /* We should not use gui_syncplash from audio thread! */
2817 gui_syncsplash(HZ
*2, msgbuf
);
2818 /* Skip invalid entry from playlist. */
2819 playlist_skip_entry(NULL
, last_peek_offset
);
2820 tracks
[track_widx
].taginfo_ready
= false;
2824 struct mp3entry
*track_id3
= bufgetid3(tracks
[track_widx
].id3_hid
);
2826 /* tracks[track_widx].start_pos = 0; */
2827 set_filebuf_watermark(buffer_margin
);
2828 track_id3
->elapsed
= 0;
2833 switch (id3
.codectype
) {
2837 track_id3
->offset
= offset
;
2838 audio_set_elapsed(&id3
);
2843 track_id3
->offset
= offset
;
2844 track_id3
->elapsed
= id3
.length
/ 2;
2848 case AFMT_OGG_VORBIS
:
2856 track_id3
->offset
= offset
;
2861 logf("alt:%s", trackname
);
2862 /* tracks[track_widx].buf_idx = buf_widx; */
2866 return audio_read_file(rebuffer
);
2869 static bool audio_read_next_metadata(void)
2876 next_idx
= track_widx
;
2877 if (tracks
[next_idx
].taginfo_ready
)
2880 next_idx
&= MAX_TRACK_MASK
;
2882 if (tracks
[next_idx
].taginfo_ready
)
2886 trackname
= playlist_peek(last_peek_offset
+ 1);
2890 fd
= open(trackname
, O_RDONLY
);
2894 struct mp3entry id3
;
2896 status
= get_metadata(&id3
, fd
, trackname
);
2897 /* Preload the glyphs in the tags */
2900 tracks
[next_idx
].taginfo_ready
= true;
2902 lcd_getstringsize(id3
.title
, NULL
, NULL
);
2904 lcd_getstringsize(id3
.artist
, NULL
, NULL
);
2906 lcd_getstringsize(id3
.album
, NULL
, NULL
);
2913 /* Send callback events to notify about new tracks. */
2914 static void audio_generate_postbuffer_events(void)
2920 logf("Postbuffer:%d/%d",track_ridx
,track_widx
);
2922 if (audio_have_tracks())
2924 cur_idx
= track_ridx
;
2927 if (!tracks
[cur_idx
].event_sent
)
2929 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2931 /* Mark the event 'sent' even if we don't really send one */
2932 tracks
[last_idx
].event_sent
= true;
2933 if (track_buffer_callback
)
2934 track_buffer_callback(&tracks
[last_idx
].id3
, false);
2938 if (cur_idx
== track_widx
)
2941 cur_idx
&= MAX_TRACK_MASK
;
2944 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2946 tracks
[last_idx
].event_sent
= true;
2947 if (track_buffer_callback
)
2948 track_buffer_callback(&tracks
[last_idx
].id3
, true);
2954 static bool audio_initialize_buffer_fill(bool clear_tracks
)
2956 /* Don't initialize if we're already initialized */
2960 logf("Starting buffer fill");
2962 /* Set the filling flag true before calling audio_clear_tracks as that
2963 * function can yield and we start looping. */
2967 audio_clear_track_entries(false);
2969 /* Save the current resume position once. */
2970 playlist_update_resume_info(audio_current_track());
2975 static void audio_fill_file_buffer(
2976 bool start_play
, bool rebuffer
, size_t offset
)
2978 bool had_next_track
= audio_next_track() != NULL
;
2979 bool continue_buffering
;
2981 /* Must reset the buffer before use if trashed or voice only - voice
2982 file size shouldn't have changed so we can go straight from
2983 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
2984 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
2985 audio_reset_buffer();
2987 if (!audio_initialize_buffer_fill(!start_play
))
2990 continue_buffering
= audio_load_track(offset
, start_play
, rebuffer
);
2992 if (!had_next_track
&& audio_next_track())
2993 track_changed
= true;
2995 audio_read_next_metadata();
2998 static void audio_rebuffer(void)
3000 logf("Forcing rebuffer");
3003 /* Stop in progress fill, and clear open file descriptor */
3004 if (current_fd
>= 0)
3011 /* Reset buffer and track pointers */
3012 CUR_TI
->buf_idx
= buf_ridx
= buf_widx
= 0;
3013 track_widx
= track_ridx
;
3014 audio_clear_track_entries(true);
3015 CUR_TI
->available
= 0;
3017 /* Fill the buffer */
3018 last_peek_offset
= -1;
3019 CUR_TI
->filesize
= 0;
3020 CUR_TI
->start_pos
= 0;
3023 if (!CUR_TI
->taginfo_ready
)
3024 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
3026 audio_fill_file_buffer(false, true, 0);
3030 static int audio_check_new_track(void)
3032 int track_count
= audio_track_count();
3033 int old_track_ridx
= track_ridx
;
3039 if (playlist_next_dir(ci
.new_track
))
3042 CUR_TI
->taginfo_ready
= false;
3048 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3049 return Q_CODEC_REQUEST_FAILED
;
3056 /* If the playlist isn't that big */
3057 if (!playlist_check(ci
.new_track
))
3059 if (ci
.new_track
>= 0)
3061 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3062 return Q_CODEC_REQUEST_FAILED
;
3064 /* Find the beginning backward if the user over-skips it */
3065 while (!playlist_check(++ci
.new_track
))
3066 if (ci
.new_track
>= 0)
3068 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3069 return Q_CODEC_REQUEST_FAILED
;
3072 /* Update the playlist */
3073 last_peek_offset
-= ci
.new_track
;
3075 if (playlist_next(ci
.new_track
) < 0)
3077 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3078 return Q_CODEC_REQUEST_FAILED
;
3084 new_playlist
= false;
3087 /* Save the old track */
3088 /* prev_ti = CUR_TI; */
3090 /* Move to the new track */
3091 track_ridx
+= ci
.new_track
;
3092 track_ridx
&= MAX_TRACK_MASK
;
3095 playlist_end
= false;
3097 track_changed
= !automatic_skip
;
3099 /* If it is not safe to even skip this many track entries */
3100 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
3103 CUR_TI
->taginfo_ready
= false;
3108 forward
= ci
.new_track
> 0;
3111 /* If the target track is clearly not in memory */
3112 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
3118 /* The track may be in memory, see if it really is */
3121 if (!audio_buffer_wind_forward(track_ridx
, old_track_ridx
))
3126 int cur_idx
= track_ridx
;
3127 bool taginfo_ready
= true;
3128 bool wrap
= track_ridx
> old_track_ridx
;
3133 cur_idx
&= MAX_TRACK_MASK
;
3134 if (!(wrap
|| cur_idx
< old_track_ridx
))
3137 /* If we hit a track in between without valid tag info, bail */
3138 if (!tracks
[cur_idx
].taginfo_ready
)
3140 taginfo_ready
= false;
3144 tracks[cur_idx].available = tracks[cur_idx].filesize;
3145 if (tracks[cur_idx].codecsize)
3146 tracks[cur_idx].has_codec = true;*/
3150 if (!audio_buffer_wind_backward(track_ridx
, old_track_ridx
))
3155 CUR_TI
->taginfo_ready
= false;
3161 audio_update_trackinfo();
3162 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3163 return Q_CODEC_REQUEST_COMPLETE
;
3166 static int audio_rebuffer_and_seek(size_t newpos
)
3169 size_t real_preseek
;
3173 /* (Re-)open current track's file handle. */
3174 trackname
= playlist_peek(0);
3175 fd
= open(trackname
, O_RDONLY
);
3178 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3179 return Q_CODEC_REQUEST_FAILED
;
3182 if (current_fd
>= 0)
3186 playlist_end
= false;
3190 /* Clear codec buffer. */
3191 track_widx
= track_ridx
;
3192 tracks
[track_widx
].buf_idx
= buf_widx
= buf_ridx
= 0;
3194 last_peek_offset
= 0;
3196 audio_initialize_buffer_fill(true);
3198 /* This may have been tweaked by the id3v1 code */
3199 CUR_TI
->filesize
=filesize(fd
);
3200 if (newpos
> conf_preseek
)
3202 CUR_TI
->start_pos
= newpos
- conf_preseek
;
3203 lseek(current_fd
, CUR_TI
->start_pos
, SEEK_SET
);
3204 CUR_TI
->filerem
= CUR_TI
->filesize
- CUR_TI
->start_pos
;
3205 real_preseek
= conf_preseek
;
3209 CUR_TI
->start_pos
= 0;
3210 CUR_TI
->filerem
= CUR_TI
->filesize
;
3211 real_preseek
= newpos
;
3214 CUR_TI
->available
= 0;
3216 audio_read_file(real_preseek
);
3218 /* Account for the data we just read that is 'behind' us now */
3219 CUR_TI
->available
-= real_preseek
;
3221 buf_ridx
= RINGBUF_ADD(buf_ridx
, real_preseek
);
3223 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3224 return Q_CODEC_REQUEST_COMPLETE
;
3228 void audio_set_track_buffer_event(void (*handler
)(struct mp3entry
*id3
,
3231 track_buffer_callback
= handler
;
3234 void audio_set_track_unbuffer_event(void (*handler
)(struct mp3entry
*id3
,
3237 track_unbuffer_callback
= handler
;
3240 void audio_set_track_changed_event(void (*handler
)(struct mp3entry
*id3
))
3242 track_changed_callback
= handler
;
3245 unsigned long audio_prev_elapsed(void)
3247 return prev_track_elapsed
;
3250 static void audio_stop_codec_flush(void)
3252 ci
.stop_codec
= true;
3255 while (audio_codec_loaded
)
3258 /* If the audio codec is not loaded any more, and the audio is still
3259 * playing, it is now and _only_ now safe to call this function from the
3261 if (pcm_is_playing())
3263 pcmbuf_pause(paused
);
3266 static void audio_stop_playback(void)
3268 /* If we were playing, save resume information */
3271 struct mp3entry
*id3
= NULL
;
3273 if (!playlist_end
|| !ci
.stop_codec
)
3275 /* Set this early, the outside code yields and may allow the codec
3276 to try to wait for a reply on a buffer wait */
3277 ci
.stop_codec
= true;
3278 id3
= audio_current_track();
3281 /* Save the current playing spot, or NULL if the playlist has ended */
3282 playlist_update_resume_info(id3
);
3284 prev_track_elapsed
= curtrack_id3
.elapsed
;
3286 /* Increment index so runtime info is saved in audio_clear_track_entries().
3287 * Done here, as audio_stop_playback() may be called more than once.
3288 * Don't update runtime unless playback is stopped because of end of playlist.
3289 * Updating runtime when manually stopping a tracks, can destroy autoscores
3295 track_ridx
&= MAX_TRACK_MASK
;
3301 audio_stop_codec_flush();
3304 /* Mark all entries null. */
3305 audio_clear_track_entries(false);
3308 static void audio_play_start(size_t offset
)
3310 #if INPUT_SRC_CAPS != 0
3311 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
3312 audio_set_output_source(AUDIO_SRC_PLAYBACK
);
3315 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
3317 audio_stop_codec_flush();
3319 track_changed
= true;
3320 playlist_end
= false;
3328 sound_set_volume(global_settings
.volume
);
3329 track_widx
= track_ridx
= 0;
3331 /* Mark all entries null. */
3332 memset(tracks
, 0, sizeof(struct track_info
) * MAX_TRACK
);
3334 last_peek_offset
= -1;
3336 /* Officially playing */
3337 queue_reply(&audio_queue
, 1);
3339 audio_fill_file_buffer(true, false, offset
);
3341 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
3342 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
3346 /* Invalidates all but currently playing track. */
3347 static void audio_invalidate_tracks(void)
3350 if (audio_have_tracks())
3352 last_peek_offset
= 0;
3353 playlist_end
= false;
3354 track_widx
= track_ridx
;
3356 /* Mark all other entries null (also buffered wrong metadata). */
3357 audio_clear_track_entries(true);
3359 /* If the current track is fully buffered, advance the write pointer */
3360 if (tracks
[track_widx
].filerem
== 0)
3361 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
3363 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3365 audio_read_next_metadata();
3370 static void audio_new_playlist(void)
3372 /* Prepare to start a new fill from the beginning of the playlist */
3373 last_peek_offset
= -1;
3374 if (audio_have_tracks())
3377 skipped_during_pause
= true;
3378 playlist_end
= false;
3379 track_widx
= track_ridx
;
3380 audio_clear_track_entries(true);
3383 track_widx
&= MAX_TRACK_MASK
;
3385 /* Mark the current track as invalid to prevent skipping back to it */
3386 CUR_TI
->taginfo_ready
= false;
3389 /* Signal the codec to initiate a track change forward */
3390 new_playlist
= true;
3393 /* Officially playing */
3394 queue_reply(&audio_queue
, 1);
3396 audio_fill_file_buffer(false, true, 0);
3399 static void audio_initiate_track_change(long direction
)
3401 playlist_end
= false;
3402 ci
.new_track
+= direction
;
3403 wps_offset
-= direction
;
3405 skipped_during_pause
= true;
3408 static void audio_initiate_dir_change(long direction
)
3410 playlist_end
= false;
3412 ci
.new_track
= direction
;
3414 skipped_during_pause
= true;
3418 * Layout audio buffer as follows - iram buffer depends on target:
3419 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
3421 static void audio_reset_buffer(void)
3423 /* see audio_get_recording_buffer if this is modified */
3424 logf("audio_reset_buffer");
3426 /* If the setup of anything allocated before the file buffer is
3427 changed, do check the adjustments after the buffer_alloc call
3428 as it will likely be affected and need sliding over */
3430 /* Initially set up file buffer as all space available */
3431 malloc_buf
= audiobuf
+ talk_get_bufsize();
3432 /* Align the malloc buf to line size. Especially important to cf
3433 targets that do line reads/writes. */
3434 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
3435 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
3436 filebuflen
= audiobufend
- filebuf
;
3438 /* Allow for codec swap space at end of audio buffer */
3439 if (talk_voice_required())
3441 /* Layout of swap buffer:
3442 * #ifdef IRAM_STEAL (dedicated iram_buf):
3443 * |iram_buf|...audiobuf...|dram_buf|audiobufend
3445 * audiobuf...|dram_buf|iram_buf|audiobufend
3447 #ifdef PLAYBACK_VOICE
3448 /* Check for an absolutely nasty situation which should never,
3449 ever happen - frankly should just panic */
3450 if (voice_codec_loaded
&& current_codec
!= CODEC_IDX_VOICE
)
3452 logf("buffer reset with voice swapped");
3454 /* line align length which line aligns the calculations below since
3455 all sizes are also at least line aligned - needed for memswap128 */
3458 filebuflen
-= CODEC_SIZE
;
3460 filebuflen
-= CODEC_SIZE
+ CODEC_IRAM_SIZE
;
3462 /* Allocate buffers for swapping voice <=> audio */
3463 /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
3464 and out of the way of buffer usage or else a call to audio_get_buffer
3465 and subsequent buffer use might trash the swap space. A plugin
3466 initializing IRAM after getting the full buffer would present similar
3467 problem. Options include: failing the request if the other buffer
3468 has been obtained already or never allowing use of the voice IRAM
3469 buffer within the audio buffer. Using buffer_alloc basically
3470 implements the second in a more convenient way. */
3471 dram_buf
= filebuf
+ filebuflen
;
3474 /* Allocate voice IRAM swap buffer once */
3475 if (iram_buf
== NULL
)
3477 iram_buf
= buffer_alloc(CODEC_IRAM_SIZE
);
3478 /* buffer_alloc moves audiobuf; this is safe because only the end
3479 * has been touched so far in this function and the address of
3480 * filebuf + filebuflen is not changed */
3481 malloc_buf
+= CODEC_IRAM_SIZE
;
3482 filebuf
+= CODEC_IRAM_SIZE
;
3483 filebuflen
-= CODEC_IRAM_SIZE
;
3486 /* Allocate iram_buf after dram_buf */
3487 iram_buf
= dram_buf
+ CODEC_SIZE
;
3488 #endif /* IRAM_STEAL */
3489 #endif /* PLAYBACK_VOICE */
3493 #ifdef PLAYBACK_VOICE
3494 /* No swap buffers needed */
3500 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
3501 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
3503 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
3504 will already be line aligned */
3507 /* Set the high watermark as 75% full...or 25% empty :) */
3509 high_watermark
= 3*filebuflen
/ 4;
3512 /* Clear any references to the file buffer */
3513 buffer_state
= BUFFER_STATE_INITIALIZED
;
3515 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
3516 /* Make sure everything adds up - yes, some info is a bit redundant but
3517 aids viewing and the sumation of certain variables should add up to
3518 the location of others. */
3521 unsigned char * pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
3522 logf("mabuf: %08X", (unsigned)malloc_buf
);
3523 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
3524 logf("fbuf: %08X", (unsigned)filebuf
);
3525 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
3526 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
3527 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
3528 logf("pcmb: %08X", (unsigned)pcmbuf
);
3529 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
3532 logf("dramb: %08X", (unsigned)dram_buf
);
3533 logf("drambe: %08X", (unsigned)(dram_buf
+ CODEC_SIZE
));
3537 logf("iramb: %08X", (unsigned)iram_buf
);
3538 logf("irambe: %08X", (unsigned)(iram_buf
+ CODEC_IRAM_SIZE
));
3545 /* we dont want this rebuffering on targets with little ram
3546 because the disk may never spin down */
3547 static bool ata_fillbuffer_callback(void)
3549 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
, 0);
3554 static void audio_thread(void)
3556 struct queue_event ev
;
3560 #ifdef PLAYBACK_VOICE
3561 /* Unlock semaphore that init stage locks before creating this thread */
3562 semaphore_release(&sem_codecthread
);
3564 /* Buffers must be set up by now - should panic - really */
3565 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
3567 logf("audio_thread start: no buffer");
3570 /* Have to wait for voice to load up or else the codec swap will be
3571 invalid when an audio codec is loaded */
3572 wait_for_voice_swap_in();
3579 queue_wait_w_tmo(&audio_queue
, &ev
, 0);
3580 if (ev
.id
== SYS_TIMEOUT
)
3581 ev
.id
= Q_AUDIO_FILL_BUFFER
;
3585 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
3587 if (playing
&& (ev
.id
== SYS_TIMEOUT
) &&
3588 (bufused() < high_watermark
))
3589 register_ata_idle_func(ata_fillbuffer_callback
);
3596 case Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
:
3597 /* only fill if the disk is still spining */
3599 if (!ata_disk_is_active())
3602 #endif /* MEM > 8 */
3603 /* else fall through to Q_AUDIO_FILL_BUFFER */
3604 case Q_AUDIO_FILL_BUFFER
:
3605 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3607 if (!playing
|| playlist_end
|| ci
.stop_codec
)
3609 audio_fill_file_buffer(false, false, 0);
3614 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3615 if (playing
&& ev
.data
<= 0)
3616 audio_new_playlist();
3619 audio_stop_playback();
3620 audio_play_start((size_t)ev
.data
);
3625 LOGFQUEUE("audio < Q_AUDIO_STOP");
3627 audio_stop_playback();
3629 queue_clear(&audio_queue
);
3633 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3634 if (!(bool) ev
.data
&& skipped_during_pause
&& !pcmbuf_is_crossfade_active())
3635 pcmbuf_play_stop(); /* Flush old track on resume after skip */
3636 skipped_during_pause
= false;
3639 pcmbuf_pause((bool)ev
.data
);
3640 paused
= (bool)ev
.data
;
3644 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3645 audio_initiate_track_change((long)ev
.data
);
3648 case Q_AUDIO_PRE_FF_REWIND
:
3649 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3655 case Q_AUDIO_FF_REWIND
:
3656 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3659 ci
.seek_time
= (long)ev
.data
+1;
3662 case Q_AUDIO_REBUFFER_SEEK
:
3663 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
3664 queue_reply(&audio_queue
, audio_rebuffer_and_seek(ev
.data
));
3667 case Q_AUDIO_CHECK_NEW_TRACK
:
3668 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3669 queue_reply(&audio_queue
, audio_check_new_track());
3672 case Q_AUDIO_DIR_SKIP
:
3673 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3674 playlist_end
= false;
3675 audio_initiate_dir_change(ev
.data
);
3679 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3680 audio_invalidate_tracks();
3683 case Q_AUDIO_TRACK_CHANGED
:
3684 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3685 if (track_changed_callback
)
3686 track_changed_callback(&curtrack_id3
);
3687 track_changed
= true;
3688 playlist_update_resume_info(audio_current_track());
3692 case SYS_USB_CONNECTED
:
3693 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3695 audio_stop_playback();
3696 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
3697 usb_wait_for_disconnect(&audio_queue
);
3702 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3706 LOGFQUEUE("audio < default");
3711 #ifdef ROCKBOX_HAS_LOGF
3712 static void audio_test_track_changed_event(struct mp3entry
*id3
)
3716 logf("tce:%s", id3
->path
);
3720 /* Initialize the audio system - called from init() in main.c.
3721 * Last function because of all the references to internal symbols
3723 void audio_init(void)
3725 #ifdef PLAYBACK_VOICE
3726 static bool voicetagtrue
= true;
3727 static struct mp3entry id3_voice
;
3728 struct thread_entry
*voice_thread_p
= NULL
;
3730 struct thread_entry
*audio_thread_p
;
3732 /* Can never do this twice */
3733 if (audio_is_initialized
)
3735 logf("audio: already initialized");
3739 logf("audio: initializing");
3741 /* Initialize queues before giving control elsewhere in case it likes
3742 to send messages. Thread creation will be delayed however so nothing
3743 starts running until ready if something yields such as talk_init. */
3744 #ifdef PLAYBACK_VOICE
3745 /* Take ownership of lock to prevent playback of anything before audio
3746 hardware is initialized - audio thread unlocks it after final init
3748 semaphore_init(&sem_codecthread
, 1, 0);
3749 event_init(&event_codecthread
, EVENT_MANUAL
| STATE_SIGNALED
);
3751 queue_init(&audio_queue
, true);
3752 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
3753 queue_init(&codec_queue
, true);
3757 #ifdef ROCKBOX_HAS_LOGF
3758 audio_set_track_changed_event(audio_test_track_changed_event
);
3761 /* Initialize codec api. */
3762 ci
.read_filebuf
= codec_filebuf_callback
;
3763 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
3764 ci
.get_codec_memory
= codec_get_memory_callback
;
3765 ci
.request_buffer
= codec_request_buffer_callback
;
3766 ci
.advance_buffer
= codec_advance_buffer_callback
;
3767 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
3768 ci
.request_next_track
= codec_request_next_track_callback
;
3769 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
3770 ci
.seek_buffer
= codec_seek_buffer_callback
;
3771 ci
.seek_complete
= codec_seek_complete_callback
;
3772 ci
.set_elapsed
= codec_set_elapsed_callback
;
3773 ci
.set_offset
= codec_set_offset_callback
;
3774 ci
.configure
= codec_configure_callback
;
3775 ci
.discard_codec
= codec_discard_codec_callback
;
3777 /* Initialize voice codec api. */
3778 #ifdef PLAYBACK_VOICE
3779 memcpy(&ci_voice
, &ci
, sizeof(ci_voice
));
3780 memset(&id3_voice
, 0, sizeof(id3_voice
));
3781 ci_voice
.read_filebuf
= voice_filebuf_callback
;
3782 ci_voice
.pcmbuf_insert
= voice_pcmbuf_insert_callback
;
3783 ci_voice
.get_codec_memory
= voice_get_memory_callback
;
3784 ci_voice
.request_buffer
= voice_request_buffer_callback
;
3785 ci_voice
.advance_buffer
= voice_advance_buffer_callback
;
3786 ci_voice
.advance_buffer_loc
= voice_advance_buffer_loc_callback
;
3787 ci_voice
.request_next_track
= voice_request_next_track_callback
;
3788 ci_voice
.mp3_get_filepos
= voice_mp3_get_filepos_callback
;
3789 ci_voice
.seek_buffer
= voice_seek_buffer_callback
;
3790 ci_voice
.seek_complete
= voice_do_nothing
;
3791 ci_voice
.set_elapsed
= voice_set_elapsed_callback
;
3792 ci_voice
.set_offset
= voice_set_offset_callback
;
3793 ci_voice
.configure
= voice_configure_callback
;
3794 ci_voice
.discard_codec
= voice_do_nothing
;
3795 ci_voice
.taginfo_ready
= &voicetagtrue
;
3796 ci_voice
.id3
= &id3_voice
;
3797 id3_voice
.frequency
= 11200;
3798 id3_voice
.length
= 1000000L;
3801 /* initialize the buffer */
3804 /* audio_reset_buffer must to know the size of voice buffer so init
3808 codec_thread_p
= create_thread(
3809 codec_thread
, codec_stack
, sizeof(codec_stack
),
3810 CREATE_THREAD_FROZEN
,
3811 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
3814 audio_thread_p
= create_thread(audio_thread
, audio_stack
,
3815 sizeof(audio_stack
), CREATE_THREAD_FROZEN
,
3816 audio_thread_name
IF_PRIO(, PRIORITY_BUFFERING
)
3819 buffering_thread_p
= create_thread( buffering_thread
, buffering_stack
,
3820 sizeof(buffering_stack
), CREATE_THREAD_FROZEN
,
3821 buffering_thread_name
IF_PRIO(, PRIORITY_BUFFERING
)
3822 IF_COP(, CPU
, true));
3824 #ifdef PLAYBACK_VOICE
3825 /* TODO: Change this around when various speech codecs can be used */
3826 if (talk_voice_required())
3828 logf("Starting voice codec");
3829 queue_init(&voice_queue
, true);
3830 voice_thread_p
= create_thread(voice_thread
, voice_stack
,
3831 sizeof(voice_stack
), CREATE_THREAD_FROZEN
,
3833 IF_PRIO(, PRIORITY_PLAYBACK
) IF_COP(, CPU
));
3837 /* Set crossfade setting for next buffer init which should be about... */
3838 pcmbuf_crossfade_enable(global_settings
.crossfade
);
3840 /* ...now! Set up the buffers */
3841 audio_reset_buffer();
3843 buffering_init(filebuf
, filebuflen
);
3845 /* Probably safe to say */
3846 audio_is_initialized
= true;
3848 sound_settings_apply();
3850 eq_hw_enable(global_settings
.eq_hw_enabled
);
3852 #ifndef HAVE_FLASH_STORAGE
3853 audio_set_buffer_margin(global_settings
.buffer_margin
);
3856 /* it's safe to let the threads run now */
3857 thread_thaw(codec_thread_p
);
3858 #ifdef PLAYBACK_VOICE
3860 thread_thaw(voice_thread_p
);
3862 thread_thaw(audio_thread_p
);
3863 thread_thaw(buffering_thread_p
);