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"
53 #include "main_menu.h"
66 #ifdef HAVE_LCD_BITMAP
68 #include "peakmeter.h"
78 #include "ata_idle_notify.h"
81 #include "recording.h"
86 #include "menus/eq_menu.h"
89 #define PLAYBACK_VOICE
92 /* default point to start buffer refill */
93 #define AUDIO_DEFAULT_WATERMARK (1024*512)
94 /* amount of data to read in one read() call */
95 #define AUDIO_DEFAULT_FILECHUNK (1024*32)
96 /* point at which the file buffer will fight for CPU time */
97 #define AUDIO_FILEBUF_CRITICAL (1024*128)
98 /* amount of guess-space to allow for codecs that must hunt and peck
99 * for their correct seeek target, 32k seems a good size */
100 #define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
102 /* macros to enable logf for queues
103 logging on SYS_TIMEOUT can be disabled */
105 /* Define this for logf output of all queuing except SYS_TIMEOUT */
106 #define PLAYBACK_LOGQUEUES
107 /* Define this to logf SYS_TIMEOUT messages */
108 #define PLAYBACK_LOGQUEUES_SYS_TIMEOUT
111 #ifdef PLAYBACK_LOGQUEUES
112 #define LOGFQUEUE logf
114 #define LOGFQUEUE(...)
117 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
118 #define LOGFQUEUE_SYS_TIMEOUT logf
120 #define LOGFQUEUE_SYS_TIMEOUT(...)
124 /* Define one constant that includes recording related functionality */
125 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
126 #define AUDIO_HAVE_RECORDING
134 Q_AUDIO_PRE_FF_REWIND
,
136 Q_AUDIO_REBUFFER_SEEK
,
137 Q_AUDIO_CHECK_NEW_TRACK
,
139 Q_AUDIO_TRACK_CHANGED
,
144 Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
,
146 Q_CODEC_REQUEST_COMPLETE
,
147 Q_CODEC_REQUEST_FAILED
,
155 #ifdef AUDIO_HAVE_RECORDING
161 /* As defined in plugins/lib/xxx2wav.h */
163 #define MALLOC_BUFSIZE (512*1024)
164 #define GUARD_BUFSIZE (32*1024)
166 #define MALLOC_BUFSIZE (100*1024)
167 #define GUARD_BUFSIZE (8*1024)
170 /* As defined in plugin.lds */
172 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
173 #define CODEC_IRAM_SIZE ((size_t)0xc000)
174 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
175 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
176 #define CODEC_IRAM_SIZE ((size_t)0x10000)
178 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
179 #define CODEC_IRAM_SIZE ((size_t)0xc000)
182 #ifndef IBSS_ATTR_VOICE_STACK
183 #define IBSS_ATTR_VOICE_STACK IBSS_ATTR
186 bool audio_is_initialized
= false;
188 /* Variables are commented with the threads that use them: *
189 * A=audio, C=codec, V=voice. A suffix of - indicates that *
190 * the variable is read but not updated on that thread. */
191 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
193 /* Main state control */
194 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR
= false; /* Codec loaded? (C/A-) */
195 static volatile bool playing NOCACHEBSS_ATTR
= false; /* Is audio playing? (A) */
196 static volatile bool paused NOCACHEBSS_ATTR
= false; /* Is audio paused? (A/C-) */
197 static volatile bool filling IDATA_ATTR
= false; /* Is file buffer refilling? (A/C-) */
199 /* Ring buffer where compressed audio and codecs are loaded */
200 static unsigned char *filebuf
= NULL
; /* Start of buffer (A/C-) */
201 static unsigned char *malloc_buf
= NULL
; /* Start of malloc buffer (A/C-) */
202 /* FIXME: make filebuflen static */
203 size_t filebuflen
= 0; /* Size of buffer (A/C-) */
204 /* FIXME: make buf_ridx (C/A-) */
205 static volatile size_t buf_ridx IDATA_ATTR
= 0; /* Buffer read position (A/C)*/
206 static volatile size_t buf_widx IDATA_ATTR
= 0; /* Buffer write position (A/C-) */
208 /* Possible arrangements of the buffer */
209 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
210 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
211 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
212 static int buffer_state
= BUFFER_STATE_TRASHED
; /* Buffer state */
214 /* Compressed ring buffer helper macros */
215 /* Buffer pointer (p) plus value (v), wrapped if necessary */
216 #define RINGBUF_ADD(p,v) ((p+v)<filebuflen ? p+v : p+v-filebuflen)
217 /* Buffer pointer (p) minus value (v), wrapped if necessary */
218 #define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+filebuflen-v)
219 /* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
220 #define RINGBUF_ADD_CROSS(p1,v,p2) \
221 ((p1<p2)?(int)(p1+v)-(int)p2:(int)(p1+v-p2)-(int)filebuflen)
222 /* Bytes available in the buffer */
223 #define FILEBUFUSED RINGBUF_SUB(buf_widx, buf_ridx)
225 /* Track info structure about songs in the file buffer (A/C-) */
226 static struct track_info tracks
[MAX_TRACK
];
227 static volatile int track_ridx
= 0; /* Track being decoded (A/C-) */
228 static int track_widx
= 0; /* Track being buffered (A) */
230 static struct track_info
*prev_ti
= NULL
; /* Previous track info pointer (A/C-) */
231 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
233 /* Set by the audio thread when the current track information has updated
234 * and the WPS may need to update its cached information */
235 static bool track_changed
= false;
237 /* Information used only for filling the buffer */
238 /* Playlist steps from playing track to next track to be buffered (A) */
239 static int last_peek_offset
= 0;
240 /* Partially loaded track file handle to continue buffering (A) */
241 static int current_fd
= -1;
243 /* Scrobbler support */
244 static unsigned long prev_track_elapsed
= 0; /* Previous track elapsed time (C/A-)*/
246 /* Track change controls */
247 static bool automatic_skip
= false; /* Who initiated in-progress skip? (C/A-) */
248 static bool playlist_end
= false; /* Has the current playlist ended? (A) */
249 static bool dir_skip
= false; /* Is a directory skip pending? (A) */
250 static bool new_playlist
= false; /* Are we starting a new playlist? (A) */
251 /* Pending track change offset, to keep WPS responsive (A) */
252 static int wps_offset
= 0;
254 /* Callbacks which applications or plugins may set */
255 /* When the playing track has changed from the user's perspective */
256 void (*track_changed_callback
)(struct mp3entry
*id3
) = NULL
;
257 /* When a track has been buffered */
258 void (*track_buffer_callback
)(struct mp3entry
*id3
, bool last_track
) = NULL
;
259 /* When a track's buffer has been overwritten or cleared */
260 void (*track_unbuffer_callback
)(struct mp3entry
*id3
, bool last_track
) = NULL
;
263 static size_t conf_watermark
= 0; /* Level to trigger filebuf fill (A/C) FIXME */
264 static size_t conf_filechunk
= 0; /* Largest chunk the codec accepts (A/C) FIXME */
265 static size_t conf_preseek
= 0; /* Codec pre-seek margin (A/C) FIXME */
266 static size_t buffer_margin
= 0; /* Buffer margin aka anti-skip buffer (A/C-) */
267 static bool v1first
= false; /* ID3 data control, true if V1 then V2 (A) */
269 static size_t high_watermark
= 0; /* High watermark for rebuffer (A/V/other) */
272 /* Multiple threads */
273 static void set_current_codec(int codec_idx
);
274 /* Set the watermark to trigger buffer fill (A/C) FIXME */
275 static void set_filebuf_watermark(int seconds
);
278 static struct event_queue audio_queue
;
279 static struct queue_sender_list audio_queue_sender_list
;
280 static long audio_stack
[(DEFAULT_STACK_SIZE
+ 0x1000)/sizeof(long)];
281 static const char audio_thread_name
[] = "audio";
283 static void audio_thread(void);
284 static void audio_initiate_track_change(long direction
);
285 static bool audio_have_tracks(void);
286 static void audio_reset_buffer(void);
289 extern struct codec_api ci
;
290 static struct event_queue codec_queue NOCACHEBSS_ATTR
;
291 static long codec_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
293 static const char codec_thread_name
[] = "codec";
294 struct thread_entry
*codec_thread_p
; /* For modifying thread priority later. */
296 static volatile int current_codec IDATA_ATTR
; /* Current codec (normal/voice) */
299 #ifdef PLAYBACK_VOICE
301 extern struct codec_api ci_voice
;
303 static struct thread_entry
*voice_thread_p
= NULL
;
304 static struct event_queue voice_queue NOCACHEBSS_ATTR
;
305 static long voice_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
306 IBSS_ATTR_VOICE_STACK
;
307 static const char voice_thread_name
[] = "voice codec";
309 /* Voice codec swapping control */
310 extern unsigned char codecbuf
[]; /* DRAM codec swap buffer */
313 /* IRAM codec swap buffer for sim*/
314 static unsigned char sim_iram
[CODEC_IRAM_SIZE
];
315 #undef CODEC_IRAM_ORIGIN
316 #define CODEC_IRAM_ORIGIN sim_iram
319 /* iram_buf and dram_buf are either both NULL or both non-NULL */
320 /* Pointer to IRAM buffer for codec swapping */
321 static unsigned char *iram_buf
= NULL
;
322 /* Pointer to DRAM buffer for codec swapping */
323 static unsigned char *dram_buf
= NULL
;
324 /* Parity of swap_codec calls - needed because one codec swapping itself in
325 automatically swaps in the other and the swap when unlocking should not
326 happen if the parity is even.
328 static bool swap_codec_parity
= false; /* true=odd, false=even */
329 /* Mutex to control which codec (normal/voice) is running */
330 static struct mutex mutex_codecthread NOCACHEBSS_ATTR
;
333 static volatile bool voice_thread_start
= false; /* Triggers voice playback (A/V) */
334 static volatile bool voice_is_playing NOCACHEBSS_ATTR
= false; /* Is voice currently playing? (V) */
335 static volatile bool voice_codec_loaded NOCACHEBSS_ATTR
= false; /* Is voice codec loaded (V/A-) */
336 static char *voicebuf
= NULL
;
337 static size_t voice_remaining
= 0;
340 /* Voice IRAM has been stolen for other use */
341 static bool voice_iram_stolen
= false;
344 static void (*voice_getmore
)(unsigned char** start
, int* size
) = NULL
;
347 void (*callback
)(unsigned char **start
, int *size
);
351 static void voice_thread(void);
352 static void voice_stop(void);
354 #endif /* PLAYBACK_VOICE */
356 /* --- External interfaces --- */
358 void mp3_play_data(const unsigned char* start
, int size
,
359 void (*get_more
)(unsigned char** start
, int* size
))
361 #ifdef PLAYBACK_VOICE
362 static struct voice_info voice_clip
;
363 voice_clip
.callback
= get_more
;
364 voice_clip
.buf
= (char *)start
;
365 voice_clip
.size
= size
;
366 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
367 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
368 LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
369 queue_post(&voice_queue
, Q_VOICE_PLAY
, (intptr_t)&voice_clip
);
370 voice_thread_start
= true;
379 void mp3_play_stop(void)
381 #ifdef PLAYBACK_VOICE
382 queue_remove_from_head(&voice_queue
, Q_VOICE_STOP
);
383 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
384 queue_post(&voice_queue
, Q_VOICE_STOP
, 1);
388 void mp3_play_pause(bool play
)
394 bool mp3_is_playing(void)
396 return voice_is_playing
;
399 void mpeg_id3_options(bool _v1first
)
404 /* If voice could be swapped out - wait for it to return
405 * Used by buffer claming functions.
407 static void wait_for_voice_swap_in(void)
409 #ifdef PLAYBACK_VOICE
410 if (NULL
== iram_buf
)
413 while (current_codec
!= CODEC_IDX_VOICE
)
415 #endif /* PLAYBACK_VOICE */
418 /* This sends a stop message and the audio thread will dump all it's
419 subsequenct messages */
420 static void audio_hard_stop(void)
423 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
424 queue_send(&audio_queue
, Q_AUDIO_STOP
, 1);
427 unsigned char *audio_get_buffer(bool talk_buf
, size_t *buffer_size
)
429 unsigned char *buf
, *end
;
431 if (audio_is_initialized
)
434 wait_for_voice_swap_in();
437 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
439 if (buffer_size
== NULL
)
441 /* Special case for talk_init to use since it already knows it's
443 buffer_state
= BUFFER_STATE_TRASHED
;
447 if (talk_buf
|| buffer_state
== BUFFER_STATE_TRASHED
448 || !talk_voice_required())
450 logf("get buffer: talk, audio");
451 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
452 the talk buffer is not needed because voice isn't being used, or
453 could be BUFFER_STATE_TRASHED already. If state is
454 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
455 without the caller knowing what's going on. Changing certain settings
456 may move it to a worse condition but the memory in use by something
457 else will remain undisturbed.
459 if (buffer_state
!= BUFFER_STATE_TRASHED
)
462 buffer_state
= BUFFER_STATE_TRASHED
;
470 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
471 still BUFFER_STATE_INITIALIZED */
472 /* Skip talk buffer and move pcm buffer to end to maximize available
473 contiguous memory - no audio running means voice will not need the
475 logf("get buffer: audio");
476 buf
= audiobuf
+ talk_get_bufsize();
477 end
= audiobufend
- pcmbuf_init(audiobufend
);
478 buffer_state
= BUFFER_STATE_VOICED_ONLY
;
481 *buffer_size
= end
- buf
;
487 void audio_iram_steal(void)
489 /* We need to stop audio playback in order to use codec IRAM */
492 #ifdef PLAYBACK_VOICE
493 if (NULL
!= iram_buf
)
495 /* Can't already be stolen */
496 if (voice_iram_stolen
)
499 /* Must wait for voice to be current again if it is swapped which
500 would cause the caller's buffer to get clobbered when voice locks
501 and runs - we'll wait for it to lock and yield again then make sure
502 the ride has come to a complete stop */
503 wait_for_voice_swap_in();
506 /* Save voice IRAM but just memcpy - safe to do here since voice
507 is current and no audio codec is loaded */
508 memcpy(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
509 voice_iram_stolen
= true;
513 /* Nothing much to do if no voice */
514 voice_iram_stolen
= false;
518 #endif /* IRAM_STEAL */
520 #ifdef HAVE_RECORDING
521 unsigned char *audio_get_recording_buffer(size_t *buffer_size
)
523 /* Don't allow overwrite of voice swap area or we'll trash the
524 swapped-out voice codec but can use whole thing if none */
527 /* Stop audio and voice. Wait for voice to swap in and be clear
528 of pending events to ensure trouble-free operation of encoders */
530 wait_for_voice_swap_in();
534 #ifdef PLAYBACK_VOICE
535 /* If no dram_buf, swap space not used and recording gets more
536 memory. Codec swap areas will remain unaffected by the next init
537 since they're allocated at the end of the buffer and their sizes
538 don't change between calls */
541 #endif /* PLAYBACK_VOICE */
544 buffer_state
= BUFFER_STATE_TRASHED
;
546 *buffer_size
= end
- audiobuf
;
548 return (unsigned char *)audiobuf
;
551 bool audio_load_encoder(int afmt
)
554 const char *enc_fn
= get_codec_filename(afmt
| CODEC_TYPE_ENCODER
);
558 audio_remove_encoder();
559 ci
.enc_codec_loaded
= 0; /* clear any previous error condition */
561 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
562 queue_post(&codec_queue
, Q_ENCODER_LOAD_DISK
, (intptr_t)enc_fn
);
564 while (ci
.enc_codec_loaded
== 0)
567 logf("codec loaded: %d", ci
.enc_codec_loaded
);
569 return ci
.enc_codec_loaded
> 0;
574 } /* audio_load_encoder */
576 void audio_remove_encoder(void)
579 /* force encoder codec unload (if currently loaded) */
580 if (ci
.enc_codec_loaded
<= 0)
583 ci
.stop_encoder
= true;
584 while (ci
.enc_codec_loaded
> 0)
587 } /* audio_remove_encoder */
589 #endif /* HAVE_RECORDING */
591 struct mp3entry
* audio_current_track(void)
593 const char *filename
;
595 static struct mp3entry temp_id3
;
597 int offset
= ci
.new_track
+ wps_offset
;
599 cur_idx
= track_ridx
+ offset
;
600 cur_idx
&= MAX_TRACK_MASK
;
602 if (tracks
[cur_idx
].taginfo_ready
)
603 return &tracks
[cur_idx
].id3
;
605 memset(&temp_id3
, 0, sizeof(struct mp3entry
));
607 filename
= playlist_peek(offset
);
609 filename
= "No file!";
611 #ifdef HAVE_TC_RAMCACHE
612 if (tagcache_fill_tags(&temp_id3
, filename
))
616 p
= strrchr(filename
, '/');
622 strncpy(temp_id3
.path
, p
, sizeof(temp_id3
.path
)-1);
623 temp_id3
.title
= &temp_id3
.path
[0];
628 struct mp3entry
* audio_next_track(void)
630 int next_idx
= track_ridx
;
632 if (!audio_have_tracks())
636 next_idx
&= MAX_TRACK_MASK
;
638 if (!tracks
[next_idx
].taginfo_ready
)
641 return &tracks
[next_idx
].id3
;
644 bool audio_has_changed_track(void)
648 track_changed
= false;
655 void audio_play(long offset
)
659 #ifdef PLAYBACK_VOICE
660 /* Truncate any existing voice output so we don't have spelling
661 * etc. over the first part of the played track */
662 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
663 queue_post(&voice_queue
, Q_VOICE_STOP
, 1);
667 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset
);
668 /* Don't return until playback has actually started */
669 queue_send(&audio_queue
, Q_AUDIO_PLAY
, offset
);
672 void audio_stop(void)
675 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
676 /* Don't return until playback has actually stopped */
677 queue_send(&audio_queue
, Q_AUDIO_STOP
, 0);
680 void audio_pause(void)
682 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
683 /* Don't return until playback has actually paused */
684 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, true);
687 void audio_resume(void)
689 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
690 /* Don't return until playback has actually resumed */
691 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, false);
694 void audio_next(void)
696 if (playlist_check(ci
.new_track
+ wps_offset
+ 1))
698 if (global_settings
.beep
)
699 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
701 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
702 queue_post(&audio_queue
, Q_AUDIO_SKIP
, 1);
703 /* Update wps while our message travels inside deep playback queues. */
705 track_changed
= true;
709 /* No more tracks. */
710 if (global_settings
.beep
)
711 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
715 void audio_prev(void)
717 if (playlist_check(ci
.new_track
+ wps_offset
- 1))
719 if (global_settings
.beep
)
720 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
722 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
723 queue_post(&audio_queue
, Q_AUDIO_SKIP
, -1);
724 /* Update wps while our message travels inside deep playback queues. */
726 track_changed
= true;
730 /* No more tracks. */
731 if (global_settings
.beep
)
732 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
736 void audio_next_dir(void)
738 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
739 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, 1);
742 void audio_prev_dir(void)
744 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
745 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, -1);
748 void audio_pre_ff_rewind(void)
750 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
751 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
754 void audio_ff_rewind(long newpos
)
756 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
757 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, newpos
);
760 void audio_flush_and_reload_tracks(void)
762 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
763 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
766 void audio_error_clear(void)
768 #ifdef AUDIO_HAVE_RECORDING
769 pcm_rec_error_clear();
773 int audio_status(void)
778 ret
|= AUDIO_STATUS_PLAY
;
781 ret
|= AUDIO_STATUS_PAUSE
;
783 #ifdef HAVE_RECORDING
784 /* Do this here for constitency with mpeg.c version */
785 ret
|= pcm_rec_status();
791 int audio_get_file_pos(void)
796 void audio_set_buffer_margin(int setting
)
798 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
799 buffer_margin
= lookup
[setting
];
800 logf("buffer margin: %ld", buffer_margin
);
801 set_filebuf_watermark(buffer_margin
);
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 /* FIXME: We need some sort of timed boost cancellation here or the CPU
919 doesn't unboost during playback when the voice codec goes back to
920 waiting - recall that mutex_lock calls block_thread which is an
921 indefinite wait that doesn't cancel the thread's CPU boost */
922 mutex_lock(&mutex_codecthread
);
925 logf("waiting for lock: %d", my_codec
);
926 set_current_codec(my_codec
);
928 /* Reload our IRAM and DRAM */
929 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
930 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
933 /* Flip parity again */
934 swap_codec_parity
= !swap_codec_parity
;
936 logf("resuming codec: %d", my_codec
);
939 /* This function is meant to be used by the buffer stealing functions to
940 ensure the codec is no longer active and so voice will be swapped-in
941 before it is called */
942 static void voice_stop(void)
944 #ifdef PLAYBACK_VOICE
945 /* Must have a voice codec loaded or we'll hang forever here */
946 if (!voice_codec_loaded
)
949 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
950 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
952 /* Loop until voice empties it's queue, stops and picks up on the new
953 track; the voice thread must be stopped and waiting for messages
955 while (voice_is_playing
|| !queue_empty(&voice_queue
) ||
963 #endif /* PLAYBACK_VOICE */
965 static void set_filebuf_watermark(int seconds
)
970 return; /* Audio buffers not yet set up */
972 bytes
= MAX(CUR_TI
->id3
.bitrate
* seconds
* (1000/8), conf_watermark
);
973 bytes
= MIN(bytes
, filebuflen
/ 2);
974 conf_watermark
= bytes
;
977 const char * get_codec_filename(int cod_spec
)
981 #ifdef HAVE_RECORDING
982 /* Can choose decoder or encoder if one available */
983 int type
= cod_spec
& CODEC_TYPE_MASK
;
984 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
986 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
987 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
989 fname
= (type
== CODEC_TYPE_ENCODER
) ?
990 audio_formats
[afmt
].codec_enc_root_fn
:
991 audio_formats
[afmt
].codec_root_fn
;
994 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
995 afmt
, fname
? fname
: "<unknown>");
996 #else /* !HAVE_RECORDING */
998 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
999 cod_spec
= AFMT_UNKNOWN
;
1000 fname
= audio_formats
[cod_spec
].codec_root_fn
;
1001 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
1002 #endif /* HAVE_RECORDING */
1005 } /* get_codec_filename */
1008 /* --- Voice thread --- */
1010 #ifdef PLAYBACK_VOICE
1012 static bool voice_pcmbuf_insert_callback(
1013 const void *ch1
, const void *ch2
, int count
)
1015 const char *src
[2] = { ch1
, ch2
};
1019 int out_count
= dsp_output_count(count
);
1023 while ((dest
= pcmbuf_request_voice_buffer(
1024 &out_count
, playing
)) == NULL
)
1026 if (playing
&& audio_codec_loaded
)
1032 /* Get the real input_size for output_size bytes, guarding
1033 * against resampling buffer overflows. */
1034 inp_count
= dsp_input_count(out_count
);
1039 /* Input size has grown, no error, just don't write more than length */
1040 if (inp_count
> count
)
1043 out_count
= dsp_process(dest
, src
, inp_count
);
1050 pcmbuf_mix_voice(out_count
);
1051 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
1056 pcmbuf_write_complete(out_count
);
1062 } /* voice_pcmbuf_insert_callback */
1064 static void* voice_get_memory_callback(size_t *size
)
1066 /* Voice should have no use for this. If it did, we'd have to
1067 swap the malloc buffer as well. */
1072 static void voice_set_elapsed_callback(unsigned int value
)
1077 static void voice_set_offset_callback(size_t value
)
1082 static void voice_configure_callback(int setting
, intptr_t value
)
1084 if (!dsp_configure(setting
, value
))
1086 logf("Illegal key:%d", setting
);
1090 static size_t voice_filebuf_callback(void *ptr
, size_t size
)
1098 /* Handle Q_VOICE_STOP and part of SYS_USB_CONNECTED */
1099 static bool voice_on_voice_stop(bool aborting
, size_t *realsize
)
1101 if (aborting
&& !playing
&& pcm_is_playing())
1103 /* Aborting: Slight hack - flush PCM buffer if
1104 only being used for voice */
1108 if (voice_is_playing
)
1110 /* Clear the current buffer */
1111 voice_is_playing
= false;
1112 voice_getmore
= NULL
;
1113 voice_remaining
= 0;
1116 /* Force the codec to think it's changing tracks */
1117 ci_voice
.new_track
= 1;
1120 return true; /* Yes, change tracks */
1126 static void* voice_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1130 if (ci_voice
.new_track
)
1138 if (voice_is_playing
|| playing
)
1140 queue_wait_w_tmo(&voice_queue
, &ev
, 0);
1141 if (!voice_is_playing
&& ev
.id
== SYS_TIMEOUT
)
1142 ev
.id
= Q_AUDIO_PLAY
;
1146 /* We must use queue_wait_w_tmo() because queue_wait() doesn't
1148 /* FIXME: when long timeouts work correctly max out the the timeout
1149 (we'll still need the timeout guard here) or an infinite timeout
1150 can unboost, use that */
1152 queue_wait_w_tmo(&voice_queue
, &ev
, HZ
*5);
1153 while (ev
.id
== SYS_TIMEOUT
); /* Fake infinite wait */
1158 LOGFQUEUE("voice < Q_AUDIO_PLAY");
1161 if (audio_codec_loaded
)
1167 #ifdef AUDIO_HAVE_RECORDING
1168 case Q_ENCODER_RECORD
:
1169 LOGFQUEUE("voice < Q_ENCODER_RECORD");
1175 LOGFQUEUE("voice < Q_VOICE_STOP");
1176 if (voice_on_voice_stop(ev
.data
, realsize
))
1180 case SYS_USB_CONNECTED
:
1182 LOGFQUEUE("voice < SYS_USB_CONNECTED");
1183 bool change_tracks
= voice_on_voice_stop(ev
.data
, realsize
);
1184 /* Voice is obviously current so let us swap ourselves away if
1185 playing so audio may stop itself - audio_codec_loaded can
1186 only be true in this case if we're here even if the codec
1187 is only about to load */
1188 if (audio_codec_loaded
)
1190 /* Playback should be finished by now - ack and wait */
1191 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
1192 usb_wait_for_disconnect(&voice_queue
);
1199 LOGFQUEUE("voice < Q_VOICE_PLAY");
1200 if (!voice_is_playing
)
1202 /* Set up new voice data */
1203 struct voice_info
*voice_data
;
1205 if (voice_iram_stolen
)
1207 /* Voice is the first to run again and is currently
1209 logf("voice: iram restore");
1210 memcpy(CODEC_IRAM_ORIGIN
, iram_buf
, CODEC_IRAM_SIZE
);
1211 voice_iram_stolen
= false;
1214 /* Must reset the buffer before any playback begins if
1216 if (buffer_state
== BUFFER_STATE_TRASHED
)
1217 audio_reset_buffer();
1219 voice_is_playing
= true;
1220 trigger_cpu_boost();
1221 voice_data
= (struct voice_info
*)ev
.data
;
1222 voice_remaining
= voice_data
->size
;
1223 voicebuf
= voice_data
->buf
;
1224 voice_getmore
= voice_data
->callback
;
1226 goto voice_play_clip
; /* To exit both switch and while */
1229 LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
1230 goto voice_play_clip
;
1233 LOGFQUEUE("voice < default");
1239 if (voice_remaining
== 0 || voicebuf
== NULL
)
1242 voice_getmore((unsigned char **)&voicebuf
, (int *)&voice_remaining
);
1244 /* If this clip is done */
1245 if (voice_remaining
== 0)
1247 LOGFQUEUE("voice > voice Q_VOICE_STOP");
1248 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
1249 /* Force pcm playback. */
1250 if (!pcm_is_playing())
1251 pcmbuf_play_start();
1255 *realsize
= MIN(voice_remaining
, reqsize
);
1261 } /* voice_request_buffer_callback */
1263 static void voice_advance_buffer_callback(size_t amount
)
1265 amount
= MIN(amount
, voice_remaining
);
1267 voice_remaining
-= amount
;
1270 static void voice_advance_buffer_loc_callback(void *ptr
)
1272 size_t amount
= (size_t)ptr
- (size_t)voicebuf
;
1274 voice_advance_buffer_callback(amount
);
1277 static off_t
voice_mp3_get_filepos_callback(int newtime
)
1284 static void voice_do_nothing(void)
1289 static bool voice_seek_buffer_callback(size_t newpos
)
1296 static bool voice_request_next_track_callback(void)
1298 ci_voice
.new_track
= 0;
1302 static void voice_thread(void)
1304 logf("Loading voice codec");
1305 voice_codec_loaded
= true;
1306 mutex_lock(&mutex_codecthread
);
1307 set_current_codec(CODEC_IDX_VOICE
);
1308 dsp_configure(DSP_RESET
, 0);
1309 voice_remaining
= 0;
1310 voice_getmore
= NULL
;
1312 /* FIXME: If we being starting the voice thread without reboot, the
1313 voice_queue could be full of old stuff and we must flush it. */
1314 codec_load_file(get_codec_filename(AFMT_MPA_L3
), &ci_voice
);
1316 logf("Voice codec finished");
1317 voice_codec_loaded
= false;
1318 mutex_unlock(&mutex_codecthread
);
1319 voice_thread_p
= NULL
;
1320 remove_thread(NULL
);
1321 } /* voice_thread */
1323 #endif /* PLAYBACK_VOICE */
1325 /* --- Codec thread --- */
1326 static bool codec_pcmbuf_insert_callback(
1327 const void *ch1
, const void *ch2
, int count
)
1329 const char *src
[2] = { ch1
, ch2
};
1333 int out_count
= dsp_output_count(count
);
1337 /* Prevent audio from a previous track from playing */
1338 if (ci
.new_track
|| ci
.stop_codec
)
1341 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
1344 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
1348 /* Get the real input_size for output_size bytes, guarding
1349 * against resampling buffer overflows. */
1350 inp_count
= dsp_input_count(out_count
);
1355 /* Input size has grown, no error, just don't write more than length */
1356 if (inp_count
> count
)
1359 out_count
= dsp_process(dest
, src
, inp_count
);
1364 pcmbuf_write_complete(out_count
);
1366 #ifdef PLAYBACK_VOICE
1367 if ((voice_is_playing
|| voice_thread_start
)
1368 && pcm_is_playing() && voice_codec_loaded
&&
1369 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1371 voice_thread_start
= false;
1380 } /* codec_pcmbuf_insert_callback */
1382 static void* codec_get_memory_callback(size_t *size
)
1384 *size
= MALLOC_BUFSIZE
;
1388 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
1389 static void codec_pcmbuf_position_callback(size_t size
)
1391 /* This is called from an ISR, so be quick */
1392 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
1393 prev_ti
->id3
.elapsed
;
1395 if (time
>= prev_ti
->id3
.length
)
1397 pcmbuf_set_position_callback(NULL
);
1398 prev_ti
->id3
.elapsed
= prev_ti
->id3
.length
;
1401 prev_ti
->id3
.elapsed
= time
;
1404 static void codec_set_elapsed_callback(unsigned int value
)
1406 unsigned int latency
;
1410 #ifdef AB_REPEAT_ENABLE
1411 ab_position_report(value
);
1414 latency
= pcmbuf_get_latency();
1415 if (value
< latency
)
1416 CUR_TI
->id3
.elapsed
= 0;
1417 else if (value
- latency
> CUR_TI
->id3
.elapsed
||
1418 value
- latency
< CUR_TI
->id3
.elapsed
- 2)
1420 CUR_TI
->id3
.elapsed
= value
- latency
;
1424 static void codec_set_offset_callback(size_t value
)
1426 unsigned int latency
;
1431 latency
= pcmbuf_get_latency() * CUR_TI
->id3
.bitrate
/ 8;
1432 if (value
< latency
)
1433 CUR_TI
->id3
.offset
= 0;
1435 CUR_TI
->id3
.offset
= value
- latency
;
1438 static void codec_advance_buffer_counters(size_t amount
)
1440 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
1441 ci
.curpos
+= amount
;
1442 CUR_TI
->available
-= amount
;
1444 /* Start buffer filling as necessary. */
1445 if (!pcmbuf_is_lowdata() && !filling
)
1447 if (FILEBUFUSED
< conf_watermark
&& playing
&& !playlist_end
)
1449 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1450 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1455 /* copy up-to size bytes into ptr and return the actual size copied */
1456 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
1458 char *buf
= (char *)ptr
;
1462 if (ci
.stop_codec
|| !playing
)
1465 /* The ammount to copy is the lesser of the requested amount and the
1466 * amount left of the current track (both on disk and already loaded) */
1467 copy_n
= MIN(size
, CUR_TI
->available
+ CUR_TI
->filerem
);
1469 /* Nothing requested OR nothing left */
1473 /* Let the disk buffer catch fill until enough data is available */
1474 while (copy_n
> CUR_TI
->available
)
1478 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1479 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1483 if (ci
.stop_codec
|| ci
.new_track
)
1487 /* Copy as much as possible without wrapping */
1488 part_n
= MIN(copy_n
, filebuflen
- buf_ridx
);
1489 memcpy(buf
, &filebuf
[buf_ridx
], part_n
);
1490 /* Copy the rest in the case of a wrap */
1491 if (part_n
< copy_n
) {
1492 memcpy(&buf
[part_n
], &filebuf
[0], copy_n
- part_n
);
1495 /* Update read and other position pointers */
1496 codec_advance_buffer_counters(copy_n
);
1498 /* Return the actual amount of data copied to the buffer */
1500 } /* codec_filebuf_callback */
1502 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1504 size_t short_n
, copy_n
, buf_rem
;
1512 copy_n
= MIN(reqsize
, CUR_TI
->available
+ CUR_TI
->filerem
);
1519 while (copy_n
> CUR_TI
->available
)
1523 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1524 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1528 if (ci
.stop_codec
|| ci
.new_track
)
1535 /* How much is left at the end of the file buffer before wrap? */
1536 buf_rem
= filebuflen
- buf_ridx
;
1538 /* If we can't satisfy the request without wrapping */
1539 if (buf_rem
< copy_n
)
1541 /* How short are we? */
1542 short_n
= copy_n
- buf_rem
;
1544 /* If we can fudge it with the guardbuf */
1545 if (short_n
< GUARD_BUFSIZE
)
1546 memcpy(&filebuf
[filebuflen
], &filebuf
[0], short_n
);
1553 return (char *)&filebuf
[buf_ridx
];
1554 } /* codec_request_buffer_callback */
1556 static int get_codec_base_type(int type
)
1568 static void codec_advance_buffer_callback(size_t amount
)
1570 if (amount
> CUR_TI
->available
+ CUR_TI
->filerem
)
1571 amount
= CUR_TI
->available
+ CUR_TI
->filerem
;
1573 while (amount
> CUR_TI
->available
&& filling
)
1576 if (amount
> CUR_TI
->available
)
1578 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1582 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1583 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1584 ci
.curpos
+ amount
);
1589 case Q_CODEC_REQUEST_FAILED
:
1590 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1591 ci
.stop_codec
= true;
1594 case Q_CODEC_REQUEST_COMPLETE
:
1595 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1599 LOGFQUEUE("codec |< default");
1600 ci
.stop_codec
= true;
1605 codec_advance_buffer_counters(amount
);
1607 codec_set_offset_callback(ci
.curpos
);
1610 static void codec_advance_buffer_loc_callback(void *ptr
)
1612 size_t amount
= (size_t)ptr
- (size_t)&filebuf
[buf_ridx
];
1614 codec_advance_buffer_callback(amount
);
1617 /* Copied from mpeg.c. Should be moved somewhere else. */
1618 static int codec_get_file_pos(void)
1621 struct mp3entry
*id3
= audio_current_track();
1627 /* Use the TOC to find the new position */
1628 unsigned int percent
, remainder
;
1629 int curtoc
, nexttoc
, plen
;
1631 percent
= (id3
->elapsed
*100)/id3
->length
;
1635 curtoc
= id3
->toc
[percent
];
1638 nexttoc
= id3
->toc
[percent
+1];
1642 pos
= (id3
->filesize
/256)*curtoc
;
1644 /* Use the remainder to get a more accurate position */
1645 remainder
= (id3
->elapsed
*100)%id3
->length
;
1646 remainder
= (remainder
*100)/id3
->length
;
1647 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1648 pos
+= (plen
/100)*remainder
;
1652 /* No TOC exists, estimate the new position */
1653 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1654 (id3
->elapsed
/ 1000);
1657 else if (id3
->bitrate
)
1658 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1662 pos
+= id3
->first_frame_offset
;
1664 /* Don't seek right to the end of the file so that we can
1665 transition properly to the next song */
1666 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1667 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1672 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1676 CUR_TI
->id3
.elapsed
= newtime
;
1677 newpos
= codec_get_file_pos();
1682 static void codec_seek_complete_callback(void)
1684 logf("seek_complete");
1685 if (pcm_is_paused())
1687 /* If this is not a seamless seek, clear the buffer */
1689 dsp_configure(DSP_FLUSH
, 0);
1691 /* If playback was not 'deliberately' paused, unpause now */
1693 pcmbuf_pause(false);
1698 static bool codec_seek_buffer_callback(size_t newpos
)
1702 logf("codec_seek_buffer_callback");
1704 if (newpos
>= CUR_TI
->filesize
)
1705 newpos
= CUR_TI
->filesize
- 1;
1707 difference
= newpos
- ci
.curpos
;
1708 if (difference
>= 0)
1710 /* Seeking forward */
1711 logf("seek: +%d", difference
);
1712 codec_advance_buffer_callback(difference
);
1716 /* Seeking backward */
1717 difference
= -difference
;
1718 if (ci
.curpos
- difference
< 0)
1719 difference
= ci
.curpos
;
1721 /* We need to reload the song. */
1722 if (newpos
< CUR_TI
->start_pos
)
1724 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1728 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1729 result
= queue_send(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
,
1735 case Q_CODEC_REQUEST_COMPLETE
:
1736 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1739 case Q_CODEC_REQUEST_FAILED
:
1740 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1741 ci
.stop_codec
= true;
1745 LOGFQUEUE("codec |< default");
1750 /* Seeking inside buffer space. */
1751 logf("seek: -%d", difference
);
1752 CUR_TI
->available
+= difference
;
1753 buf_ridx
= RINGBUF_SUB(buf_ridx
, (unsigned)difference
);
1754 ci
.curpos
-= difference
;
1759 static void codec_configure_callback(int setting
, intptr_t value
)
1762 case CODEC_SET_FILEBUF_WATERMARK
:
1763 conf_watermark
= value
;
1764 set_filebuf_watermark(buffer_margin
);
1767 case CODEC_SET_FILEBUF_CHUNKSIZE
:
1768 conf_filechunk
= value
;
1771 case CODEC_SET_FILEBUF_PRESEEK
:
1772 conf_preseek
= value
;
1776 if (!dsp_configure(setting
, value
)) { logf("Illegal key:%d", setting
); }
1780 static void codec_track_changed(void)
1782 automatic_skip
= false;
1783 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1784 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1787 static void codec_pcmbuf_track_changed_callback(void)
1789 pcmbuf_set_position_callback(NULL
);
1790 codec_track_changed();
1793 static void codec_discard_codec_callback(void)
1795 if (CUR_TI
->has_codec
)
1797 CUR_TI
->has_codec
= false;
1798 buf_ridx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->codecsize
);
1802 /* Check if a buffer desync has happened, log it and stop playback. */
1803 if (buf_ridx
!= CUR_TI
->buf_idx
)
1805 int offset
= CUR_TI
->buf_idx
- buf_ridx
;
1806 size_t new_used
= FILEBUFUSED
- offset
;
1808 logf("Buf off :%d=%d-%d", offset
, CUR_TI
->buf_idx
, buf_ridx
);
1809 logf("Used off:%d",FILEBUFUSED
- new_used
);
1811 /* This is a fatal internal error and it's not safe to
1812 * continue playback. */
1813 ci
.stop_codec
= true;
1814 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1819 static inline void codec_gapless_track_change(void) {
1820 /* callback keeps the progress bar moving while the pcmbuf empties */
1821 pcmbuf_set_position_callback(codec_pcmbuf_position_callback
);
1822 /* set the pcmbuf callback for when the track really changes */
1823 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1826 static inline void codec_crossfade_track_change(void) {
1827 /* Initiate automatic crossfade mode */
1828 pcmbuf_crossfade_init(false);
1829 /* Notify the wps that the track change starts now */
1830 codec_track_changed();
1833 static void codec_track_skip_done(bool was_manual
)
1835 int crossfade_mode
= global_settings
.crossfade
;
1837 /* Manual track change (always crossfade or flush audio). */
1840 pcmbuf_crossfade_init(true);
1841 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1842 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1844 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1845 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1846 && crossfade_mode
!= CROSSFADE_ENABLE_TRACKSKIP
)
1848 if (crossfade_mode
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1850 if (global_settings
.playlist_shuffle
)
1851 /* shuffle mode is on, so crossfade: */
1852 codec_crossfade_track_change();
1854 /* shuffle mode is off, so do a gapless track change */
1855 codec_gapless_track_change();
1858 /* normal crossfade: */
1859 codec_crossfade_track_change();
1862 /* normal gapless playback. */
1863 codec_gapless_track_change();
1866 static bool codec_load_next_track(void)
1868 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1870 prev_track_elapsed
= CUR_TI
->id3
.elapsed
;
1873 codec_seek_complete_callback();
1875 #ifdef AB_REPEAT_ENABLE
1876 ab_end_of_track_report();
1879 logf("Request new track");
1881 if (ci
.new_track
== 0)
1884 automatic_skip
= true;
1889 trigger_cpu_boost();
1890 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1891 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1896 case Q_CODEC_REQUEST_COMPLETE
:
1897 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1898 codec_track_skip_done(!automatic_skip
);
1901 case Q_CODEC_REQUEST_FAILED
:
1902 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1904 ci
.stop_codec
= true;
1908 LOGFQUEUE("codec |< default");
1909 ci
.stop_codec
= true;
1914 static bool codec_request_next_track_callback(void)
1918 if (ci
.stop_codec
|| !playing
)
1921 prev_codectype
= get_codec_base_type(CUR_TI
->id3
.codectype
);
1923 if (!codec_load_next_track())
1926 /* Check if the next codec is the same file. */
1927 if (prev_codectype
== get_codec_base_type(CUR_TI
->id3
.codectype
))
1929 logf("New track loaded");
1930 codec_discard_codec_callback();
1935 logf("New codec:%d/%d", CUR_TI
->id3
.codectype
, prev_codectype
);
1940 static void codec_thread(void)
1948 queue_wait(&codec_queue
, &ev
);
1951 case Q_CODEC_LOAD_DISK
:
1952 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1953 audio_codec_loaded
= true;
1954 #ifdef PLAYBACK_VOICE
1955 /* Don't sent messages to voice codec if it's already swapped
1956 out or it will never get this */
1957 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1959 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1960 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1962 mutex_lock(&mutex_codecthread
);
1964 set_current_codec(CODEC_IDX_AUDIO
);
1965 ci
.stop_codec
= false;
1966 status
= codec_load_file((const char *)ev
.data
, &ci
);
1967 #ifdef PLAYBACK_VOICE
1968 mutex_unlock(&mutex_codecthread
);
1973 LOGFQUEUE("codec < Q_CODEC_LOAD");
1974 if (!CUR_TI
->has_codec
) {
1975 logf("Codec slot is empty!");
1976 /* Wait for the pcm buffer to go empty */
1977 while (pcm_is_playing())
1979 /* This must be set to prevent an infinite loop */
1980 ci
.stop_codec
= true;
1981 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1982 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
1986 audio_codec_loaded
= true;
1987 #ifdef PLAYBACK_VOICE
1988 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1990 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1991 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1993 mutex_lock(&mutex_codecthread
);
1995 set_current_codec(CODEC_IDX_AUDIO
);
1996 ci
.stop_codec
= false;
1997 wrap
= (size_t)&filebuf
[filebuflen
] - (size_t)CUR_TI
->codecbuf
;
1998 status
= codec_load_ram(CUR_TI
->codecbuf
, CUR_TI
->codecsize
,
1999 &filebuf
[0], wrap
, &ci
);
2000 #ifdef PLAYBACK_VOICE
2001 mutex_unlock(&mutex_codecthread
);
2005 #ifdef AUDIO_HAVE_RECORDING
2006 case Q_ENCODER_LOAD_DISK
:
2007 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2008 audio_codec_loaded
= false; /* Not audio codec! */
2009 #ifdef PLAYBACK_VOICE
2010 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
2012 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
2013 queue_post(&voice_queue
, Q_ENCODER_RECORD
, 0);
2015 mutex_lock(&mutex_codecthread
);
2017 logf("loading encoder");
2018 set_current_codec(CODEC_IDX_AUDIO
);
2019 ci
.stop_encoder
= false;
2020 status
= codec_load_file((const char *)ev
.data
, &ci
);
2021 #ifdef PLAYBACK_VOICE
2022 mutex_unlock(&mutex_codecthread
);
2024 logf("encoder stopped");
2026 #endif /* AUDIO_HAVE_RECORDING */
2029 case SYS_USB_CONNECTED
:
2030 LOGFQUEUE("codec < SYS_USB_CONNECTED");
2031 queue_clear(&codec_queue
);
2032 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
2033 usb_wait_for_disconnect(&codec_queue
);
2038 LOGFQUEUE("codec < default");
2041 if (audio_codec_loaded
)
2050 audio_codec_loaded
= false;
2054 case Q_CODEC_LOAD_DISK
:
2056 LOGFQUEUE("codec < Q_CODEC_LOAD");
2059 if (ci
.new_track
|| status
!= CODEC_OK
)
2063 logf("Codec failure");
2064 gui_syncsplash(HZ
*2, "Codec failure");
2067 if (!codec_load_next_track())
2069 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2070 /* End of playlist */
2071 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2077 logf("Codec finished");
2080 /* Wait for the audio to stop playing before
2081 * triggering the WPS exit */
2082 while(pcm_is_playing())
2084 CUR_TI
->id3
.elapsed
=
2085 CUR_TI
->id3
.length
- pcmbuf_get_latency();
2088 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2089 /* End of playlist */
2090 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2095 if (CUR_TI
->has_codec
)
2097 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2098 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
2102 const char *codec_fn
=
2103 get_codec_filename(CUR_TI
->id3
.codectype
);
2104 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2105 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
2106 (intptr_t)codec_fn
);
2111 #ifdef AUDIO_HAVE_RECORDING
2112 case Q_ENCODER_LOAD_DISK
:
2113 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2115 if (status
== CODEC_OK
)
2118 logf("Encoder failure");
2119 gui_syncsplash(HZ
*2, "Encoder failure");
2121 if (ci
.enc_codec_loaded
< 0)
2124 logf("Encoder failed to load");
2125 ci
.enc_codec_loaded
= -1;
2127 #endif /* AUDIO_HAVE_RECORDING */
2130 LOGFQUEUE("codec < default");
2137 /* --- Audio thread --- */
2139 static bool audio_filebuf_is_lowdata(void)
2141 return FILEBUFUSED
< AUDIO_FILEBUF_CRITICAL
;
2144 static bool audio_have_tracks(void)
2146 return track_ridx
!= track_widx
|| CUR_TI
->filesize
;
2149 static bool audio_have_free_tracks(void)
2151 if (track_widx
< track_ridx
)
2152 return track_widx
+ 1 < track_ridx
;
2153 else if (track_ridx
== 0)
2154 return track_widx
< MAX_TRACK
- 1;
2159 int audio_track_count(void)
2161 if (audio_have_tracks())
2163 int relative_track_widx
= track_widx
;
2165 if (track_ridx
> track_widx
)
2166 relative_track_widx
+= MAX_TRACK
;
2168 return relative_track_widx
- track_ridx
+ 1;
2174 long audio_filebufused(void)
2176 return (long) FILEBUFUSED
;
2179 /* Count the data BETWEEN the selected tracks */
2180 static size_t audio_buffer_count_tracks(int from_track
, int to_track
)
2183 bool need_wrap
= to_track
< from_track
;
2187 if (++from_track
>= MAX_TRACK
)
2189 from_track
-= MAX_TRACK
;
2193 if (from_track
>= to_track
&& !need_wrap
)
2196 amount
+= tracks
[from_track
].codecsize
+ tracks
[from_track
].filesize
;
2201 static bool audio_buffer_wind_forward(int new_track_ridx
, int old_track_ridx
)
2205 /* Start with the remainder of the previously playing track */
2206 amount
= tracks
[old_track_ridx
].filesize
- ci
.curpos
;
2207 /* Then collect all data from tracks in between them */
2208 amount
+= audio_buffer_count_tracks(old_track_ridx
, new_track_ridx
);
2209 logf("bwf:%ldB", (long) amount
);
2211 if (amount
> FILEBUFUSED
)
2214 /* Wind the buffer to the beginning of the target track or its codec */
2215 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
2220 static bool audio_buffer_wind_backward(int new_track_ridx
, int old_track_ridx
)
2222 /* Available buffer data */
2224 /* Start with the previously playing track's data and our data */
2228 buf_back
= RINGBUF_SUB(buf_ridx
, buf_widx
);
2230 /* If we're not just resetting the current track */
2231 if (new_track_ridx
!= old_track_ridx
)
2233 /* Need to wind to before the old track's codec and our filesize */
2234 amount
+= tracks
[old_track_ridx
].codecsize
;
2235 amount
+= tracks
[new_track_ridx
].filesize
;
2237 /* Rewind the old track to its beginning */
2238 tracks
[old_track_ridx
].available
=
2239 tracks
[old_track_ridx
].filesize
- tracks
[old_track_ridx
].filerem
;
2242 /* If the codec was ever buffered */
2243 if (tracks
[new_track_ridx
].codecsize
)
2245 /* Add the codec to the needed size */
2246 amount
+= tracks
[new_track_ridx
].codecsize
;
2247 tracks
[new_track_ridx
].has_codec
= true;
2250 /* Then collect all data from tracks between new and old */
2251 amount
+= audio_buffer_count_tracks(new_track_ridx
, old_track_ridx
);
2253 /* Do we have space to make this skip? */
2254 if (amount
> buf_back
)
2257 logf("bwb:%ldB",amount
);
2259 /* Rewind the buffer to the beginning of the target track or its codec */
2260 buf_ridx
= RINGBUF_SUB(buf_ridx
, amount
);
2262 /* Reset to the beginning of the new track */
2263 tracks
[new_track_ridx
].available
= tracks
[new_track_ridx
].filesize
;
2268 static void audio_update_trackinfo(void)
2270 ci
.filesize
= CUR_TI
->filesize
;
2271 CUR_TI
->id3
.elapsed
= 0;
2272 CUR_TI
->id3
.offset
= 0;
2273 ci
.id3
= &CUR_TI
->id3
;
2275 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2278 /* Yield to codecs for as long as possible if they are in need of data
2279 * return true if the caller should break to let the audio thread process
2281 static bool audio_yield_codecs(void)
2285 if (!queue_empty(&audio_queue
))
2288 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
2289 && !ci
.stop_codec
&& playing
&& !audio_filebuf_is_lowdata())
2296 if (!queue_empty(&audio_queue
))
2303 static void audio_clear_track_entries(bool clear_unbuffered
)
2305 int cur_idx
= track_widx
;
2308 logf("Clearing tracks:%d/%d, %d", track_ridx
, track_widx
, clear_unbuffered
);
2310 /* Loop over all tracks from write-to-read */
2314 cur_idx
&= MAX_TRACK_MASK
;
2316 if (cur_idx
== track_ridx
)
2319 /* If the track is buffered, conditionally clear/notify,
2320 * otherwise clear the track if that option is selected */
2321 if (tracks
[cur_idx
].event_sent
)
2325 /* If there is an unbuffer callback, call it, otherwise,
2326 * just clear the track */
2327 if (track_unbuffer_callback
)
2328 track_unbuffer_callback(&tracks
[last_idx
].id3
, false);
2330 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2334 else if (clear_unbuffered
)
2335 memset(&tracks
[cur_idx
], 0, sizeof(struct track_info
));
2338 /* We clear the previous instance of a buffered track throughout
2339 * the above loop to facilitate 'last' detection. Clear/notify
2340 * the last track here */
2343 if (track_unbuffer_callback
)
2344 track_unbuffer_callback(&tracks
[last_idx
].id3
, true);
2345 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2349 /* FIXME: This code should be made more generic and move to metadata.c */
2350 static void audio_strip_tags(void)
2353 static const unsigned char tag
[] = "TAG";
2354 static const unsigned char apetag
[] = "APETAGEX";
2357 size_t len
, version
;
2359 tag_idx
= RINGBUF_SUB(buf_widx
, 128);
2361 if (FILEBUFUSED
> 128 && tag_idx
> buf_ridx
)
2364 for(i
= 0;i
< 3;i
++)
2366 if(filebuf
[cur_idx
] != tag
[i
])
2369 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2372 /* Skip id3v1 tag */
2373 logf("Skipping ID3v1 tag");
2375 tracks
[track_widx
].available
-= 128;
2376 tracks
[track_widx
].filesize
-= 128;
2380 /* Check for APE tag (look for the APE tag footer) */
2381 tag_idx
= RINGBUF_SUB(buf_widx
, 32);
2383 if (FILEBUFUSED
> 32 && tag_idx
> buf_ridx
)
2386 for(i
= 0;i
< 8;i
++)
2388 if(filebuf
[cur_idx
] != apetag
[i
])
2391 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2394 /* Read the version and length from the footer */
2395 version
= filebuf
[tag_idx
+8] | (filebuf
[tag_idx
+9] << 8) |
2396 (filebuf
[tag_idx
+10] << 16) | (filebuf
[tag_idx
+11] << 24);
2397 len
= filebuf
[tag_idx
+12] | (filebuf
[tag_idx
+13] << 8) |
2398 (filebuf
[tag_idx
+14] << 16) | (filebuf
[tag_idx
+15] << 24);
2399 if (version
== 2000)
2400 len
+= 32; /* APEv2 has a 32 byte header */
2403 if (FILEBUFUSED
> len
)
2405 logf("Skipping APE tag (%ldB)", len
);
2406 buf_widx
= RINGBUF_SUB(buf_widx
, len
);
2407 tracks
[track_widx
].available
-= len
;
2408 tracks
[track_widx
].filesize
-= len
;
2413 /* Returns true if a whole file is read, false otherwise */
2414 static bool audio_read_file(size_t minimum
)
2416 bool ret_val
= false;
2418 /* If we're called and no file is open, this is an error */
2421 logf("Bad fd in arf");
2422 /* Give some hope of miraculous recovery by forcing a track reload */
2423 tracks
[track_widx
].filesize
= 0;
2424 /* Stop this buffering run */
2428 trigger_cpu_boost();
2429 while (tracks
[track_widx
].filerem
> 0)
2435 /* copy_n is the largest chunk that is safe to read */
2436 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2438 /* buf_widx == buf_ridx is defined as buffer empty, not buffer full */
2439 if (RINGBUF_ADD_CROSS(buf_widx
,copy_n
,buf_ridx
) >= 0)
2442 /* rc is the actual amount read */
2443 rc
= read(current_fd
, &filebuf
[buf_widx
], copy_n
);
2447 logf("File ended %ldB early", tracks
[track_widx
].filerem
);
2448 tracks
[track_widx
].filesize
-= tracks
[track_widx
].filerem
;
2449 tracks
[track_widx
].filerem
= 0;
2453 /* How much of the playing track did we overwrite */
2454 if (buf_widx
== CUR_TI
->buf_idx
)
2456 /* Special handling; zero or full overlap? */
2457 if (track_widx
== track_ridx
&& CUR_TI
->available
== 0)
2463 overlap
= RINGBUF_ADD_CROSS(buf_widx
,rc
,CUR_TI
->buf_idx
);
2465 if ((unsigned)rc
> tracks
[track_widx
].filerem
)
2467 logf("Bad: rc-filerem=%ld, fixing", rc
-tracks
[track_widx
].filerem
);
2468 tracks
[track_widx
].filesize
+= rc
- tracks
[track_widx
].filerem
;
2469 tracks
[track_widx
].filerem
= rc
;
2472 /* Advance buffer */
2473 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2474 tracks
[track_widx
].available
+= rc
;
2475 tracks
[track_widx
].filerem
-= rc
;
2477 /* If we write into the playing track, adjust it's buffer info */
2480 CUR_TI
->buf_idx
+= overlap
;
2481 CUR_TI
->start_pos
+= overlap
;
2484 /* For a rebuffer, fill at least this minimum */
2485 if (minimum
> (unsigned)rc
)
2487 /* Let the codec process up to the watermark */
2488 /* Break immediately if this is a quick buffer, or there is an event */
2489 else if (minimum
|| audio_yield_codecs())
2491 /* Exit quickly, but don't stop the overall buffering process */
2497 if (tracks
[track_widx
].filerem
== 0)
2499 logf("Finished buf:%ldB", tracks
[track_widx
].filesize
);
2505 track_widx
&= MAX_TRACK_MASK
;
2507 tracks
[track_widx
].filesize
= 0;
2512 logf("%s buf:%ldB", ret_val
?"Quick":"Partially",
2513 tracks
[track_widx
].filesize
- tracks
[track_widx
].filerem
);
2518 static bool audio_loadcodec(bool start_play
)
2525 char codec_path
[MAX_PATH
]; /* Full path to codec */
2527 const char * codec_fn
=
2528 get_codec_filename(tracks
[track_widx
].id3
.codectype
);
2529 if (codec_fn
== NULL
)
2532 tracks
[track_widx
].has_codec
= false;
2536 /* Load the codec directly from disk and save some memory. */
2537 track_ridx
= track_widx
;
2538 ci
.filesize
= CUR_TI
->filesize
;
2539 ci
.id3
= &CUR_TI
->id3
;
2540 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2542 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2543 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
2548 /* If we already have another track than this one buffered */
2549 if (track_widx
!= track_ridx
)
2551 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
2553 /* If the previous codec is the same as this one, there is no need
2554 * to put another copy of it on the file buffer */
2555 if (get_codec_base_type(tracks
[track_widx
].id3
.codectype
) ==
2556 get_codec_base_type(tracks
[prev_track
].id3
.codectype
)
2557 && audio_codec_loaded
)
2559 logf("Reusing prev. codec");
2565 codec_get_full_path(codec_path
, codec_fn
);
2567 fd
= open(codec_path
, O_RDONLY
);
2570 logf("Codec doesn't exist!");
2574 tracks
[track_widx
].codecsize
= filesize(fd
);
2576 /* Never load a partial codec */
2577 if (RINGBUF_ADD_CROSS(buf_widx
,tracks
[track_widx
].codecsize
,buf_ridx
) >= 0)
2579 logf("Not enough space");
2584 while (size
< tracks
[track_widx
].codecsize
)
2586 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2587 rc
= read(fd
, &filebuf
[buf_widx
], copy_n
);
2591 /* This is an error condition, likely the codec file is corrupt */
2592 logf("Partial codec loaded");
2593 /* Must undo the buffer write of the partial codec */
2594 buf_widx
= RINGBUF_SUB(buf_widx
, size
);
2595 tracks
[track_widx
].codecsize
= 0;
2599 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2604 tracks
[track_widx
].has_codec
= true;
2607 logf("Done: %ldB", size
);
2612 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2613 static void audio_set_elapsed(struct mp3entry
* id3
)
2615 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
2616 id3
->offset
- id3
->first_frame_offset
: 0;
2619 if ( id3
->has_toc
) {
2620 /* calculate elapsed time using TOC */
2622 unsigned int remainder
, plen
, relpos
, nextpos
;
2624 /* find wich percent we're at */
2625 for (i
=0; i
<100; i
++ )
2626 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
2633 relpos
= id3
->toc
[i
];
2636 nextpos
= id3
->toc
[i
+1];
2640 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
2642 /* set time for this percent (divide before multiply to prevent
2643 overflow on long files. loss of precision is negligible on
2645 id3
->elapsed
= i
* (id3
->length
/ 100);
2647 /* calculate remainder time */
2648 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
2649 id3
->elapsed
+= (((remainder
* 100) / plen
) *
2650 (id3
->length
/ 10000));
2653 /* no TOC exists. set a rough estimate using average bitrate */
2654 int tpk
= id3
->length
/
2655 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
2657 id3
->elapsed
= offset
/ 1024 * tpk
;
2662 /* constant bitrate, use exact calculation */
2663 if (id3
->bitrate
!= 0)
2664 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
2668 static bool audio_load_track(int offset
, bool start_play
, bool rebuffer
)
2674 /* Stop buffer filling if there is no free track entries.
2675 Don't fill up the last track entry (we wan't to store next track
2677 if (!audio_have_free_tracks())
2679 logf("No free tracks");
2683 if (current_fd
>= 0)
2685 logf("Nonzero fd in alt");
2692 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
2693 /* Get track name from current playlist read position. */
2694 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
2696 /* Handle broken playlists. */
2697 current_fd
= open(trackname
, O_RDONLY
);
2700 logf("Open failed");
2701 /* Skip invalid entry from playlist. */
2702 playlist_skip_entry(NULL
, last_peek_offset
);
2710 logf("End-of-playlist");
2711 playlist_end
= true;
2715 /* Initialize track entry. */
2716 size
= filesize(current_fd
);
2717 tracks
[track_widx
].filerem
= size
;
2718 tracks
[track_widx
].filesize
= size
;
2719 tracks
[track_widx
].available
= 0;
2721 /* Set default values */
2724 int last_codec
= current_codec
;
2726 set_current_codec(CODEC_IDX_AUDIO
);
2727 conf_watermark
= AUDIO_DEFAULT_WATERMARK
;
2728 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
2729 conf_preseek
= AUDIO_REBUFFER_GUESS_SIZE
;
2730 dsp_configure(DSP_RESET
, 0);
2731 set_current_codec(last_codec
);
2734 /* Get track metadata if we don't already have it. */
2735 if (!tracks
[track_widx
].taginfo_ready
)
2737 if (get_metadata(&tracks
[track_widx
],current_fd
,trackname
,v1first
))
2741 track_changed
= true;
2742 playlist_update_resume_info(audio_current_track());
2747 logf("mde:%s!",trackname
);
2749 /* Set filesize to zero to indicate no file was loaded. */
2750 tracks
[track_widx
].filesize
= 0;
2751 tracks
[track_widx
].filerem
= 0;
2755 /* Skip invalid entry from playlist. */
2756 playlist_skip_entry(NULL
, last_peek_offset
);
2757 tracks
[track_widx
].taginfo_ready
= false;
2763 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
2765 char cuepath
[MAX_PATH
];
2766 strncpy(cuepath
, trackname
, MAX_PATH
);
2767 char *dot
= strrchr(cuepath
, '.');
2768 strcpy(dot
, ".cue");
2770 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
2772 if (parse_cuesheet(cuepath
, cue
))
2774 strcpy((cue
)->audio_filename
, trackname
);
2776 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
2780 /* Load the codec. */
2781 tracks
[track_widx
].codecbuf
= &filebuf
[buf_widx
];
2782 if (!audio_loadcodec(start_play
))
2784 /* Set filesize to zero to indicate no file was loaded. */
2785 tracks
[track_widx
].filesize
= 0;
2786 tracks
[track_widx
].filerem
= 0;
2790 if (tracks
[track_widx
].codecsize
)
2792 /* No space for codec on buffer, not an error */
2793 tracks
[track_widx
].codecsize
= 0;
2797 /* This is an error condition, either no codec was found, or reading
2798 * the codec file failed part way through, either way, skip the track */
2799 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
2800 /* We should not use gui_syncplash from audio thread! */
2801 gui_syncsplash(HZ
*2, msgbuf
);
2802 /* Skip invalid entry from playlist. */
2803 playlist_skip_entry(NULL
, last_peek_offset
);
2804 tracks
[track_widx
].taginfo_ready
= false;
2808 tracks
[track_widx
].start_pos
= 0;
2809 set_filebuf_watermark(buffer_margin
);
2810 tracks
[track_widx
].id3
.elapsed
= 0;
2814 switch (tracks
[track_widx
].id3
.codectype
) {
2818 lseek(current_fd
, offset
, SEEK_SET
);
2819 tracks
[track_widx
].id3
.offset
= offset
;
2820 audio_set_elapsed(&tracks
[track_widx
].id3
);
2821 tracks
[track_widx
].filerem
= size
- offset
;
2823 tracks
[track_widx
].start_pos
= offset
;
2827 lseek(current_fd
, offset
, SEEK_SET
);
2828 tracks
[track_widx
].id3
.offset
= offset
;
2829 tracks
[track_widx
].id3
.elapsed
=
2830 tracks
[track_widx
].id3
.length
/ 2;
2831 tracks
[track_widx
].filerem
= size
- offset
;
2833 tracks
[track_widx
].start_pos
= offset
;
2836 case AFMT_OGG_VORBIS
:
2843 tracks
[track_widx
].id3
.offset
= offset
;
2848 logf("alt:%s", trackname
);
2849 tracks
[track_widx
].buf_idx
= buf_widx
;
2851 return audio_read_file(rebuffer
);
2854 static bool audio_read_next_metadata(void)
2861 next_idx
= track_widx
;
2862 if (tracks
[next_idx
].taginfo_ready
)
2865 next_idx
&= MAX_TRACK_MASK
;
2867 if (tracks
[next_idx
].taginfo_ready
)
2871 trackname
= playlist_peek(last_peek_offset
+ 1);
2875 fd
= open(trackname
, O_RDONLY
);
2879 status
= get_metadata(&tracks
[next_idx
],fd
,trackname
,v1first
);
2880 /* Preload the glyphs in the tags */
2883 if (tracks
[next_idx
].id3
.title
)
2884 lcd_getstringsize(tracks
[next_idx
].id3
.title
, NULL
, NULL
);
2885 if (tracks
[next_idx
].id3
.artist
)
2886 lcd_getstringsize(tracks
[next_idx
].id3
.artist
, NULL
, NULL
);
2887 if (tracks
[next_idx
].id3
.album
)
2888 lcd_getstringsize(tracks
[next_idx
].id3
.album
, NULL
, NULL
);
2895 /* Send callback events to notify about new tracks. */
2896 static void audio_generate_postbuffer_events(void)
2901 logf("Postbuffer:%d/%d",track_ridx
,track_widx
);
2903 if (audio_have_tracks())
2905 cur_idx
= track_ridx
;
2908 if (!tracks
[cur_idx
].event_sent
)
2910 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2912 /* Mark the event 'sent' even if we don't really send one */
2913 tracks
[last_idx
].event_sent
= true;
2914 if (track_buffer_callback
)
2915 track_buffer_callback(&tracks
[last_idx
].id3
, false);
2919 if (cur_idx
== track_widx
)
2922 cur_idx
&= MAX_TRACK_MASK
;
2925 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2927 tracks
[last_idx
].event_sent
= true;
2928 if (track_buffer_callback
)
2929 track_buffer_callback(&tracks
[last_idx
].id3
, true);
2934 static bool audio_initialize_buffer_fill(bool clear_tracks
)
2936 /* Don't initialize if we're already initialized */
2940 logf("Starting buffer fill");
2942 /* Set the filling flag true before calling audio_clear_tracks as that
2943 * function can yield and we start looping. */
2947 audio_clear_track_entries(false);
2949 /* Save the current resume position once. */
2950 playlist_update_resume_info(audio_current_track());
2955 static void audio_fill_file_buffer(
2956 bool start_play
, bool rebuffer
, size_t offset
)
2958 bool had_next_track
= audio_next_track() != NULL
;
2959 bool continue_buffering
;
2961 /* Must reset the buffer before use if trashed or voice only - voice
2962 file size shouldn't have changed so we can go straight from
2963 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
2964 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
2965 audio_reset_buffer();
2967 if (!audio_initialize_buffer_fill(!start_play
))
2970 /* If we have a partially buffered track, continue loading,
2971 * otherwise load a new track */
2972 if (tracks
[track_widx
].filesize
> 0)
2973 continue_buffering
= audio_read_file(rebuffer
);
2975 continue_buffering
= audio_load_track(offset
, start_play
, rebuffer
);
2977 if (!had_next_track
&& audio_next_track())
2978 track_changed
= true;
2980 /* If we're done buffering */
2981 if (!continue_buffering
)
2983 audio_read_next_metadata();
2985 audio_generate_postbuffer_events();
2994 static void audio_rebuffer(void)
2996 logf("Forcing rebuffer");
2998 /* Stop in progress fill, and clear open file descriptor */
2999 if (current_fd
>= 0)
3006 /* Reset buffer and track pointers */
3007 CUR_TI
->buf_idx
= buf_ridx
= buf_widx
= 0;
3008 track_widx
= track_ridx
;
3009 audio_clear_track_entries(true);
3010 CUR_TI
->available
= 0;
3012 /* Fill the buffer */
3013 last_peek_offset
= -1;
3014 CUR_TI
->filesize
= 0;
3015 CUR_TI
->start_pos
= 0;
3018 if (!CUR_TI
->taginfo_ready
)
3019 memset(&CUR_TI
->id3
, 0, sizeof(struct mp3entry
));
3021 audio_fill_file_buffer(false, true, 0);
3024 static int audio_check_new_track(void)
3026 int track_count
= audio_track_count();
3027 int old_track_ridx
= track_ridx
;
3033 if (playlist_next_dir(ci
.new_track
))
3036 CUR_TI
->taginfo_ready
= false;
3042 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3043 return Q_CODEC_REQUEST_FAILED
;
3050 /* If the playlist isn't that big */
3051 if (!playlist_check(ci
.new_track
))
3053 if (ci
.new_track
>= 0)
3055 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3056 return Q_CODEC_REQUEST_FAILED
;
3058 /* Find the beginning backward if the user over-skips it */
3059 while (!playlist_check(++ci
.new_track
))
3060 if (ci
.new_track
>= 0)
3062 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3063 return Q_CODEC_REQUEST_FAILED
;
3066 /* Update the playlist */
3067 last_peek_offset
-= ci
.new_track
;
3069 if (playlist_next(ci
.new_track
) < 0)
3071 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3072 return Q_CODEC_REQUEST_FAILED
;
3078 new_playlist
= false;
3081 /* Save the old track */
3084 /* Move to the new track */
3085 track_ridx
+= ci
.new_track
;
3086 track_ridx
&= MAX_TRACK_MASK
;
3089 playlist_end
= false;
3091 track_changed
= !automatic_skip
;
3093 /* If it is not safe to even skip this many track entries */
3094 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
3097 CUR_TI
->taginfo_ready
= false;
3102 forward
= ci
.new_track
> 0;
3105 /* If the target track is clearly not in memory */
3106 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
3112 /* The track may be in memory, see if it really is */
3115 if (!audio_buffer_wind_forward(track_ridx
, old_track_ridx
))
3120 int cur_idx
= track_ridx
;
3121 bool taginfo_ready
= true;
3122 bool wrap
= track_ridx
> old_track_ridx
;
3127 cur_idx
&= MAX_TRACK_MASK
;
3128 if (!(wrap
|| cur_idx
< old_track_ridx
))
3131 /* If we hit a track in between without valid tag info, bail */
3132 if (!tracks
[cur_idx
].taginfo_ready
)
3134 taginfo_ready
= false;
3138 tracks
[cur_idx
].available
= tracks
[cur_idx
].filesize
;
3139 if (tracks
[cur_idx
].codecsize
)
3140 tracks
[cur_idx
].has_codec
= true;
3144 if (!audio_buffer_wind_backward(track_ridx
, old_track_ridx
))
3149 CUR_TI
->taginfo_ready
= false;
3155 audio_update_trackinfo();
3156 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3157 return Q_CODEC_REQUEST_COMPLETE
;
3160 static int audio_rebuffer_and_seek(size_t newpos
)
3162 size_t real_preseek
;
3166 /* (Re-)open current track's file handle. */
3167 trackname
= playlist_peek(0);
3168 fd
= open(trackname
, O_RDONLY
);
3171 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3172 return Q_CODEC_REQUEST_FAILED
;
3175 if (current_fd
>= 0)
3179 playlist_end
= false;
3183 /* Clear codec buffer. */
3184 track_widx
= track_ridx
;
3185 tracks
[track_widx
].buf_idx
= buf_widx
= buf_ridx
= 0;
3187 last_peek_offset
= 0;
3189 audio_initialize_buffer_fill(true);
3191 /* This may have been tweaked by the id3v1 code */
3192 CUR_TI
->filesize
=filesize(fd
);
3193 if (newpos
> conf_preseek
)
3195 CUR_TI
->start_pos
= newpos
- conf_preseek
;
3196 lseek(current_fd
, CUR_TI
->start_pos
, SEEK_SET
);
3197 CUR_TI
->filerem
= CUR_TI
->filesize
- CUR_TI
->start_pos
;
3198 real_preseek
= conf_preseek
;
3202 CUR_TI
->start_pos
= 0;
3203 CUR_TI
->filerem
= CUR_TI
->filesize
;
3204 real_preseek
= newpos
;
3207 CUR_TI
->available
= 0;
3209 audio_read_file(real_preseek
);
3211 /* Account for the data we just read that is 'behind' us now */
3212 CUR_TI
->available
-= real_preseek
;
3214 buf_ridx
= RINGBUF_ADD(buf_ridx
, real_preseek
);
3216 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3217 return Q_CODEC_REQUEST_COMPLETE
;
3220 void audio_set_track_buffer_event(void (*handler
)(struct mp3entry
*id3
,
3223 track_buffer_callback
= handler
;
3226 void audio_set_track_unbuffer_event(void (*handler
)(struct mp3entry
*id3
,
3229 track_unbuffer_callback
= handler
;
3232 void audio_set_track_changed_event(void (*handler
)(struct mp3entry
*id3
))
3234 track_changed_callback
= handler
;
3237 unsigned long audio_prev_elapsed(void)
3239 return prev_track_elapsed
;
3242 static void audio_stop_codec_flush(void)
3244 ci
.stop_codec
= true;
3247 while (audio_codec_loaded
)
3250 /* If the audio codec is not loaded any more, and the audio is still
3251 * playing, it is now and _only_ now safe to call this function from the
3253 if (pcm_is_playing())
3255 pcmbuf_pause(paused
);
3258 static void audio_stop_playback(void)
3260 /* If we were playing, save resume information */
3263 struct mp3entry
*id3
= NULL
;
3265 if (!playlist_end
|| !ci
.stop_codec
)
3267 /* Set this early, the outside code yields and may allow the codec
3268 to try to wait for a reply on a buffer wait */
3269 ci
.stop_codec
= true;
3270 id3
= audio_current_track();
3273 /* Save the current playing spot, or NULL if the playlist has ended */
3274 playlist_update_resume_info(id3
);
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 defined(HAVE_RECORDING) || CONFIG_TUNER
3307 rec_set_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
3310 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
3312 audio_stop_codec_flush();
3314 track_changed
= true;
3315 playlist_end
= false;
3323 if (current_fd
>= 0)
3329 sound_set_volume(global_settings
.volume
);
3330 track_widx
= track_ridx
= 0;
3331 buf_ridx
= buf_widx
= 0;
3333 /* Mark all entries null. */
3334 memset(tracks
, 0, sizeof(struct track_info
) * MAX_TRACK
);
3336 last_peek_offset
= -1;
3338 /* Officially playing */
3339 queue_reply(&audio_queue
, 1);
3341 audio_fill_file_buffer(true, false, offset
);
3345 /* Invalidates all but currently playing track. */
3346 static void audio_invalidate_tracks(void)
3348 if (audio_have_tracks()) {
3349 last_peek_offset
= 0;
3351 playlist_end
= false;
3352 track_widx
= track_ridx
;
3353 /* Mark all other entries null (also buffered wrong metadata). */
3354 audio_clear_track_entries(true);
3356 /* If the current track is fully buffered, advance the write pointer */
3357 if (tracks
[track_widx
].filerem
== 0)
3358 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
3360 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3362 audio_read_next_metadata();
3366 static void audio_new_playlist(void)
3368 /* Prepare to start a new fill from the beginning of the playlist */
3369 last_peek_offset
= -1;
3370 if (audio_have_tracks()) {
3371 playlist_end
= false;
3372 track_widx
= track_ridx
;
3373 audio_clear_track_entries(true);
3376 track_widx
&= MAX_TRACK_MASK
;
3378 /* Stop reading the current track */
3379 CUR_TI
->filerem
= 0;
3383 /* Mark the current track as invalid to prevent skipping back to it */
3384 CUR_TI
->taginfo_ready
= false;
3386 /* Invalidate the buffer other than the playing track */
3387 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3390 /* Signal the codec to initiate a track change forward */
3391 new_playlist
= true;
3394 /* Officially playing */
3395 queue_reply(&audio_queue
, 1);
3397 audio_fill_file_buffer(false, true, 0);
3400 static void audio_initiate_track_change(long direction
)
3402 playlist_end
= false;
3403 ci
.new_track
+= direction
;
3404 wps_offset
-= direction
;
3407 static void audio_initiate_dir_change(long direction
)
3409 playlist_end
= false;
3411 ci
.new_track
= direction
;
3415 * Layout audio buffer as follows - iram buffer depends on target:
3416 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
3418 static void audio_reset_buffer(void)
3420 /* see audio_get_recording_buffer if this is modified */
3421 logf("audio_reset_buffer");
3423 /* If the setup of anything allocated before the file buffer is
3424 changed, do check the adjustments after the buffer_alloc call
3425 as it will likely be affected and need sliding over */
3427 /* Initially set up file buffer as all space available */
3428 malloc_buf
= audiobuf
+ talk_get_bufsize();
3429 /* Align the malloc buf to line size. Especially important to cf
3430 targets that do line reads/writes. */
3431 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
3432 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
3433 filebuflen
= audiobufend
- filebuf
;
3435 /* Allow for codec swap space at end of audio buffer */
3436 if (talk_voice_required())
3438 /* Layout of swap buffer:
3439 * #ifdef IRAM_STEAL (dedicated iram_buf):
3440 * |iram_buf|...audiobuf...|dram_buf|audiobufend
3442 * audiobuf...|dram_buf|iram_buf|audiobufend
3444 #ifdef PLAYBACK_VOICE
3445 /* Check for an absolutely nasty situation which should never,
3446 ever happen - frankly should just panic */
3447 if (voice_codec_loaded
&& current_codec
!= CODEC_IDX_VOICE
)
3449 logf("buffer reset with voice swapped");
3451 /* line align length which line aligns the calculations below since
3452 all sizes are also at least line aligned - needed for memswap128 */
3455 filebuflen
-= CODEC_SIZE
;
3457 filebuflen
-= CODEC_SIZE
+ CODEC_IRAM_SIZE
;
3459 /* Allocate buffers for swapping voice <=> audio */
3460 /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
3461 and out of the way of buffer usage or else a call to audio_get_buffer
3462 and subsequent buffer use might trash the swap space. A plugin
3463 initializing IRAM after getting the full buffer would present similar
3464 problem. Options include: failing the request if the other buffer
3465 has been obtained already or never allowing use of the voice IRAM
3466 buffer within the audio buffer. Using buffer_alloc basically
3467 implements the second in a more convenient way. */
3468 dram_buf
= filebuf
+ filebuflen
;
3471 /* Allocate voice IRAM swap buffer once */
3472 if (iram_buf
== NULL
)
3474 iram_buf
= buffer_alloc(CODEC_IRAM_SIZE
);
3475 /* buffer_alloc moves audiobuf; this is safe because only the end
3476 * has been touched so far in this function and the address of
3477 * filebuf + filebuflen is not changed */
3478 malloc_buf
+= CODEC_IRAM_SIZE
;
3479 filebuf
+= CODEC_IRAM_SIZE
;
3480 filebuflen
-= CODEC_IRAM_SIZE
;
3483 /* Allocate iram_buf after dram_buf */
3484 iram_buf
= dram_buf
+ CODEC_SIZE
;
3485 #endif /* IRAM_STEAL */
3486 #endif /* PLAYBACK_VOICE */
3490 #ifdef PLAYBACK_VOICE
3491 /* No swap buffers needed */
3497 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
3498 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
3500 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
3501 will already be line aligned */
3504 /* Set the high watermark as 75% full...or 25% empty :) */
3506 high_watermark
= 3*filebuflen
/ 4;
3509 /* Clear any references to the file buffer */
3510 buffer_state
= BUFFER_STATE_INITIALIZED
;
3512 #ifdef ROCKBOX_HAS_LOGF
3513 /* Make sure everything adds up - yes, some info is a bit redundant but
3514 aids viewing and the sumation of certain variables should add up to
3515 the location of others. */
3518 unsigned char * pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
3519 logf("mabuf: %08X", (unsigned)malloc_buf
);
3520 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
3521 logf("fbuf: %08X", (unsigned)filebuf
);
3522 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
3523 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
3524 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
3525 logf("pcmb: %08X", (unsigned)pcmbuf
);
3526 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
3529 logf("dramb: %08X", (unsigned)dram_buf
);
3530 logf("drambe: %08X", (unsigned)(dram_buf
+ CODEC_SIZE
));
3534 logf("iramb: %08X", (unsigned)iram_buf
);
3535 logf("irambe: %08X", (unsigned)(iram_buf
+ CODEC_IRAM_SIZE
));
3542 /* we dont want this rebuffering on targets with little ram
3543 because the disk may never spin down */
3544 static bool ata_fillbuffer_callback(void)
3546 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
, 0);
3551 static void audio_thread(void)
3557 #ifdef PLAYBACK_VOICE
3558 /* Unlock mutex that init stage locks before creating this thread */
3559 mutex_unlock(&mutex_codecthread
);
3561 /* Buffers must be set up by now - should panic - really */
3562 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
3564 logf("audio_thread start: no buffer");
3567 /* Have to wait for voice to load up or else the codec swap will be
3568 invalid when an audio codec is loaded */
3569 wait_for_voice_swap_in();
3574 intptr_t result
= 0;
3578 queue_wait_w_tmo(&audio_queue
, &ev
, 0);
3579 if (ev
.id
== SYS_TIMEOUT
)
3580 ev
.id
= Q_AUDIO_FILL_BUFFER
;
3584 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
3586 if (playing
&& (ev
.id
== SYS_TIMEOUT
) &&
3587 (FILEBUFUSED
< high_watermark
))
3588 register_ata_idle_func(ata_fillbuffer_callback
);
3594 case Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA
:
3595 /* only fill if the disk is still spining */
3597 if (!ata_disk_is_active())
3600 #endif /* MEM > 8 */
3601 /* else fall through to Q_AUDIO_FILL_BUFFER */
3602 case Q_AUDIO_FILL_BUFFER
:
3603 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3605 if (!playing
|| playlist_end
|| ci
.stop_codec
)
3607 audio_fill_file_buffer(false, false, 0);
3611 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3612 if (playing
&& ev
.data
<= 0)
3613 audio_new_playlist();
3616 audio_stop_playback();
3617 audio_play_start((size_t)ev
.data
);
3622 LOGFQUEUE("audio < Q_AUDIO_STOP");
3624 audio_stop_playback();
3626 queue_clear(&audio_queue
);
3630 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3633 pcmbuf_pause((bool)ev
.data
);
3634 paused
= (bool)ev
.data
;
3638 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3639 audio_initiate_track_change((long)ev
.data
);
3642 case Q_AUDIO_PRE_FF_REWIND
:
3643 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3649 case Q_AUDIO_FF_REWIND
:
3650 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3653 ci
.seek_time
= (long)ev
.data
+1;
3656 case Q_AUDIO_REBUFFER_SEEK
:
3657 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
3658 result
= audio_rebuffer_and_seek(ev
.data
);
3661 case Q_AUDIO_CHECK_NEW_TRACK
:
3662 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3663 result
= audio_check_new_track();
3666 case Q_AUDIO_DIR_SKIP
:
3667 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3668 playlist_end
= false;
3669 audio_initiate_dir_change(ev
.data
);
3673 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3674 audio_invalidate_tracks();
3677 case Q_AUDIO_TRACK_CHANGED
:
3678 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3679 if (track_changed_callback
)
3680 track_changed_callback(&CUR_TI
->id3
);
3681 track_changed
= true;
3682 playlist_update_resume_info(audio_current_track());
3686 case SYS_USB_CONNECTED
:
3687 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3689 audio_stop_playback();
3690 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
3691 usb_wait_for_disconnect(&audio_queue
);
3696 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3700 LOGFQUEUE("audio < default");
3703 queue_reply(&audio_queue
, result
);
3707 #ifdef ROCKBOX_HAS_LOGF
3708 static void audio_test_track_changed_event(struct mp3entry
*id3
)
3712 logf("tce:%s", id3
->path
);
3716 /* Initialize the audio system - called from init() in main.c.
3717 * Last function because of all the references to internal symbols
3719 void audio_init(void)
3721 #ifdef PLAYBACK_VOICE
3722 static bool voicetagtrue
= true;
3723 static struct mp3entry id3_voice
;
3726 /* Can never do this twice */
3727 if (audio_is_initialized
)
3729 logf("audio: already initialized");
3733 logf("audio: initializing");
3735 /* Initialize queues before giving control elsewhere in case it likes
3736 to send messages. Thread creation will be delayed however so nothing
3737 starts running until ready if something yields such as talk_init. */
3738 #ifdef PLAYBACK_VOICE
3739 mutex_init(&mutex_codecthread
);
3740 /* Take ownership of lock to prevent playback of anything before audio
3741 hardware is initialized - audio thread unlocks it after final init
3743 mutex_lock(&mutex_codecthread
);
3745 queue_init(&audio_queue
, true);
3746 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
3747 queue_init(&codec_queue
, true);
3751 #ifdef ROCKBOX_HAS_LOGF
3752 audio_set_track_changed_event(audio_test_track_changed_event
);
3755 /* Initialize codec api. */
3756 ci
.read_filebuf
= codec_filebuf_callback
;
3757 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
3758 ci
.get_codec_memory
= codec_get_memory_callback
;
3759 ci
.request_buffer
= codec_request_buffer_callback
;
3760 ci
.advance_buffer
= codec_advance_buffer_callback
;
3761 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
3762 ci
.request_next_track
= codec_request_next_track_callback
;
3763 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
3764 ci
.seek_buffer
= codec_seek_buffer_callback
;
3765 ci
.seek_complete
= codec_seek_complete_callback
;
3766 ci
.set_elapsed
= codec_set_elapsed_callback
;
3767 ci
.set_offset
= codec_set_offset_callback
;
3768 ci
.configure
= codec_configure_callback
;
3769 ci
.discard_codec
= codec_discard_codec_callback
;
3771 /* Initialize voice codec api. */
3772 #ifdef PLAYBACK_VOICE
3773 memcpy(&ci_voice
, &ci
, sizeof(ci_voice
));
3774 memset(&id3_voice
, 0, sizeof(id3_voice
));
3775 ci_voice
.read_filebuf
= voice_filebuf_callback
;
3776 ci_voice
.pcmbuf_insert
= voice_pcmbuf_insert_callback
;
3777 ci_voice
.get_codec_memory
= voice_get_memory_callback
;
3778 ci_voice
.request_buffer
= voice_request_buffer_callback
;
3779 ci_voice
.advance_buffer
= voice_advance_buffer_callback
;
3780 ci_voice
.advance_buffer_loc
= voice_advance_buffer_loc_callback
;
3781 ci_voice
.request_next_track
= voice_request_next_track_callback
;
3782 ci_voice
.mp3_get_filepos
= voice_mp3_get_filepos_callback
;
3783 ci_voice
.seek_buffer
= voice_seek_buffer_callback
;
3784 ci_voice
.seek_complete
= voice_do_nothing
;
3785 ci_voice
.set_elapsed
= voice_set_elapsed_callback
;
3786 ci_voice
.set_offset
= voice_set_offset_callback
;
3787 ci_voice
.configure
= voice_configure_callback
;
3788 ci_voice
.discard_codec
= voice_do_nothing
;
3789 ci_voice
.taginfo_ready
= &voicetagtrue
;
3790 ci_voice
.id3
= &id3_voice
;
3791 id3_voice
.frequency
= 11200;
3792 id3_voice
.length
= 1000000L;
3795 /* initialize the buffer */
3798 /* audio_reset_buffer must to know the size of voice buffer so init
3802 /* Create the threads late now that we shouldn't be yielding again before
3804 codec_thread_p
= create_thread(
3805 codec_thread
, codec_stack
, sizeof(codec_stack
),
3806 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
3807 IF_COP(, CPU
, true));
3809 create_thread(audio_thread
, audio_stack
, sizeof(audio_stack
),
3810 audio_thread_name
IF_PRIO(, PRIORITY_BUFFERING
)
3811 IF_COP(, CPU
, false));
3813 #ifdef PLAYBACK_VOICE
3814 /* TODO: Change this around when various speech codecs can be used */
3815 if (talk_voice_required())
3817 logf("Starting voice codec");
3818 queue_init(&voice_queue
, true);
3819 create_thread(voice_thread
, voice_stack
,
3820 sizeof(voice_stack
), voice_thread_name
3821 IF_PRIO(, PRIORITY_PLAYBACK
) IF_COP(, CPU
, false));
3825 /* Set crossfade setting for next buffer init which should be about... */
3826 pcmbuf_crossfade_enable(global_settings
.crossfade
);
3828 /* ...now! Set up the buffers */
3829 audio_reset_buffer();
3831 /* Probably safe to say */
3832 audio_is_initialized
= true;
3834 sound_settings_apply();
3836 eq_hw_enable(global_settings
.eq_hw_enabled
);
3838 audio_set_buffer_margin(global_settings
.buffer_margin
);