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 */
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 /* macros to enable logf for queues
102 logging on SYS_TIMEOUT can be disabled */
104 /* Define this for logf output of all queuing except SYS_TIMEOUT */
105 #define PLAYBACK_LOGQUEUES
106 /* Define this to logf SYS_TIMEOUT messages */
107 #define PLAYBACK_LOGQUEUES_SYS_TIMEOUT
110 #ifdef PLAYBACK_LOGQUEUES
111 #define LOGFQUEUE logf
113 #define LOGFQUEUE(...)
116 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
117 #define LOGFQUEUE_SYS_TIMEOUT logf
119 #define LOGFQUEUE_SYS_TIMEOUT(...)
123 /* Define one constant that includes recording related functionality */
124 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
125 #define AUDIO_HAVE_RECORDING
133 Q_AUDIO_PRE_FF_REWIND
,
135 Q_AUDIO_REBUFFER_SEEK
,
136 Q_AUDIO_CHECK_NEW_TRACK
,
138 Q_AUDIO_TRACK_CHANGED
,
143 Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
,
145 Q_CODEC_REQUEST_COMPLETE
,
146 Q_CODEC_REQUEST_FAILED
,
154 #ifdef AUDIO_HAVE_RECORDING
160 /* As defined in plugins/lib/xxx2wav.h */
162 #define MALLOC_BUFSIZE (512*1024)
163 #define GUARD_BUFSIZE (32*1024)
165 #define MALLOC_BUFSIZE (100*1024)
166 #define GUARD_BUFSIZE (8*1024)
169 /* As defined in plugin.lds */
171 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
172 #define CODEC_IRAM_SIZE ((size_t)0xc000)
173 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
174 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
175 #define CODEC_IRAM_SIZE ((size_t)0x10000)
177 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
178 #define CODEC_IRAM_SIZE ((size_t)0xc000)
181 #ifndef IBSS_ATTR_VOICE_STACK
182 #define IBSS_ATTR_VOICE_STACK IBSS_ATTR
185 bool audio_is_initialized
= false;
187 /* Variables are commented with the threads that use them: *
188 * A=audio, C=codec, V=voice. A suffix of - indicates that *
189 * the variable is read but not updated on that thread. */
190 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
192 /* Main state control */
193 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR
= false; /* Codec loaded? (C/A-) */
194 static volatile bool playing NOCACHEBSS_ATTR
= false; /* Is audio playing? (A) */
195 static volatile bool paused NOCACHEBSS_ATTR
= false; /* Is audio paused? (A/C-) */
196 static volatile bool filling IDATA_ATTR
= false; /* Is file buffer refilling? (A/C-) */
198 /* Ring buffer where compressed audio and codecs are loaded */
199 static unsigned char *filebuf
= NULL
; /* Start of buffer (A/C-) */
200 static unsigned char *malloc_buf
= NULL
; /* Start of malloc buffer (A/C-) */
201 /* FIXME: make filebuflen static */
202 size_t filebuflen
= 0; /* Size of buffer (A/C-) */
203 /* FIXME: make buf_ridx (C/A-) */
204 static volatile size_t buf_ridx IDATA_ATTR
= 0; /* Buffer read position (A/C)*/
205 static volatile size_t buf_widx IDATA_ATTR
= 0; /* Buffer write position (A/C-) */
207 /* Possible arrangements of the buffer */
208 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
209 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
210 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
211 static int buffer_state
= BUFFER_STATE_TRASHED
; /* Buffer state */
213 /* Compressed ring buffer helper macros */
214 /* Buffer pointer (p) plus value (v), wrapped if necessary */
215 #define RINGBUF_ADD(p,v) ((p+v)<filebuflen ? p+v : p+v-filebuflen)
216 /* Buffer pointer (p) minus value (v), wrapped if necessary */
217 #define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+filebuflen-v)
218 /* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
219 #define RINGBUF_ADD_CROSS(p1,v,p2) \
220 ((p1<p2)?(int)(p1+v)-(int)p2:(int)(p1+v-p2)-(int)filebuflen)
221 /* Bytes available in the buffer */
222 #define FILEBUFUSED RINGBUF_SUB(buf_widx, buf_ridx)
224 /* Track info structure about songs in the file buffer (A/C-) */
225 static struct track_info tracks
[MAX_TRACK
];
226 static volatile int track_ridx
= 0; /* Track being decoded (A/C-) */
227 static int track_widx
= 0; /* Track being buffered (A) */
229 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;
239 /* Partially loaded track file handle to continue buffering (A) */
240 static int current_fd
= -1;
242 /* Scrobbler support */
243 static unsigned long prev_track_elapsed
= 0; /* Previous track elapsed time (C/A-)*/
245 /* Track change controls */
246 static bool automatic_skip
= false; /* Who initiated in-progress skip? (C/A-) */
247 static bool playlist_end
= false; /* Has the current playlist ended? (A) */
248 static bool dir_skip
= false; /* Is a directory skip pending? (A) */
249 static bool new_playlist
= false; /* Are we starting a new playlist? (A) */
250 static int wps_offset
= 0; /* Pending track change offset, to keep WPS responsive (A) */
251 static bool skipped_during_pause
= false; /* Do we need to clear the PCM buffer when playback resumes (A) */
253 /* Callbacks which applications or plugins may set */
254 /* When the playing track has changed from the user's perspective */
255 void (*track_changed_callback
)(struct mp3entry
*id3
) = NULL
;
256 /* When a track has been buffered */
257 void (*track_buffer_callback
)(struct mp3entry
*id3
, bool last_track
) = NULL
;
258 /* When a track's buffer has been overwritten or cleared */
259 void (*track_unbuffer_callback
)(struct mp3entry
*id3
, bool last_track
) = NULL
;
262 static size_t conf_watermark
= 0; /* Level to trigger filebuf fill (A/C) FIXME */
263 static size_t conf_filechunk
= 0; /* Largest chunk the codec accepts (A/C) FIXME */
264 static size_t conf_preseek
= 0; /* Codec pre-seek margin (A/C) FIXME */
265 static size_t buffer_margin
= 0; /* Buffer margin aka anti-skip buffer (A/C-) */
266 static bool v1first
= false; /* ID3 data control, true if V1 then V2 (A) */
268 static size_t high_watermark
= 0; /* High watermark for rebuffer (A/V/other) */
271 /* Multiple threads */
272 static void set_current_codec(int codec_idx
);
273 /* Set the watermark to trigger buffer fill (A/C) FIXME */
274 static void set_filebuf_watermark(int seconds
);
277 static struct event_queue audio_queue
;
278 static struct queue_sender_list audio_queue_sender_list
;
279 static long audio_stack
[(DEFAULT_STACK_SIZE
+ 0x1000)/sizeof(long)];
280 static const char audio_thread_name
[] = "audio";
282 static void audio_thread(void);
283 static void audio_initiate_track_change(long direction
);
284 static bool audio_have_tracks(void);
285 static void audio_reset_buffer(void);
288 extern struct codec_api ci
;
289 static struct event_queue codec_queue NOCACHEBSS_ATTR
;
290 static long codec_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
292 static const char codec_thread_name
[] = "codec";
293 struct thread_entry
*codec_thread_p
; /* For modifying thread priority later. */
295 static volatile int current_codec IDATA_ATTR
; /* Current codec (normal/voice) */
298 #ifdef PLAYBACK_VOICE
300 extern struct codec_api ci_voice
;
302 static struct thread_entry
*voice_thread_p
= NULL
;
303 static struct event_queue voice_queue NOCACHEBSS_ATTR
;
304 static long voice_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
305 IBSS_ATTR_VOICE_STACK
;
306 static const char voice_thread_name
[] = "voice codec";
308 /* Voice codec swapping control */
309 extern unsigned char codecbuf
[]; /* DRAM codec swap buffer */
312 /* IRAM codec swap buffer for sim*/
313 static unsigned char sim_iram
[CODEC_IRAM_SIZE
];
314 #undef CODEC_IRAM_ORIGIN
315 #define CODEC_IRAM_ORIGIN sim_iram
318 /* iram_buf and dram_buf are either both NULL or both non-NULL */
319 /* Pointer to IRAM buffer for codec swapping */
320 static unsigned char *iram_buf
= NULL
;
321 /* Pointer to DRAM buffer for codec swapping */
322 static unsigned char *dram_buf
= NULL
;
323 /* Parity of swap_codec calls - needed because one codec swapping itself in
324 automatically swaps in the other and the swap when unlocking should not
325 happen if the parity is even.
327 static bool swap_codec_parity
= false; /* true=odd, false=even */
328 /* Mutex to control which codec (normal/voice) is running */
329 static struct mutex mutex_codecthread NOCACHEBSS_ATTR
;
332 static volatile bool voice_thread_start
= false; /* Triggers voice playback (A/V) */
333 static volatile bool voice_is_playing NOCACHEBSS_ATTR
= false; /* Is voice currently playing? (V) */
334 static volatile bool voice_codec_loaded NOCACHEBSS_ATTR
= false; /* Is voice codec loaded (V/A-) */
335 static unsigned char *voicebuf
= NULL
;
336 static size_t voice_remaining
= 0;
339 /* Voice IRAM has been stolen for other use */
340 static bool voice_iram_stolen
= false;
343 static void (*voice_getmore
)(unsigned char** start
, size_t* size
) = NULL
;
346 void (*callback
)(unsigned char **start
, size_t* size
);
350 static void voice_thread(void);
351 static void voice_stop(void);
353 #endif /* PLAYBACK_VOICE */
355 /* --- External interfaces --- */
357 void mp3_play_data(const unsigned char* start
, int size
,
358 void (*get_more
)(unsigned char** start
, size_t* size
))
360 #ifdef PLAYBACK_VOICE
361 static struct voice_info voice_clip
;
362 voice_clip
.callback
= get_more
;
363 voice_clip
.buf
= (unsigned char*)start
;
364 voice_clip
.size
= size
;
365 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
366 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
367 LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
368 queue_post(&voice_queue
, Q_VOICE_PLAY
, (intptr_t)&voice_clip
);
369 voice_thread_start
= true;
378 void mp3_play_stop(void)
380 #ifdef PLAYBACK_VOICE
381 queue_remove_from_head(&voice_queue
, Q_VOICE_STOP
);
382 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
383 queue_post(&voice_queue
, Q_VOICE_STOP
, 1);
387 void mp3_play_pause(bool play
)
393 bool mp3_is_playing(void)
395 return voice_is_playing
;
398 void mpeg_id3_options(bool _v1first
)
403 /* If voice could be swapped out - wait for it to return
404 * Used by buffer claming functions.
406 static void wait_for_voice_swap_in(void)
408 #ifdef PLAYBACK_VOICE
409 if (NULL
== iram_buf
)
412 while (current_codec
!= CODEC_IDX_VOICE
)
414 #endif /* PLAYBACK_VOICE */
417 /* This sends a stop message and the audio thread will dump all it's
418 subsequenct messages */
419 static void audio_hard_stop(void)
422 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
423 queue_send(&audio_queue
, Q_AUDIO_STOP
, 1);
426 unsigned char *audio_get_buffer(bool talk_buf
, size_t *buffer_size
)
428 unsigned char *buf
, *end
;
430 if (audio_is_initialized
)
433 wait_for_voice_swap_in();
436 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
438 if (buffer_size
== NULL
)
440 /* Special case for talk_init to use since it already knows it's
442 buffer_state
= BUFFER_STATE_TRASHED
;
446 if (talk_buf
|| buffer_state
== BUFFER_STATE_TRASHED
447 || !talk_voice_required())
449 logf("get buffer: talk, audio");
450 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
451 the talk buffer is not needed because voice isn't being used, or
452 could be BUFFER_STATE_TRASHED already. If state is
453 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
454 without the caller knowing what's going on. Changing certain settings
455 may move it to a worse condition but the memory in use by something
456 else will remain undisturbed.
458 if (buffer_state
!= BUFFER_STATE_TRASHED
)
461 buffer_state
= BUFFER_STATE_TRASHED
;
469 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
470 still BUFFER_STATE_INITIALIZED */
471 /* Skip talk buffer and move pcm buffer to end to maximize available
472 contiguous memory - no audio running means voice will not need the
474 logf("get buffer: audio");
475 buf
= audiobuf
+ talk_get_bufsize();
476 end
= audiobufend
- pcmbuf_init(audiobufend
);
477 buffer_state
= BUFFER_STATE_VOICED_ONLY
;
480 *buffer_size
= end
- buf
;
486 void audio_iram_steal(void)
488 /* We need to stop audio playback in order to use codec IRAM */
491 #ifdef PLAYBACK_VOICE
492 if (NULL
!= iram_buf
)
494 /* Can't already be stolen */
495 if (voice_iram_stolen
)
498 /* Must wait for voice to be current again if it is swapped which
499 would cause the caller's buffer to get clobbered when voice locks
500 and runs - we'll wait for it to lock and yield again then make sure
501 the ride has come to a complete stop */
502 wait_for_voice_swap_in();
505 /* Save voice IRAM but just memcpy - safe to do here since voice
506 is current and no audio codec is loaded */
507 memcpy(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
508 voice_iram_stolen
= true;
512 /* Nothing much to do if no voice */
513 voice_iram_stolen
= false;
517 #endif /* IRAM_STEAL */
519 #ifdef HAVE_RECORDING
520 unsigned char *audio_get_recording_buffer(size_t *buffer_size
)
522 /* Don't allow overwrite of voice swap area or we'll trash the
523 swapped-out voice codec but can use whole thing if none */
526 /* Stop audio and voice. Wait for voice to swap in and be clear
527 of pending events to ensure trouble-free operation of encoders */
529 wait_for_voice_swap_in();
533 #ifdef PLAYBACK_VOICE
534 /* If no dram_buf, swap space not used and recording gets more
535 memory. Codec swap areas will remain unaffected by the next init
536 since they're allocated at the end of the buffer and their sizes
537 don't change between calls */
540 #endif /* PLAYBACK_VOICE */
543 buffer_state
= BUFFER_STATE_TRASHED
;
545 *buffer_size
= end
- audiobuf
;
547 return (unsigned char *)audiobuf
;
550 bool audio_load_encoder(int afmt
)
553 const char *enc_fn
= get_codec_filename(afmt
| CODEC_TYPE_ENCODER
);
557 audio_remove_encoder();
558 ci
.enc_codec_loaded
= 0; /* clear any previous error condition */
560 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
561 queue_post(&codec_queue
, Q_ENCODER_LOAD_DISK
, (intptr_t)enc_fn
);
563 while (ci
.enc_codec_loaded
== 0)
566 logf("codec loaded: %d", ci
.enc_codec_loaded
);
568 return ci
.enc_codec_loaded
> 0;
573 } /* audio_load_encoder */
575 void audio_remove_encoder(void)
578 /* force encoder codec unload (if currently loaded) */
579 if (ci
.enc_codec_loaded
<= 0)
582 ci
.stop_encoder
= true;
583 while (ci
.enc_codec_loaded
> 0)
586 } /* audio_remove_encoder */
588 #endif /* HAVE_RECORDING */
590 struct mp3entry
* audio_current_track(void)
592 const char *filename
;
594 static struct mp3entry temp_id3
;
596 int offset
= ci
.new_track
+ wps_offset
;
598 cur_idx
= track_ridx
+ offset
;
599 cur_idx
&= MAX_TRACK_MASK
;
601 if (tracks
[cur_idx
].taginfo_ready
)
602 return &tracks
[cur_idx
].id3
;
604 memset(&temp_id3
, 0, sizeof(struct mp3entry
));
606 filename
= playlist_peek(0);
608 filename
= "No file!";
610 #ifdef HAVE_TC_RAMCACHE
611 if (tagcache_fill_tags(&temp_id3
, filename
))
615 p
= strrchr(filename
, '/');
621 strncpy(temp_id3
.path
, p
, sizeof(temp_id3
.path
)-1);
622 temp_id3
.title
= &temp_id3
.path
[0];
627 struct mp3entry
* audio_next_track(void)
629 int next_idx
= track_ridx
;
631 if (!audio_have_tracks())
635 next_idx
&= MAX_TRACK_MASK
;
637 if (!tracks
[next_idx
].taginfo_ready
)
640 return &tracks
[next_idx
].id3
;
643 bool audio_has_changed_track(void)
647 track_changed
= false;
654 void audio_play(long offset
)
658 #ifdef PLAYBACK_VOICE
659 /* Truncate any existing voice output so we don't have spelling
660 * etc. over the first part of the played track */
661 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
662 queue_post(&voice_queue
, Q_VOICE_STOP
, 1);
666 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset
);
667 /* Don't return until playback has actually started */
668 queue_send(&audio_queue
, Q_AUDIO_PLAY
, offset
);
671 void audio_stop(void)
674 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
675 /* Don't return until playback has actually stopped */
676 queue_send(&audio_queue
, Q_AUDIO_STOP
, 0);
679 void audio_pause(void)
681 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
682 /* Don't return until playback has actually paused */
683 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, true);
686 void audio_resume(void)
688 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
689 /* Don't return until playback has actually resumed */
690 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, false);
693 void audio_next(void)
695 if (playlist_check(ci
.new_track
+ wps_offset
+ 1))
697 if (global_settings
.beep
)
698 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
700 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
701 queue_post(&audio_queue
, Q_AUDIO_SKIP
, 1);
702 /* Update wps while our message travels inside deep playback queues. */
704 track_changed
= true;
708 /* No more tracks. */
709 if (global_settings
.beep
)
710 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
714 void audio_prev(void)
716 if (playlist_check(ci
.new_track
+ wps_offset
- 1))
718 if (global_settings
.beep
)
719 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
721 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
722 queue_post(&audio_queue
, Q_AUDIO_SKIP
, -1);
723 /* Update wps while our message travels inside deep playback queues. */
725 track_changed
= true;
729 /* No more tracks. */
730 if (global_settings
.beep
)
731 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
735 void audio_next_dir(void)
737 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
738 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, 1);
741 void audio_prev_dir(void)
743 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
744 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, -1);
747 void audio_pre_ff_rewind(void)
749 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
750 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
753 void audio_ff_rewind(long newpos
)
755 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
756 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, newpos
);
759 void audio_flush_and_reload_tracks(void)
761 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
762 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
765 void audio_error_clear(void)
767 #ifdef AUDIO_HAVE_RECORDING
768 pcm_rec_error_clear();
772 int audio_status(void)
777 ret
|= AUDIO_STATUS_PLAY
;
780 ret
|= AUDIO_STATUS_PAUSE
;
782 #ifdef HAVE_RECORDING
783 /* Do this here for constitency with mpeg.c version */
784 ret
|= pcm_rec_status();
790 int audio_get_file_pos(void)
795 #ifndef HAVE_FLASH_STORAGE
796 void audio_set_buffer_margin(int setting
)
798 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
799 buffer_margin
= lookup
[setting
];
800 logf("buffer margin: %ld", buffer_margin
);
801 set_filebuf_watermark(buffer_margin
);
805 /* Take nescessary steps to enable or disable the crossfade setting */
806 void audio_set_crossfade(int enable
)
812 /* Tell it the next setting to use */
813 pcmbuf_crossfade_enable(enable
);
815 /* Return if size hasn't changed or this is too early to determine
816 which in the second case there's no way we could be playing
818 if (pcmbuf_is_same_size())
820 /* This function is a copout and just syncs some variables -
821 to be removed at a later date */
822 pcmbuf_crossfade_enable_finished();
827 was_playing
= playing
;
829 /* Playback has to be stopped before changing the buffer size */
832 /* Store the track resume position */
833 offset
= CUR_TI
->id3
.offset
;
834 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK
));
837 /* Blast it - audio buffer will have to be setup again next time
839 audio_get_buffer(true, &size
);
841 /* Restart playback if audio was running previously */
846 /* --- Routines called from multiple threads --- */
847 static void set_current_codec(int codec_idx
)
849 current_codec
= codec_idx
;
850 dsp_configure(DSP_SWITCH_CODEC
, codec_idx
);
853 #ifdef PLAYBACK_VOICE
854 static void swap_codec(void)
858 /* Swap nothing if no swap buffers exist */
859 if (dram_buf
== NULL
)
861 logf("swap: no swap buffers");
865 my_codec
= current_codec
;
867 logf("swapping out codec: %d", my_codec
);
869 /* Invert this when a codec thread enters and leaves */
870 swap_codec_parity
= !swap_codec_parity
;
872 /* If this is true, an odd number of calls has occurred and there's
873 no codec thread waiting to swap us out when it locks and runs. This
874 occurs when playback is stopped or when just starting playback and
875 the audio thread is loading a codec; parities should always be even
876 on entry when a thread calls this during playback */
877 if (swap_codec_parity
)
879 /* Save our current IRAM and DRAM */
881 if (voice_iram_stolen
)
883 logf("swap: iram restore");
884 voice_iram_stolen
= false;
885 /* Don't swap trashed data into buffer as the voice IRAM will
886 already be swapped out - should _always_ be the case if
887 voice_iram_stolen is true since the voice has been swapped
889 if (my_codec
== CODEC_IDX_VOICE
)
891 logf("voice iram already swapped");
897 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
903 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
904 /* No cache invalidation needed; it will be done in codec_load_ram
905 or we won't be here otherwise */
908 /* Release my semaphore */
909 mutex_unlock(&mutex_codecthread
);
910 logf("unlocked: %d", my_codec
);
912 /* Loop until the other codec has locked and run */
914 /* Release my semaphore and force a task switch. */
916 } while (my_codec
== current_codec
);
918 /* Wait for other codec to unlock */
919 mutex_lock(&mutex_codecthread
);
922 logf("waiting for lock: %d", my_codec
);
923 set_current_codec(my_codec
);
925 /* Reload our IRAM and DRAM */
926 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
927 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
930 /* Flip parity again */
931 swap_codec_parity
= !swap_codec_parity
;
933 logf("resuming codec: %d", my_codec
);
936 /* This function is meant to be used by the buffer stealing functions to
937 ensure the codec is no longer active and so voice will be swapped-in
938 before it is called */
939 static void voice_stop(void)
941 #ifdef PLAYBACK_VOICE
942 /* Must have a voice codec loaded or we'll hang forever here */
943 if (!voice_codec_loaded
)
946 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
947 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
949 /* Loop until voice empties it's queue, stops and picks up on the new
950 track; the voice thread must be stopped and waiting for messages
952 while (voice_is_playing
|| !queue_empty(&voice_queue
) ||
961 /* Is voice still speaking */
962 /* Unfortunately only reliable when music is not also playing. */
963 static bool is_voice_speaking(void)
965 return is_voice_queued()
967 || (!playing
&& pcm_is_playing());
970 /* Wait for voice to finish speaking. */
971 /* Also only reliable when music is not also playing. */
972 void voice_wait(void)
974 while (is_voice_speaking())
978 #endif /* PLAYBACK_VOICE */
980 static void set_filebuf_watermark(int seconds
)
985 return; /* Audio buffers not yet set up */
987 bytes
= MAX(CUR_TI
->id3
.bitrate
* seconds
* (1000/8), conf_watermark
);
988 bytes
= MIN(bytes
, filebuflen
/ 2);
989 conf_watermark
= bytes
;
992 const char * get_codec_filename(int cod_spec
)
996 #ifdef HAVE_RECORDING
997 /* Can choose decoder or encoder if one available */
998 int type
= cod_spec
& CODEC_TYPE_MASK
;
999 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
1001 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
1002 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
1004 fname
= (type
== CODEC_TYPE_ENCODER
) ?
1005 audio_formats
[afmt
].codec_enc_root_fn
:
1006 audio_formats
[afmt
].codec_root_fn
;
1009 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
1010 afmt
, fname
? fname
: "<unknown>");
1011 #else /* !HAVE_RECORDING */
1012 /* Always decoder */
1013 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
1014 cod_spec
= AFMT_UNKNOWN
;
1015 fname
= audio_formats
[cod_spec
].codec_root_fn
;
1016 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
1017 #endif /* HAVE_RECORDING */
1020 } /* get_codec_filename */
1023 /* --- Voice thread --- */
1025 #ifdef PLAYBACK_VOICE
1027 static bool voice_pcmbuf_insert_callback(
1028 const void *ch1
, const void *ch2
, int count
)
1030 const char *src
[2] = { ch1
, ch2
};
1034 int out_count
= dsp_output_count(count
);
1038 while ((dest
= pcmbuf_request_voice_buffer(
1039 &out_count
, playing
)) == NULL
)
1041 if (playing
&& audio_codec_loaded
)
1047 /* Get the real input_size for output_size bytes, guarding
1048 * against resampling buffer overflows. */
1049 inp_count
= dsp_input_count(out_count
);
1054 /* Input size has grown, no error, just don't write more than length */
1055 if (inp_count
> count
)
1058 out_count
= dsp_process(dest
, src
, inp_count
);
1065 pcmbuf_mix_voice(out_count
);
1066 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
1071 pcmbuf_write_complete(out_count
);
1077 } /* voice_pcmbuf_insert_callback */
1079 static void* voice_get_memory_callback(size_t *size
)
1081 /* Voice should have no use for this. If it did, we'd have to
1082 swap the malloc buffer as well. */
1087 static void voice_set_elapsed_callback(unsigned int value
)
1092 static void voice_set_offset_callback(size_t value
)
1097 static void voice_configure_callback(int setting
, intptr_t value
)
1099 if (!dsp_configure(setting
, value
))
1101 logf("Illegal key:%d", setting
);
1105 static size_t voice_filebuf_callback(void *ptr
, size_t size
)
1113 /* Handle Q_VOICE_STOP and part of SYS_USB_CONNECTED */
1114 static bool voice_on_voice_stop(bool aborting
, size_t *realsize
)
1116 if (aborting
&& !playing
&& pcm_is_playing())
1118 /* Aborting: Slight hack - flush PCM buffer if
1119 only being used for voice */
1123 if (voice_is_playing
)
1125 /* Clear the current buffer */
1126 voice_is_playing
= false;
1127 voice_getmore
= NULL
;
1128 voice_remaining
= 0;
1131 /* Cancel any automatic boost if no more clips requested. */
1132 if (!playing
|| !voice_thread_start
)
1135 /* Force the codec to think it's changing tracks */
1136 ci_voice
.new_track
= 1;
1139 return true; /* Yes, change tracks */
1145 static void* voice_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1149 if (ci_voice
.new_track
)
1157 if (voice_is_playing
|| playing
)
1159 queue_wait_w_tmo(&voice_queue
, &ev
, 0);
1160 if (!voice_is_playing
&& ev
.id
== SYS_TIMEOUT
)
1161 ev
.id
= Q_AUDIO_PLAY
;
1165 queue_wait(&voice_queue
, &ev
);
1170 LOGFQUEUE("voice < Q_AUDIO_PLAY");
1173 if (audio_codec_loaded
)
1179 #ifdef AUDIO_HAVE_RECORDING
1180 case Q_ENCODER_RECORD
:
1181 LOGFQUEUE("voice < Q_ENCODER_RECORD");
1187 LOGFQUEUE("voice < Q_VOICE_STOP");
1188 if (voice_on_voice_stop(ev
.data
, realsize
))
1192 case SYS_USB_CONNECTED
:
1194 LOGFQUEUE("voice < SYS_USB_CONNECTED");
1195 bool change_tracks
= voice_on_voice_stop(ev
.data
, realsize
);
1196 /* Voice is obviously current so let us swap ourselves away if
1197 playing so audio may stop itself - audio_codec_loaded can
1198 only be true in this case if we're here even if the codec
1199 is only about to load */
1200 if (audio_codec_loaded
)
1202 /* Playback should be finished by now - ack and wait */
1203 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
1204 usb_wait_for_disconnect(&voice_queue
);
1211 LOGFQUEUE("voice < Q_VOICE_PLAY");
1212 if (!voice_is_playing
)
1214 /* Set up new voice data */
1215 struct voice_info
*voice_data
;
1217 if (voice_iram_stolen
)
1219 /* Voice is the first to run again and is currently
1221 logf("voice: iram restore");
1222 memcpy(CODEC_IRAM_ORIGIN
, iram_buf
, CODEC_IRAM_SIZE
);
1223 voice_iram_stolen
= false;
1226 /* Must reset the buffer before any playback begins if
1228 if (buffer_state
== BUFFER_STATE_TRASHED
)
1229 audio_reset_buffer();
1231 voice_is_playing
= true;
1232 trigger_cpu_boost();
1233 voice_data
= (struct voice_info
*)ev
.data
;
1234 voice_remaining
= voice_data
->size
;
1235 voicebuf
= voice_data
->buf
;
1236 voice_getmore
= voice_data
->callback
;
1238 goto voice_play_clip
; /* To exit both switch and while */
1241 LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
1242 goto voice_play_clip
;
1245 LOGFQUEUE("voice < default");
1251 if (voice_remaining
== 0 || voicebuf
== NULL
)
1254 voice_getmore((unsigned char **)&voicebuf
, &voice_remaining
);
1256 /* If this clip is done */
1257 if (voice_remaining
== 0)
1259 LOGFQUEUE("voice > voice Q_VOICE_STOP");
1260 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
1261 /* Force pcm playback. */
1262 if (!pcm_is_playing())
1263 pcmbuf_play_start();
1267 *realsize
= MIN(voice_remaining
, reqsize
);
1273 } /* voice_request_buffer_callback */
1275 static void voice_advance_buffer_callback(size_t amount
)
1277 amount
= MIN(amount
, voice_remaining
);
1279 voice_remaining
-= amount
;
1282 static void voice_advance_buffer_loc_callback(void *ptr
)
1284 size_t amount
= (size_t)ptr
- (size_t)voicebuf
;
1286 voice_advance_buffer_callback(amount
);
1289 static off_t
voice_mp3_get_filepos_callback(int newtime
)
1296 static void voice_do_nothing(void)
1301 static bool voice_seek_buffer_callback(size_t newpos
)
1308 static bool voice_request_next_track_callback(void)
1310 ci_voice
.new_track
= 0;
1314 static void voice_thread(void)
1316 logf("Loading voice codec");
1317 voice_codec_loaded
= true;
1318 mutex_lock(&mutex_codecthread
);
1319 set_current_codec(CODEC_IDX_VOICE
);
1320 dsp_configure(DSP_RESET
, 0);
1321 voice_remaining
= 0;
1322 voice_getmore
= NULL
;
1324 /* FIXME: If we being starting the voice thread without reboot, the
1325 voice_queue could be full of old stuff and we must flush it. */
1326 codec_load_file(get_codec_filename(AFMT_MPA_L3
), &ci_voice
);
1328 logf("Voice codec finished");
1329 voice_codec_loaded
= false;
1330 mutex_unlock(&mutex_codecthread
);
1331 voice_thread_p
= NULL
;
1332 remove_thread(NULL
);
1333 } /* voice_thread */
1335 #endif /* PLAYBACK_VOICE */
1337 /* --- Codec thread --- */
1338 static bool codec_pcmbuf_insert_callback(
1339 const void *ch1
, const void *ch2
, int count
)
1341 const char *src
[2] = { ch1
, ch2
};
1345 int out_count
= dsp_output_count(count
);
1349 /* Prevent audio from a previous track from playing */
1350 if (ci
.new_track
|| ci
.stop_codec
)
1353 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
1356 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
1360 /* Get the real input_size for output_size bytes, guarding
1361 * against resampling buffer overflows. */
1362 inp_count
= dsp_input_count(out_count
);
1367 /* Input size has grown, no error, just don't write more than length */
1368 if (inp_count
> count
)
1371 out_count
= dsp_process(dest
, src
, inp_count
);
1376 pcmbuf_write_complete(out_count
);
1378 #ifdef PLAYBACK_VOICE
1379 if ((voice_is_playing
|| voice_thread_start
)
1380 && pcm_is_playing() && voice_codec_loaded
&&
1381 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1383 voice_thread_start
= false;
1392 } /* codec_pcmbuf_insert_callback */
1394 static void* codec_get_memory_callback(size_t *size
)
1396 *size
= MALLOC_BUFSIZE
;
1400 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
1401 static void codec_pcmbuf_position_callback(size_t size
)
1403 /* This is called from an ISR, so be quick */
1404 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
1405 prev_ti
->id3
.elapsed
;
1407 if (time
>= prev_ti
->id3
.length
)
1409 pcmbuf_set_position_callback(NULL
);
1410 prev_ti
->id3
.elapsed
= prev_ti
->id3
.length
;
1413 prev_ti
->id3
.elapsed
= time
;
1416 static void codec_set_elapsed_callback(unsigned int value
)
1418 unsigned int latency
;
1422 #ifdef AB_REPEAT_ENABLE
1423 ab_position_report(value
);
1426 latency
= pcmbuf_get_latency();
1427 if (value
< latency
)
1428 CUR_TI
->id3
.elapsed
= 0;
1429 else if (value
- latency
> CUR_TI
->id3
.elapsed
||
1430 value
- latency
< CUR_TI
->id3
.elapsed
- 2)
1432 CUR_TI
->id3
.elapsed
= value
- latency
;
1436 static void codec_set_offset_callback(size_t value
)
1438 unsigned int latency
;
1443 latency
= pcmbuf_get_latency() * CUR_TI
->id3
.bitrate
/ 8;
1444 if (value
< latency
)
1445 CUR_TI
->id3
.offset
= 0;
1447 CUR_TI
->id3
.offset
= value
- latency
;
1450 static void codec_advance_buffer_counters(size_t amount
)
1452 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
1453 ci
.curpos
+= amount
;
1454 CUR_TI
->available
-= amount
;
1456 /* Start buffer filling as necessary. */
1457 if (!pcmbuf_is_lowdata() && !filling
)
1459 if (FILEBUFUSED
< conf_watermark
&& playing
&& !playlist_end
)
1461 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1462 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1467 /* copy up-to size bytes into ptr and return the actual size copied */
1468 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
1470 char *buf
= (char *)ptr
;
1474 if (ci
.stop_codec
|| !playing
)
1477 /* The ammount to copy is the lesser of the requested amount and the
1478 * amount left of the current track (both on disk and already loaded) */
1479 copy_n
= MIN(size
, CUR_TI
->available
+ CUR_TI
->filerem
);
1481 /* Nothing requested OR nothing left */
1485 /* Let the disk buffer catch fill until enough data is available */
1486 while (copy_n
> CUR_TI
->available
)
1490 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1491 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1495 if (ci
.stop_codec
|| ci
.new_track
)
1499 /* Copy as much as possible without wrapping */
1500 part_n
= MIN(copy_n
, filebuflen
- buf_ridx
);
1501 memcpy(buf
, &filebuf
[buf_ridx
], part_n
);
1502 /* Copy the rest in the case of a wrap */
1503 if (part_n
< copy_n
) {
1504 memcpy(&buf
[part_n
], &filebuf
[0], copy_n
- part_n
);
1507 /* Update read and other position pointers */
1508 codec_advance_buffer_counters(copy_n
);
1510 /* Return the actual amount of data copied to the buffer */
1512 } /* codec_filebuf_callback */
1514 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1516 size_t short_n
, copy_n
, buf_rem
;
1524 copy_n
= MIN(reqsize
, CUR_TI
->available
+ CUR_TI
->filerem
);
1531 while (copy_n
> CUR_TI
->available
)
1535 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1536 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1540 if (ci
.stop_codec
|| ci
.new_track
)
1547 /* How much is left at the end of the file buffer before wrap? */
1548 buf_rem
= filebuflen
- buf_ridx
;
1550 /* If we can't satisfy the request without wrapping */
1551 if (buf_rem
< copy_n
)
1553 /* How short are we? */
1554 short_n
= copy_n
- buf_rem
;
1556 /* If we can fudge it with the guardbuf */
1557 if (short_n
< GUARD_BUFSIZE
)
1558 memcpy(&filebuf
[filebuflen
], &filebuf
[0], short_n
);
1565 return (char *)&filebuf
[buf_ridx
];
1566 } /* codec_request_buffer_callback */
1568 static int get_codec_base_type(int type
)
1580 static void codec_advance_buffer_callback(size_t amount
)
1582 if (amount
> CUR_TI
->available
+ CUR_TI
->filerem
)
1583 amount
= CUR_TI
->available
+ CUR_TI
->filerem
;
1585 while (amount
> CUR_TI
->available
&& filling
)
1588 if (amount
> CUR_TI
->available
)
1590 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1594 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1595 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1596 ci
.curpos
+ amount
);
1601 case Q_CODEC_REQUEST_FAILED
:
1602 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1603 ci
.stop_codec
= true;
1606 case Q_CODEC_REQUEST_COMPLETE
:
1607 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1611 LOGFQUEUE("codec |< default");
1612 ci
.stop_codec
= true;
1617 codec_advance_buffer_counters(amount
);
1619 codec_set_offset_callback(ci
.curpos
);
1622 static void codec_advance_buffer_loc_callback(void *ptr
)
1624 size_t amount
= (size_t)ptr
- (size_t)&filebuf
[buf_ridx
];
1626 codec_advance_buffer_callback(amount
);
1629 /* Copied from mpeg.c. Should be moved somewhere else. */
1630 static int codec_get_file_pos(void)
1633 struct mp3entry
*id3
= audio_current_track();
1639 /* Use the TOC to find the new position */
1640 unsigned int percent
, remainder
;
1641 int curtoc
, nexttoc
, plen
;
1643 percent
= (id3
->elapsed
*100)/id3
->length
;
1647 curtoc
= id3
->toc
[percent
];
1650 nexttoc
= id3
->toc
[percent
+1];
1654 pos
= (id3
->filesize
/256)*curtoc
;
1656 /* Use the remainder to get a more accurate position */
1657 remainder
= (id3
->elapsed
*100)%id3
->length
;
1658 remainder
= (remainder
*100)/id3
->length
;
1659 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1660 pos
+= (plen
/100)*remainder
;
1664 /* No TOC exists, estimate the new position */
1665 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1666 (id3
->elapsed
/ 1000);
1669 else if (id3
->bitrate
)
1670 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1674 pos
+= id3
->first_frame_offset
;
1676 /* Don't seek right to the end of the file so that we can
1677 transition properly to the next song */
1678 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1679 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1684 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1688 CUR_TI
->id3
.elapsed
= newtime
;
1689 newpos
= codec_get_file_pos();
1694 static void codec_seek_complete_callback(void)
1696 logf("seek_complete");
1697 if (pcm_is_paused())
1699 /* If this is not a seamless seek, clear the buffer */
1701 dsp_configure(DSP_FLUSH
, 0);
1703 /* If playback was not 'deliberately' paused, unpause now */
1705 pcmbuf_pause(false);
1710 static bool codec_seek_buffer_callback(size_t newpos
)
1714 logf("codec_seek_buffer_callback");
1716 if (newpos
>= CUR_TI
->filesize
)
1717 newpos
= CUR_TI
->filesize
- 1;
1719 difference
= newpos
- ci
.curpos
;
1720 if (difference
>= 0)
1722 /* Seeking forward */
1723 logf("seek: +%d", difference
);
1724 codec_advance_buffer_callback(difference
);
1728 /* Seeking backward */
1729 difference
= -difference
;
1730 if (ci
.curpos
- difference
< 0)
1731 difference
= ci
.curpos
;
1733 /* We need to reload the song. */
1734 if (newpos
< CUR_TI
->start_pos
)
1736 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1740 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1741 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1747 case Q_CODEC_REQUEST_COMPLETE
:
1748 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1751 case Q_CODEC_REQUEST_FAILED
:
1752 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1753 ci
.stop_codec
= true;
1757 LOGFQUEUE("codec |< default");
1762 /* Seeking inside buffer space. */
1763 logf("seek: -%d", difference
);
1764 CUR_TI
->available
+= difference
;
1765 buf_ridx
= RINGBUF_SUB(buf_ridx
, (unsigned)difference
);
1766 ci
.curpos
-= difference
;
1771 static void codec_configure_callback(int setting
, intptr_t value
)
1774 case CODEC_SET_FILEBUF_WATERMARK
:
1775 conf_watermark
= value
;
1776 set_filebuf_watermark(buffer_margin
);
1779 case CODEC_SET_FILEBUF_CHUNKSIZE
:
1780 conf_filechunk
= value
;
1783 case CODEC_SET_FILEBUF_PRESEEK
:
1784 conf_preseek
= value
;
1788 if (!dsp_configure(setting
, value
)) { logf("Illegal key:%d", setting
); }
1792 static void codec_track_changed(void)
1794 automatic_skip
= false;
1795 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1796 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1799 static void codec_pcmbuf_track_changed_callback(void)
1801 pcmbuf_set_position_callback(NULL
);
1802 codec_track_changed();
1805 static void codec_discard_codec_callback(void)
1807 if (CUR_TI
->has_codec
)
1809 CUR_TI
->has_codec
= false;
1810 buf_ridx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->codecsize
);
1814 /* Check if a buffer desync has happened, log it and stop playback. */
1815 if (buf_ridx
!= CUR_TI
->buf_idx
)
1817 int offset
= CUR_TI
->buf_idx
- buf_ridx
;
1818 size_t new_used
= FILEBUFUSED
- offset
;
1820 logf("Buf off :%d=%d-%d", offset
, CUR_TI
->buf_idx
, buf_ridx
);
1821 logf("Used off:%d",FILEBUFUSED
- new_used
);
1823 /* This is a fatal internal error and it's not safe to
1824 * continue playback. */
1825 ci
.stop_codec
= true;
1826 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1831 static inline void codec_gapless_track_change(void) {
1832 /* callback keeps the progress bar moving while the pcmbuf empties */
1833 pcmbuf_set_position_callback(codec_pcmbuf_position_callback
);
1834 /* set the pcmbuf callback for when the track really changes */
1835 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1838 static inline void codec_crossfade_track_change(void) {
1839 /* Initiate automatic crossfade mode */
1840 pcmbuf_crossfade_init(false);
1841 /* Notify the wps that the track change starts now */
1842 codec_track_changed();
1845 static void codec_track_skip_done(bool was_manual
)
1847 int crossfade_mode
= global_settings
.crossfade
;
1849 /* Manual track change (always crossfade or flush audio). */
1852 pcmbuf_crossfade_init(true);
1853 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1854 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1856 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1857 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1858 && crossfade_mode
!= CROSSFADE_ENABLE_TRACKSKIP
)
1860 if (crossfade_mode
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1862 if (global_settings
.playlist_shuffle
)
1863 /* shuffle mode is on, so crossfade: */
1864 codec_crossfade_track_change();
1866 /* shuffle mode is off, so do a gapless track change */
1867 codec_gapless_track_change();
1870 /* normal crossfade: */
1871 codec_crossfade_track_change();
1874 /* normal gapless playback. */
1875 codec_gapless_track_change();
1878 static bool codec_load_next_track(void)
1880 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1882 prev_track_elapsed
= CUR_TI
->id3
.elapsed
;
1885 codec_seek_complete_callback();
1887 #ifdef AB_REPEAT_ENABLE
1888 ab_end_of_track_report();
1891 logf("Request new track");
1893 if (ci
.new_track
== 0)
1896 automatic_skip
= true;
1901 trigger_cpu_boost();
1902 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1903 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1908 case Q_CODEC_REQUEST_COMPLETE
:
1909 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1910 codec_track_skip_done(!automatic_skip
);
1913 case Q_CODEC_REQUEST_FAILED
:
1914 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1916 ci
.stop_codec
= true;
1920 LOGFQUEUE("codec |< default");
1921 ci
.stop_codec
= true;
1926 static bool codec_request_next_track_callback(void)
1930 if (ci
.stop_codec
|| !playing
)
1933 prev_codectype
= get_codec_base_type(CUR_TI
->id3
.codectype
);
1935 if (!codec_load_next_track())
1938 /* Check if the next codec is the same file. */
1939 if (prev_codectype
== get_codec_base_type(CUR_TI
->id3
.codectype
))
1941 logf("New track loaded");
1942 codec_discard_codec_callback();
1947 logf("New codec:%d/%d", CUR_TI
->id3
.codectype
, prev_codectype
);
1952 static void codec_thread(void)
1960 queue_wait(&codec_queue
, &ev
);
1963 case Q_CODEC_LOAD_DISK
:
1964 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1965 audio_codec_loaded
= true;
1966 #ifdef PLAYBACK_VOICE
1967 /* Don't sent messages to voice codec if it's already swapped
1968 out or it will never get this */
1969 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1971 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1972 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1974 mutex_lock(&mutex_codecthread
);
1976 set_current_codec(CODEC_IDX_AUDIO
);
1977 ci
.stop_codec
= false;
1978 status
= codec_load_file((const char *)ev
.data
, &ci
);
1979 #ifdef PLAYBACK_VOICE
1980 mutex_unlock(&mutex_codecthread
);
1985 LOGFQUEUE("codec < Q_CODEC_LOAD");
1986 if (!CUR_TI
->has_codec
) {
1987 logf("Codec slot is empty!");
1988 /* Wait for the pcm buffer to go empty */
1989 while (pcm_is_playing())
1991 /* This must be set to prevent an infinite loop */
1992 ci
.stop_codec
= true;
1993 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1994 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
1998 audio_codec_loaded
= true;
1999 #ifdef PLAYBACK_VOICE
2000 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2002 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
2003 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
2005 mutex_lock(&mutex_codecthread
);
2007 set_current_codec(CODEC_IDX_AUDIO
);
2008 ci
.stop_codec
= false;
2009 wrap
= (size_t)&filebuf
[filebuflen
] - (size_t)CUR_TI
->codecbuf
;
2010 status
= codec_load_ram(CUR_TI
->codecbuf
, CUR_TI
->codecsize
,
2011 &filebuf
[0], wrap
, &ci
);
2012 #ifdef PLAYBACK_VOICE
2013 mutex_unlock(&mutex_codecthread
);
2017 #ifdef AUDIO_HAVE_RECORDING
2018 case Q_ENCODER_LOAD_DISK
:
2019 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2020 audio_codec_loaded
= false; /* Not audio codec! */
2021 #ifdef PLAYBACK_VOICE
2022 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2024 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
2025 queue_post(&voice_queue
, Q_ENCODER_RECORD
, 0);
2027 mutex_lock(&mutex_codecthread
);
2029 logf("loading encoder");
2030 set_current_codec(CODEC_IDX_AUDIO
);
2031 ci
.stop_encoder
= false;
2032 status
= codec_load_file((const char *)ev
.data
, &ci
);
2033 #ifdef PLAYBACK_VOICE
2034 mutex_unlock(&mutex_codecthread
);
2036 logf("encoder stopped");
2038 #endif /* AUDIO_HAVE_RECORDING */
2041 case SYS_USB_CONNECTED
:
2042 LOGFQUEUE("codec < SYS_USB_CONNECTED");
2043 queue_clear(&codec_queue
);
2044 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
2045 usb_wait_for_disconnect(&codec_queue
);
2050 LOGFQUEUE("codec < default");
2053 if (audio_codec_loaded
)
2062 audio_codec_loaded
= false;
2066 case Q_CODEC_LOAD_DISK
:
2068 LOGFQUEUE("codec < Q_CODEC_LOAD");
2071 if (ci
.new_track
|| status
!= CODEC_OK
)
2075 logf("Codec failure");
2076 gui_syncsplash(HZ
*2, "Codec failure");
2079 if (!codec_load_next_track())
2081 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2082 /* End of playlist */
2083 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2089 logf("Codec finished");
2092 /* Wait for the audio to stop playing before
2093 * triggering the WPS exit */
2094 while(pcm_is_playing())
2096 CUR_TI
->id3
.elapsed
=
2097 CUR_TI
->id3
.length
- pcmbuf_get_latency();
2100 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2101 /* End of playlist */
2102 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2107 if (CUR_TI
->has_codec
)
2109 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2110 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
2114 const char *codec_fn
=
2115 get_codec_filename(CUR_TI
->id3
.codectype
);
2116 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2117 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
2118 (intptr_t)codec_fn
);
2123 #ifdef AUDIO_HAVE_RECORDING
2124 case Q_ENCODER_LOAD_DISK
:
2125 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2127 if (status
== CODEC_OK
)
2130 logf("Encoder failure");
2131 gui_syncsplash(HZ
*2, "Encoder failure");
2133 if (ci
.enc_codec_loaded
< 0)
2136 logf("Encoder failed to load");
2137 ci
.enc_codec_loaded
= -1;
2139 #endif /* AUDIO_HAVE_RECORDING */
2142 LOGFQUEUE("codec < default");
2149 /* --- Audio thread --- */
2151 static bool audio_filebuf_is_lowdata(void)
2153 return FILEBUFUSED
< AUDIO_FILEBUF_CRITICAL
;
2156 static bool audio_have_tracks(void)
2158 return track_ridx
!= track_widx
|| CUR_TI
->filesize
;
2161 static bool audio_have_free_tracks(void)
2163 if (track_widx
< track_ridx
)
2164 return track_widx
+ 1 < track_ridx
;
2165 else if (track_ridx
== 0)
2166 return track_widx
< MAX_TRACK
- 1;
2171 int audio_track_count(void)
2173 if (audio_have_tracks())
2175 int relative_track_widx
= track_widx
;
2177 if (track_ridx
> track_widx
)
2178 relative_track_widx
+= MAX_TRACK
;
2180 return relative_track_widx
- track_ridx
+ 1;
2186 long audio_filebufused(void)
2188 return (long) FILEBUFUSED
;
2191 /* Count the data BETWEEN the selected tracks */
2192 static size_t audio_buffer_count_tracks(int from_track
, int to_track
)
2195 bool need_wrap
= to_track
< from_track
;
2199 if (++from_track
>= MAX_TRACK
)
2201 from_track
-= MAX_TRACK
;
2205 if (from_track
>= to_track
&& !need_wrap
)
2208 amount
+= tracks
[from_track
].codecsize
+ tracks
[from_track
].filesize
;
2213 static bool audio_buffer_wind_forward(int new_track_ridx
, int old_track_ridx
)
2217 /* Start with the remainder of the previously playing track */
2218 amount
= tracks
[old_track_ridx
].filesize
- ci
.curpos
;
2219 /* Then collect all data from tracks in between them */
2220 amount
+= audio_buffer_count_tracks(old_track_ridx
, new_track_ridx
);
2221 logf("bwf:%ldB", (long) amount
);
2223 if (amount
> FILEBUFUSED
)
2226 /* Wind the buffer to the beginning of the target track or its codec */
2227 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
2232 static bool audio_buffer_wind_backward(int new_track_ridx
, int old_track_ridx
)
2234 /* Available buffer data */
2236 /* Start with the previously playing track's data and our data */
2240 buf_back
= RINGBUF_SUB(buf_ridx
, buf_widx
);
2242 /* If we're not just resetting the current track */
2243 if (new_track_ridx
!= old_track_ridx
)
2245 /* Need to wind to before the old track's codec and our filesize */
2246 amount
+= tracks
[old_track_ridx
].codecsize
;
2247 amount
+= tracks
[new_track_ridx
].filesize
;
2249 /* Rewind the old track to its beginning */
2250 tracks
[old_track_ridx
].available
=
2251 tracks
[old_track_ridx
].filesize
- tracks
[old_track_ridx
].filerem
;
2254 /* If the codec was ever buffered */
2255 if (tracks
[new_track_ridx
].codecsize
)
2257 /* Add the codec to the needed size */
2258 amount
+= tracks
[new_track_ridx
].codecsize
;
2259 tracks
[new_track_ridx
].has_codec
= true;
2262 /* Then collect all data from tracks between new and old */
2263 amount
+= audio_buffer_count_tracks(new_track_ridx
, old_track_ridx
);
2265 /* Do we have space to make this skip? */
2266 if (amount
> buf_back
)
2269 logf("bwb:%ldB",amount
);
2271 /* Rewind the buffer to the beginning of the target track or its codec */
2272 buf_ridx
= RINGBUF_SUB(buf_ridx
, amount
);
2274 /* Reset to the beginning of the new track */
2275 tracks
[new_track_ridx
].available
= tracks
[new_track_ridx
].filesize
;
2280 static void audio_update_trackinfo(void)
2282 ci
.filesize
= CUR_TI
->filesize
;
2283 CUR_TI
->id3
.elapsed
= 0;
2284 CUR_TI
->id3
.offset
= 0;
2285 ci
.id3
= &CUR_TI
->id3
;
2287 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2290 /* Yield to codecs for as long as possible if they are in need of data
2291 * return true if the caller should break to let the audio thread process
2293 static bool audio_yield_codecs(void)
2297 if (!queue_empty(&audio_queue
))
2300 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
2301 && !ci
.stop_codec
&& playing
&& !audio_filebuf_is_lowdata())
2308 if (!queue_empty(&audio_queue
))
2315 static void audio_clear_track_entries(bool clear_unbuffered
)
2317 int cur_idx
= track_widx
;
2320 logf("Clearing tracks:%d/%d, %d", track_ridx
, track_widx
, clear_unbuffered
);
2322 /* Loop over all tracks from write-to-read */
2326 cur_idx
&= MAX_TRACK_MASK
;
2328 if (cur_idx
== track_ridx
)
2331 /* If the track is buffered, conditionally clear/notify,
2332 * otherwise clear the track if that option is selected */
2333 if (tracks
[cur_idx
].event_sent
)
2337 /* If there is an unbuffer callback, call it, otherwise,
2338 * just clear the track */
2339 if (track_unbuffer_callback
)
2340 track_unbuffer_callback(&tracks
[last_idx
].id3
, false);
2342 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2346 else if (clear_unbuffered
)
2347 memset(&tracks
[cur_idx
], 0, sizeof(struct track_info
));
2350 /* We clear the previous instance of a buffered track throughout
2351 * the above loop to facilitate 'last' detection. Clear/notify
2352 * the last track here */
2355 if (track_unbuffer_callback
)
2356 track_unbuffer_callback(&tracks
[last_idx
].id3
, true);
2357 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2361 /* FIXME: This code should be made more generic and move to metadata.c */
2362 static void audio_strip_tags(void)
2365 static const unsigned char tag
[] = "TAG";
2366 static const unsigned char apetag
[] = "APETAGEX";
2369 size_t len
, version
;
2371 tag_idx
= RINGBUF_SUB(buf_widx
, 128);
2373 if (FILEBUFUSED
> 128 && tag_idx
> buf_ridx
)
2376 for(i
= 0;i
< 3;i
++)
2378 if(filebuf
[cur_idx
] != tag
[i
])
2381 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2384 /* Skip id3v1 tag */
2385 logf("Skipping ID3v1 tag");
2387 tracks
[track_widx
].available
-= 128;
2388 tracks
[track_widx
].filesize
-= 128;
2392 /* Check for APE tag (look for the APE tag footer) */
2393 tag_idx
= RINGBUF_SUB(buf_widx
, 32);
2395 if (FILEBUFUSED
> 32 && tag_idx
> buf_ridx
)
2398 for(i
= 0;i
< 8;i
++)
2400 if(filebuf
[cur_idx
] != apetag
[i
])
2403 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2406 /* Read the version and length from the footer */
2407 version
= filebuf
[tag_idx
+8] | (filebuf
[tag_idx
+9] << 8) |
2408 (filebuf
[tag_idx
+10] << 16) | (filebuf
[tag_idx
+11] << 24);
2409 len
= filebuf
[tag_idx
+12] | (filebuf
[tag_idx
+13] << 8) |
2410 (filebuf
[tag_idx
+14] << 16) | (filebuf
[tag_idx
+15] << 24);
2411 if (version
== 2000)
2412 len
+= 32; /* APEv2 has a 32 byte header */
2415 if (FILEBUFUSED
> len
)
2417 logf("Skipping APE tag (%ldB)", len
);
2418 buf_widx
= RINGBUF_SUB(buf_widx
, len
);
2419 tracks
[track_widx
].available
-= len
;
2420 tracks
[track_widx
].filesize
-= len
;
2425 /* Returns true if a whole file is read, false otherwise */
2426 static bool audio_read_file(size_t minimum
)
2428 bool ret_val
= false;
2430 /* If we're called and no file is open, this is an error */
2433 logf("Bad fd in arf");
2434 /* Give some hope of miraculous recovery by forcing a track reload */
2435 tracks
[track_widx
].filesize
= 0;
2436 /* Stop this buffering run */
2440 trigger_cpu_boost();
2441 while (tracks
[track_widx
].filerem
> 0)
2447 /* copy_n is the largest chunk that is safe to read */
2448 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2450 /* buf_widx == buf_ridx is defined as buffer empty, not buffer full */
2451 if (RINGBUF_ADD_CROSS(buf_widx
,copy_n
,buf_ridx
) >= 0)
2454 /* rc is the actual amount read */
2455 rc
= read(current_fd
, &filebuf
[buf_widx
], copy_n
);
2459 logf("File ended %ldB early", tracks
[track_widx
].filerem
);
2460 tracks
[track_widx
].filesize
-= tracks
[track_widx
].filerem
;
2461 tracks
[track_widx
].filerem
= 0;
2465 /* How much of the playing track did we overwrite */
2466 if (buf_widx
== CUR_TI
->buf_idx
)
2468 /* Special handling; zero or full overlap? */
2469 if (track_widx
== track_ridx
&& CUR_TI
->available
== 0)
2475 overlap
= RINGBUF_ADD_CROSS(buf_widx
,rc
,CUR_TI
->buf_idx
);
2477 if ((unsigned)rc
> tracks
[track_widx
].filerem
)
2479 logf("Bad: rc-filerem=%ld, fixing", rc
-tracks
[track_widx
].filerem
);
2480 tracks
[track_widx
].filesize
+= rc
- tracks
[track_widx
].filerem
;
2481 tracks
[track_widx
].filerem
= rc
;
2484 /* Advance buffer */
2485 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2486 tracks
[track_widx
].available
+= rc
;
2487 tracks
[track_widx
].filerem
-= rc
;
2489 /* If we write into the playing track, adjust it's buffer info */
2492 CUR_TI
->buf_idx
+= overlap
;
2493 CUR_TI
->start_pos
+= overlap
;
2496 /* For a rebuffer, fill at least this minimum */
2497 if (minimum
> (unsigned)rc
)
2499 /* Let the codec process up to the watermark */
2500 /* Break immediately if this is a quick buffer, or there is an event */
2501 else if (minimum
|| audio_yield_codecs())
2503 /* Exit quickly, but don't stop the overall buffering process */
2509 if (tracks
[track_widx
].filerem
== 0)
2511 logf("Finished buf:%ldB", tracks
[track_widx
].filesize
);
2517 track_widx
&= MAX_TRACK_MASK
;
2519 tracks
[track_widx
].filesize
= 0;
2524 logf("%s buf:%ldB", ret_val
?"Quick":"Partially",
2525 tracks
[track_widx
].filesize
- tracks
[track_widx
].filerem
);
2530 static bool audio_loadcodec(bool start_play
)
2537 char codec_path
[MAX_PATH
]; /* Full path to codec */
2539 const char * codec_fn
=
2540 get_codec_filename(tracks
[track_widx
].id3
.codectype
);
2541 if (codec_fn
== NULL
)
2544 tracks
[track_widx
].has_codec
= false;
2548 /* Load the codec directly from disk and save some memory. */
2549 track_ridx
= track_widx
;
2550 ci
.filesize
= CUR_TI
->filesize
;
2551 ci
.id3
= &CUR_TI
->id3
;
2552 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2554 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2555 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
2560 /* If we already have another track than this one buffered */
2561 if (track_widx
!= track_ridx
)
2563 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
2565 /* If the previous codec is the same as this one, there is no need
2566 * to put another copy of it on the file buffer */
2567 if (get_codec_base_type(tracks
[track_widx
].id3
.codectype
) ==
2568 get_codec_base_type(tracks
[prev_track
].id3
.codectype
)
2569 && audio_codec_loaded
)
2571 logf("Reusing prev. codec");
2577 codec_get_full_path(codec_path
, codec_fn
);
2579 fd
= open(codec_path
, O_RDONLY
);
2582 logf("Codec doesn't exist!");
2586 tracks
[track_widx
].codecsize
= filesize(fd
);
2588 /* Never load a partial codec */
2589 if (RINGBUF_ADD_CROSS(buf_widx
,tracks
[track_widx
].codecsize
,buf_ridx
) >= 0)
2591 logf("Not enough space");
2596 while (size
< tracks
[track_widx
].codecsize
)
2598 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2599 rc
= read(fd
, &filebuf
[buf_widx
], copy_n
);
2603 /* This is an error condition, likely the codec file is corrupt */
2604 logf("Partial codec loaded");
2605 /* Must undo the buffer write of the partial codec */
2606 buf_widx
= RINGBUF_SUB(buf_widx
, size
);
2607 tracks
[track_widx
].codecsize
= 0;
2611 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2616 tracks
[track_widx
].has_codec
= true;
2619 logf("Done: %ldB", size
);
2624 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2625 static void audio_set_elapsed(struct mp3entry
* id3
)
2627 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
2628 id3
->offset
- id3
->first_frame_offset
: 0;
2631 if ( id3
->has_toc
) {
2632 /* calculate elapsed time using TOC */
2634 unsigned int remainder
, plen
, relpos
, nextpos
;
2636 /* find wich percent we're at */
2637 for (i
=0; i
<100; i
++ )
2638 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
2645 relpos
= id3
->toc
[i
];
2648 nextpos
= id3
->toc
[i
+1];
2652 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
2654 /* set time for this percent (divide before multiply to prevent
2655 overflow on long files. loss of precision is negligible on
2657 id3
->elapsed
= i
* (id3
->length
/ 100);
2659 /* calculate remainder time */
2660 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
2661 id3
->elapsed
+= (((remainder
* 100) / plen
) *
2662 (id3
->length
/ 10000));
2665 /* no TOC exists. set a rough estimate using average bitrate */
2666 int tpk
= id3
->length
/
2667 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
2669 id3
->elapsed
= offset
/ 1024 * tpk
;
2674 /* constant bitrate, use exact calculation */
2675 if (id3
->bitrate
!= 0)
2676 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
2680 static bool audio_load_track(int offset
, bool start_play
, bool rebuffer
)
2686 /* Stop buffer filling if there is no free track entries.
2687 Don't fill up the last track entry (we wan't to store next track
2689 if (!audio_have_free_tracks())
2691 logf("No free tracks");
2695 if (current_fd
>= 0)
2697 logf("Nonzero fd in alt");
2704 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
2705 /* Get track name from current playlist read position. */
2706 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
2708 /* Handle broken playlists. */
2709 current_fd
= open(trackname
, O_RDONLY
);
2712 logf("Open failed");
2713 /* Skip invalid entry from playlist. */
2714 playlist_skip_entry(NULL
, last_peek_offset
);
2722 logf("End-of-playlist");
2723 playlist_end
= true;
2727 /* Initialize track entry. */
2728 size
= filesize(current_fd
);
2729 tracks
[track_widx
].filerem
= size
;
2730 tracks
[track_widx
].filesize
= size
;
2731 tracks
[track_widx
].available
= 0;
2733 /* Set default values */
2736 int last_codec
= current_codec
;
2738 set_current_codec(CODEC_IDX_AUDIO
);
2739 conf_watermark
= AUDIO_DEFAULT_WATERMARK
;
2740 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
2741 conf_preseek
= AUDIO_REBUFFER_GUESS_SIZE
;
2742 dsp_configure(DSP_RESET
, 0);
2743 set_current_codec(last_codec
);
2746 /* Get track metadata if we don't already have it. */
2747 if (!tracks
[track_widx
].taginfo_ready
)
2749 if (get_metadata(&tracks
[track_widx
],current_fd
,trackname
,v1first
))
2753 track_changed
= true;
2754 playlist_update_resume_info(audio_current_track());
2759 logf("mde:%s!",trackname
);
2761 /* Set filesize to zero to indicate no file was loaded. */
2762 tracks
[track_widx
].filesize
= 0;
2763 tracks
[track_widx
].filerem
= 0;
2767 /* Skip invalid entry from playlist. */
2768 playlist_skip_entry(NULL
, last_peek_offset
);
2769 tracks
[track_widx
].taginfo_ready
= false;
2775 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
2777 char cuepath
[MAX_PATH
];
2779 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
2781 if (look_for_cuesheet_file(trackname
, cuepath
) &&
2782 parse_cuesheet(cuepath
, cue
))
2784 strcpy((cue
)->audio_filename
, trackname
);
2786 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
2790 /* Load the codec. */
2791 tracks
[track_widx
].codecbuf
= &filebuf
[buf_widx
];
2792 if (!audio_loadcodec(start_play
))
2794 /* Set filesize to zero to indicate no file was loaded. */
2795 tracks
[track_widx
].filesize
= 0;
2796 tracks
[track_widx
].filerem
= 0;
2800 if (tracks
[track_widx
].codecsize
)
2802 /* No space for codec on buffer, not an error */
2803 tracks
[track_widx
].codecsize
= 0;
2807 /* This is an error condition, either no codec was found, or reading
2808 * the codec file failed part way through, either way, skip the track */
2809 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
2810 /* We should not use gui_syncplash from audio thread! */
2811 gui_syncsplash(HZ
*2, msgbuf
);
2812 /* Skip invalid entry from playlist. */
2813 playlist_skip_entry(NULL
, last_peek_offset
);
2814 tracks
[track_widx
].taginfo_ready
= false;
2818 tracks
[track_widx
].start_pos
= 0;
2819 set_filebuf_watermark(buffer_margin
);
2820 tracks
[track_widx
].id3
.elapsed
= 0;
2824 switch (tracks
[track_widx
].id3
.codectype
) {
2828 lseek(current_fd
, offset
, SEEK_SET
);
2829 tracks
[track_widx
].id3
.offset
= offset
;
2830 audio_set_elapsed(&tracks
[track_widx
].id3
);
2831 tracks
[track_widx
].filerem
= size
- offset
;
2833 tracks
[track_widx
].start_pos
= offset
;
2837 lseek(current_fd
, offset
, SEEK_SET
);
2838 tracks
[track_widx
].id3
.offset
= offset
;
2839 tracks
[track_widx
].id3
.elapsed
=
2840 tracks
[track_widx
].id3
.length
/ 2;
2841 tracks
[track_widx
].filerem
= size
- offset
;
2843 tracks
[track_widx
].start_pos
= offset
;
2846 case AFMT_OGG_VORBIS
:
2854 tracks
[track_widx
].id3
.offset
= offset
;
2859 logf("alt:%s", trackname
);
2860 tracks
[track_widx
].buf_idx
= buf_widx
;
2862 return audio_read_file(rebuffer
);
2865 static bool audio_read_next_metadata(void)
2872 next_idx
= track_widx
;
2873 if (tracks
[next_idx
].taginfo_ready
)
2876 next_idx
&= MAX_TRACK_MASK
;
2878 if (tracks
[next_idx
].taginfo_ready
)
2882 trackname
= playlist_peek(last_peek_offset
+ 1);
2886 fd
= open(trackname
, O_RDONLY
);
2890 status
= get_metadata(&tracks
[next_idx
],fd
,trackname
,v1first
);
2891 /* Preload the glyphs in the tags */
2894 if (tracks
[next_idx
].id3
.title
)
2895 lcd_getstringsize(tracks
[next_idx
].id3
.title
, NULL
, NULL
);
2896 if (tracks
[next_idx
].id3
.artist
)
2897 lcd_getstringsize(tracks
[next_idx
].id3
.artist
, NULL
, NULL
);
2898 if (tracks
[next_idx
].id3
.album
)
2899 lcd_getstringsize(tracks
[next_idx
].id3
.album
, NULL
, NULL
);
2906 /* Send callback events to notify about new tracks. */
2907 static void audio_generate_postbuffer_events(void)
2912 logf("Postbuffer:%d/%d",track_ridx
,track_widx
);
2914 if (audio_have_tracks())
2916 cur_idx
= track_ridx
;
2919 if (!tracks
[cur_idx
].event_sent
)
2921 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2923 /* Mark the event 'sent' even if we don't really send one */
2924 tracks
[last_idx
].event_sent
= true;
2925 if (track_buffer_callback
)
2926 track_buffer_callback(&tracks
[last_idx
].id3
, false);
2930 if (cur_idx
== track_widx
)
2933 cur_idx
&= MAX_TRACK_MASK
;
2936 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2938 tracks
[last_idx
].event_sent
= true;
2939 if (track_buffer_callback
)
2940 track_buffer_callback(&tracks
[last_idx
].id3
, true);
2945 static bool audio_initialize_buffer_fill(bool clear_tracks
)
2947 /* Don't initialize if we're already initialized */
2951 logf("Starting buffer fill");
2953 /* Set the filling flag true before calling audio_clear_tracks as that
2954 * function can yield and we start looping. */
2958 audio_clear_track_entries(false);
2960 /* Save the current resume position once. */
2961 playlist_update_resume_info(audio_current_track());
2966 static void audio_fill_file_buffer(
2967 bool start_play
, bool rebuffer
, size_t offset
)
2969 bool had_next_track
= audio_next_track() != NULL
;
2970 bool continue_buffering
;
2972 /* Must reset the buffer before use if trashed or voice only - voice
2973 file size shouldn't have changed so we can go straight from
2974 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
2975 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
2976 audio_reset_buffer();
2978 if (!audio_initialize_buffer_fill(!start_play
))
2981 /* If we have a partially buffered track, continue loading,
2982 * otherwise load a new track */
2983 if (tracks
[track_widx
].filesize
> 0)
2984 continue_buffering
= audio_read_file(rebuffer
);
2986 continue_buffering
= audio_load_track(offset
, start_play
, rebuffer
);
2988 if (!had_next_track
&& audio_next_track())
2989 track_changed
= true;
2991 /* If we're done buffering */
2992 if (!continue_buffering
)
2994 audio_read_next_metadata();
2996 audio_generate_postbuffer_events();
3005 static void audio_rebuffer(void)
3007 logf("Forcing rebuffer");
3009 /* Stop in progress fill, and clear open file descriptor */
3010 if (current_fd
>= 0)
3017 /* Reset buffer and track pointers */
3018 CUR_TI
->buf_idx
= buf_ridx
= buf_widx
= 0;
3019 track_widx
= track_ridx
;
3020 audio_clear_track_entries(true);
3021 CUR_TI
->available
= 0;
3023 /* Fill the buffer */
3024 last_peek_offset
= -1;
3025 CUR_TI
->filesize
= 0;
3026 CUR_TI
->start_pos
= 0;
3029 if (!CUR_TI
->taginfo_ready
)
3030 memset(&CUR_TI
->id3
, 0, sizeof(struct mp3entry
));
3032 audio_fill_file_buffer(false, true, 0);
3035 static int audio_check_new_track(void)
3037 int track_count
= audio_track_count();
3038 int old_track_ridx
= track_ridx
;
3044 if (playlist_next_dir(ci
.new_track
))
3047 CUR_TI
->taginfo_ready
= false;
3053 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3054 return Q_CODEC_REQUEST_FAILED
;
3061 /* If the playlist isn't that big */
3062 if (!playlist_check(ci
.new_track
))
3064 if (ci
.new_track
>= 0)
3066 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3067 return Q_CODEC_REQUEST_FAILED
;
3069 /* Find the beginning backward if the user over-skips it */
3070 while (!playlist_check(++ci
.new_track
))
3071 if (ci
.new_track
>= 0)
3073 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3074 return Q_CODEC_REQUEST_FAILED
;
3077 /* Update the playlist */
3078 last_peek_offset
-= ci
.new_track
;
3080 if (playlist_next(ci
.new_track
) < 0)
3082 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3083 return Q_CODEC_REQUEST_FAILED
;
3089 new_playlist
= false;
3092 /* Save the old track */
3095 /* Move to the new track */
3096 track_ridx
+= ci
.new_track
;
3097 track_ridx
&= MAX_TRACK_MASK
;
3100 playlist_end
= false;
3102 track_changed
= !automatic_skip
;
3104 /* If it is not safe to even skip this many track entries */
3105 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
3108 CUR_TI
->taginfo_ready
= false;
3113 forward
= ci
.new_track
> 0;
3116 /* If the target track is clearly not in memory */
3117 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
3123 /* The track may be in memory, see if it really is */
3126 if (!audio_buffer_wind_forward(track_ridx
, old_track_ridx
))
3131 int cur_idx
= track_ridx
;
3132 bool taginfo_ready
= true;
3133 bool wrap
= track_ridx
> old_track_ridx
;
3138 cur_idx
&= MAX_TRACK_MASK
;
3139 if (!(wrap
|| cur_idx
< old_track_ridx
))
3142 /* If we hit a track in between without valid tag info, bail */
3143 if (!tracks
[cur_idx
].taginfo_ready
)
3145 taginfo_ready
= false;
3149 tracks
[cur_idx
].available
= tracks
[cur_idx
].filesize
;
3150 if (tracks
[cur_idx
].codecsize
)
3151 tracks
[cur_idx
].has_codec
= true;
3155 if (!audio_buffer_wind_backward(track_ridx
, old_track_ridx
))
3160 CUR_TI
->taginfo_ready
= false;
3166 audio_update_trackinfo();
3167 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3168 return Q_CODEC_REQUEST_COMPLETE
;
3171 static int audio_rebuffer_and_seek(size_t newpos
)
3173 size_t real_preseek
;
3177 /* (Re-)open current track's file handle. */
3178 trackname
= playlist_peek(0);
3179 fd
= open(trackname
, O_RDONLY
);
3182 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3183 return Q_CODEC_REQUEST_FAILED
;
3186 if (current_fd
>= 0)
3190 playlist_end
= false;
3194 /* Clear codec buffer. */
3195 track_widx
= track_ridx
;
3196 tracks
[track_widx
].buf_idx
= buf_widx
= buf_ridx
= 0;
3198 last_peek_offset
= 0;
3200 audio_initialize_buffer_fill(true);
3202 /* This may have been tweaked by the id3v1 code */
3203 CUR_TI
->filesize
=filesize(fd
);
3204 if (newpos
> conf_preseek
)
3206 CUR_TI
->start_pos
= newpos
- conf_preseek
;
3207 lseek(current_fd
, CUR_TI
->start_pos
, SEEK_SET
);
3208 CUR_TI
->filerem
= CUR_TI
->filesize
- CUR_TI
->start_pos
;
3209 real_preseek
= conf_preseek
;
3213 CUR_TI
->start_pos
= 0;
3214 CUR_TI
->filerem
= CUR_TI
->filesize
;
3215 real_preseek
= newpos
;
3218 CUR_TI
->available
= 0;
3220 audio_read_file(real_preseek
);
3222 /* Account for the data we just read that is 'behind' us now */
3223 CUR_TI
->available
-= real_preseek
;
3225 buf_ridx
= RINGBUF_ADD(buf_ridx
, real_preseek
);
3227 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3228 return Q_CODEC_REQUEST_COMPLETE
;
3231 void audio_set_track_buffer_event(void (*handler
)(struct mp3entry
*id3
,
3234 track_buffer_callback
= handler
;
3237 void audio_set_track_unbuffer_event(void (*handler
)(struct mp3entry
*id3
,
3240 track_unbuffer_callback
= handler
;
3243 void audio_set_track_changed_event(void (*handler
)(struct mp3entry
*id3
))
3245 track_changed_callback
= handler
;
3248 unsigned long audio_prev_elapsed(void)
3250 return prev_track_elapsed
;
3253 static void audio_stop_codec_flush(void)
3255 ci
.stop_codec
= true;
3258 while (audio_codec_loaded
)
3261 /* If the audio codec is not loaded any more, and the audio is still
3262 * playing, it is now and _only_ now safe to call this function from the
3264 if (pcm_is_playing())
3266 pcmbuf_pause(paused
);
3269 static void audio_stop_playback(void)
3271 /* If we were playing, save resume information */
3274 struct mp3entry
*id3
= NULL
;
3276 if (!playlist_end
|| !ci
.stop_codec
)
3278 /* Set this early, the outside code yields and may allow the codec
3279 to try to wait for a reply on a buffer wait */
3280 ci
.stop_codec
= true;
3281 id3
= audio_current_track();
3284 /* Save the current playing spot, or NULL if the playlist has ended */
3285 playlist_update_resume_info(id3
);
3287 prev_track_elapsed
= CUR_TI
->id3
.elapsed
;
3289 /* Increment index so runtime info is saved in audio_clear_track_entries().
3290 * Done here, as audio_stop_playback() may be called more than once.
3291 * Don't update runtime unless playback is stopped because of end of playlist.
3292 * Updating runtime when manually stopping a tracks, can destroy autoscores
3298 track_ridx
&= MAX_TRACK_MASK
;
3304 audio_stop_codec_flush();
3307 if (current_fd
>= 0)
3313 /* Mark all entries null. */
3314 audio_clear_track_entries(false);
3317 static void audio_play_start(size_t offset
)
3319 #if INPUT_SRC_CAPS != 0
3320 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
3321 audio_set_output_source(AUDIO_SRC_PLAYBACK
);
3324 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
3326 audio_stop_codec_flush();
3328 track_changed
= true;
3329 playlist_end
= false;
3337 if (current_fd
>= 0)
3343 sound_set_volume(global_settings
.volume
);
3344 track_widx
= track_ridx
= 0;
3345 buf_ridx
= buf_widx
= 0;
3347 /* Mark all entries null. */
3348 memset(tracks
, 0, sizeof(struct track_info
) * MAX_TRACK
);
3350 last_peek_offset
= -1;
3352 /* Officially playing */
3353 queue_reply(&audio_queue
, 1);
3355 audio_fill_file_buffer(true, false, offset
);
3357 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
3358 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
3362 /* Invalidates all but currently playing track. */
3363 static void audio_invalidate_tracks(void)
3365 if (audio_have_tracks())
3367 last_peek_offset
= 0;
3368 playlist_end
= false;
3369 track_widx
= track_ridx
;
3371 /* Mark all other entries null (also buffered wrong metadata). */
3372 audio_clear_track_entries(true);
3374 /* If the current track is fully buffered, advance the write pointer */
3375 if (tracks
[track_widx
].filerem
== 0)
3376 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
3378 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3380 audio_read_next_metadata();
3384 static void audio_new_playlist(void)
3386 /* Prepare to start a new fill from the beginning of the playlist */
3387 last_peek_offset
= -1;
3388 if (audio_have_tracks())
3391 skipped_during_pause
= true;
3392 playlist_end
= false;
3393 track_widx
= track_ridx
;
3394 audio_clear_track_entries(true);
3397 track_widx
&= MAX_TRACK_MASK
;
3399 /* Stop reading the current track */
3400 CUR_TI
->filerem
= 0;
3404 /* Mark the current track as invalid to prevent skipping back to it */
3405 CUR_TI
->taginfo_ready
= false;
3407 /* Invalidate the buffer other than the playing track */
3408 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3411 /* Signal the codec to initiate a track change forward */
3412 new_playlist
= true;
3415 /* Officially playing */
3416 queue_reply(&audio_queue
, 1);
3418 audio_fill_file_buffer(false, true, 0);
3421 static void audio_initiate_track_change(long direction
)
3423 playlist_end
= false;
3424 ci
.new_track
+= direction
;
3425 wps_offset
-= direction
;
3427 skipped_during_pause
= true;
3430 static void audio_initiate_dir_change(long direction
)
3432 playlist_end
= false;
3434 ci
.new_track
= direction
;
3436 skipped_during_pause
= true;
3440 * Layout audio buffer as follows - iram buffer depends on target:
3441 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
3443 static void audio_reset_buffer(void)
3445 /* see audio_get_recording_buffer if this is modified */
3446 logf("audio_reset_buffer");
3448 /* If the setup of anything allocated before the file buffer is
3449 changed, do check the adjustments after the buffer_alloc call
3450 as it will likely be affected and need sliding over */
3452 /* Initially set up file buffer as all space available */
3453 malloc_buf
= audiobuf
+ talk_get_bufsize();
3454 /* Align the malloc buf to line size. Especially important to cf
3455 targets that do line reads/writes. */
3456 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
3457 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
3458 filebuflen
= audiobufend
- filebuf
;
3460 /* Allow for codec swap space at end of audio buffer */
3461 if (talk_voice_required())
3463 /* Layout of swap buffer:
3464 * #ifdef IRAM_STEAL (dedicated iram_buf):
3465 * |iram_buf|...audiobuf...|dram_buf|audiobufend
3467 * audiobuf...|dram_buf|iram_buf|audiobufend
3469 #ifdef PLAYBACK_VOICE
3470 /* Check for an absolutely nasty situation which should never,
3471 ever happen - frankly should just panic */
3472 if (voice_codec_loaded
&& current_codec
!= CODEC_IDX_VOICE
)
3474 logf("buffer reset with voice swapped");
3476 /* line align length which line aligns the calculations below since
3477 all sizes are also at least line aligned - needed for memswap128 */
3480 filebuflen
-= CODEC_SIZE
;
3482 filebuflen
-= CODEC_SIZE
+ CODEC_IRAM_SIZE
;
3484 /* Allocate buffers for swapping voice <=> audio */
3485 /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
3486 and out of the way of buffer usage or else a call to audio_get_buffer
3487 and subsequent buffer use might trash the swap space. A plugin
3488 initializing IRAM after getting the full buffer would present similar
3489 problem. Options include: failing the request if the other buffer
3490 has been obtained already or never allowing use of the voice IRAM
3491 buffer within the audio buffer. Using buffer_alloc basically
3492 implements the second in a more convenient way. */
3493 dram_buf
= filebuf
+ filebuflen
;
3496 /* Allocate voice IRAM swap buffer once */
3497 if (iram_buf
== NULL
)
3499 iram_buf
= buffer_alloc(CODEC_IRAM_SIZE
);
3500 /* buffer_alloc moves audiobuf; this is safe because only the end
3501 * has been touched so far in this function and the address of
3502 * filebuf + filebuflen is not changed */
3503 malloc_buf
+= CODEC_IRAM_SIZE
;
3504 filebuf
+= CODEC_IRAM_SIZE
;
3505 filebuflen
-= CODEC_IRAM_SIZE
;
3508 /* Allocate iram_buf after dram_buf */
3509 iram_buf
= dram_buf
+ CODEC_SIZE
;
3510 #endif /* IRAM_STEAL */
3511 #endif /* PLAYBACK_VOICE */
3515 #ifdef PLAYBACK_VOICE
3516 /* No swap buffers needed */
3522 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
3523 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
3525 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
3526 will already be line aligned */
3529 /* Set the high watermark as 75% full...or 25% empty :) */
3531 high_watermark
= 3*filebuflen
/ 4;
3534 /* Clear any references to the file buffer */
3535 buffer_state
= BUFFER_STATE_INITIALIZED
;
3537 #ifdef ROCKBOX_HAS_LOGF
3538 /* Make sure everything adds up - yes, some info is a bit redundant but
3539 aids viewing and the sumation of certain variables should add up to
3540 the location of others. */
3543 unsigned char * pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
3544 logf("mabuf: %08X", (unsigned)malloc_buf
);
3545 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
3546 logf("fbuf: %08X", (unsigned)filebuf
);
3547 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
3548 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
3549 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
3550 logf("pcmb: %08X", (unsigned)pcmbuf
);
3551 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
3554 logf("dramb: %08X", (unsigned)dram_buf
);
3555 logf("drambe: %08X", (unsigned)(dram_buf
+ CODEC_SIZE
));
3559 logf("iramb: %08X", (unsigned)iram_buf
);
3560 logf("irambe: %08X", (unsigned)(iram_buf
+ CODEC_IRAM_SIZE
));
3567 /* we dont want this rebuffering on targets with little ram
3568 because the disk may never spin down */
3569 static bool ata_fillbuffer_callback(void)
3571 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
, 0);
3576 static void audio_thread(void)
3582 #ifdef PLAYBACK_VOICE
3583 /* Unlock mutex that init stage locks before creating this thread */
3584 mutex_unlock(&mutex_codecthread
);
3586 /* Buffers must be set up by now - should panic - really */
3587 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
3589 logf("audio_thread start: no buffer");
3592 /* Have to wait for voice to load up or else the codec swap will be
3593 invalid when an audio codec is loaded */
3594 wait_for_voice_swap_in();
3599 intptr_t result
= 0;
3603 queue_wait_w_tmo(&audio_queue
, &ev
, 0);
3604 if (ev
.id
== SYS_TIMEOUT
)
3605 ev
.id
= Q_AUDIO_FILL_BUFFER
;
3609 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
3611 if (playing
&& (ev
.id
== SYS_TIMEOUT
) &&
3612 (FILEBUFUSED
< high_watermark
))
3613 register_ata_idle_func(ata_fillbuffer_callback
);
3619 case Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
:
3620 /* only fill if the disk is still spining */
3622 if (!ata_disk_is_active())
3625 #endif /* MEM > 8 */
3626 /* else fall through to Q_AUDIO_FILL_BUFFER */
3627 case Q_AUDIO_FILL_BUFFER
:
3628 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3630 if (!playing
|| playlist_end
|| ci
.stop_codec
)
3632 audio_fill_file_buffer(false, false, 0);
3636 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3637 if (playing
&& ev
.data
<= 0)
3638 audio_new_playlist();
3641 audio_stop_playback();
3642 audio_play_start((size_t)ev
.data
);
3647 LOGFQUEUE("audio < Q_AUDIO_STOP");
3649 audio_stop_playback();
3651 queue_clear(&audio_queue
);
3655 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3656 if (!(bool) ev
.data
&& skipped_during_pause
&& !pcmbuf_is_crossfade_active())
3657 pcmbuf_play_stop(); /* Flush old track on resume after skip */
3658 skipped_during_pause
= false;
3661 pcmbuf_pause((bool)ev
.data
);
3662 paused
= (bool)ev
.data
;
3666 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3667 audio_initiate_track_change((long)ev
.data
);
3670 case Q_AUDIO_PRE_FF_REWIND
:
3671 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3677 case Q_AUDIO_FF_REWIND
:
3678 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3681 ci
.seek_time
= (long)ev
.data
+1;
3684 case Q_AUDIO_REBUFFER_SEEK
:
3685 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
3686 result
= audio_rebuffer_and_seek(ev
.data
);
3689 case Q_AUDIO_CHECK_NEW_TRACK
:
3690 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3691 result
= audio_check_new_track();
3694 case Q_AUDIO_DIR_SKIP
:
3695 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3696 playlist_end
= false;
3697 audio_initiate_dir_change(ev
.data
);
3701 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3702 audio_invalidate_tracks();
3705 case Q_AUDIO_TRACK_CHANGED
:
3706 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3707 if (track_changed_callback
)
3708 track_changed_callback(&CUR_TI
->id3
);
3709 track_changed
= true;
3710 playlist_update_resume_info(audio_current_track());
3714 case SYS_USB_CONNECTED
:
3715 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3717 audio_stop_playback();
3718 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
3719 usb_wait_for_disconnect(&audio_queue
);
3724 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3728 LOGFQUEUE("audio < default");
3731 queue_reply(&audio_queue
, result
);
3735 #ifdef ROCKBOX_HAS_LOGF
3736 static void audio_test_track_changed_event(struct mp3entry
*id3
)
3740 logf("tce:%s", id3
->path
);
3744 /* Initialize the audio system - called from init() in main.c.
3745 * Last function because of all the references to internal symbols
3747 void audio_init(void)
3749 #ifdef PLAYBACK_VOICE
3750 static bool voicetagtrue
= true;
3751 static struct mp3entry id3_voice
;
3754 /* Can never do this twice */
3755 if (audio_is_initialized
)
3757 logf("audio: already initialized");
3761 logf("audio: initializing");
3763 /* Initialize queues before giving control elsewhere in case it likes
3764 to send messages. Thread creation will be delayed however so nothing
3765 starts running until ready if something yields such as talk_init. */
3766 #ifdef PLAYBACK_VOICE
3767 mutex_init(&mutex_codecthread
);
3768 /* Take ownership of lock to prevent playback of anything before audio
3769 hardware is initialized - audio thread unlocks it after final init
3771 mutex_lock(&mutex_codecthread
);
3773 queue_init(&audio_queue
, true);
3774 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
3775 queue_init(&codec_queue
, true);
3779 #ifdef ROCKBOX_HAS_LOGF
3780 audio_set_track_changed_event(audio_test_track_changed_event
);
3783 /* Initialize codec api. */
3784 ci
.read_filebuf
= codec_filebuf_callback
;
3785 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
3786 ci
.get_codec_memory
= codec_get_memory_callback
;
3787 ci
.request_buffer
= codec_request_buffer_callback
;
3788 ci
.advance_buffer
= codec_advance_buffer_callback
;
3789 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
3790 ci
.request_next_track
= codec_request_next_track_callback
;
3791 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
3792 ci
.seek_buffer
= codec_seek_buffer_callback
;
3793 ci
.seek_complete
= codec_seek_complete_callback
;
3794 ci
.set_elapsed
= codec_set_elapsed_callback
;
3795 ci
.set_offset
= codec_set_offset_callback
;
3796 ci
.configure
= codec_configure_callback
;
3797 ci
.discard_codec
= codec_discard_codec_callback
;
3799 /* Initialize voice codec api. */
3800 #ifdef PLAYBACK_VOICE
3801 memcpy(&ci_voice
, &ci
, sizeof(ci_voice
));
3802 memset(&id3_voice
, 0, sizeof(id3_voice
));
3803 ci_voice
.read_filebuf
= voice_filebuf_callback
;
3804 ci_voice
.pcmbuf_insert
= voice_pcmbuf_insert_callback
;
3805 ci_voice
.get_codec_memory
= voice_get_memory_callback
;
3806 ci_voice
.request_buffer
= voice_request_buffer_callback
;
3807 ci_voice
.advance_buffer
= voice_advance_buffer_callback
;
3808 ci_voice
.advance_buffer_loc
= voice_advance_buffer_loc_callback
;
3809 ci_voice
.request_next_track
= voice_request_next_track_callback
;
3810 ci_voice
.mp3_get_filepos
= voice_mp3_get_filepos_callback
;
3811 ci_voice
.seek_buffer
= voice_seek_buffer_callback
;
3812 ci_voice
.seek_complete
= voice_do_nothing
;
3813 ci_voice
.set_elapsed
= voice_set_elapsed_callback
;
3814 ci_voice
.set_offset
= voice_set_offset_callback
;
3815 ci_voice
.configure
= voice_configure_callback
;
3816 ci_voice
.discard_codec
= voice_do_nothing
;
3817 ci_voice
.taginfo_ready
= &voicetagtrue
;
3818 ci_voice
.id3
= &id3_voice
;
3819 id3_voice
.frequency
= 11200;
3820 id3_voice
.length
= 1000000L;
3823 /* initialize the buffer */
3826 /* audio_reset_buffer must to know the size of voice buffer so init
3830 /* Create the threads late now that we shouldn't be yielding again before
3832 codec_thread_p
= create_thread(
3833 codec_thread
, codec_stack
, sizeof(codec_stack
),
3834 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
3835 IF_COP(, CPU
, true));
3837 create_thread(audio_thread
, audio_stack
, sizeof(audio_stack
),
3838 audio_thread_name
IF_PRIO(, PRIORITY_BUFFERING
)
3839 IF_COP(, CPU
, false));
3841 #ifdef PLAYBACK_VOICE
3842 /* TODO: Change this around when various speech codecs can be used */
3843 if (talk_voice_required())
3845 logf("Starting voice codec");
3846 queue_init(&voice_queue
, true);
3847 create_thread(voice_thread
, voice_stack
,
3848 sizeof(voice_stack
), voice_thread_name
3849 IF_PRIO(, PRIORITY_PLAYBACK
) IF_COP(, CPU
, false));
3853 /* Set crossfade setting for next buffer init which should be about... */
3854 pcmbuf_crossfade_enable(global_settings
.crossfade
);
3856 /* ...now! Set up the buffers */
3857 audio_reset_buffer();
3859 /* Probably safe to say */
3860 audio_is_initialized
= true;
3862 sound_settings_apply();
3864 eq_hw_enable(global_settings
.eq_hw_enabled
);
3866 #ifndef HAVE_FLASH_STORAGE
3867 audio_set_buffer_margin(global_settings
.buffer_margin
);