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 */
665 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset
);
666 /* Don't return until playback has actually started */
667 queue_send(&audio_queue
, Q_AUDIO_PLAY
, offset
);
670 void audio_stop(void)
673 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
674 /* Don't return until playback has actually stopped */
675 queue_send(&audio_queue
, Q_AUDIO_STOP
, 0);
678 void audio_pause(void)
680 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
681 /* Don't return until playback has actually paused */
682 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, true);
685 void audio_resume(void)
687 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
688 /* Don't return until playback has actually resumed */
689 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, false);
692 void audio_next(void)
694 if (playlist_check(ci
.new_track
+ wps_offset
+ 1))
696 if (global_settings
.beep
)
697 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
699 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
700 queue_post(&audio_queue
, Q_AUDIO_SKIP
, 1);
701 /* Update wps while our message travels inside deep playback queues. */
703 track_changed
= true;
707 /* No more tracks. */
708 if (global_settings
.beep
)
709 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
713 void audio_prev(void)
715 if (playlist_check(ci
.new_track
+ wps_offset
- 1))
717 if (global_settings
.beep
)
718 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
720 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
721 queue_post(&audio_queue
, Q_AUDIO_SKIP
, -1);
722 /* Update wps while our message travels inside deep playback queues. */
724 track_changed
= true;
728 /* No more tracks. */
729 if (global_settings
.beep
)
730 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
734 void audio_next_dir(void)
736 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
737 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, 1);
740 void audio_prev_dir(void)
742 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
743 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, -1);
746 void audio_pre_ff_rewind(void)
748 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
749 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
752 void audio_ff_rewind(long newpos
)
754 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
755 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, newpos
);
758 void audio_flush_and_reload_tracks(void)
760 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
761 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
764 void audio_error_clear(void)
766 #ifdef AUDIO_HAVE_RECORDING
767 pcm_rec_error_clear();
771 int audio_status(void)
776 ret
|= AUDIO_STATUS_PLAY
;
779 ret
|= AUDIO_STATUS_PAUSE
;
781 #ifdef HAVE_RECORDING
782 /* Do this here for constitency with mpeg.c version */
783 ret
|= pcm_rec_status();
789 int audio_get_file_pos(void)
794 #ifndef HAVE_FLASH_STORAGE
795 void audio_set_buffer_margin(int setting
)
797 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
798 buffer_margin
= lookup
[setting
];
799 logf("buffer margin: %ld", buffer_margin
);
800 set_filebuf_watermark(buffer_margin
);
804 /* Take nescessary steps to enable or disable the crossfade setting */
805 void audio_set_crossfade(int enable
)
811 /* Tell it the next setting to use */
812 pcmbuf_crossfade_enable(enable
);
814 /* Return if size hasn't changed or this is too early to determine
815 which in the second case there's no way we could be playing
817 if (pcmbuf_is_same_size())
819 /* This function is a copout and just syncs some variables -
820 to be removed at a later date */
821 pcmbuf_crossfade_enable_finished();
826 was_playing
= playing
;
828 /* Playback has to be stopped before changing the buffer size */
831 /* Store the track resume position */
832 offset
= CUR_TI
->id3
.offset
;
833 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK
));
836 /* Blast it - audio buffer will have to be setup again next time
838 audio_get_buffer(true, &size
);
840 /* Restart playback if audio was running previously */
845 /* --- Routines called from multiple threads --- */
846 static void set_current_codec(int codec_idx
)
848 current_codec
= codec_idx
;
849 dsp_configure(DSP_SWITCH_CODEC
, codec_idx
);
852 #ifdef PLAYBACK_VOICE
853 static void swap_codec(void)
857 /* Swap nothing if no swap buffers exist */
858 if (dram_buf
== NULL
)
860 logf("swap: no swap buffers");
864 my_codec
= current_codec
;
866 logf("swapping out codec: %d", my_codec
);
868 /* Invert this when a codec thread enters and leaves */
869 swap_codec_parity
= !swap_codec_parity
;
871 /* If this is true, an odd number of calls has occurred and there's
872 no codec thread waiting to swap us out when it locks and runs. This
873 occurs when playback is stopped or when just starting playback and
874 the audio thread is loading a codec; parities should always be even
875 on entry when a thread calls this during playback */
876 if (swap_codec_parity
)
878 /* Save our current IRAM and DRAM */
880 if (voice_iram_stolen
)
882 logf("swap: iram restore");
883 voice_iram_stolen
= false;
884 /* Don't swap trashed data into buffer as the voice IRAM will
885 already be swapped out - should _always_ be the case if
886 voice_iram_stolen is true since the voice has been swapped
888 if (my_codec
== CODEC_IDX_VOICE
)
890 logf("voice iram already swapped");
896 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
902 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
903 /* No cache invalidation needed; it will be done in codec_load_ram
904 or we won't be here otherwise */
907 /* Release my semaphore */
908 mutex_unlock(&mutex_codecthread
);
909 logf("unlocked: %d", my_codec
);
911 /* Loop until the other codec has locked and run */
913 /* Release my semaphore and force a task switch. */
915 } while (my_codec
== current_codec
);
917 /* Wait for other codec to unlock */
918 mutex_lock(&mutex_codecthread
);
921 logf("waiting for lock: %d", my_codec
);
922 set_current_codec(my_codec
);
924 /* Reload our IRAM and DRAM */
925 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
926 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
929 /* Flip parity again */
930 swap_codec_parity
= !swap_codec_parity
;
932 logf("resuming codec: %d", my_codec
);
935 /* This function is meant to be used by the buffer stealing functions to
936 ensure the codec is no longer active and so voice will be swapped-in
937 before it is called */
938 static void voice_stop(void)
940 #ifdef PLAYBACK_VOICE
941 /* Must have a voice codec loaded or we'll hang forever here */
942 if (!voice_codec_loaded
)
947 /* Loop until voice empties it's queue, stops and picks up on the new
948 track; the voice thread must be stopped and waiting for messages
950 while (voice_is_playing
|| !queue_empty(&voice_queue
) ||
959 /* Is voice still speaking */
960 /* Unfortunately only reliable when music is not also playing. */
961 static bool is_voice_speaking(void)
963 return is_voice_queued()
965 || (!playing
&& pcm_is_playing());
968 /* Wait for voice to finish speaking. */
969 /* Also only reliable when music is not also playing. */
970 void voice_wait(void)
972 while (is_voice_speaking())
976 #endif /* PLAYBACK_VOICE */
978 static void set_filebuf_watermark(int seconds
)
983 return; /* Audio buffers not yet set up */
985 bytes
= MAX(CUR_TI
->id3
.bitrate
* seconds
* (1000/8), conf_watermark
);
986 bytes
= MIN(bytes
, filebuflen
/ 2);
987 conf_watermark
= bytes
;
990 const char * get_codec_filename(int cod_spec
)
994 #ifdef HAVE_RECORDING
995 /* Can choose decoder or encoder if one available */
996 int type
= cod_spec
& CODEC_TYPE_MASK
;
997 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
999 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
1000 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
1002 fname
= (type
== CODEC_TYPE_ENCODER
) ?
1003 audio_formats
[afmt
].codec_enc_root_fn
:
1004 audio_formats
[afmt
].codec_root_fn
;
1007 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
1008 afmt
, fname
? fname
: "<unknown>");
1009 #else /* !HAVE_RECORDING */
1010 /* Always decoder */
1011 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
1012 cod_spec
= AFMT_UNKNOWN
;
1013 fname
= audio_formats
[cod_spec
].codec_root_fn
;
1014 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
1015 #endif /* HAVE_RECORDING */
1018 } /* get_codec_filename */
1021 /* --- Voice thread --- */
1023 #ifdef PLAYBACK_VOICE
1025 static bool voice_pcmbuf_insert_callback(
1026 const void *ch1
, const void *ch2
, int count
)
1028 const char *src
[2] = { ch1
, ch2
};
1032 int out_count
= dsp_output_count(count
);
1036 while ((dest
= pcmbuf_request_voice_buffer(
1037 &out_count
, playing
)) == NULL
)
1039 if (playing
&& audio_codec_loaded
)
1045 /* Get the real input_size for output_size bytes, guarding
1046 * against resampling buffer overflows. */
1047 inp_count
= dsp_input_count(out_count
);
1052 /* Input size has grown, no error, just don't write more than length */
1053 if (inp_count
> count
)
1056 out_count
= dsp_process(dest
, src
, inp_count
);
1063 pcmbuf_mix_voice(out_count
);
1064 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
1069 pcmbuf_write_complete(out_count
);
1075 } /* voice_pcmbuf_insert_callback */
1077 static void* voice_get_memory_callback(size_t *size
)
1079 /* Voice should have no use for this. If it did, we'd have to
1080 swap the malloc buffer as well. */
1085 static void voice_set_elapsed_callback(unsigned int value
)
1090 static void voice_set_offset_callback(size_t value
)
1095 static void voice_configure_callback(int setting
, intptr_t value
)
1097 if (!dsp_configure(setting
, value
))
1099 logf("Illegal key:%d", setting
);
1103 static size_t voice_filebuf_callback(void *ptr
, size_t size
)
1111 /* Handle Q_VOICE_STOP and part of SYS_USB_CONNECTED */
1112 static bool voice_on_voice_stop(bool aborting
, size_t *realsize
)
1114 if (aborting
&& !playing
&& pcm_is_playing())
1116 /* Aborting: Slight hack - flush PCM buffer if
1117 only being used for voice */
1121 if (voice_is_playing
)
1123 /* Clear the current buffer */
1124 voice_is_playing
= false;
1125 voice_getmore
= NULL
;
1126 voice_remaining
= 0;
1129 /* Cancel any automatic boost if no more clips requested. */
1130 if (!playing
|| !voice_thread_start
)
1133 /* Force the codec to think it's changing tracks */
1134 ci_voice
.new_track
= 1;
1137 return true; /* Yes, change tracks */
1143 static void* voice_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1147 if (ci_voice
.new_track
)
1155 if (voice_is_playing
|| playing
)
1157 queue_wait_w_tmo(&voice_queue
, &ev
, 0);
1158 if (!voice_is_playing
&& ev
.id
== SYS_TIMEOUT
)
1159 ev
.id
= Q_AUDIO_PLAY
;
1163 queue_wait(&voice_queue
, &ev
);
1168 LOGFQUEUE("voice < Q_AUDIO_PLAY");
1171 if (audio_codec_loaded
)
1177 #ifdef AUDIO_HAVE_RECORDING
1178 case Q_ENCODER_RECORD
:
1179 LOGFQUEUE("voice < Q_ENCODER_RECORD");
1185 LOGFQUEUE("voice < Q_VOICE_STOP");
1186 if (voice_on_voice_stop(ev
.data
, realsize
))
1190 case SYS_USB_CONNECTED
:
1192 LOGFQUEUE("voice < SYS_USB_CONNECTED");
1193 bool change_tracks
= voice_on_voice_stop(ev
.data
, realsize
);
1194 /* Voice is obviously current so let us swap ourselves away if
1195 playing so audio may stop itself - audio_codec_loaded can
1196 only be true in this case if we're here even if the codec
1197 is only about to load */
1198 if (audio_codec_loaded
)
1200 /* Playback should be finished by now - ack and wait */
1201 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
1202 usb_wait_for_disconnect(&voice_queue
);
1209 LOGFQUEUE("voice < Q_VOICE_PLAY");
1210 if (!voice_is_playing
)
1212 /* Set up new voice data */
1213 struct voice_info
*voice_data
;
1215 if (voice_iram_stolen
)
1217 /* Voice is the first to run again and is currently
1219 logf("voice: iram restore");
1220 memcpy(CODEC_IRAM_ORIGIN
, iram_buf
, CODEC_IRAM_SIZE
);
1221 voice_iram_stolen
= false;
1224 /* Must reset the buffer before any playback begins if
1226 if (buffer_state
== BUFFER_STATE_TRASHED
)
1227 audio_reset_buffer();
1229 voice_is_playing
= true;
1230 trigger_cpu_boost();
1231 voice_data
= (struct voice_info
*)ev
.data
;
1232 voice_remaining
= voice_data
->size
;
1233 voicebuf
= voice_data
->buf
;
1234 voice_getmore
= voice_data
->callback
;
1236 goto voice_play_clip
; /* To exit both switch and while */
1239 LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
1240 goto voice_play_clip
;
1243 LOGFQUEUE("voice < default");
1249 if (voice_remaining
== 0 || voicebuf
== NULL
)
1252 voice_getmore((unsigned char **)&voicebuf
, &voice_remaining
);
1254 /* If this clip is done */
1255 if (voice_remaining
== 0)
1257 LOGFQUEUE("voice > voice Q_VOICE_STOP");
1258 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
1259 /* Force pcm playback. */
1260 if (!pcm_is_playing())
1261 pcmbuf_play_start();
1265 *realsize
= MIN(voice_remaining
, reqsize
);
1271 } /* voice_request_buffer_callback */
1273 static void voice_advance_buffer_callback(size_t amount
)
1275 amount
= MIN(amount
, voice_remaining
);
1277 voice_remaining
-= amount
;
1280 static void voice_advance_buffer_loc_callback(void *ptr
)
1282 size_t amount
= (size_t)ptr
- (size_t)voicebuf
;
1284 voice_advance_buffer_callback(amount
);
1287 static off_t
voice_mp3_get_filepos_callback(int newtime
)
1294 static void voice_do_nothing(void)
1299 static bool voice_seek_buffer_callback(size_t newpos
)
1306 static bool voice_request_next_track_callback(void)
1308 ci_voice
.new_track
= 0;
1312 static void voice_thread(void)
1314 logf("Loading voice codec");
1315 voice_codec_loaded
= true;
1316 mutex_lock(&mutex_codecthread
);
1317 set_current_codec(CODEC_IDX_VOICE
);
1318 dsp_configure(DSP_RESET
, 0);
1319 voice_remaining
= 0;
1320 voice_getmore
= NULL
;
1322 /* FIXME: If we being starting the voice thread without reboot, the
1323 voice_queue could be full of old stuff and we must flush it. */
1324 codec_load_file(get_codec_filename(AFMT_MPA_L3
), &ci_voice
);
1326 logf("Voice codec finished");
1327 voice_codec_loaded
= false;
1328 mutex_unlock(&mutex_codecthread
);
1329 voice_thread_p
= NULL
;
1330 remove_thread(NULL
);
1331 } /* voice_thread */
1333 #endif /* PLAYBACK_VOICE */
1335 /* --- Codec thread --- */
1336 static bool codec_pcmbuf_insert_callback(
1337 const void *ch1
, const void *ch2
, int count
)
1339 const char *src
[2] = { ch1
, ch2
};
1343 int out_count
= dsp_output_count(count
);
1347 /* Prevent audio from a previous track from playing */
1348 if (ci
.new_track
|| ci
.stop_codec
)
1351 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
1354 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
1358 /* Get the real input_size for output_size bytes, guarding
1359 * against resampling buffer overflows. */
1360 inp_count
= dsp_input_count(out_count
);
1365 /* Input size has grown, no error, just don't write more than length */
1366 if (inp_count
> count
)
1369 out_count
= dsp_process(dest
, src
, inp_count
);
1374 pcmbuf_write_complete(out_count
);
1376 #ifdef PLAYBACK_VOICE
1377 if ((voice_is_playing
|| voice_thread_start
)
1378 && pcm_is_playing() && voice_codec_loaded
&&
1379 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1381 voice_thread_start
= false;
1390 } /* codec_pcmbuf_insert_callback */
1392 static void* codec_get_memory_callback(size_t *size
)
1394 *size
= MALLOC_BUFSIZE
;
1398 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
1399 static void codec_pcmbuf_position_callback(size_t size
)
1401 /* This is called from an ISR, so be quick */
1402 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
1403 prev_ti
->id3
.elapsed
;
1405 if (time
>= prev_ti
->id3
.length
)
1407 pcmbuf_set_position_callback(NULL
);
1408 prev_ti
->id3
.elapsed
= prev_ti
->id3
.length
;
1411 prev_ti
->id3
.elapsed
= time
;
1414 static void codec_set_elapsed_callback(unsigned int value
)
1416 unsigned int latency
;
1420 #ifdef AB_REPEAT_ENABLE
1421 ab_position_report(value
);
1424 latency
= pcmbuf_get_latency();
1425 if (value
< latency
)
1426 CUR_TI
->id3
.elapsed
= 0;
1427 else if (value
- latency
> CUR_TI
->id3
.elapsed
||
1428 value
- latency
< CUR_TI
->id3
.elapsed
- 2)
1430 CUR_TI
->id3
.elapsed
= value
- latency
;
1434 static void codec_set_offset_callback(size_t value
)
1436 unsigned int latency
;
1441 latency
= pcmbuf_get_latency() * CUR_TI
->id3
.bitrate
/ 8;
1442 if (value
< latency
)
1443 CUR_TI
->id3
.offset
= 0;
1445 CUR_TI
->id3
.offset
= value
- latency
;
1448 static void codec_advance_buffer_counters(size_t amount
)
1450 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
1451 ci
.curpos
+= amount
;
1452 CUR_TI
->available
-= amount
;
1454 /* Start buffer filling as necessary. */
1455 if (!pcmbuf_is_lowdata() && !filling
)
1457 if (FILEBUFUSED
< conf_watermark
&& playing
&& !playlist_end
)
1459 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1460 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1465 /* copy up-to size bytes into ptr and return the actual size copied */
1466 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
1468 char *buf
= (char *)ptr
;
1472 if (ci
.stop_codec
|| !playing
)
1475 /* The ammount to copy is the lesser of the requested amount and the
1476 * amount left of the current track (both on disk and already loaded) */
1477 copy_n
= MIN(size
, CUR_TI
->available
+ CUR_TI
->filerem
);
1479 /* Nothing requested OR nothing left */
1483 /* Let the disk buffer catch fill until enough data is available */
1484 while (copy_n
> CUR_TI
->available
)
1488 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1489 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1493 if (ci
.stop_codec
|| ci
.new_track
)
1497 /* Copy as much as possible without wrapping */
1498 part_n
= MIN(copy_n
, filebuflen
- buf_ridx
);
1499 memcpy(buf
, &filebuf
[buf_ridx
], part_n
);
1500 /* Copy the rest in the case of a wrap */
1501 if (part_n
< copy_n
) {
1502 memcpy(&buf
[part_n
], &filebuf
[0], copy_n
- part_n
);
1505 /* Update read and other position pointers */
1506 codec_advance_buffer_counters(copy_n
);
1508 /* Return the actual amount of data copied to the buffer */
1510 } /* codec_filebuf_callback */
1512 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1514 size_t short_n
, copy_n
, buf_rem
;
1522 copy_n
= MIN(reqsize
, CUR_TI
->available
+ CUR_TI
->filerem
);
1529 while (copy_n
> CUR_TI
->available
)
1533 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1534 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1538 if (ci
.stop_codec
|| ci
.new_track
)
1545 /* How much is left at the end of the file buffer before wrap? */
1546 buf_rem
= filebuflen
- buf_ridx
;
1548 /* If we can't satisfy the request without wrapping */
1549 if (buf_rem
< copy_n
)
1551 /* How short are we? */
1552 short_n
= copy_n
- buf_rem
;
1554 /* If we can fudge it with the guardbuf */
1555 if (short_n
< GUARD_BUFSIZE
)
1556 memcpy(&filebuf
[filebuflen
], &filebuf
[0], short_n
);
1563 return (char *)&filebuf
[buf_ridx
];
1564 } /* codec_request_buffer_callback */
1566 static int get_codec_base_type(int type
)
1578 static void codec_advance_buffer_callback(size_t amount
)
1580 if (amount
> CUR_TI
->available
+ CUR_TI
->filerem
)
1581 amount
= CUR_TI
->available
+ CUR_TI
->filerem
;
1583 while (amount
> CUR_TI
->available
&& filling
)
1586 if (amount
> CUR_TI
->available
)
1588 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1592 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1593 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1594 ci
.curpos
+ amount
);
1599 case Q_CODEC_REQUEST_FAILED
:
1600 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1601 ci
.stop_codec
= true;
1604 case Q_CODEC_REQUEST_COMPLETE
:
1605 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1609 LOGFQUEUE("codec |< default");
1610 ci
.stop_codec
= true;
1615 codec_advance_buffer_counters(amount
);
1617 codec_set_offset_callback(ci
.curpos
);
1620 static void codec_advance_buffer_loc_callback(void *ptr
)
1622 size_t amount
= (size_t)ptr
- (size_t)&filebuf
[buf_ridx
];
1624 codec_advance_buffer_callback(amount
);
1627 /* Copied from mpeg.c. Should be moved somewhere else. */
1628 static int codec_get_file_pos(void)
1631 struct mp3entry
*id3
= audio_current_track();
1637 /* Use the TOC to find the new position */
1638 unsigned int percent
, remainder
;
1639 int curtoc
, nexttoc
, plen
;
1641 percent
= (id3
->elapsed
*100)/id3
->length
;
1645 curtoc
= id3
->toc
[percent
];
1648 nexttoc
= id3
->toc
[percent
+1];
1652 pos
= (id3
->filesize
/256)*curtoc
;
1654 /* Use the remainder to get a more accurate position */
1655 remainder
= (id3
->elapsed
*100)%id3
->length
;
1656 remainder
= (remainder
*100)/id3
->length
;
1657 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1658 pos
+= (plen
/100)*remainder
;
1662 /* No TOC exists, estimate the new position */
1663 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1664 (id3
->elapsed
/ 1000);
1667 else if (id3
->bitrate
)
1668 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1672 pos
+= id3
->first_frame_offset
;
1674 /* Don't seek right to the end of the file so that we can
1675 transition properly to the next song */
1676 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1677 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1682 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1686 CUR_TI
->id3
.elapsed
= newtime
;
1687 newpos
= codec_get_file_pos();
1692 static void codec_seek_complete_callback(void)
1694 logf("seek_complete");
1695 if (pcm_is_paused())
1697 /* If this is not a seamless seek, clear the buffer */
1699 dsp_configure(DSP_FLUSH
, 0);
1701 /* If playback was not 'deliberately' paused, unpause now */
1703 pcmbuf_pause(false);
1708 static bool codec_seek_buffer_callback(size_t newpos
)
1712 logf("codec_seek_buffer_callback");
1714 if (newpos
>= CUR_TI
->filesize
)
1715 newpos
= CUR_TI
->filesize
- 1;
1717 difference
= newpos
- ci
.curpos
;
1718 if (difference
>= 0)
1720 /* Seeking forward */
1721 logf("seek: +%d", difference
);
1722 codec_advance_buffer_callback(difference
);
1726 /* Seeking backward */
1727 difference
= -difference
;
1728 if (ci
.curpos
- difference
< 0)
1729 difference
= ci
.curpos
;
1731 /* We need to reload the song. */
1732 if (newpos
< CUR_TI
->start_pos
)
1734 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1738 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1739 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1745 case Q_CODEC_REQUEST_COMPLETE
:
1746 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1749 case Q_CODEC_REQUEST_FAILED
:
1750 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1751 ci
.stop_codec
= true;
1755 LOGFQUEUE("codec |< default");
1760 /* Seeking inside buffer space. */
1761 logf("seek: -%d", difference
);
1762 CUR_TI
->available
+= difference
;
1763 buf_ridx
= RINGBUF_SUB(buf_ridx
, (unsigned)difference
);
1764 ci
.curpos
-= difference
;
1769 static void codec_configure_callback(int setting
, intptr_t value
)
1772 case CODEC_SET_FILEBUF_WATERMARK
:
1773 conf_watermark
= value
;
1774 set_filebuf_watermark(buffer_margin
);
1777 case CODEC_SET_FILEBUF_CHUNKSIZE
:
1778 conf_filechunk
= value
;
1781 case CODEC_SET_FILEBUF_PRESEEK
:
1782 conf_preseek
= value
;
1786 if (!dsp_configure(setting
, value
)) { logf("Illegal key:%d", setting
); }
1790 static void codec_track_changed(void)
1792 automatic_skip
= false;
1793 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1794 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1797 static void codec_pcmbuf_track_changed_callback(void)
1799 pcmbuf_set_position_callback(NULL
);
1800 codec_track_changed();
1803 static void codec_discard_codec_callback(void)
1805 if (CUR_TI
->has_codec
)
1807 CUR_TI
->has_codec
= false;
1808 buf_ridx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->codecsize
);
1812 /* Check if a buffer desync has happened, log it and stop playback. */
1813 if (buf_ridx
!= CUR_TI
->buf_idx
)
1815 int offset
= CUR_TI
->buf_idx
- buf_ridx
;
1816 size_t new_used
= FILEBUFUSED
- offset
;
1818 logf("Buf off :%d=%d-%d", offset
, CUR_TI
->buf_idx
, buf_ridx
);
1819 logf("Used off:%d",FILEBUFUSED
- new_used
);
1821 /* This is a fatal internal error and it's not safe to
1822 * continue playback. */
1823 ci
.stop_codec
= true;
1824 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1829 static inline void codec_gapless_track_change(void) {
1830 /* callback keeps the progress bar moving while the pcmbuf empties */
1831 pcmbuf_set_position_callback(codec_pcmbuf_position_callback
);
1832 /* set the pcmbuf callback for when the track really changes */
1833 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1836 static inline void codec_crossfade_track_change(void) {
1837 /* Initiate automatic crossfade mode */
1838 pcmbuf_crossfade_init(false);
1839 /* Notify the wps that the track change starts now */
1840 codec_track_changed();
1843 static void codec_track_skip_done(bool was_manual
)
1845 int crossfade_mode
= global_settings
.crossfade
;
1847 /* Manual track change (always crossfade or flush audio). */
1850 pcmbuf_crossfade_init(true);
1851 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1852 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1854 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1855 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1856 && crossfade_mode
!= CROSSFADE_ENABLE_TRACKSKIP
)
1858 if (crossfade_mode
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1860 if (global_settings
.playlist_shuffle
)
1861 /* shuffle mode is on, so crossfade: */
1862 codec_crossfade_track_change();
1864 /* shuffle mode is off, so do a gapless track change */
1865 codec_gapless_track_change();
1868 /* normal crossfade: */
1869 codec_crossfade_track_change();
1872 /* normal gapless playback. */
1873 codec_gapless_track_change();
1876 static bool codec_load_next_track(void)
1878 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1880 prev_track_elapsed
= CUR_TI
->id3
.elapsed
;
1883 codec_seek_complete_callback();
1885 #ifdef AB_REPEAT_ENABLE
1886 ab_end_of_track_report();
1889 logf("Request new track");
1891 if (ci
.new_track
== 0)
1894 automatic_skip
= true;
1899 trigger_cpu_boost();
1900 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1901 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1906 case Q_CODEC_REQUEST_COMPLETE
:
1907 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1908 codec_track_skip_done(!automatic_skip
);
1911 case Q_CODEC_REQUEST_FAILED
:
1912 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1914 ci
.stop_codec
= true;
1918 LOGFQUEUE("codec |< default");
1919 ci
.stop_codec
= true;
1924 static bool codec_request_next_track_callback(void)
1928 if (ci
.stop_codec
|| !playing
)
1931 prev_codectype
= get_codec_base_type(CUR_TI
->id3
.codectype
);
1933 if (!codec_load_next_track())
1936 /* Check if the next codec is the same file. */
1937 if (prev_codectype
== get_codec_base_type(CUR_TI
->id3
.codectype
))
1939 logf("New track loaded");
1940 codec_discard_codec_callback();
1945 logf("New codec:%d/%d", CUR_TI
->id3
.codectype
, prev_codectype
);
1950 static void codec_thread(void)
1958 queue_wait(&codec_queue
, &ev
);
1961 case Q_CODEC_LOAD_DISK
:
1962 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1963 audio_codec_loaded
= true;
1964 #ifdef PLAYBACK_VOICE
1965 /* Don't sent messages to voice codec if it's already swapped
1966 out or it will never get this */
1967 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1969 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1970 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1972 mutex_lock(&mutex_codecthread
);
1974 set_current_codec(CODEC_IDX_AUDIO
);
1975 ci
.stop_codec
= false;
1976 status
= codec_load_file((const char *)ev
.data
, &ci
);
1977 #ifdef PLAYBACK_VOICE
1978 mutex_unlock(&mutex_codecthread
);
1983 LOGFQUEUE("codec < Q_CODEC_LOAD");
1984 if (!CUR_TI
->has_codec
) {
1985 logf("Codec slot is empty!");
1986 /* Wait for the pcm buffer to go empty */
1987 while (pcm_is_playing())
1989 /* This must be set to prevent an infinite loop */
1990 ci
.stop_codec
= true;
1991 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1992 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
1996 audio_codec_loaded
= true;
1997 #ifdef PLAYBACK_VOICE
1998 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2000 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
2001 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
2003 mutex_lock(&mutex_codecthread
);
2005 set_current_codec(CODEC_IDX_AUDIO
);
2006 ci
.stop_codec
= false;
2007 wrap
= (size_t)&filebuf
[filebuflen
] - (size_t)CUR_TI
->codecbuf
;
2008 status
= codec_load_ram(CUR_TI
->codecbuf
, CUR_TI
->codecsize
,
2009 &filebuf
[0], wrap
, &ci
);
2010 #ifdef PLAYBACK_VOICE
2011 mutex_unlock(&mutex_codecthread
);
2015 #ifdef AUDIO_HAVE_RECORDING
2016 case Q_ENCODER_LOAD_DISK
:
2017 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2018 audio_codec_loaded
= false; /* Not audio codec! */
2019 #ifdef PLAYBACK_VOICE
2020 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2022 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
2023 queue_post(&voice_queue
, Q_ENCODER_RECORD
, 0);
2025 mutex_lock(&mutex_codecthread
);
2027 logf("loading encoder");
2028 set_current_codec(CODEC_IDX_AUDIO
);
2029 ci
.stop_encoder
= false;
2030 status
= codec_load_file((const char *)ev
.data
, &ci
);
2031 #ifdef PLAYBACK_VOICE
2032 mutex_unlock(&mutex_codecthread
);
2034 logf("encoder stopped");
2036 #endif /* AUDIO_HAVE_RECORDING */
2039 case SYS_USB_CONNECTED
:
2040 LOGFQUEUE("codec < SYS_USB_CONNECTED");
2041 queue_clear(&codec_queue
);
2042 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
2043 usb_wait_for_disconnect(&codec_queue
);
2048 LOGFQUEUE("codec < default");
2051 if (audio_codec_loaded
)
2060 audio_codec_loaded
= false;
2064 case Q_CODEC_LOAD_DISK
:
2066 LOGFQUEUE("codec < Q_CODEC_LOAD");
2069 if (ci
.new_track
|| status
!= CODEC_OK
)
2073 logf("Codec failure");
2074 gui_syncsplash(HZ
*2, "Codec failure");
2077 if (!codec_load_next_track())
2079 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2080 /* End of playlist */
2081 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2087 logf("Codec finished");
2090 /* Wait for the audio to stop playing before
2091 * triggering the WPS exit */
2092 while(pcm_is_playing())
2094 CUR_TI
->id3
.elapsed
=
2095 CUR_TI
->id3
.length
- pcmbuf_get_latency();
2098 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2099 /* End of playlist */
2100 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2105 if (CUR_TI
->has_codec
)
2107 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2108 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
2112 const char *codec_fn
=
2113 get_codec_filename(CUR_TI
->id3
.codectype
);
2114 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2115 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
2116 (intptr_t)codec_fn
);
2121 #ifdef AUDIO_HAVE_RECORDING
2122 case Q_ENCODER_LOAD_DISK
:
2123 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2125 if (status
== CODEC_OK
)
2128 logf("Encoder failure");
2129 gui_syncsplash(HZ
*2, "Encoder failure");
2131 if (ci
.enc_codec_loaded
< 0)
2134 logf("Encoder failed to load");
2135 ci
.enc_codec_loaded
= -1;
2137 #endif /* AUDIO_HAVE_RECORDING */
2140 LOGFQUEUE("codec < default");
2147 /* --- Audio thread --- */
2149 static bool audio_filebuf_is_lowdata(void)
2151 return FILEBUFUSED
< AUDIO_FILEBUF_CRITICAL
;
2154 static bool audio_have_tracks(void)
2156 return track_ridx
!= track_widx
|| CUR_TI
->filesize
;
2159 static bool audio_have_free_tracks(void)
2161 if (track_widx
< track_ridx
)
2162 return track_widx
+ 1 < track_ridx
;
2163 else if (track_ridx
== 0)
2164 return track_widx
< MAX_TRACK
- 1;
2169 int audio_track_count(void)
2171 if (audio_have_tracks())
2173 int relative_track_widx
= track_widx
;
2175 if (track_ridx
> track_widx
)
2176 relative_track_widx
+= MAX_TRACK
;
2178 return relative_track_widx
- track_ridx
+ 1;
2184 long audio_filebufused(void)
2186 return (long) FILEBUFUSED
;
2189 /* Count the data BETWEEN the selected tracks */
2190 static size_t audio_buffer_count_tracks(int from_track
, int to_track
)
2193 bool need_wrap
= to_track
< from_track
;
2197 if (++from_track
>= MAX_TRACK
)
2199 from_track
-= MAX_TRACK
;
2203 if (from_track
>= to_track
&& !need_wrap
)
2206 amount
+= tracks
[from_track
].codecsize
+ tracks
[from_track
].filesize
;
2211 static bool audio_buffer_wind_forward(int new_track_ridx
, int old_track_ridx
)
2215 /* Start with the remainder of the previously playing track */
2216 amount
= tracks
[old_track_ridx
].filesize
- ci
.curpos
;
2217 /* Then collect all data from tracks in between them */
2218 amount
+= audio_buffer_count_tracks(old_track_ridx
, new_track_ridx
);
2219 logf("bwf:%ldB", (long) amount
);
2221 if (amount
> FILEBUFUSED
)
2224 /* Wind the buffer to the beginning of the target track or its codec */
2225 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
2230 static bool audio_buffer_wind_backward(int new_track_ridx
, int old_track_ridx
)
2232 /* Available buffer data */
2234 /* Start with the previously playing track's data and our data */
2238 buf_back
= RINGBUF_SUB(buf_ridx
, buf_widx
);
2240 /* If we're not just resetting the current track */
2241 if (new_track_ridx
!= old_track_ridx
)
2243 /* Need to wind to before the old track's codec and our filesize */
2244 amount
+= tracks
[old_track_ridx
].codecsize
;
2245 amount
+= tracks
[new_track_ridx
].filesize
;
2247 /* Rewind the old track to its beginning */
2248 tracks
[old_track_ridx
].available
=
2249 tracks
[old_track_ridx
].filesize
- tracks
[old_track_ridx
].filerem
;
2252 /* If the codec was ever buffered */
2253 if (tracks
[new_track_ridx
].codecsize
)
2255 /* Add the codec to the needed size */
2256 amount
+= tracks
[new_track_ridx
].codecsize
;
2257 tracks
[new_track_ridx
].has_codec
= true;
2260 /* Then collect all data from tracks between new and old */
2261 amount
+= audio_buffer_count_tracks(new_track_ridx
, old_track_ridx
);
2263 /* Do we have space to make this skip? */
2264 if (amount
> buf_back
)
2267 logf("bwb:%ldB",amount
);
2269 /* Rewind the buffer to the beginning of the target track or its codec */
2270 buf_ridx
= RINGBUF_SUB(buf_ridx
, amount
);
2272 /* Reset to the beginning of the new track */
2273 tracks
[new_track_ridx
].available
= tracks
[new_track_ridx
].filesize
;
2278 static void audio_update_trackinfo(void)
2280 ci
.filesize
= CUR_TI
->filesize
;
2281 CUR_TI
->id3
.elapsed
= 0;
2282 CUR_TI
->id3
.offset
= 0;
2283 ci
.id3
= &CUR_TI
->id3
;
2285 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2288 /* Yield to codecs for as long as possible if they are in need of data
2289 * return true if the caller should break to let the audio thread process
2291 static bool audio_yield_codecs(void)
2295 if (!queue_empty(&audio_queue
))
2298 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
2299 && !ci
.stop_codec
&& playing
&& !audio_filebuf_is_lowdata())
2306 if (!queue_empty(&audio_queue
))
2313 static void audio_clear_track_entries(bool clear_unbuffered
)
2315 int cur_idx
= track_widx
;
2318 logf("Clearing tracks:%d/%d, %d", track_ridx
, track_widx
, clear_unbuffered
);
2320 /* Loop over all tracks from write-to-read */
2324 cur_idx
&= MAX_TRACK_MASK
;
2326 if (cur_idx
== track_ridx
)
2329 /* If the track is buffered, conditionally clear/notify,
2330 * otherwise clear the track if that option is selected */
2331 if (tracks
[cur_idx
].event_sent
)
2335 /* If there is an unbuffer callback, call it, otherwise,
2336 * just clear the track */
2337 if (track_unbuffer_callback
)
2338 track_unbuffer_callback(&tracks
[last_idx
].id3
, false);
2340 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2344 else if (clear_unbuffered
)
2345 memset(&tracks
[cur_idx
], 0, sizeof(struct track_info
));
2348 /* We clear the previous instance of a buffered track throughout
2349 * the above loop to facilitate 'last' detection. Clear/notify
2350 * the last track here */
2353 if (track_unbuffer_callback
)
2354 track_unbuffer_callback(&tracks
[last_idx
].id3
, true);
2355 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2359 /* FIXME: This code should be made more generic and move to metadata.c */
2360 static void audio_strip_tags(void)
2363 static const unsigned char tag
[] = "TAG";
2364 static const unsigned char apetag
[] = "APETAGEX";
2367 size_t len
, version
;
2369 tag_idx
= RINGBUF_SUB(buf_widx
, 128);
2371 if (FILEBUFUSED
> 128 && tag_idx
> buf_ridx
)
2374 for(i
= 0;i
< 3;i
++)
2376 if(filebuf
[cur_idx
] != tag
[i
])
2379 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2382 /* Skip id3v1 tag */
2383 logf("Skipping ID3v1 tag");
2385 tracks
[track_widx
].available
-= 128;
2386 tracks
[track_widx
].filesize
-= 128;
2390 /* Check for APE tag (look for the APE tag footer) */
2391 tag_idx
= RINGBUF_SUB(buf_widx
, 32);
2393 if (FILEBUFUSED
> 32 && tag_idx
> buf_ridx
)
2396 for(i
= 0;i
< 8;i
++)
2398 if(filebuf
[cur_idx
] != apetag
[i
])
2401 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2404 /* Read the version and length from the footer */
2405 version
= filebuf
[tag_idx
+8] | (filebuf
[tag_idx
+9] << 8) |
2406 (filebuf
[tag_idx
+10] << 16) | (filebuf
[tag_idx
+11] << 24);
2407 len
= filebuf
[tag_idx
+12] | (filebuf
[tag_idx
+13] << 8) |
2408 (filebuf
[tag_idx
+14] << 16) | (filebuf
[tag_idx
+15] << 24);
2409 if (version
== 2000)
2410 len
+= 32; /* APEv2 has a 32 byte header */
2413 if (FILEBUFUSED
> len
)
2415 logf("Skipping APE tag (%ldB)", len
);
2416 buf_widx
= RINGBUF_SUB(buf_widx
, len
);
2417 tracks
[track_widx
].available
-= len
;
2418 tracks
[track_widx
].filesize
-= len
;
2423 /* Returns true if a whole file is read, false otherwise */
2424 static bool audio_read_file(size_t minimum
)
2426 bool ret_val
= false;
2428 /* If we're called and no file is open, this is an error */
2431 logf("Bad fd in arf");
2432 /* Give some hope of miraculous recovery by forcing a track reload */
2433 tracks
[track_widx
].filesize
= 0;
2434 /* Stop this buffering run */
2438 trigger_cpu_boost();
2439 while (tracks
[track_widx
].filerem
> 0)
2445 /* copy_n is the largest chunk that is safe to read */
2446 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2448 /* buf_widx == buf_ridx is defined as buffer empty, not buffer full */
2449 if (RINGBUF_ADD_CROSS(buf_widx
,copy_n
,buf_ridx
) >= 0)
2452 /* rc is the actual amount read */
2453 rc
= read(current_fd
, &filebuf
[buf_widx
], copy_n
);
2457 logf("File ended %ldB early", tracks
[track_widx
].filerem
);
2458 tracks
[track_widx
].filesize
-= tracks
[track_widx
].filerem
;
2459 tracks
[track_widx
].filerem
= 0;
2463 /* How much of the playing track did we overwrite */
2464 if (buf_widx
== CUR_TI
->buf_idx
)
2466 /* Special handling; zero or full overlap? */
2467 if (track_widx
== track_ridx
&& CUR_TI
->available
== 0)
2473 overlap
= RINGBUF_ADD_CROSS(buf_widx
,rc
,CUR_TI
->buf_idx
);
2475 if ((unsigned)rc
> tracks
[track_widx
].filerem
)
2477 logf("Bad: rc-filerem=%ld, fixing", rc
-tracks
[track_widx
].filerem
);
2478 tracks
[track_widx
].filesize
+= rc
- tracks
[track_widx
].filerem
;
2479 tracks
[track_widx
].filerem
= rc
;
2482 /* Advance buffer */
2483 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2484 tracks
[track_widx
].available
+= rc
;
2485 tracks
[track_widx
].filerem
-= rc
;
2487 /* If we write into the playing track, adjust it's buffer info */
2490 CUR_TI
->buf_idx
+= overlap
;
2491 CUR_TI
->start_pos
+= overlap
;
2494 /* For a rebuffer, fill at least this minimum */
2495 if (minimum
> (unsigned)rc
)
2497 /* Let the codec process up to the watermark */
2498 /* Break immediately if this is a quick buffer, or there is an event */
2499 else if (minimum
|| audio_yield_codecs())
2501 /* Exit quickly, but don't stop the overall buffering process */
2507 if (tracks
[track_widx
].filerem
== 0)
2509 logf("Finished buf:%ldB", tracks
[track_widx
].filesize
);
2515 track_widx
&= MAX_TRACK_MASK
;
2517 tracks
[track_widx
].filesize
= 0;
2522 logf("%s buf:%ldB", ret_val
?"Quick":"Partially",
2523 tracks
[track_widx
].filesize
- tracks
[track_widx
].filerem
);
2528 static bool audio_loadcodec(bool start_play
)
2535 char codec_path
[MAX_PATH
]; /* Full path to codec */
2537 const char * codec_fn
=
2538 get_codec_filename(tracks
[track_widx
].id3
.codectype
);
2539 if (codec_fn
== NULL
)
2542 tracks
[track_widx
].has_codec
= false;
2546 /* Load the codec directly from disk and save some memory. */
2547 track_ridx
= track_widx
;
2548 ci
.filesize
= CUR_TI
->filesize
;
2549 ci
.id3
= &CUR_TI
->id3
;
2550 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2552 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2553 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
2558 /* If we already have another track than this one buffered */
2559 if (track_widx
!= track_ridx
)
2561 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
2563 /* If the previous codec is the same as this one, there is no need
2564 * to put another copy of it on the file buffer */
2565 if (get_codec_base_type(tracks
[track_widx
].id3
.codectype
) ==
2566 get_codec_base_type(tracks
[prev_track
].id3
.codectype
)
2567 && audio_codec_loaded
)
2569 logf("Reusing prev. codec");
2575 codec_get_full_path(codec_path
, codec_fn
);
2577 fd
= open(codec_path
, O_RDONLY
);
2580 logf("Codec doesn't exist!");
2584 tracks
[track_widx
].codecsize
= filesize(fd
);
2586 /* Never load a partial codec */
2587 if (RINGBUF_ADD_CROSS(buf_widx
,tracks
[track_widx
].codecsize
,buf_ridx
) >= 0)
2589 logf("Not enough space");
2594 while (size
< tracks
[track_widx
].codecsize
)
2596 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2597 rc
= read(fd
, &filebuf
[buf_widx
], copy_n
);
2601 /* This is an error condition, likely the codec file is corrupt */
2602 logf("Partial codec loaded");
2603 /* Must undo the buffer write of the partial codec */
2604 buf_widx
= RINGBUF_SUB(buf_widx
, size
);
2605 tracks
[track_widx
].codecsize
= 0;
2609 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2614 tracks
[track_widx
].has_codec
= true;
2617 logf("Done: %ldB", size
);
2622 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2623 static void audio_set_elapsed(struct mp3entry
* id3
)
2625 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
2626 id3
->offset
- id3
->first_frame_offset
: 0;
2629 if ( id3
->has_toc
) {
2630 /* calculate elapsed time using TOC */
2632 unsigned int remainder
, plen
, relpos
, nextpos
;
2634 /* find wich percent we're at */
2635 for (i
=0; i
<100; i
++ )
2636 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
2643 relpos
= id3
->toc
[i
];
2646 nextpos
= id3
->toc
[i
+1];
2650 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
2652 /* set time for this percent (divide before multiply to prevent
2653 overflow on long files. loss of precision is negligible on
2655 id3
->elapsed
= i
* (id3
->length
/ 100);
2657 /* calculate remainder time */
2658 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
2659 id3
->elapsed
+= (((remainder
* 100) / plen
) *
2660 (id3
->length
/ 10000));
2663 /* no TOC exists. set a rough estimate using average bitrate */
2664 int tpk
= id3
->length
/
2665 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
2667 id3
->elapsed
= offset
/ 1024 * tpk
;
2672 /* constant bitrate, use exact calculation */
2673 if (id3
->bitrate
!= 0)
2674 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
2678 static bool audio_load_track(int offset
, bool start_play
, bool rebuffer
)
2684 /* Stop buffer filling if there is no free track entries.
2685 Don't fill up the last track entry (we wan't to store next track
2687 if (!audio_have_free_tracks())
2689 logf("No free tracks");
2693 if (current_fd
>= 0)
2695 logf("Nonzero fd in alt");
2702 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
2703 /* Get track name from current playlist read position. */
2704 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
2706 /* Handle broken playlists. */
2707 current_fd
= open(trackname
, O_RDONLY
);
2710 logf("Open failed");
2711 /* Skip invalid entry from playlist. */
2712 playlist_skip_entry(NULL
, last_peek_offset
);
2720 logf("End-of-playlist");
2721 playlist_end
= true;
2725 /* Initialize track entry. */
2726 size
= filesize(current_fd
);
2727 tracks
[track_widx
].filerem
= size
;
2728 tracks
[track_widx
].filesize
= size
;
2729 tracks
[track_widx
].available
= 0;
2731 /* Set default values */
2734 int last_codec
= current_codec
;
2736 set_current_codec(CODEC_IDX_AUDIO
);
2737 conf_watermark
= AUDIO_DEFAULT_WATERMARK
;
2738 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
2739 conf_preseek
= AUDIO_REBUFFER_GUESS_SIZE
;
2740 dsp_configure(DSP_RESET
, 0);
2741 set_current_codec(last_codec
);
2744 /* Get track metadata if we don't already have it. */
2745 if (!tracks
[track_widx
].taginfo_ready
)
2747 if (get_metadata(&(tracks
[track_widx
].id3
),current_fd
,trackname
,v1first
))
2749 tracks
[track_widx
].taginfo_ready
= true;
2752 track_changed
= true;
2753 playlist_update_resume_info(audio_current_track());
2758 logf("mde:%s!",trackname
);
2760 /* Set filesize to zero to indicate no file was loaded. */
2761 tracks
[track_widx
].filesize
= 0;
2762 tracks
[track_widx
].filerem
= 0;
2766 /* Skip invalid entry from playlist. */
2767 playlist_skip_entry(NULL
, last_peek_offset
);
2768 tracks
[track_widx
].taginfo_ready
= false;
2774 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
2776 char cuepath
[MAX_PATH
];
2778 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
2780 if (look_for_cuesheet_file(trackname
, cuepath
) &&
2781 parse_cuesheet(cuepath
, cue
))
2783 strcpy((cue
)->audio_filename
, trackname
);
2785 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
2789 /* Load the codec. */
2790 tracks
[track_widx
].codecbuf
= &filebuf
[buf_widx
];
2791 if (!audio_loadcodec(start_play
))
2793 /* Set filesize to zero to indicate no file was loaded. */
2794 tracks
[track_widx
].filesize
= 0;
2795 tracks
[track_widx
].filerem
= 0;
2799 if (tracks
[track_widx
].codecsize
)
2801 /* No space for codec on buffer, not an error */
2802 tracks
[track_widx
].codecsize
= 0;
2806 /* This is an error condition, either no codec was found, or reading
2807 * the codec file failed part way through, either way, skip the track */
2808 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
2809 /* We should not use gui_syncplash from audio thread! */
2810 gui_syncsplash(HZ
*2, msgbuf
);
2811 /* Skip invalid entry from playlist. */
2812 playlist_skip_entry(NULL
, last_peek_offset
);
2813 tracks
[track_widx
].taginfo_ready
= false;
2817 tracks
[track_widx
].start_pos
= 0;
2818 set_filebuf_watermark(buffer_margin
);
2819 tracks
[track_widx
].id3
.elapsed
= 0;
2823 switch (tracks
[track_widx
].id3
.codectype
) {
2827 lseek(current_fd
, offset
, SEEK_SET
);
2828 tracks
[track_widx
].id3
.offset
= offset
;
2829 audio_set_elapsed(&tracks
[track_widx
].id3
);
2830 tracks
[track_widx
].filerem
= size
- offset
;
2832 tracks
[track_widx
].start_pos
= offset
;
2836 lseek(current_fd
, offset
, SEEK_SET
);
2837 tracks
[track_widx
].id3
.offset
= offset
;
2838 tracks
[track_widx
].id3
.elapsed
=
2839 tracks
[track_widx
].id3
.length
/ 2;
2840 tracks
[track_widx
].filerem
= size
- offset
;
2842 tracks
[track_widx
].start_pos
= offset
;
2845 case AFMT_OGG_VORBIS
:
2853 tracks
[track_widx
].id3
.offset
= offset
;
2858 logf("alt:%s", trackname
);
2859 tracks
[track_widx
].buf_idx
= buf_widx
;
2861 return audio_read_file(rebuffer
);
2864 static bool audio_read_next_metadata(void)
2871 next_idx
= track_widx
;
2872 if (tracks
[next_idx
].taginfo_ready
)
2875 next_idx
&= MAX_TRACK_MASK
;
2877 if (tracks
[next_idx
].taginfo_ready
)
2881 trackname
= playlist_peek(last_peek_offset
+ 1);
2885 fd
= open(trackname
, O_RDONLY
);
2889 status
= get_metadata(&(tracks
[next_idx
].id3
),fd
,trackname
,v1first
);
2890 /* Preload the glyphs in the tags */
2893 tracks
[next_idx
].taginfo_ready
= true;
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
);