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 /* Pending track change offset, to keep WPS responsive (A) */
251 static int wps_offset
= 0;
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(offset
);
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 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
);
803 /* Take nescessary steps to enable or disable the crossfade setting */
804 void audio_set_crossfade(int enable
)
810 /* Tell it the next setting to use */
811 pcmbuf_crossfade_enable(enable
);
813 /* Return if size hasn't changed or this is too early to determine
814 which in the second case there's no way we could be playing
816 if (pcmbuf_is_same_size())
818 /* This function is a copout and just syncs some variables -
819 to be removed at a later date */
820 pcmbuf_crossfade_enable_finished();
825 was_playing
= playing
;
827 /* Playback has to be stopped before changing the buffer size */
830 /* Store the track resume position */
831 offset
= CUR_TI
->id3
.offset
;
832 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK
));
835 /* Blast it - audio buffer will have to be setup again next time
837 audio_get_buffer(true, &size
);
839 /* Restart playback if audio was running previously */
844 /* --- Routines called from multiple threads --- */
845 static void set_current_codec(int codec_idx
)
847 current_codec
= codec_idx
;
848 dsp_configure(DSP_SWITCH_CODEC
, codec_idx
);
851 #ifdef PLAYBACK_VOICE
852 static void swap_codec(void)
856 /* Swap nothing if no swap buffers exist */
857 if (dram_buf
== NULL
)
859 logf("swap: no swap buffers");
863 my_codec
= current_codec
;
865 logf("swapping out codec: %d", my_codec
);
867 /* Invert this when a codec thread enters and leaves */
868 swap_codec_parity
= !swap_codec_parity
;
870 /* If this is true, an odd number of calls has occurred and there's
871 no codec thread waiting to swap us out when it locks and runs. This
872 occurs when playback is stopped or when just starting playback and
873 the audio thread is loading a codec; parities should always be even
874 on entry when a thread calls this during playback */
875 if (swap_codec_parity
)
877 /* Save our current IRAM and DRAM */
879 if (voice_iram_stolen
)
881 logf("swap: iram restore");
882 voice_iram_stolen
= false;
883 /* Don't swap trashed data into buffer as the voice IRAM will
884 already be swapped out - should _always_ be the case if
885 voice_iram_stolen is true since the voice has been swapped
887 if (my_codec
== CODEC_IDX_VOICE
)
889 logf("voice iram already swapped");
895 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
901 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
902 /* No cache invalidation needed; it will be done in codec_load_ram
903 or we won't be here otherwise */
906 /* Release my semaphore */
907 mutex_unlock(&mutex_codecthread
);
908 logf("unlocked: %d", my_codec
);
910 /* Loop until the other codec has locked and run */
912 /* Release my semaphore and force a task switch. */
914 } while (my_codec
== current_codec
);
916 /* Wait for other codec to unlock */
917 /* FIXME: We need some sort of timed boost cancellation here or the CPU
918 doesn't unboost during playback when the voice codec goes back to
919 waiting - recall that mutex_lock calls block_thread which is an
920 indefinite wait that doesn't cancel the thread's CPU boost */
921 mutex_lock(&mutex_codecthread
);
924 logf("waiting for lock: %d", my_codec
);
925 set_current_codec(my_codec
);
927 /* Reload our IRAM and DRAM */
928 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
929 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
932 /* Flip parity again */
933 swap_codec_parity
= !swap_codec_parity
;
935 logf("resuming codec: %d", my_codec
);
938 /* This function is meant to be used by the buffer stealing functions to
939 ensure the codec is no longer active and so voice will be swapped-in
940 before it is called */
941 static void voice_stop(void)
943 #ifdef PLAYBACK_VOICE
944 /* Must have a voice codec loaded or we'll hang forever here */
945 if (!voice_codec_loaded
)
948 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
949 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
951 /* Loop until voice empties it's queue, stops and picks up on the new
952 track; the voice thread must be stopped and waiting for messages
954 while (voice_is_playing
|| !queue_empty(&voice_queue
) ||
962 #endif /* PLAYBACK_VOICE */
964 static void set_filebuf_watermark(int seconds
)
969 return; /* Audio buffers not yet set up */
971 bytes
= MAX(CUR_TI
->id3
.bitrate
* seconds
* (1000/8), conf_watermark
);
972 bytes
= MIN(bytes
, filebuflen
/ 2);
973 conf_watermark
= bytes
;
976 const char * get_codec_filename(int cod_spec
)
980 #ifdef HAVE_RECORDING
981 /* Can choose decoder or encoder if one available */
982 int type
= cod_spec
& CODEC_TYPE_MASK
;
983 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
985 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
986 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
988 fname
= (type
== CODEC_TYPE_ENCODER
) ?
989 audio_formats
[afmt
].codec_enc_root_fn
:
990 audio_formats
[afmt
].codec_root_fn
;
993 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
994 afmt
, fname
? fname
: "<unknown>");
995 #else /* !HAVE_RECORDING */
997 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
998 cod_spec
= AFMT_UNKNOWN
;
999 fname
= audio_formats
[cod_spec
].codec_root_fn
;
1000 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
1001 #endif /* HAVE_RECORDING */
1004 } /* get_codec_filename */
1007 /* --- Voice thread --- */
1009 #ifdef PLAYBACK_VOICE
1011 static bool voice_pcmbuf_insert_callback(
1012 const void *ch1
, const void *ch2
, int count
)
1014 const char *src
[2] = { ch1
, ch2
};
1018 int out_count
= dsp_output_count(count
);
1022 while ((dest
= pcmbuf_request_voice_buffer(
1023 &out_count
, playing
)) == NULL
)
1025 if (playing
&& audio_codec_loaded
)
1031 /* Get the real input_size for output_size bytes, guarding
1032 * against resampling buffer overflows. */
1033 inp_count
= dsp_input_count(out_count
);
1038 /* Input size has grown, no error, just don't write more than length */
1039 if (inp_count
> count
)
1042 out_count
= dsp_process(dest
, src
, inp_count
);
1049 pcmbuf_mix_voice(out_count
);
1050 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
1055 pcmbuf_write_complete(out_count
);
1061 } /* voice_pcmbuf_insert_callback */
1063 static void* voice_get_memory_callback(size_t *size
)
1065 /* Voice should have no use for this. If it did, we'd have to
1066 swap the malloc buffer as well. */
1071 static void voice_set_elapsed_callback(unsigned int value
)
1076 static void voice_set_offset_callback(size_t value
)
1081 static void voice_configure_callback(int setting
, intptr_t value
)
1083 if (!dsp_configure(setting
, value
))
1085 logf("Illegal key:%d", setting
);
1089 static size_t voice_filebuf_callback(void *ptr
, size_t size
)
1097 /* Handle Q_VOICE_STOP and part of SYS_USB_CONNECTED */
1098 static bool voice_on_voice_stop(bool aborting
, size_t *realsize
)
1100 if (aborting
&& !playing
&& pcm_is_playing())
1102 /* Aborting: Slight hack - flush PCM buffer if
1103 only being used for voice */
1107 if (voice_is_playing
)
1109 /* Clear the current buffer */
1110 voice_is_playing
= false;
1111 voice_getmore
= NULL
;
1112 voice_remaining
= 0;
1115 /* Force the codec to think it's changing tracks */
1116 ci_voice
.new_track
= 1;
1119 return true; /* Yes, change tracks */
1125 static void* voice_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1129 if (ci_voice
.new_track
)
1137 if (voice_is_playing
|| playing
)
1139 queue_wait_w_tmo(&voice_queue
, &ev
, 0);
1140 if (!voice_is_playing
&& ev
.id
== SYS_TIMEOUT
)
1141 ev
.id
= Q_AUDIO_PLAY
;
1145 /* We must use queue_wait_w_tmo() because queue_wait() doesn't
1147 /* FIXME: when long timeouts work correctly max out the the timeout
1148 (we'll still need the timeout guard here) or an infinite timeout
1149 can unboost, use that */
1151 queue_wait_w_tmo(&voice_queue
, &ev
, HZ
*5);
1152 while (ev
.id
== SYS_TIMEOUT
); /* Fake infinite wait */
1157 LOGFQUEUE("voice < Q_AUDIO_PLAY");
1160 if (audio_codec_loaded
)
1166 #ifdef AUDIO_HAVE_RECORDING
1167 case Q_ENCODER_RECORD
:
1168 LOGFQUEUE("voice < Q_ENCODER_RECORD");
1174 LOGFQUEUE("voice < Q_VOICE_STOP");
1175 if (voice_on_voice_stop(ev
.data
, realsize
))
1179 case SYS_USB_CONNECTED
:
1181 LOGFQUEUE("voice < SYS_USB_CONNECTED");
1182 bool change_tracks
= voice_on_voice_stop(ev
.data
, realsize
);
1183 /* Voice is obviously current so let us swap ourselves away if
1184 playing so audio may stop itself - audio_codec_loaded can
1185 only be true in this case if we're here even if the codec
1186 is only about to load */
1187 if (audio_codec_loaded
)
1189 /* Playback should be finished by now - ack and wait */
1190 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
1191 usb_wait_for_disconnect(&voice_queue
);
1198 LOGFQUEUE("voice < Q_VOICE_PLAY");
1199 if (!voice_is_playing
)
1201 /* Set up new voice data */
1202 struct voice_info
*voice_data
;
1204 if (voice_iram_stolen
)
1206 /* Voice is the first to run again and is currently
1208 logf("voice: iram restore");
1209 memcpy(CODEC_IRAM_ORIGIN
, iram_buf
, CODEC_IRAM_SIZE
);
1210 voice_iram_stolen
= false;
1213 /* Must reset the buffer before any playback begins if
1215 if (buffer_state
== BUFFER_STATE_TRASHED
)
1216 audio_reset_buffer();
1218 voice_is_playing
= true;
1219 trigger_cpu_boost();
1220 voice_data
= (struct voice_info
*)ev
.data
;
1221 voice_remaining
= voice_data
->size
;
1222 voicebuf
= voice_data
->buf
;
1223 voice_getmore
= voice_data
->callback
;
1225 goto voice_play_clip
; /* To exit both switch and while */
1228 LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
1229 goto voice_play_clip
;
1232 LOGFQUEUE("voice < default");
1238 if (voice_remaining
== 0 || voicebuf
== NULL
)
1241 voice_getmore((unsigned char **)&voicebuf
, &voice_remaining
);
1243 /* If this clip is done */
1244 if (voice_remaining
== 0)
1246 LOGFQUEUE("voice > voice Q_VOICE_STOP");
1247 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
1248 /* Force pcm playback. */
1249 if (!pcm_is_playing())
1250 pcmbuf_play_start();
1254 *realsize
= MIN(voice_remaining
, reqsize
);
1260 } /* voice_request_buffer_callback */
1262 static void voice_advance_buffer_callback(size_t amount
)
1264 amount
= MIN(amount
, voice_remaining
);
1266 voice_remaining
-= amount
;
1269 static void voice_advance_buffer_loc_callback(void *ptr
)
1271 size_t amount
= (size_t)ptr
- (size_t)voicebuf
;
1273 voice_advance_buffer_callback(amount
);
1276 static off_t
voice_mp3_get_filepos_callback(int newtime
)
1283 static void voice_do_nothing(void)
1288 static bool voice_seek_buffer_callback(size_t newpos
)
1295 static bool voice_request_next_track_callback(void)
1297 ci_voice
.new_track
= 0;
1301 static void voice_thread(void)
1303 logf("Loading voice codec");
1304 voice_codec_loaded
= true;
1305 mutex_lock(&mutex_codecthread
);
1306 set_current_codec(CODEC_IDX_VOICE
);
1307 dsp_configure(DSP_RESET
, 0);
1308 voice_remaining
= 0;
1309 voice_getmore
= NULL
;
1311 /* FIXME: If we being starting the voice thread without reboot, the
1312 voice_queue could be full of old stuff and we must flush it. */
1313 codec_load_file(get_codec_filename(AFMT_MPA_L3
), &ci_voice
);
1315 logf("Voice codec finished");
1316 voice_codec_loaded
= false;
1317 mutex_unlock(&mutex_codecthread
);
1318 voice_thread_p
= NULL
;
1319 remove_thread(NULL
);
1320 } /* voice_thread */
1322 #endif /* PLAYBACK_VOICE */
1324 /* --- Codec thread --- */
1325 static bool codec_pcmbuf_insert_callback(
1326 const void *ch1
, const void *ch2
, int count
)
1328 const char *src
[2] = { ch1
, ch2
};
1332 int out_count
= dsp_output_count(count
);
1336 /* Prevent audio from a previous track from playing */
1337 if (ci
.new_track
|| ci
.stop_codec
)
1340 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
1343 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
1347 /* Get the real input_size for output_size bytes, guarding
1348 * against resampling buffer overflows. */
1349 inp_count
= dsp_input_count(out_count
);
1354 /* Input size has grown, no error, just don't write more than length */
1355 if (inp_count
> count
)
1358 out_count
= dsp_process(dest
, src
, inp_count
);
1363 pcmbuf_write_complete(out_count
);
1365 #ifdef PLAYBACK_VOICE
1366 if ((voice_is_playing
|| voice_thread_start
)
1367 && pcm_is_playing() && voice_codec_loaded
&&
1368 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1370 voice_thread_start
= false;
1379 } /* codec_pcmbuf_insert_callback */
1381 static void* codec_get_memory_callback(size_t *size
)
1383 *size
= MALLOC_BUFSIZE
;
1387 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
1388 static void codec_pcmbuf_position_callback(size_t size
)
1390 /* This is called from an ISR, so be quick */
1391 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
1392 prev_ti
->id3
.elapsed
;
1394 if (time
>= prev_ti
->id3
.length
)
1396 pcmbuf_set_position_callback(NULL
);
1397 prev_ti
->id3
.elapsed
= prev_ti
->id3
.length
;
1400 prev_ti
->id3
.elapsed
= time
;
1403 static void codec_set_elapsed_callback(unsigned int value
)
1405 unsigned int latency
;
1409 #ifdef AB_REPEAT_ENABLE
1410 ab_position_report(value
);
1413 latency
= pcmbuf_get_latency();
1414 if (value
< latency
)
1415 CUR_TI
->id3
.elapsed
= 0;
1416 else if (value
- latency
> CUR_TI
->id3
.elapsed
||
1417 value
- latency
< CUR_TI
->id3
.elapsed
- 2)
1419 CUR_TI
->id3
.elapsed
= value
- latency
;
1423 static void codec_set_offset_callback(size_t value
)
1425 unsigned int latency
;
1430 latency
= pcmbuf_get_latency() * CUR_TI
->id3
.bitrate
/ 8;
1431 if (value
< latency
)
1432 CUR_TI
->id3
.offset
= 0;
1434 CUR_TI
->id3
.offset
= value
- latency
;
1437 static void codec_advance_buffer_counters(size_t amount
)
1439 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
1440 ci
.curpos
+= amount
;
1441 CUR_TI
->available
-= amount
;
1443 /* Start buffer filling as necessary. */
1444 if (!pcmbuf_is_lowdata() && !filling
)
1446 if (FILEBUFUSED
< conf_watermark
&& playing
&& !playlist_end
)
1448 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1449 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1454 /* copy up-to size bytes into ptr and return the actual size copied */
1455 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
1457 char *buf
= (char *)ptr
;
1461 if (ci
.stop_codec
|| !playing
)
1464 /* The ammount to copy is the lesser of the requested amount and the
1465 * amount left of the current track (both on disk and already loaded) */
1466 copy_n
= MIN(size
, CUR_TI
->available
+ CUR_TI
->filerem
);
1468 /* Nothing requested OR nothing left */
1472 /* Let the disk buffer catch fill until enough data is available */
1473 while (copy_n
> CUR_TI
->available
)
1477 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1478 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1482 if (ci
.stop_codec
|| ci
.new_track
)
1486 /* Copy as much as possible without wrapping */
1487 part_n
= MIN(copy_n
, filebuflen
- buf_ridx
);
1488 memcpy(buf
, &filebuf
[buf_ridx
], part_n
);
1489 /* Copy the rest in the case of a wrap */
1490 if (part_n
< copy_n
) {
1491 memcpy(&buf
[part_n
], &filebuf
[0], copy_n
- part_n
);
1494 /* Update read and other position pointers */
1495 codec_advance_buffer_counters(copy_n
);
1497 /* Return the actual amount of data copied to the buffer */
1499 } /* codec_filebuf_callback */
1501 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1503 size_t short_n
, copy_n
, buf_rem
;
1511 copy_n
= MIN(reqsize
, CUR_TI
->available
+ CUR_TI
->filerem
);
1518 while (copy_n
> CUR_TI
->available
)
1522 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1523 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1527 if (ci
.stop_codec
|| ci
.new_track
)
1534 /* How much is left at the end of the file buffer before wrap? */
1535 buf_rem
= filebuflen
- buf_ridx
;
1537 /* If we can't satisfy the request without wrapping */
1538 if (buf_rem
< copy_n
)
1540 /* How short are we? */
1541 short_n
= copy_n
- buf_rem
;
1543 /* If we can fudge it with the guardbuf */
1544 if (short_n
< GUARD_BUFSIZE
)
1545 memcpy(&filebuf
[filebuflen
], &filebuf
[0], short_n
);
1552 return (char *)&filebuf
[buf_ridx
];
1553 } /* codec_request_buffer_callback */
1555 static int get_codec_base_type(int type
)
1567 static void codec_advance_buffer_callback(size_t amount
)
1569 if (amount
> CUR_TI
->available
+ CUR_TI
->filerem
)
1570 amount
= CUR_TI
->available
+ CUR_TI
->filerem
;
1572 while (amount
> CUR_TI
->available
&& filling
)
1575 if (amount
> CUR_TI
->available
)
1577 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1581 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1582 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1583 ci
.curpos
+ amount
);
1588 case Q_CODEC_REQUEST_FAILED
:
1589 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1590 ci
.stop_codec
= true;
1593 case Q_CODEC_REQUEST_COMPLETE
:
1594 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1598 LOGFQUEUE("codec |< default");
1599 ci
.stop_codec
= true;
1604 codec_advance_buffer_counters(amount
);
1606 codec_set_offset_callback(ci
.curpos
);
1609 static void codec_advance_buffer_loc_callback(void *ptr
)
1611 size_t amount
= (size_t)ptr
- (size_t)&filebuf
[buf_ridx
];
1613 codec_advance_buffer_callback(amount
);
1616 /* Copied from mpeg.c. Should be moved somewhere else. */
1617 static int codec_get_file_pos(void)
1620 struct mp3entry
*id3
= audio_current_track();
1626 /* Use the TOC to find the new position */
1627 unsigned int percent
, remainder
;
1628 int curtoc
, nexttoc
, plen
;
1630 percent
= (id3
->elapsed
*100)/id3
->length
;
1634 curtoc
= id3
->toc
[percent
];
1637 nexttoc
= id3
->toc
[percent
+1];
1641 pos
= (id3
->filesize
/256)*curtoc
;
1643 /* Use the remainder to get a more accurate position */
1644 remainder
= (id3
->elapsed
*100)%id3
->length
;
1645 remainder
= (remainder
*100)/id3
->length
;
1646 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1647 pos
+= (plen
/100)*remainder
;
1651 /* No TOC exists, estimate the new position */
1652 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1653 (id3
->elapsed
/ 1000);
1656 else if (id3
->bitrate
)
1657 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1661 pos
+= id3
->first_frame_offset
;
1663 /* Don't seek right to the end of the file so that we can
1664 transition properly to the next song */
1665 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1666 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1671 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1675 CUR_TI
->id3
.elapsed
= newtime
;
1676 newpos
= codec_get_file_pos();
1681 static void codec_seek_complete_callback(void)
1683 logf("seek_complete");
1684 if (pcm_is_paused())
1686 /* If this is not a seamless seek, clear the buffer */
1688 dsp_configure(DSP_FLUSH
, 0);
1690 /* If playback was not 'deliberately' paused, unpause now */
1692 pcmbuf_pause(false);
1697 static bool codec_seek_buffer_callback(size_t newpos
)
1701 logf("codec_seek_buffer_callback");
1703 if (newpos
>= CUR_TI
->filesize
)
1704 newpos
= CUR_TI
->filesize
- 1;
1706 difference
= newpos
- ci
.curpos
;
1707 if (difference
>= 0)
1709 /* Seeking forward */
1710 logf("seek: +%d", difference
);
1711 codec_advance_buffer_callback(difference
);
1715 /* Seeking backward */
1716 difference
= -difference
;
1717 if (ci
.curpos
- difference
< 0)
1718 difference
= ci
.curpos
;
1720 /* We need to reload the song. */
1721 if (newpos
< CUR_TI
->start_pos
)
1723 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1727 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1728 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1734 case Q_CODEC_REQUEST_COMPLETE
:
1735 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1738 case Q_CODEC_REQUEST_FAILED
:
1739 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1740 ci
.stop_codec
= true;
1744 LOGFQUEUE("codec |< default");
1749 /* Seeking inside buffer space. */
1750 logf("seek: -%d", difference
);
1751 CUR_TI
->available
+= difference
;
1752 buf_ridx
= RINGBUF_SUB(buf_ridx
, (unsigned)difference
);
1753 ci
.curpos
-= difference
;
1758 static void codec_configure_callback(int setting
, intptr_t value
)
1761 case CODEC_SET_FILEBUF_WATERMARK
:
1762 conf_watermark
= value
;
1763 set_filebuf_watermark(buffer_margin
);
1766 case CODEC_SET_FILEBUF_CHUNKSIZE
:
1767 conf_filechunk
= value
;
1770 case CODEC_SET_FILEBUF_PRESEEK
:
1771 conf_preseek
= value
;
1775 if (!dsp_configure(setting
, value
)) { logf("Illegal key:%d", setting
); }
1779 static void codec_track_changed(void)
1781 automatic_skip
= false;
1782 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1783 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1786 static void codec_pcmbuf_track_changed_callback(void)
1788 pcmbuf_set_position_callback(NULL
);
1789 codec_track_changed();
1792 static void codec_discard_codec_callback(void)
1794 if (CUR_TI
->has_codec
)
1796 CUR_TI
->has_codec
= false;
1797 buf_ridx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->codecsize
);
1801 /* Check if a buffer desync has happened, log it and stop playback. */
1802 if (buf_ridx
!= CUR_TI
->buf_idx
)
1804 int offset
= CUR_TI
->buf_idx
- buf_ridx
;
1805 size_t new_used
= FILEBUFUSED
- offset
;
1807 logf("Buf off :%d=%d-%d", offset
, CUR_TI
->buf_idx
, buf_ridx
);
1808 logf("Used off:%d",FILEBUFUSED
- new_used
);
1810 /* This is a fatal internal error and it's not safe to
1811 * continue playback. */
1812 ci
.stop_codec
= true;
1813 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1818 static inline void codec_gapless_track_change(void) {
1819 /* callback keeps the progress bar moving while the pcmbuf empties */
1820 pcmbuf_set_position_callback(codec_pcmbuf_position_callback
);
1821 /* set the pcmbuf callback for when the track really changes */
1822 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1825 static inline void codec_crossfade_track_change(void) {
1826 /* Initiate automatic crossfade mode */
1827 pcmbuf_crossfade_init(false);
1828 /* Notify the wps that the track change starts now */
1829 codec_track_changed();
1832 static void codec_track_skip_done(bool was_manual
)
1834 int crossfade_mode
= global_settings
.crossfade
;
1836 /* Manual track change (always crossfade or flush audio). */
1839 pcmbuf_crossfade_init(true);
1840 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1841 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1843 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1844 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1845 && crossfade_mode
!= CROSSFADE_ENABLE_TRACKSKIP
)
1847 if (crossfade_mode
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1849 if (global_settings
.playlist_shuffle
)
1850 /* shuffle mode is on, so crossfade: */
1851 codec_crossfade_track_change();
1853 /* shuffle mode is off, so do a gapless track change */
1854 codec_gapless_track_change();
1857 /* normal crossfade: */
1858 codec_crossfade_track_change();
1861 /* normal gapless playback. */
1862 codec_gapless_track_change();
1865 static bool codec_load_next_track(void)
1867 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1869 prev_track_elapsed
= CUR_TI
->id3
.elapsed
;
1872 codec_seek_complete_callback();
1874 #ifdef AB_REPEAT_ENABLE
1875 ab_end_of_track_report();
1878 logf("Request new track");
1880 if (ci
.new_track
== 0)
1883 automatic_skip
= true;
1888 trigger_cpu_boost();
1889 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1890 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1895 case Q_CODEC_REQUEST_COMPLETE
:
1896 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1897 codec_track_skip_done(!automatic_skip
);
1900 case Q_CODEC_REQUEST_FAILED
:
1901 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1903 ci
.stop_codec
= true;
1907 LOGFQUEUE("codec |< default");
1908 ci
.stop_codec
= true;
1913 static bool codec_request_next_track_callback(void)
1917 if (ci
.stop_codec
|| !playing
)
1920 prev_codectype
= get_codec_base_type(CUR_TI
->id3
.codectype
);
1922 if (!codec_load_next_track())
1925 /* Check if the next codec is the same file. */
1926 if (prev_codectype
== get_codec_base_type(CUR_TI
->id3
.codectype
))
1928 logf("New track loaded");
1929 codec_discard_codec_callback();
1934 logf("New codec:%d/%d", CUR_TI
->id3
.codectype
, prev_codectype
);
1939 static void codec_thread(void)
1947 queue_wait(&codec_queue
, &ev
);
1950 case Q_CODEC_LOAD_DISK
:
1951 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1952 audio_codec_loaded
= true;
1953 #ifdef PLAYBACK_VOICE
1954 /* Don't sent messages to voice codec if it's already swapped
1955 out or it will never get this */
1956 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1958 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1959 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1961 mutex_lock(&mutex_codecthread
);
1963 set_current_codec(CODEC_IDX_AUDIO
);
1964 ci
.stop_codec
= false;
1965 status
= codec_load_file((const char *)ev
.data
, &ci
);
1966 #ifdef PLAYBACK_VOICE
1967 mutex_unlock(&mutex_codecthread
);
1972 LOGFQUEUE("codec < Q_CODEC_LOAD");
1973 if (!CUR_TI
->has_codec
) {
1974 logf("Codec slot is empty!");
1975 /* Wait for the pcm buffer to go empty */
1976 while (pcm_is_playing())
1978 /* This must be set to prevent an infinite loop */
1979 ci
.stop_codec
= true;
1980 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1981 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
1985 audio_codec_loaded
= true;
1986 #ifdef PLAYBACK_VOICE
1987 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1989 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1990 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1992 mutex_lock(&mutex_codecthread
);
1994 set_current_codec(CODEC_IDX_AUDIO
);
1995 ci
.stop_codec
= false;
1996 wrap
= (size_t)&filebuf
[filebuflen
] - (size_t)CUR_TI
->codecbuf
;
1997 status
= codec_load_ram(CUR_TI
->codecbuf
, CUR_TI
->codecsize
,
1998 &filebuf
[0], wrap
, &ci
);
1999 #ifdef PLAYBACK_VOICE
2000 mutex_unlock(&mutex_codecthread
);
2004 #ifdef AUDIO_HAVE_RECORDING
2005 case Q_ENCODER_LOAD_DISK
:
2006 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2007 audio_codec_loaded
= false; /* Not audio codec! */
2008 #ifdef PLAYBACK_VOICE
2009 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2011 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
2012 queue_post(&voice_queue
, Q_ENCODER_RECORD
, 0);
2014 mutex_lock(&mutex_codecthread
);
2016 logf("loading encoder");
2017 set_current_codec(CODEC_IDX_AUDIO
);
2018 ci
.stop_encoder
= false;
2019 status
= codec_load_file((const char *)ev
.data
, &ci
);
2020 #ifdef PLAYBACK_VOICE
2021 mutex_unlock(&mutex_codecthread
);
2023 logf("encoder stopped");
2025 #endif /* AUDIO_HAVE_RECORDING */
2028 case SYS_USB_CONNECTED
:
2029 LOGFQUEUE("codec < SYS_USB_CONNECTED");
2030 queue_clear(&codec_queue
);
2031 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
2032 usb_wait_for_disconnect(&codec_queue
);
2037 LOGFQUEUE("codec < default");
2040 if (audio_codec_loaded
)
2049 audio_codec_loaded
= false;
2053 case Q_CODEC_LOAD_DISK
:
2055 LOGFQUEUE("codec < Q_CODEC_LOAD");
2058 if (ci
.new_track
|| status
!= CODEC_OK
)
2062 logf("Codec failure");
2063 gui_syncsplash(HZ
*2, "Codec failure");
2066 if (!codec_load_next_track())
2068 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2069 /* End of playlist */
2070 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2076 logf("Codec finished");
2079 /* Wait for the audio to stop playing before
2080 * triggering the WPS exit */
2081 while(pcm_is_playing())
2083 CUR_TI
->id3
.elapsed
=
2084 CUR_TI
->id3
.length
- pcmbuf_get_latency();
2087 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2088 /* End of playlist */
2089 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2094 if (CUR_TI
->has_codec
)
2096 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2097 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
2101 const char *codec_fn
=
2102 get_codec_filename(CUR_TI
->id3
.codectype
);
2103 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2104 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
2105 (intptr_t)codec_fn
);
2110 #ifdef AUDIO_HAVE_RECORDING
2111 case Q_ENCODER_LOAD_DISK
:
2112 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2114 if (status
== CODEC_OK
)
2117 logf("Encoder failure");
2118 gui_syncsplash(HZ
*2, "Encoder failure");
2120 if (ci
.enc_codec_loaded
< 0)
2123 logf("Encoder failed to load");
2124 ci
.enc_codec_loaded
= -1;
2126 #endif /* AUDIO_HAVE_RECORDING */
2129 LOGFQUEUE("codec < default");
2136 /* --- Audio thread --- */
2138 static bool audio_filebuf_is_lowdata(void)
2140 return FILEBUFUSED
< AUDIO_FILEBUF_CRITICAL
;
2143 static bool audio_have_tracks(void)
2145 return track_ridx
!= track_widx
|| CUR_TI
->filesize
;
2148 static bool audio_have_free_tracks(void)
2150 if (track_widx
< track_ridx
)
2151 return track_widx
+ 1 < track_ridx
;
2152 else if (track_ridx
== 0)
2153 return track_widx
< MAX_TRACK
- 1;
2158 int audio_track_count(void)
2160 if (audio_have_tracks())
2162 int relative_track_widx
= track_widx
;
2164 if (track_ridx
> track_widx
)
2165 relative_track_widx
+= MAX_TRACK
;
2167 return relative_track_widx
- track_ridx
+ 1;
2173 long audio_filebufused(void)
2175 return (long) FILEBUFUSED
;
2178 /* Count the data BETWEEN the selected tracks */
2179 static size_t audio_buffer_count_tracks(int from_track
, int to_track
)
2182 bool need_wrap
= to_track
< from_track
;
2186 if (++from_track
>= MAX_TRACK
)
2188 from_track
-= MAX_TRACK
;
2192 if (from_track
>= to_track
&& !need_wrap
)
2195 amount
+= tracks
[from_track
].codecsize
+ tracks
[from_track
].filesize
;
2200 static bool audio_buffer_wind_forward(int new_track_ridx
, int old_track_ridx
)
2204 /* Start with the remainder of the previously playing track */
2205 amount
= tracks
[old_track_ridx
].filesize
- ci
.curpos
;
2206 /* Then collect all data from tracks in between them */
2207 amount
+= audio_buffer_count_tracks(old_track_ridx
, new_track_ridx
);
2208 logf("bwf:%ldB", (long) amount
);
2210 if (amount
> FILEBUFUSED
)
2213 /* Wind the buffer to the beginning of the target track or its codec */
2214 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
2219 static bool audio_buffer_wind_backward(int new_track_ridx
, int old_track_ridx
)
2221 /* Available buffer data */
2223 /* Start with the previously playing track's data and our data */
2227 buf_back
= RINGBUF_SUB(buf_ridx
, buf_widx
);
2229 /* If we're not just resetting the current track */
2230 if (new_track_ridx
!= old_track_ridx
)
2232 /* Need to wind to before the old track's codec and our filesize */
2233 amount
+= tracks
[old_track_ridx
].codecsize
;
2234 amount
+= tracks
[new_track_ridx
].filesize
;
2236 /* Rewind the old track to its beginning */
2237 tracks
[old_track_ridx
].available
=
2238 tracks
[old_track_ridx
].filesize
- tracks
[old_track_ridx
].filerem
;
2241 /* If the codec was ever buffered */
2242 if (tracks
[new_track_ridx
].codecsize
)
2244 /* Add the codec to the needed size */
2245 amount
+= tracks
[new_track_ridx
].codecsize
;
2246 tracks
[new_track_ridx
].has_codec
= true;
2249 /* Then collect all data from tracks between new and old */
2250 amount
+= audio_buffer_count_tracks(new_track_ridx
, old_track_ridx
);
2252 /* Do we have space to make this skip? */
2253 if (amount
> buf_back
)
2256 logf("bwb:%ldB",amount
);
2258 /* Rewind the buffer to the beginning of the target track or its codec */
2259 buf_ridx
= RINGBUF_SUB(buf_ridx
, amount
);
2261 /* Reset to the beginning of the new track */
2262 tracks
[new_track_ridx
].available
= tracks
[new_track_ridx
].filesize
;
2267 static void audio_update_trackinfo(void)
2269 ci
.filesize
= CUR_TI
->filesize
;
2270 CUR_TI
->id3
.elapsed
= 0;
2271 CUR_TI
->id3
.offset
= 0;
2272 ci
.id3
= &CUR_TI
->id3
;
2274 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2277 /* Yield to codecs for as long as possible if they are in need of data
2278 * return true if the caller should break to let the audio thread process
2280 static bool audio_yield_codecs(void)
2284 if (!queue_empty(&audio_queue
))
2287 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
2288 && !ci
.stop_codec
&& playing
&& !audio_filebuf_is_lowdata())
2295 if (!queue_empty(&audio_queue
))
2302 static void audio_clear_track_entries(bool clear_unbuffered
)
2304 int cur_idx
= track_widx
;
2307 logf("Clearing tracks:%d/%d, %d", track_ridx
, track_widx
, clear_unbuffered
);
2309 /* Loop over all tracks from write-to-read */
2313 cur_idx
&= MAX_TRACK_MASK
;
2315 if (cur_idx
== track_ridx
)
2318 /* If the track is buffered, conditionally clear/notify,
2319 * otherwise clear the track if that option is selected */
2320 if (tracks
[cur_idx
].event_sent
)
2324 /* If there is an unbuffer callback, call it, otherwise,
2325 * just clear the track */
2326 if (track_unbuffer_callback
)
2327 track_unbuffer_callback(&tracks
[last_idx
].id3
, false);
2329 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2333 else if (clear_unbuffered
)
2334 memset(&tracks
[cur_idx
], 0, sizeof(struct track_info
));
2337 /* We clear the previous instance of a buffered track throughout
2338 * the above loop to facilitate 'last' detection. Clear/notify
2339 * the last track here */
2342 if (track_unbuffer_callback
)
2343 track_unbuffer_callback(&tracks
[last_idx
].id3
, true);
2344 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2348 /* FIXME: This code should be made more generic and move to metadata.c */
2349 static void audio_strip_tags(void)
2352 static const unsigned char tag
[] = "TAG";
2353 static const unsigned char apetag
[] = "APETAGEX";
2356 size_t len
, version
;
2358 tag_idx
= RINGBUF_SUB(buf_widx
, 128);
2360 if (FILEBUFUSED
> 128 && tag_idx
> buf_ridx
)
2363 for(i
= 0;i
< 3;i
++)
2365 if(filebuf
[cur_idx
] != tag
[i
])
2368 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2371 /* Skip id3v1 tag */
2372 logf("Skipping ID3v1 tag");
2374 tracks
[track_widx
].available
-= 128;
2375 tracks
[track_widx
].filesize
-= 128;
2379 /* Check for APE tag (look for the APE tag footer) */
2380 tag_idx
= RINGBUF_SUB(buf_widx
, 32);
2382 if (FILEBUFUSED
> 32 && tag_idx
> buf_ridx
)
2385 for(i
= 0;i
< 8;i
++)
2387 if(filebuf
[cur_idx
] != apetag
[i
])
2390 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2393 /* Read the version and length from the footer */
2394 version
= filebuf
[tag_idx
+8] | (filebuf
[tag_idx
+9] << 8) |
2395 (filebuf
[tag_idx
+10] << 16) | (filebuf
[tag_idx
+11] << 24);
2396 len
= filebuf
[tag_idx
+12] | (filebuf
[tag_idx
+13] << 8) |
2397 (filebuf
[tag_idx
+14] << 16) | (filebuf
[tag_idx
+15] << 24);
2398 if (version
== 2000)
2399 len
+= 32; /* APEv2 has a 32 byte header */
2402 if (FILEBUFUSED
> len
)
2404 logf("Skipping APE tag (%ldB)", len
);
2405 buf_widx
= RINGBUF_SUB(buf_widx
, len
);
2406 tracks
[track_widx
].available
-= len
;
2407 tracks
[track_widx
].filesize
-= len
;
2412 /* Returns true if a whole file is read, false otherwise */
2413 static bool audio_read_file(size_t minimum
)
2415 bool ret_val
= false;
2417 /* If we're called and no file is open, this is an error */
2420 logf("Bad fd in arf");
2421 /* Give some hope of miraculous recovery by forcing a track reload */
2422 tracks
[track_widx
].filesize
= 0;
2423 /* Stop this buffering run */
2427 trigger_cpu_boost();
2428 while (tracks
[track_widx
].filerem
> 0)
2434 /* copy_n is the largest chunk that is safe to read */
2435 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2437 /* buf_widx == buf_ridx is defined as buffer empty, not buffer full */
2438 if (RINGBUF_ADD_CROSS(buf_widx
,copy_n
,buf_ridx
) >= 0)
2441 /* rc is the actual amount read */
2442 rc
= read(current_fd
, &filebuf
[buf_widx
], copy_n
);
2446 logf("File ended %ldB early", tracks
[track_widx
].filerem
);
2447 tracks
[track_widx
].filesize
-= tracks
[track_widx
].filerem
;
2448 tracks
[track_widx
].filerem
= 0;
2452 /* How much of the playing track did we overwrite */
2453 if (buf_widx
== CUR_TI
->buf_idx
)
2455 /* Special handling; zero or full overlap? */
2456 if (track_widx
== track_ridx
&& CUR_TI
->available
== 0)
2462 overlap
= RINGBUF_ADD_CROSS(buf_widx
,rc
,CUR_TI
->buf_idx
);
2464 if ((unsigned)rc
> tracks
[track_widx
].filerem
)
2466 logf("Bad: rc-filerem=%ld, fixing", rc
-tracks
[track_widx
].filerem
);
2467 tracks
[track_widx
].filesize
+= rc
- tracks
[track_widx
].filerem
;
2468 tracks
[track_widx
].filerem
= rc
;
2471 /* Advance buffer */
2472 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2473 tracks
[track_widx
].available
+= rc
;
2474 tracks
[track_widx
].filerem
-= rc
;
2476 /* If we write into the playing track, adjust it's buffer info */
2479 CUR_TI
->buf_idx
+= overlap
;
2480 CUR_TI
->start_pos
+= overlap
;
2483 /* For a rebuffer, fill at least this minimum */
2484 if (minimum
> (unsigned)rc
)
2486 /* Let the codec process up to the watermark */
2487 /* Break immediately if this is a quick buffer, or there is an event */
2488 else if (minimum
|| audio_yield_codecs())
2490 /* Exit quickly, but don't stop the overall buffering process */
2496 if (tracks
[track_widx
].filerem
== 0)
2498 logf("Finished buf:%ldB", tracks
[track_widx
].filesize
);
2504 track_widx
&= MAX_TRACK_MASK
;
2506 tracks
[track_widx
].filesize
= 0;
2511 logf("%s buf:%ldB", ret_val
?"Quick":"Partially",
2512 tracks
[track_widx
].filesize
- tracks
[track_widx
].filerem
);
2517 static bool audio_loadcodec(bool start_play
)
2524 char codec_path
[MAX_PATH
]; /* Full path to codec */
2526 const char * codec_fn
=
2527 get_codec_filename(tracks
[track_widx
].id3
.codectype
);
2528 if (codec_fn
== NULL
)
2531 tracks
[track_widx
].has_codec
= false;
2535 /* Load the codec directly from disk and save some memory. */
2536 track_ridx
= track_widx
;
2537 ci
.filesize
= CUR_TI
->filesize
;
2538 ci
.id3
= &CUR_TI
->id3
;
2539 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2541 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2542 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
2547 /* If we already have another track than this one buffered */
2548 if (track_widx
!= track_ridx
)
2550 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
2552 /* If the previous codec is the same as this one, there is no need
2553 * to put another copy of it on the file buffer */
2554 if (get_codec_base_type(tracks
[track_widx
].id3
.codectype
) ==
2555 get_codec_base_type(tracks
[prev_track
].id3
.codectype
)
2556 && audio_codec_loaded
)
2558 logf("Reusing prev. codec");
2564 codec_get_full_path(codec_path
, codec_fn
);
2566 fd
= open(codec_path
, O_RDONLY
);
2569 logf("Codec doesn't exist!");
2573 tracks
[track_widx
].codecsize
= filesize(fd
);
2575 /* Never load a partial codec */
2576 if (RINGBUF_ADD_CROSS(buf_widx
,tracks
[track_widx
].codecsize
,buf_ridx
) >= 0)
2578 logf("Not enough space");
2583 while (size
< tracks
[track_widx
].codecsize
)
2585 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2586 rc
= read(fd
, &filebuf
[buf_widx
], copy_n
);
2590 /* This is an error condition, likely the codec file is corrupt */
2591 logf("Partial codec loaded");
2592 /* Must undo the buffer write of the partial codec */
2593 buf_widx
= RINGBUF_SUB(buf_widx
, size
);
2594 tracks
[track_widx
].codecsize
= 0;
2598 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2603 tracks
[track_widx
].has_codec
= true;
2606 logf("Done: %ldB", size
);
2611 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2612 static void audio_set_elapsed(struct mp3entry
* id3
)
2614 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
2615 id3
->offset
- id3
->first_frame_offset
: 0;
2618 if ( id3
->has_toc
) {
2619 /* calculate elapsed time using TOC */
2621 unsigned int remainder
, plen
, relpos
, nextpos
;
2623 /* find wich percent we're at */
2624 for (i
=0; i
<100; i
++ )
2625 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
2632 relpos
= id3
->toc
[i
];
2635 nextpos
= id3
->toc
[i
+1];
2639 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
2641 /* set time for this percent (divide before multiply to prevent
2642 overflow on long files. loss of precision is negligible on
2644 id3
->elapsed
= i
* (id3
->length
/ 100);
2646 /* calculate remainder time */
2647 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
2648 id3
->elapsed
+= (((remainder
* 100) / plen
) *
2649 (id3
->length
/ 10000));
2652 /* no TOC exists. set a rough estimate using average bitrate */
2653 int tpk
= id3
->length
/
2654 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
2656 id3
->elapsed
= offset
/ 1024 * tpk
;
2661 /* constant bitrate, use exact calculation */
2662 if (id3
->bitrate
!= 0)
2663 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
2667 static bool audio_load_track(int offset
, bool start_play
, bool rebuffer
)
2673 /* Stop buffer filling if there is no free track entries.
2674 Don't fill up the last track entry (we wan't to store next track
2676 if (!audio_have_free_tracks())
2678 logf("No free tracks");
2682 if (current_fd
>= 0)
2684 logf("Nonzero fd in alt");
2691 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
2692 /* Get track name from current playlist read position. */
2693 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
2695 /* Handle broken playlists. */
2696 current_fd
= open(trackname
, O_RDONLY
);
2699 logf("Open failed");
2700 /* Skip invalid entry from playlist. */
2701 playlist_skip_entry(NULL
, last_peek_offset
);
2709 logf("End-of-playlist");
2710 playlist_end
= true;
2714 /* Initialize track entry. */
2715 size
= filesize(current_fd
);
2716 tracks
[track_widx
].filerem
= size
;
2717 tracks
[track_widx
].filesize
= size
;
2718 tracks
[track_widx
].available
= 0;
2720 /* Set default values */
2723 int last_codec
= current_codec
;
2725 set_current_codec(CODEC_IDX_AUDIO
);
2726 conf_watermark
= AUDIO_DEFAULT_WATERMARK
;
2727 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
2728 conf_preseek
= AUDIO_REBUFFER_GUESS_SIZE
;
2729 dsp_configure(DSP_RESET
, 0);
2730 set_current_codec(last_codec
);
2733 /* Get track metadata if we don't already have it. */
2734 if (!tracks
[track_widx
].taginfo_ready
)
2736 if (get_metadata(&tracks
[track_widx
],current_fd
,trackname
,v1first
))
2740 track_changed
= true;
2741 playlist_update_resume_info(audio_current_track());
2746 logf("mde:%s!",trackname
);
2748 /* Set filesize to zero to indicate no file was loaded. */
2749 tracks
[track_widx
].filesize
= 0;
2750 tracks
[track_widx
].filerem
= 0;
2754 /* Skip invalid entry from playlist. */
2755 playlist_skip_entry(NULL
, last_peek_offset
);
2756 tracks
[track_widx
].taginfo_ready
= false;
2762 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
2764 char cuepath
[MAX_PATH
];
2766 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
2768 if (look_for_cuesheet_file(trackname
, cuepath
) &&
2769 parse_cuesheet(cuepath
, cue
))
2771 strcpy((cue
)->audio_filename
, trackname
);
2773 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
2777 /* Load the codec. */
2778 tracks
[track_widx
].codecbuf
= &filebuf
[buf_widx
];
2779 if (!audio_loadcodec(start_play
))
2781 /* Set filesize to zero to indicate no file was loaded. */
2782 tracks
[track_widx
].filesize
= 0;
2783 tracks
[track_widx
].filerem
= 0;
2787 if (tracks
[track_widx
].codecsize
)
2789 /* No space for codec on buffer, not an error */
2790 tracks
[track_widx
].codecsize
= 0;
2794 /* This is an error condition, either no codec was found, or reading
2795 * the codec file failed part way through, either way, skip the track */
2796 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
2797 /* We should not use gui_syncplash from audio thread! */
2798 gui_syncsplash(HZ
*2, msgbuf
);
2799 /* Skip invalid entry from playlist. */
2800 playlist_skip_entry(NULL
, last_peek_offset
);
2801 tracks
[track_widx
].taginfo_ready
= false;
2805 tracks
[track_widx
].start_pos
= 0;
2806 set_filebuf_watermark(buffer_margin
);
2807 tracks
[track_widx
].id3
.elapsed
= 0;
2811 switch (tracks
[track_widx
].id3
.codectype
) {
2815 lseek(current_fd
, offset
, SEEK_SET
);
2816 tracks
[track_widx
].id3
.offset
= offset
;
2817 audio_set_elapsed(&tracks
[track_widx
].id3
);
2818 tracks
[track_widx
].filerem
= size
- offset
;
2820 tracks
[track_widx
].start_pos
= offset
;
2824 lseek(current_fd
, offset
, SEEK_SET
);
2825 tracks
[track_widx
].id3
.offset
= offset
;
2826 tracks
[track_widx
].id3
.elapsed
=
2827 tracks
[track_widx
].id3
.length
/ 2;
2828 tracks
[track_widx
].filerem
= size
- offset
;
2830 tracks
[track_widx
].start_pos
= offset
;
2833 case AFMT_OGG_VORBIS
:
2841 tracks
[track_widx
].id3
.offset
= offset
;
2846 logf("alt:%s", trackname
);
2847 tracks
[track_widx
].buf_idx
= buf_widx
;
2849 return audio_read_file(rebuffer
);
2852 static bool audio_read_next_metadata(void)
2859 next_idx
= track_widx
;
2860 if (tracks
[next_idx
].taginfo_ready
)
2863 next_idx
&= MAX_TRACK_MASK
;
2865 if (tracks
[next_idx
].taginfo_ready
)
2869 trackname
= playlist_peek(last_peek_offset
+ 1);
2873 fd
= open(trackname
, O_RDONLY
);
2877 status
= get_metadata(&tracks
[next_idx
],fd
,trackname
,v1first
);
2878 /* Preload the glyphs in the tags */
2881 if (tracks
[next_idx
].id3
.title
)
2882 lcd_getstringsize(tracks
[next_idx
].id3
.title
, NULL
, NULL
);
2883 if (tracks
[next_idx
].id3
.artist
)
2884 lcd_getstringsize(tracks
[next_idx
].id3
.artist
, NULL
, NULL
);
2885 if (tracks
[next_idx
].id3
.album
)
2886 lcd_getstringsize(tracks
[next_idx
].id3
.album
, NULL
, NULL
);
2893 /* Send callback events to notify about new tracks. */
2894 static void audio_generate_postbuffer_events(void)
2899 logf("Postbuffer:%d/%d",track_ridx
,track_widx
);
2901 if (audio_have_tracks())
2903 cur_idx
= track_ridx
;
2906 if (!tracks
[cur_idx
].event_sent
)
2908 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2910 /* Mark the event 'sent' even if we don't really send one */
2911 tracks
[last_idx
].event_sent
= true;
2912 if (track_buffer_callback
)
2913 track_buffer_callback(&tracks
[last_idx
].id3
, false);
2917 if (cur_idx
== track_widx
)
2920 cur_idx
&= MAX_TRACK_MASK
;
2923 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2925 tracks
[last_idx
].event_sent
= true;
2926 if (track_buffer_callback
)
2927 track_buffer_callback(&tracks
[last_idx
].id3
, true);
2932 static bool audio_initialize_buffer_fill(bool clear_tracks
)
2934 /* Don't initialize if we're already initialized */
2938 logf("Starting buffer fill");
2940 /* Set the filling flag true before calling audio_clear_tracks as that
2941 * function can yield and we start looping. */
2945 audio_clear_track_entries(false);
2947 /* Save the current resume position once. */
2948 playlist_update_resume_info(audio_current_track());
2953 static void audio_fill_file_buffer(
2954 bool start_play
, bool rebuffer
, size_t offset
)
2956 bool had_next_track
= audio_next_track() != NULL
;
2957 bool continue_buffering
;
2959 /* Must reset the buffer before use if trashed or voice only - voice
2960 file size shouldn't have changed so we can go straight from
2961 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
2962 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
2963 audio_reset_buffer();
2965 if (!audio_initialize_buffer_fill(!start_play
))
2968 /* If we have a partially buffered track, continue loading,
2969 * otherwise load a new track */
2970 if (tracks
[track_widx
].filesize
> 0)
2971 continue_buffering
= audio_read_file(rebuffer
);
2973 continue_buffering
= audio_load_track(offset
, start_play
, rebuffer
);
2975 if (!had_next_track
&& audio_next_track())
2976 track_changed
= true;
2978 /* If we're done buffering */
2979 if (!continue_buffering
)
2981 audio_read_next_metadata();
2983 audio_generate_postbuffer_events();
2992 static void audio_rebuffer(void)
2994 logf("Forcing rebuffer");
2996 /* Stop in progress fill, and clear open file descriptor */
2997 if (current_fd
>= 0)
3004 /* Reset buffer and track pointers */
3005 CUR_TI
->buf_idx
= buf_ridx
= buf_widx
= 0;
3006 track_widx
= track_ridx
;
3007 audio_clear_track_entries(true);
3008 CUR_TI
->available
= 0;
3010 /* Fill the buffer */
3011 last_peek_offset
= -1;
3012 CUR_TI
->filesize
= 0;
3013 CUR_TI
->start_pos
= 0;
3016 if (!CUR_TI
->taginfo_ready
)
3017 memset(&CUR_TI
->id3
, 0, sizeof(struct mp3entry
));
3019 audio_fill_file_buffer(false, true, 0);
3022 static int audio_check_new_track(void)
3024 int track_count
= audio_track_count();
3025 int old_track_ridx
= track_ridx
;
3031 if (playlist_next_dir(ci
.new_track
))
3034 CUR_TI
->taginfo_ready
= false;
3040 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3041 return Q_CODEC_REQUEST_FAILED
;
3048 /* If the playlist isn't that big */
3049 if (!playlist_check(ci
.new_track
))
3051 if (ci
.new_track
>= 0)
3053 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3054 return Q_CODEC_REQUEST_FAILED
;
3056 /* Find the beginning backward if the user over-skips it */
3057 while (!playlist_check(++ci
.new_track
))
3058 if (ci
.new_track
>= 0)
3060 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3061 return Q_CODEC_REQUEST_FAILED
;
3064 /* Update the playlist */
3065 last_peek_offset
-= ci
.new_track
;
3067 if (playlist_next(ci
.new_track
) < 0)
3069 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3070 return Q_CODEC_REQUEST_FAILED
;
3076 new_playlist
= false;
3079 /* Save the old track */
3082 /* Move to the new track */
3083 track_ridx
+= ci
.new_track
;
3084 track_ridx
&= MAX_TRACK_MASK
;
3087 playlist_end
= false;
3089 track_changed
= !automatic_skip
;
3091 /* If it is not safe to even skip this many track entries */
3092 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
3095 CUR_TI
->taginfo_ready
= false;
3100 forward
= ci
.new_track
> 0;
3103 /* If the target track is clearly not in memory */
3104 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
3110 /* The track may be in memory, see if it really is */
3113 if (!audio_buffer_wind_forward(track_ridx
, old_track_ridx
))
3118 int cur_idx
= track_ridx
;
3119 bool taginfo_ready
= true;
3120 bool wrap
= track_ridx
> old_track_ridx
;
3125 cur_idx
&= MAX_TRACK_MASK
;
3126 if (!(wrap
|| cur_idx
< old_track_ridx
))
3129 /* If we hit a track in between without valid tag info, bail */
3130 if (!tracks
[cur_idx
].taginfo_ready
)
3132 taginfo_ready
= false;
3136 tracks
[cur_idx
].available
= tracks
[cur_idx
].filesize
;
3137 if (tracks
[cur_idx
].codecsize
)
3138 tracks
[cur_idx
].has_codec
= true;
3142 if (!audio_buffer_wind_backward(track_ridx
, old_track_ridx
))
3147 CUR_TI
->taginfo_ready
= false;
3153 audio_update_trackinfo();
3154 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3155 return Q_CODEC_REQUEST_COMPLETE
;
3158 static int audio_rebuffer_and_seek(size_t newpos
)
3160 size_t real_preseek
;
3164 /* (Re-)open current track's file handle. */
3165 trackname
= playlist_peek(0);
3166 fd
= open(trackname
, O_RDONLY
);
3169 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3170 return Q_CODEC_REQUEST_FAILED
;
3173 if (current_fd
>= 0)
3177 playlist_end
= false;
3181 /* Clear codec buffer. */
3182 track_widx
= track_ridx
;
3183 tracks
[track_widx
].buf_idx
= buf_widx
= buf_ridx
= 0;
3185 last_peek_offset
= 0;
3187 audio_initialize_buffer_fill(true);
3189 /* This may have been tweaked by the id3v1 code */
3190 CUR_TI
->filesize
=filesize(fd
);
3191 if (newpos
> conf_preseek
)
3193 CUR_TI
->start_pos
= newpos
- conf_preseek
;
3194 lseek(current_fd
, CUR_TI
->start_pos
, SEEK_SET
);
3195 CUR_TI
->filerem
= CUR_TI
->filesize
- CUR_TI
->start_pos
;
3196 real_preseek
= conf_preseek
;
3200 CUR_TI
->start_pos
= 0;
3201 CUR_TI
->filerem
= CUR_TI
->filesize
;
3202 real_preseek
= newpos
;
3205 CUR_TI
->available
= 0;
3207 audio_read_file(real_preseek
);
3209 /* Account for the data we just read that is 'behind' us now */
3210 CUR_TI
->available
-= real_preseek
;
3212 buf_ridx
= RINGBUF_ADD(buf_ridx
, real_preseek
);
3214 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3215 return Q_CODEC_REQUEST_COMPLETE
;
3218 void audio_set_track_buffer_event(void (*handler
)(struct mp3entry
*id3
,
3221 track_buffer_callback
= handler
;
3224 void audio_set_track_unbuffer_event(void (*handler
)(struct mp3entry
*id3
,
3227 track_unbuffer_callback
= handler
;
3230 void audio_set_track_changed_event(void (*handler
)(struct mp3entry
*id3
))
3232 track_changed_callback
= handler
;
3235 unsigned long audio_prev_elapsed(void)
3237 return prev_track_elapsed
;
3240 static void audio_stop_codec_flush(void)
3242 ci
.stop_codec
= true;
3245 while (audio_codec_loaded
)
3248 /* If the audio codec is not loaded any more, and the audio is still
3249 * playing, it is now and _only_ now safe to call this function from the
3251 if (pcm_is_playing())
3253 pcmbuf_pause(paused
);
3256 static void audio_stop_playback(void)
3258 /* If we were playing, save resume information */
3261 struct mp3entry
*id3
= NULL
;
3263 if (!playlist_end
|| !ci
.stop_codec
)
3265 /* Set this early, the outside code yields and may allow the codec
3266 to try to wait for a reply on a buffer wait */
3267 ci
.stop_codec
= true;
3268 id3
= audio_current_track();
3271 /* Save the current playing spot, or NULL if the playlist has ended */
3272 playlist_update_resume_info(id3
);
3274 prev_track_elapsed
= CUR_TI
->id3
.elapsed
;
3276 /* Increment index so runtime info is saved in audio_clear_track_entries().
3277 * Done here, as audio_stop_playback() may be called more than once.
3278 * Don't update runtime unless playback is stopped because of end of playlist.
3279 * Updating runtime when manually stopping a tracks, can destroy autoscores
3285 track_ridx
&= MAX_TRACK_MASK
;
3291 audio_stop_codec_flush();
3294 if (current_fd
>= 0)
3300 /* Mark all entries null. */
3301 audio_clear_track_entries(false);
3304 static void audio_play_start(size_t offset
)
3306 #if INPUT_SRC_CAPS != 0
3307 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
3308 audio_set_output_source(AUDIO_SRC_PLAYBACK
);
3311 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
3313 audio_stop_codec_flush();
3315 track_changed
= true;
3316 playlist_end
= false;
3324 if (current_fd
>= 0)
3330 sound_set_volume(global_settings
.volume
);
3331 track_widx
= track_ridx
= 0;
3332 buf_ridx
= buf_widx
= 0;
3334 /* Mark all entries null. */
3335 memset(tracks
, 0, sizeof(struct track_info
) * MAX_TRACK
);
3337 last_peek_offset
= -1;
3339 /* Officially playing */
3340 queue_reply(&audio_queue
, 1);
3342 audio_fill_file_buffer(true, false, offset
);
3344 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
3345 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
3349 /* Invalidates all but currently playing track. */
3350 static void audio_invalidate_tracks(void)
3352 if (audio_have_tracks()) {
3353 last_peek_offset
= 0;
3355 playlist_end
= false;
3356 track_widx
= track_ridx
;
3357 /* Mark all other entries null (also buffered wrong metadata). */
3358 audio_clear_track_entries(true);
3360 /* If the current track is fully buffered, advance the write pointer */
3361 if (tracks
[track_widx
].filerem
== 0)
3362 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
3364 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3366 audio_read_next_metadata();
3370 static void audio_new_playlist(void)
3372 /* Prepare to start a new fill from the beginning of the playlist */
3373 last_peek_offset
= -1;
3374 if (audio_have_tracks()) {
3375 playlist_end
= false;
3376 track_widx
= track_ridx
;
3377 audio_clear_track_entries(true);
3380 track_widx
&= MAX_TRACK_MASK
;
3382 /* Stop reading the current track */
3383 CUR_TI
->filerem
= 0;
3387 /* Mark the current track as invalid to prevent skipping back to it */
3388 CUR_TI
->taginfo_ready
= false;
3390 /* Invalidate the buffer other than the playing track */
3391 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3394 /* Signal the codec to initiate a track change forward */
3395 new_playlist
= true;
3398 /* Officially playing */
3399 queue_reply(&audio_queue
, 1);
3401 audio_fill_file_buffer(false, true, 0);
3404 static void audio_initiate_track_change(long direction
)
3406 playlist_end
= false;
3407 ci
.new_track
+= direction
;
3408 wps_offset
-= direction
;
3411 static void audio_initiate_dir_change(long direction
)
3413 playlist_end
= false;
3415 ci
.new_track
= direction
;
3419 * Layout audio buffer as follows - iram buffer depends on target:
3420 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
3422 static void audio_reset_buffer(void)
3424 /* see audio_get_recording_buffer if this is modified */
3425 logf("audio_reset_buffer");
3427 /* If the setup of anything allocated before the file buffer is
3428 changed, do check the adjustments after the buffer_alloc call
3429 as it will likely be affected and need sliding over */
3431 /* Initially set up file buffer as all space available */
3432 malloc_buf
= audiobuf
+ talk_get_bufsize();
3433 /* Align the malloc buf to line size. Especially important to cf
3434 targets that do line reads/writes. */
3435 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
3436 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
3437 filebuflen
= audiobufend
- filebuf
;
3439 /* Allow for codec swap space at end of audio buffer */
3440 if (talk_voice_required())
3442 /* Layout of swap buffer:
3443 * #ifdef IRAM_STEAL (dedicated iram_buf):
3444 * |iram_buf|...audiobuf...|dram_buf|audiobufend
3446 * audiobuf...|dram_buf|iram_buf|audiobufend
3448 #ifdef PLAYBACK_VOICE
3449 /* Check for an absolutely nasty situation which should never,
3450 ever happen - frankly should just panic */
3451 if (voice_codec_loaded
&& current_codec
!= CODEC_IDX_VOICE
)
3453 logf("buffer reset with voice swapped");
3455 /* line align length which line aligns the calculations below since
3456 all sizes are also at least line aligned - needed for memswap128 */
3459 filebuflen
-= CODEC_SIZE
;
3461 filebuflen
-= CODEC_SIZE
+ CODEC_IRAM_SIZE
;
3463 /* Allocate buffers for swapping voice <=> audio */
3464 /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
3465 and out of the way of buffer usage or else a call to audio_get_buffer
3466 and subsequent buffer use might trash the swap space. A plugin
3467 initializing IRAM after getting the full buffer would present similar
3468 problem. Options include: failing the request if the other buffer
3469 has been obtained already or never allowing use of the voice IRAM
3470 buffer within the audio buffer. Using buffer_alloc basically
3471 implements the second in a more convenient way. */
3472 dram_buf
= filebuf
+ filebuflen
;
3475 /* Allocate voice IRAM swap buffer once */
3476 if (iram_buf
== NULL
)
3478 iram_buf
= buffer_alloc(CODEC_IRAM_SIZE
);
3479 /* buffer_alloc moves audiobuf; this is safe because only the end
3480 * has been touched so far in this function and the address of
3481 * filebuf + filebuflen is not changed */
3482 malloc_buf
+= CODEC_IRAM_SIZE
;
3483 filebuf
+= CODEC_IRAM_SIZE
;
3484 filebuflen
-= CODEC_IRAM_SIZE
;
3487 /* Allocate iram_buf after dram_buf */
3488 iram_buf
= dram_buf
+ CODEC_SIZE
;
3489 #endif /* IRAM_STEAL */
3490 #endif /* PLAYBACK_VOICE */
3494 #ifdef PLAYBACK_VOICE
3495 /* No swap buffers needed */
3501 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
3502 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
3504 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
3505 will already be line aligned */
3508 /* Set the high watermark as 75% full...or 25% empty :) */
3510 high_watermark
= 3*filebuflen
/ 4;
3513 /* Clear any references to the file buffer */
3514 buffer_state
= BUFFER_STATE_INITIALIZED
;
3516 #ifdef ROCKBOX_HAS_LOGF
3517 /* Make sure everything adds up - yes, some info is a bit redundant but
3518 aids viewing and the sumation of certain variables should add up to
3519 the location of others. */
3522 unsigned char * pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
3523 logf("mabuf: %08X", (unsigned)malloc_buf
);
3524 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
3525 logf("fbuf: %08X", (unsigned)filebuf
);
3526 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
3527 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
3528 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
3529 logf("pcmb: %08X", (unsigned)pcmbuf
);
3530 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
3533 logf("dramb: %08X", (unsigned)dram_buf
);
3534 logf("drambe: %08X", (unsigned)(dram_buf
+ CODEC_SIZE
));
3538 logf("iramb: %08X", (unsigned)iram_buf
);
3539 logf("irambe: %08X", (unsigned)(iram_buf
+ CODEC_IRAM_SIZE
));
3546 /* we dont want this rebuffering on targets with little ram
3547 because the disk may never spin down */
3548 static bool ata_fillbuffer_callback(void)
3550 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
, 0);
3555 static void audio_thread(void)
3561 #ifdef PLAYBACK_VOICE
3562 /* Unlock mutex that init stage locks before creating this thread */
3563 mutex_unlock(&mutex_codecthread
);
3565 /* Buffers must be set up by now - should panic - really */
3566 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
3568 logf("audio_thread start: no buffer");
3571 /* Have to wait for voice to load up or else the codec swap will be
3572 invalid when an audio codec is loaded */
3573 wait_for_voice_swap_in();
3578 intptr_t result
= 0;
3582 queue_wait_w_tmo(&audio_queue
, &ev
, 0);
3583 if (ev
.id
== SYS_TIMEOUT
)
3584 ev
.id
= Q_AUDIO_FILL_BUFFER
;
3588 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
3590 if (playing
&& (ev
.id
== SYS_TIMEOUT
) &&
3591 (FILEBUFUSED
< high_watermark
))
3592 register_ata_idle_func(ata_fillbuffer_callback
);
3598 case Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
:
3599 /* only fill if the disk is still spining */
3601 if (!ata_disk_is_active())
3604 #endif /* MEM > 8 */
3605 /* else fall through to Q_AUDIO_FILL_BUFFER */
3606 case Q_AUDIO_FILL_BUFFER
:
3607 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3609 if (!playing
|| playlist_end
|| ci
.stop_codec
)
3611 audio_fill_file_buffer(false, false, 0);
3615 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3616 if (playing
&& ev
.data
<= 0)
3617 audio_new_playlist();
3620 audio_stop_playback();
3621 audio_play_start((size_t)ev
.data
);
3626 LOGFQUEUE("audio < Q_AUDIO_STOP");
3628 audio_stop_playback();
3630 queue_clear(&audio_queue
);
3634 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3637 pcmbuf_pause((bool)ev
.data
);
3638 paused
= (bool)ev
.data
;
3642 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3643 audio_initiate_track_change((long)ev
.data
);
3646 case Q_AUDIO_PRE_FF_REWIND
:
3647 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3653 case Q_AUDIO_FF_REWIND
:
3654 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3657 ci
.seek_time
= (long)ev
.data
+1;
3660 case Q_AUDIO_REBUFFER_SEEK
:
3661 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
3662 result
= audio_rebuffer_and_seek(ev
.data
);
3665 case Q_AUDIO_CHECK_NEW_TRACK
:
3666 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3667 result
= audio_check_new_track();
3670 case Q_AUDIO_DIR_SKIP
:
3671 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3672 playlist_end
= false;
3673 audio_initiate_dir_change(ev
.data
);
3677 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3678 audio_invalidate_tracks();
3681 case Q_AUDIO_TRACK_CHANGED
:
3682 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3683 if (track_changed_callback
)
3684 track_changed_callback(&CUR_TI
->id3
);
3685 track_changed
= true;
3686 playlist_update_resume_info(audio_current_track());
3690 case SYS_USB_CONNECTED
:
3691 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3693 audio_stop_playback();
3694 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
3695 usb_wait_for_disconnect(&audio_queue
);
3700 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3704 LOGFQUEUE("audio < default");
3707 queue_reply(&audio_queue
, result
);
3711 #ifdef ROCKBOX_HAS_LOGF
3712 static void audio_test_track_changed_event(struct mp3entry
*id3
)
3716 logf("tce:%s", id3
->path
);
3720 /* Initialize the audio system - called from init() in main.c.
3721 * Last function because of all the references to internal symbols
3723 void audio_init(void)
3725 #ifdef PLAYBACK_VOICE
3726 static bool voicetagtrue
= true;
3727 static struct mp3entry id3_voice
;
3730 /* Can never do this twice */
3731 if (audio_is_initialized
)
3733 logf("audio: already initialized");
3737 logf("audio: initializing");
3739 /* Initialize queues before giving control elsewhere in case it likes
3740 to send messages. Thread creation will be delayed however so nothing
3741 starts running until ready if something yields such as talk_init. */
3742 #ifdef PLAYBACK_VOICE
3743 mutex_init(&mutex_codecthread
);
3744 /* Take ownership of lock to prevent playback of anything before audio
3745 hardware is initialized - audio thread unlocks it after final init
3747 mutex_lock(&mutex_codecthread
);
3749 queue_init(&audio_queue
, true);
3750 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
3751 queue_init(&codec_queue
, true);
3755 #ifdef ROCKBOX_HAS_LOGF
3756 audio_set_track_changed_event(audio_test_track_changed_event
);
3759 /* Initialize codec api. */
3760 ci
.read_filebuf
= codec_filebuf_callback
;
3761 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
3762 ci
.get_codec_memory
= codec_get_memory_callback
;
3763 ci
.request_buffer
= codec_request_buffer_callback
;
3764 ci
.advance_buffer
= codec_advance_buffer_callback
;
3765 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
3766 ci
.request_next_track
= codec_request_next_track_callback
;
3767 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
3768 ci
.seek_buffer
= codec_seek_buffer_callback
;
3769 ci
.seek_complete
= codec_seek_complete_callback
;
3770 ci
.set_elapsed
= codec_set_elapsed_callback
;
3771 ci
.set_offset
= codec_set_offset_callback
;
3772 ci
.configure
= codec_configure_callback
;
3773 ci
.discard_codec
= codec_discard_codec_callback
;
3775 /* Initialize voice codec api. */
3776 #ifdef PLAYBACK_VOICE
3777 memcpy(&ci_voice
, &ci
, sizeof(ci_voice
));
3778 memset(&id3_voice
, 0, sizeof(id3_voice
));
3779 ci_voice
.read_filebuf
= voice_filebuf_callback
;
3780 ci_voice
.pcmbuf_insert
= voice_pcmbuf_insert_callback
;
3781 ci_voice
.get_codec_memory
= voice_get_memory_callback
;
3782 ci_voice
.request_buffer
= voice_request_buffer_callback
;
3783 ci_voice
.advance_buffer
= voice_advance_buffer_callback
;
3784 ci_voice
.advance_buffer_loc
= voice_advance_buffer_loc_callback
;
3785 ci_voice
.request_next_track
= voice_request_next_track_callback
;
3786 ci_voice
.mp3_get_filepos
= voice_mp3_get_filepos_callback
;
3787 ci_voice
.seek_buffer
= voice_seek_buffer_callback
;
3788 ci_voice
.seek_complete
= voice_do_nothing
;
3789 ci_voice
.set_elapsed
= voice_set_elapsed_callback
;
3790 ci_voice
.set_offset
= voice_set_offset_callback
;
3791 ci_voice
.configure
= voice_configure_callback
;
3792 ci_voice
.discard_codec
= voice_do_nothing
;
3793 ci_voice
.taginfo_ready
= &voicetagtrue
;
3794 ci_voice
.id3
= &id3_voice
;
3795 id3_voice
.frequency
= 11200;
3796 id3_voice
.length
= 1000000L;
3799 /* initialize the buffer */
3802 /* audio_reset_buffer must to know the size of voice buffer so init
3806 /* Create the threads late now that we shouldn't be yielding again before
3808 codec_thread_p
= create_thread(
3809 codec_thread
, codec_stack
, sizeof(codec_stack
),
3810 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
3811 IF_COP(, CPU
, true));
3813 create_thread(audio_thread
, audio_stack
, sizeof(audio_stack
),
3814 audio_thread_name
IF_PRIO(, PRIORITY_BUFFERING
)
3815 IF_COP(, CPU
, false));
3817 #ifdef PLAYBACK_VOICE
3818 /* TODO: Change this around when various speech codecs can be used */
3819 if (talk_voice_required())
3821 logf("Starting voice codec");
3822 queue_init(&voice_queue
, true);
3823 create_thread(voice_thread
, voice_stack
,
3824 sizeof(voice_stack
), voice_thread_name
3825 IF_PRIO(, PRIORITY_PLAYBACK
) IF_COP(, CPU
, false));
3829 /* Set crossfade setting for next buffer init which should be about... */
3830 pcmbuf_crossfade_enable(global_settings
.crossfade
);
3832 /* ...now! Set up the buffers */
3833 audio_reset_buffer();
3835 /* Probably safe to say */
3836 audio_is_initialized
= true;
3838 sound_settings_apply();
3840 eq_hw_enable(global_settings
.eq_hw_enabled
);
3842 audio_set_buffer_margin(global_settings
.buffer_margin
);