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
].id3
),current_fd
,trackname
,v1first
))
2751 tracks
[track_widx
].taginfo_ready
= true;
2754 track_changed
= true;
2755 playlist_update_resume_info(audio_current_track());
2760 logf("mde:%s!",trackname
);
2762 /* Set filesize to zero to indicate no file was loaded. */
2763 tracks
[track_widx
].filesize
= 0;
2764 tracks
[track_widx
].filerem
= 0;
2768 /* Skip invalid entry from playlist. */
2769 playlist_skip_entry(NULL
, last_peek_offset
);
2770 tracks
[track_widx
].taginfo_ready
= false;
2776 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
2778 char cuepath
[MAX_PATH
];
2780 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
2782 if (look_for_cuesheet_file(trackname
, cuepath
) &&
2783 parse_cuesheet(cuepath
, cue
))
2785 strcpy((cue
)->audio_filename
, trackname
);
2787 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
2791 /* Load the codec. */
2792 tracks
[track_widx
].codecbuf
= &filebuf
[buf_widx
];
2793 if (!audio_loadcodec(start_play
))
2795 /* Set filesize to zero to indicate no file was loaded. */
2796 tracks
[track_widx
].filesize
= 0;
2797 tracks
[track_widx
].filerem
= 0;
2801 if (tracks
[track_widx
].codecsize
)
2803 /* No space for codec on buffer, not an error */
2804 tracks
[track_widx
].codecsize
= 0;
2808 /* This is an error condition, either no codec was found, or reading
2809 * the codec file failed part way through, either way, skip the track */
2810 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
2811 /* We should not use gui_syncplash from audio thread! */
2812 gui_syncsplash(HZ
*2, msgbuf
);
2813 /* Skip invalid entry from playlist. */
2814 playlist_skip_entry(NULL
, last_peek_offset
);
2815 tracks
[track_widx
].taginfo_ready
= false;
2819 tracks
[track_widx
].start_pos
= 0;
2820 set_filebuf_watermark(buffer_margin
);
2821 tracks
[track_widx
].id3
.elapsed
= 0;
2825 switch (tracks
[track_widx
].id3
.codectype
) {
2829 lseek(current_fd
, offset
, SEEK_SET
);
2830 tracks
[track_widx
].id3
.offset
= offset
;
2831 audio_set_elapsed(&tracks
[track_widx
].id3
);
2832 tracks
[track_widx
].filerem
= size
- offset
;
2834 tracks
[track_widx
].start_pos
= offset
;
2838 lseek(current_fd
, offset
, SEEK_SET
);
2839 tracks
[track_widx
].id3
.offset
= offset
;
2840 tracks
[track_widx
].id3
.elapsed
=
2841 tracks
[track_widx
].id3
.length
/ 2;
2842 tracks
[track_widx
].filerem
= size
- offset
;
2844 tracks
[track_widx
].start_pos
= offset
;
2847 case AFMT_OGG_VORBIS
:
2855 tracks
[track_widx
].id3
.offset
= offset
;
2860 logf("alt:%s", trackname
);
2861 tracks
[track_widx
].buf_idx
= buf_widx
;
2863 return audio_read_file(rebuffer
);
2866 static bool audio_read_next_metadata(void)
2873 next_idx
= track_widx
;
2874 if (tracks
[next_idx
].taginfo_ready
)
2877 next_idx
&= MAX_TRACK_MASK
;
2879 if (tracks
[next_idx
].taginfo_ready
)
2883 trackname
= playlist_peek(last_peek_offset
+ 1);
2887 fd
= open(trackname
, O_RDONLY
);
2891 status
= get_metadata(&(tracks
[next_idx
].id3
),fd
,trackname
,v1first
);
2892 /* Preload the glyphs in the tags */
2895 tracks
[next_idx
].taginfo_ready
= true;
2896 if (tracks
[next_idx
].id3
.title
)
2897 lcd_getstringsize(tracks
[next_idx
].id3
.title
, NULL
, NULL
);
2898 if (tracks
[next_idx
].id3
.artist
)
2899 lcd_getstringsize(tracks
[next_idx
].id3
.artist
, NULL
, NULL
);
2900 if (tracks
[next_idx
].id3
.album
)
2901 lcd_getstringsize(tracks
[next_idx
].id3
.album
, NULL
, NULL
);
2908 /* Send callback events to notify about new tracks. */
2909 static void audio_generate_postbuffer_events(void)
2914 logf("Postbuffer:%d/%d",track_ridx
,track_widx
);
2916 if (audio_have_tracks())
2918 cur_idx
= track_ridx
;
2921 if (!tracks
[cur_idx
].event_sent
)
2923 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2925 /* Mark the event 'sent' even if we don't really send one */
2926 tracks
[last_idx
].event_sent
= true;
2927 if (track_buffer_callback
)
2928 track_buffer_callback(&tracks
[last_idx
].id3
, false);
2932 if (cur_idx
== track_widx
)
2935 cur_idx
&= MAX_TRACK_MASK
;
2938 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2940 tracks
[last_idx
].event_sent
= true;
2941 if (track_buffer_callback
)
2942 track_buffer_callback(&tracks
[last_idx
].id3
, true);
2947 static bool audio_initialize_buffer_fill(bool clear_tracks
)
2949 /* Don't initialize if we're already initialized */
2953 logf("Starting buffer fill");
2955 /* Set the filling flag true before calling audio_clear_tracks as that
2956 * function can yield and we start looping. */
2960 audio_clear_track_entries(false);
2962 /* Save the current resume position once. */
2963 playlist_update_resume_info(audio_current_track());
2968 static void audio_fill_file_buffer(
2969 bool start_play
, bool rebuffer
, size_t offset
)
2971 bool had_next_track
= audio_next_track() != NULL
;
2972 bool continue_buffering
;
2974 /* Must reset the buffer before use if trashed or voice only - voice
2975 file size shouldn't have changed so we can go straight from
2976 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
2977 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
2978 audio_reset_buffer();
2980 if (!audio_initialize_buffer_fill(!start_play
))
2983 /* If we have a partially buffered track, continue loading,
2984 * otherwise load a new track */
2985 if (tracks
[track_widx
].filesize
> 0)
2986 continue_buffering
= audio_read_file(rebuffer
);
2988 continue_buffering
= audio_load_track(offset
, start_play
, rebuffer
);
2990 if (!had_next_track
&& audio_next_track())
2991 track_changed
= true;
2993 /* If we're done buffering */
2994 if (!continue_buffering
)
2996 audio_read_next_metadata();
2998 audio_generate_postbuffer_events();
3007 static void audio_rebuffer(void)
3009 logf("Forcing rebuffer");
3011 /* Stop in progress fill, and clear open file descriptor */
3012 if (current_fd
>= 0)
3019 /* Reset buffer and track pointers */
3020 CUR_TI
->buf_idx
= buf_ridx
= buf_widx
= 0;
3021 track_widx
= track_ridx
;
3022 audio_clear_track_entries(true);
3023 CUR_TI
->available
= 0;
3025 /* Fill the buffer */
3026 last_peek_offset
= -1;
3027 CUR_TI
->filesize
= 0;
3028 CUR_TI
->start_pos
= 0;
3031 if (!CUR_TI
->taginfo_ready
)
3032 memset(&CUR_TI
->id3
, 0, sizeof(struct mp3entry
));
3034 audio_fill_file_buffer(false, true, 0);
3037 static int audio_check_new_track(void)
3039 int track_count
= audio_track_count();
3040 int old_track_ridx
= track_ridx
;
3046 if (playlist_next_dir(ci
.new_track
))
3049 CUR_TI
->taginfo_ready
= false;
3055 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3056 return Q_CODEC_REQUEST_FAILED
;
3063 /* If the playlist isn't that big */
3064 if (!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
;
3071 /* Find the beginning backward if the user over-skips it */
3072 while (!playlist_check(++ci
.new_track
))
3073 if (ci
.new_track
>= 0)
3075 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3076 return Q_CODEC_REQUEST_FAILED
;
3079 /* Update the playlist */
3080 last_peek_offset
-= ci
.new_track
;
3082 if (playlist_next(ci
.new_track
) < 0)
3084 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3085 return Q_CODEC_REQUEST_FAILED
;
3091 new_playlist
= false;
3094 /* Save the old track */
3097 /* Move to the new track */
3098 track_ridx
+= ci
.new_track
;
3099 track_ridx
&= MAX_TRACK_MASK
;
3102 playlist_end
= false;
3104 track_changed
= !automatic_skip
;
3106 /* If it is not safe to even skip this many track entries */
3107 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
3110 CUR_TI
->taginfo_ready
= false;
3115 forward
= ci
.new_track
> 0;
3118 /* If the target track is clearly not in memory */
3119 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
3125 /* The track may be in memory, see if it really is */
3128 if (!audio_buffer_wind_forward(track_ridx
, old_track_ridx
))
3133 int cur_idx
= track_ridx
;
3134 bool taginfo_ready
= true;
3135 bool wrap
= track_ridx
> old_track_ridx
;
3140 cur_idx
&= MAX_TRACK_MASK
;
3141 if (!(wrap
|| cur_idx
< old_track_ridx
))
3144 /* If we hit a track in between without valid tag info, bail */
3145 if (!tracks
[cur_idx
].taginfo_ready
)
3147 taginfo_ready
= false;
3151 tracks
[cur_idx
].available
= tracks
[cur_idx
].filesize
;
3152 if (tracks
[cur_idx
].codecsize
)
3153 tracks
[cur_idx
].has_codec
= true;
3157 if (!audio_buffer_wind_backward(track_ridx
, old_track_ridx
))
3162 CUR_TI
->taginfo_ready
= false;
3168 audio_update_trackinfo();
3169 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3170 return Q_CODEC_REQUEST_COMPLETE
;
3173 static int audio_rebuffer_and_seek(size_t newpos
)
3175 size_t real_preseek
;
3179 /* (Re-)open current track's file handle. */
3180 trackname
= playlist_peek(0);
3181 fd
= open(trackname
, O_RDONLY
);
3184 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3185 return Q_CODEC_REQUEST_FAILED
;
3188 if (current_fd
>= 0)
3192 playlist_end
= false;
3196 /* Clear codec buffer. */
3197 track_widx
= track_ridx
;
3198 tracks
[track_widx
].buf_idx
= buf_widx
= buf_ridx
= 0;
3200 last_peek_offset
= 0;
3202 audio_initialize_buffer_fill(true);
3204 /* This may have been tweaked by the id3v1 code */
3205 CUR_TI
->filesize
=filesize(fd
);
3206 if (newpos
> conf_preseek
)
3208 CUR_TI
->start_pos
= newpos
- conf_preseek
;
3209 lseek(current_fd
, CUR_TI
->start_pos
, SEEK_SET
);
3210 CUR_TI
->filerem
= CUR_TI
->filesize
- CUR_TI
->start_pos
;
3211 real_preseek
= conf_preseek
;
3215 CUR_TI
->start_pos
= 0;
3216 CUR_TI
->filerem
= CUR_TI
->filesize
;
3217 real_preseek
= newpos
;
3220 CUR_TI
->available
= 0;
3222 audio_read_file(real_preseek
);
3224 /* Account for the data we just read that is 'behind' us now */
3225 CUR_TI
->available
-= real_preseek
;
3227 buf_ridx
= RINGBUF_ADD(buf_ridx
, real_preseek
);
3229 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3230 return Q_CODEC_REQUEST_COMPLETE
;
3233 void audio_set_track_buffer_event(void (*handler
)(struct mp3entry
*id3
,
3236 track_buffer_callback
= handler
;
3239 void audio_set_track_unbuffer_event(void (*handler
)(struct mp3entry
*id3
,
3242 track_unbuffer_callback
= handler
;
3245 void audio_set_track_changed_event(void (*handler
)(struct mp3entry
*id3
))
3247 track_changed_callback
= handler
;
3250 unsigned long audio_prev_elapsed(void)
3252 return prev_track_elapsed
;
3255 static void audio_stop_codec_flush(void)
3257 ci
.stop_codec
= true;
3260 while (audio_codec_loaded
)
3263 /* If the audio codec is not loaded any more, and the audio is still
3264 * playing, it is now and _only_ now safe to call this function from the
3266 if (pcm_is_playing())
3268 pcmbuf_pause(paused
);
3271 static void audio_stop_playback(void)
3273 /* If we were playing, save resume information */
3276 struct mp3entry
*id3
= NULL
;
3278 if (!playlist_end
|| !ci
.stop_codec
)
3280 /* Set this early, the outside code yields and may allow the codec
3281 to try to wait for a reply on a buffer wait */
3282 ci
.stop_codec
= true;
3283 id3
= audio_current_track();
3286 /* Save the current playing spot, or NULL if the playlist has ended */
3287 playlist_update_resume_info(id3
);
3289 prev_track_elapsed
= CUR_TI
->id3
.elapsed
;
3291 /* Increment index so runtime info is saved in audio_clear_track_entries().
3292 * Done here, as audio_stop_playback() may be called more than once.
3293 * Don't update runtime unless playback is stopped because of end of playlist.
3294 * Updating runtime when manually stopping a tracks, can destroy autoscores
3300 track_ridx
&= MAX_TRACK_MASK
;
3306 audio_stop_codec_flush();
3309 if (current_fd
>= 0)
3315 /* Mark all entries null. */
3316 audio_clear_track_entries(false);
3319 static void audio_play_start(size_t offset
)
3321 #if INPUT_SRC_CAPS != 0
3322 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
3323 audio_set_output_source(AUDIO_SRC_PLAYBACK
);
3326 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
3328 audio_stop_codec_flush();
3330 track_changed
= true;
3331 playlist_end
= false;
3339 if (current_fd
>= 0)
3345 sound_set_volume(global_settings
.volume
);
3346 track_widx
= track_ridx
= 0;
3347 buf_ridx
= buf_widx
= 0;
3349 /* Mark all entries null. */
3350 memset(tracks
, 0, sizeof(struct track_info
) * MAX_TRACK
);
3352 last_peek_offset
= -1;
3354 /* Officially playing */
3355 queue_reply(&audio_queue
, 1);
3357 audio_fill_file_buffer(true, false, offset
);
3359 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
3360 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
3364 /* Invalidates all but currently playing track. */
3365 static void audio_invalidate_tracks(void)
3367 if (audio_have_tracks())
3369 last_peek_offset
= 0;
3370 playlist_end
= false;
3371 track_widx
= track_ridx
;
3373 /* Mark all other entries null (also buffered wrong metadata). */
3374 audio_clear_track_entries(true);
3376 /* If the current track is fully buffered, advance the write pointer */
3377 if (tracks
[track_widx
].filerem
== 0)
3378 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
3380 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3382 audio_read_next_metadata();
3386 static void audio_new_playlist(void)
3388 /* Prepare to start a new fill from the beginning of the playlist */
3389 last_peek_offset
= -1;
3390 if (audio_have_tracks())
3393 skipped_during_pause
= true;
3394 playlist_end
= false;
3395 track_widx
= track_ridx
;
3396 audio_clear_track_entries(true);
3399 track_widx
&= MAX_TRACK_MASK
;
3401 /* Stop reading the current track */
3402 CUR_TI
->filerem
= 0;
3406 /* Mark the current track as invalid to prevent skipping back to it */
3407 CUR_TI
->taginfo_ready
= false;
3409 /* Invalidate the buffer other than the playing track */
3410 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3413 /* Signal the codec to initiate a track change forward */
3414 new_playlist
= true;
3417 /* Officially playing */
3418 queue_reply(&audio_queue
, 1);
3420 audio_fill_file_buffer(false, true, 0);
3423 static void audio_initiate_track_change(long direction
)
3425 playlist_end
= false;
3426 ci
.new_track
+= direction
;
3427 wps_offset
-= direction
;
3429 skipped_during_pause
= true;
3432 static void audio_initiate_dir_change(long direction
)
3434 playlist_end
= false;
3436 ci
.new_track
= direction
;
3438 skipped_during_pause
= true;
3442 * Layout audio buffer as follows - iram buffer depends on target:
3443 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
3445 static void audio_reset_buffer(void)
3447 /* see audio_get_recording_buffer if this is modified */
3448 logf("audio_reset_buffer");
3450 /* If the setup of anything allocated before the file buffer is
3451 changed, do check the adjustments after the buffer_alloc call
3452 as it will likely be affected and need sliding over */
3454 /* Initially set up file buffer as all space available */
3455 malloc_buf
= audiobuf
+ talk_get_bufsize();
3456 /* Align the malloc buf to line size. Especially important to cf
3457 targets that do line reads/writes. */
3458 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
3459 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
3460 filebuflen
= audiobufend
- filebuf
;
3462 /* Allow for codec swap space at end of audio buffer */
3463 if (talk_voice_required())
3465 /* Layout of swap buffer:
3466 * #ifdef IRAM_STEAL (dedicated iram_buf):
3467 * |iram_buf|...audiobuf...|dram_buf|audiobufend
3469 * audiobuf...|dram_buf|iram_buf|audiobufend
3471 #ifdef PLAYBACK_VOICE
3472 /* Check for an absolutely nasty situation which should never,
3473 ever happen - frankly should just panic */
3474 if (voice_codec_loaded
&& current_codec
!= CODEC_IDX_VOICE
)
3476 logf("buffer reset with voice swapped");
3478 /* line align length which line aligns the calculations below since
3479 all sizes are also at least line aligned - needed for memswap128 */
3482 filebuflen
-= CODEC_SIZE
;
3484 filebuflen
-= CODEC_SIZE
+ CODEC_IRAM_SIZE
;
3486 /* Allocate buffers for swapping voice <=> audio */
3487 /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
3488 and out of the way of buffer usage or else a call to audio_get_buffer
3489 and subsequent buffer use might trash the swap space. A plugin
3490 initializing IRAM after getting the full buffer would present similar
3491 problem. Options include: failing the request if the other buffer
3492 has been obtained already or never allowing use of the voice IRAM
3493 buffer within the audio buffer. Using buffer_alloc basically
3494 implements the second in a more convenient way. */
3495 dram_buf
= filebuf
+ filebuflen
;
3498 /* Allocate voice IRAM swap buffer once */
3499 if (iram_buf
== NULL
)
3501 iram_buf
= buffer_alloc(CODEC_IRAM_SIZE
);
3502 /* buffer_alloc moves audiobuf; this is safe because only the end
3503 * has been touched so far in this function and the address of
3504 * filebuf + filebuflen is not changed */
3505 malloc_buf
+= CODEC_IRAM_SIZE
;
3506 filebuf
+= CODEC_IRAM_SIZE
;
3507 filebuflen
-= CODEC_IRAM_SIZE
;
3510 /* Allocate iram_buf after dram_buf */
3511 iram_buf
= dram_buf
+ CODEC_SIZE
;
3512 #endif /* IRAM_STEAL */
3513 #endif /* PLAYBACK_VOICE */
3517 #ifdef PLAYBACK_VOICE
3518 /* No swap buffers needed */
3524 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
3525 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
3527 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
3528 will already be line aligned */
3531 /* Set the high watermark as 75% full...or 25% empty :) */
3533 high_watermark
= 3*filebuflen
/ 4;
3536 /* Clear any references to the file buffer */
3537 buffer_state
= BUFFER_STATE_INITIALIZED
;
3539 #ifdef ROCKBOX_HAS_LOGF
3540 /* Make sure everything adds up - yes, some info is a bit redundant but
3541 aids viewing and the sumation of certain variables should add up to
3542 the location of others. */
3545 unsigned char * pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
3546 logf("mabuf: %08X", (unsigned)malloc_buf
);
3547 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
3548 logf("fbuf: %08X", (unsigned)filebuf
);
3549 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
3550 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
3551 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
3552 logf("pcmb: %08X", (unsigned)pcmbuf
);
3553 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
3556 logf("dramb: %08X", (unsigned)dram_buf
);
3557 logf("drambe: %08X", (unsigned)(dram_buf
+ CODEC_SIZE
));
3561 logf("iramb: %08X", (unsigned)iram_buf
);
3562 logf("irambe: %08X", (unsigned)(iram_buf
+ CODEC_IRAM_SIZE
));
3569 /* we dont want this rebuffering on targets with little ram
3570 because the disk may never spin down */
3571 static bool ata_fillbuffer_callback(void)
3573 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
, 0);
3578 static void audio_thread(void)
3584 #ifdef PLAYBACK_VOICE
3585 /* Unlock mutex that init stage locks before creating this thread */
3586 mutex_unlock(&mutex_codecthread
);
3588 /* Buffers must be set up by now - should panic - really */
3589 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
3591 logf("audio_thread start: no buffer");
3594 /* Have to wait for voice to load up or else the codec swap will be
3595 invalid when an audio codec is loaded */
3596 wait_for_voice_swap_in();
3601 intptr_t result
= 0;
3605 queue_wait_w_tmo(&audio_queue
, &ev
, 0);
3606 if (ev
.id
== SYS_TIMEOUT
)
3607 ev
.id
= Q_AUDIO_FILL_BUFFER
;
3611 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
3613 if (playing
&& (ev
.id
== SYS_TIMEOUT
) &&
3614 (FILEBUFUSED
< high_watermark
))
3615 register_ata_idle_func(ata_fillbuffer_callback
);
3621 case Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
:
3622 /* only fill if the disk is still spining */
3624 if (!ata_disk_is_active())
3627 #endif /* MEM > 8 */
3628 /* else fall through to Q_AUDIO_FILL_BUFFER */
3629 case Q_AUDIO_FILL_BUFFER
:
3630 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3632 if (!playing
|| playlist_end
|| ci
.stop_codec
)
3634 audio_fill_file_buffer(false, false, 0);
3638 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3639 if (playing
&& ev
.data
<= 0)
3640 audio_new_playlist();
3643 audio_stop_playback();
3644 audio_play_start((size_t)ev
.data
);
3649 LOGFQUEUE("audio < Q_AUDIO_STOP");
3651 audio_stop_playback();
3653 queue_clear(&audio_queue
);
3657 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3658 if (!(bool) ev
.data
&& skipped_during_pause
&& !pcmbuf_is_crossfade_active())
3659 pcmbuf_play_stop(); /* Flush old track on resume after skip */
3660 skipped_during_pause
= false;
3663 pcmbuf_pause((bool)ev
.data
);
3664 paused
= (bool)ev
.data
;
3668 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3669 audio_initiate_track_change((long)ev
.data
);
3672 case Q_AUDIO_PRE_FF_REWIND
:
3673 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3679 case Q_AUDIO_FF_REWIND
:
3680 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3683 ci
.seek_time
= (long)ev
.data
+1;
3686 case Q_AUDIO_REBUFFER_SEEK
:
3687 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
3688 result
= audio_rebuffer_and_seek(ev
.data
);
3691 case Q_AUDIO_CHECK_NEW_TRACK
:
3692 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3693 result
= audio_check_new_track();
3696 case Q_AUDIO_DIR_SKIP
:
3697 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3698 playlist_end
= false;
3699 audio_initiate_dir_change(ev
.data
);
3703 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3704 audio_invalidate_tracks();
3707 case Q_AUDIO_TRACK_CHANGED
:
3708 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3709 if (track_changed_callback
)
3710 track_changed_callback(&CUR_TI
->id3
);
3711 track_changed
= true;
3712 playlist_update_resume_info(audio_current_track());
3716 case SYS_USB_CONNECTED
:
3717 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3719 audio_stop_playback();
3720 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
3721 usb_wait_for_disconnect(&audio_queue
);
3726 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3730 LOGFQUEUE("audio < default");
3733 queue_reply(&audio_queue
, result
);
3737 #ifdef ROCKBOX_HAS_LOGF
3738 static void audio_test_track_changed_event(struct mp3entry
*id3
)
3742 logf("tce:%s", id3
->path
);
3746 /* Initialize the audio system - called from init() in main.c.
3747 * Last function because of all the references to internal symbols
3749 void audio_init(void)
3751 #ifdef PLAYBACK_VOICE
3752 static bool voicetagtrue
= true;
3753 static struct mp3entry id3_voice
;
3756 /* Can never do this twice */
3757 if (audio_is_initialized
)
3759 logf("audio: already initialized");
3763 logf("audio: initializing");
3765 /* Initialize queues before giving control elsewhere in case it likes
3766 to send messages. Thread creation will be delayed however so nothing
3767 starts running until ready if something yields such as talk_init. */
3768 #ifdef PLAYBACK_VOICE
3769 mutex_init(&mutex_codecthread
);
3770 /* Take ownership of lock to prevent playback of anything before audio
3771 hardware is initialized - audio thread unlocks it after final init
3773 mutex_lock(&mutex_codecthread
);
3775 queue_init(&audio_queue
, true);
3776 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
3777 queue_init(&codec_queue
, true);
3781 #ifdef ROCKBOX_HAS_LOGF
3782 audio_set_track_changed_event(audio_test_track_changed_event
);
3785 /* Initialize codec api. */
3786 ci
.read_filebuf
= codec_filebuf_callback
;
3787 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
3788 ci
.get_codec_memory
= codec_get_memory_callback
;
3789 ci
.request_buffer
= codec_request_buffer_callback
;
3790 ci
.advance_buffer
= codec_advance_buffer_callback
;
3791 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
3792 ci
.request_next_track
= codec_request_next_track_callback
;
3793 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
3794 ci
.seek_buffer
= codec_seek_buffer_callback
;
3795 ci
.seek_complete
= codec_seek_complete_callback
;
3796 ci
.set_elapsed
= codec_set_elapsed_callback
;
3797 ci
.set_offset
= codec_set_offset_callback
;
3798 ci
.configure
= codec_configure_callback
;
3799 ci
.discard_codec
= codec_discard_codec_callback
;
3801 /* Initialize voice codec api. */
3802 #ifdef PLAYBACK_VOICE
3803 memcpy(&ci_voice
, &ci
, sizeof(ci_voice
));
3804 memset(&id3_voice
, 0, sizeof(id3_voice
));
3805 ci_voice
.read_filebuf
= voice_filebuf_callback
;
3806 ci_voice
.pcmbuf_insert
= voice_pcmbuf_insert_callback
;
3807 ci_voice
.get_codec_memory
= voice_get_memory_callback
;
3808 ci_voice
.request_buffer
= voice_request_buffer_callback
;
3809 ci_voice
.advance_buffer
= voice_advance_buffer_callback
;
3810 ci_voice
.advance_buffer_loc
= voice_advance_buffer_loc_callback
;
3811 ci_voice
.request_next_track
= voice_request_next_track_callback
;
3812 ci_voice
.mp3_get_filepos
= voice_mp3_get_filepos_callback
;
3813 ci_voice
.seek_buffer
= voice_seek_buffer_callback
;
3814 ci_voice
.seek_complete
= voice_do_nothing
;
3815 ci_voice
.set_elapsed
= voice_set_elapsed_callback
;
3816 ci_voice
.set_offset
= voice_set_offset_callback
;
3817 ci_voice
.configure
= voice_configure_callback
;
3818 ci_voice
.discard_codec
= voice_do_nothing
;
3819 ci_voice
.taginfo_ready
= &voicetagtrue
;
3820 ci_voice
.id3
= &id3_voice
;
3821 id3_voice
.frequency
= 11200;
3822 id3_voice
.length
= 1000000L;
3825 /* initialize the buffer */
3828 /* audio_reset_buffer must to know the size of voice buffer so init
3832 /* Create the threads late now that we shouldn't be yielding again before
3834 codec_thread_p
= create_thread(
3835 codec_thread
, codec_stack
, sizeof(codec_stack
),
3836 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
3837 IF_COP(, CPU
, true));
3839 create_thread(audio_thread
, audio_stack
, sizeof(audio_stack
),
3840 audio_thread_name
IF_PRIO(, PRIORITY_BUFFERING
)
3841 IF_COP(, CPU
, false));
3843 #ifdef PLAYBACK_VOICE
3844 /* TODO: Change this around when various speech codecs can be used */
3845 if (talk_voice_required())
3847 logf("Starting voice codec");
3848 queue_init(&voice_queue
, true);
3849 create_thread(voice_thread
, voice_stack
,
3850 sizeof(voice_stack
), voice_thread_name
3851 IF_PRIO(, PRIORITY_PLAYBACK
) IF_COP(, CPU
, false));
3855 /* Set crossfade setting for next buffer init which should be about... */
3856 pcmbuf_crossfade_enable(global_settings
.crossfade
);
3858 /* ...now! Set up the buffers */
3859 audio_reset_buffer();
3861 /* Probably safe to say */
3862 audio_is_initialized
= true;
3864 sound_settings_apply();
3866 eq_hw_enable(global_settings
.eq_hw_enabled
);
3868 #ifndef HAVE_FLASH_STORAGE
3869 audio_set_buffer_margin(global_settings
.buffer_margin
);