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 */
49 #include "buffering.h"
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 /* Define LOGF_ENABLE to enable logf output in this file */
92 /*#define LOGF_ENABLE*/
95 /* macros to enable logf for queues
96 logging on SYS_TIMEOUT can be disabled */
98 /* Define this for logf output of all queuing except SYS_TIMEOUT */
99 #define PLAYBACK_LOGQUEUES
100 /* Define this to logf SYS_TIMEOUT messages */
101 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
104 #ifdef PLAYBACK_LOGQUEUES
105 #define LOGFQUEUE logf
107 #define LOGFQUEUE(...)
110 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
111 #define LOGFQUEUE_SYS_TIMEOUT logf
113 #define LOGFQUEUE_SYS_TIMEOUT(...)
117 /* Define one constant that includes recording related functionality */
118 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
119 #define AUDIO_HAVE_RECORDING
127 Q_AUDIO_PRE_FF_REWIND
,
129 Q_AUDIO_CHECK_NEW_TRACK
,
131 Q_AUDIO_TRACK_CHANGED
,
135 Q_CODEC_REQUEST_COMPLETE
,
136 Q_CODEC_REQUEST_FAILED
,
144 #ifdef AUDIO_HAVE_RECORDING
150 /* As defined in plugins/lib/xxx2wav.h */
152 #define MALLOC_BUFSIZE (512*1024)
153 #define GUARD_BUFSIZE (32*1024)
155 #define MALLOC_BUFSIZE (100*1024)
156 #define GUARD_BUFSIZE (8*1024)
159 /* As defined in plugin.lds */
161 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
162 #define CODEC_IRAM_SIZE ((size_t)0xc000)
163 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
164 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
165 #define CODEC_IRAM_SIZE ((size_t)0x10000)
167 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
168 #define CODEC_IRAM_SIZE ((size_t)0xc000)
171 #ifndef IBSS_ATTR_VOICE_STACK
172 #define IBSS_ATTR_VOICE_STACK IBSS_ATTR
175 bool audio_is_initialized
= false;
177 /* Variables are commented with the threads that use them: *
178 * A=audio, C=codec, V=voice. A suffix of - indicates that *
179 * the variable is read but not updated on that thread. */
180 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
182 /* Main state control */
183 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR
= false; /* Codec loaded? (C/A-) */
184 static volatile bool playing NOCACHEBSS_ATTR
= false; /* Is audio playing? (A) */
185 static volatile bool paused NOCACHEBSS_ATTR
= false; /* Is audio paused? (A/C-) */
187 /* Ring buffer where compressed audio and codecs are loaded */
188 static unsigned char *filebuf
= NULL
; /* Start of buffer (A/C-) */
189 static unsigned char *malloc_buf
= NULL
; /* Start of malloc buffer (A/C-) */
190 /* FIXME: make filebuflen static */
191 size_t filebuflen
= 0; /* Size of buffer (A/C-) */
192 /* FIXME: make buf_ridx (C/A-) */
194 /* Possible arrangements of the buffer */
195 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
196 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
197 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
198 static int buffer_state
= BUFFER_STATE_TRASHED
; /* Buffer state */
200 static struct mp3entry prevtrack_id3
;
201 static struct mp3entry curtrack_id3
;
202 static struct mp3entry nexttrack_id3
;
204 /* Track info structure about songs in the file buffer (A/C-) */
206 int audio_hid
; /* The ID for the track's buffer handle */
207 int id3_hid
; /* The ID for the track's metadata handle */
208 int codec_hid
; /* The ID for the track's codec handle */
210 size_t codecsize
; /* Codec length in bytes */
211 size_t filesize
; /* File total length */
213 bool taginfo_ready
; /* Is metadata read */
215 bool event_sent
; /* Was this track's buffered event sent */
218 static struct track_info tracks
[MAX_TRACK
];
219 static volatile int track_ridx
= 0; /* Track being decoded (A/C-) */
220 static int track_widx
= 0; /* Track being buffered (A) */
222 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
224 /* Set by the audio thread when the current track information has updated
225 * and the WPS may need to update its cached information */
226 static bool track_changed
= false;
228 /* Information used only for filling the buffer */
229 /* Playlist steps from playing track to next track to be buffered (A) */
230 static int last_peek_offset
= 0;
232 /* Scrobbler support */
233 static unsigned long prev_track_elapsed
= 0; /* Previous track elapsed time (C/A-)*/
235 /* Track change controls */
236 static bool automatic_skip
= false; /* Who initiated in-progress skip? (C/A-) */
237 static bool playlist_end
= false; /* Has the current playlist ended? (A) */
238 static bool dir_skip
= false; /* Is a directory skip pending? (A) */
239 static bool new_playlist
= false; /* Are we starting a new playlist? (A) */
240 static int wps_offset
= 0; /* Pending track change offset, to keep WPS responsive (A) */
241 static bool skipped_during_pause
= false; /* Do we need to clear the PCM buffer when playback resumes (A) */
243 /* Callbacks which applications or plugins may set */
244 /* When the playing track has changed from the user's perspective */
245 void (*track_changed_callback
)(struct mp3entry
*id3
) = NULL
;
246 /* When a track has been buffered */
247 void (*track_buffer_callback
)(struct mp3entry
*id3
, bool last_track
) = NULL
;
248 /* When a track's buffer has been overwritten or cleared */
249 void (*track_unbuffer_callback
)(struct mp3entry
*id3
, bool last_track
) = NULL
;
252 static size_t conf_watermark
= 0; /* Level to trigger filebuf fill (A/C) FIXME */
253 static size_t conf_filechunk
= 0; /* Largest chunk the codec accepts (A/C) FIXME */
254 static size_t conf_preseek
= 0; /* Codec pre-seek margin (A/C) FIXME */
255 static size_t buffer_margin
= 0; /* Buffer margin aka anti-skip buffer (A/C-) */
257 static size_t high_watermark
= 0; /* High watermark for rebuffer (A/V/other) */
260 /* Multiple threads */
261 static void set_current_codec(int codec_idx
);
262 /* Set the watermark to trigger buffer fill (A/C) FIXME */
263 static void set_filebuf_watermark(int seconds
);
266 static struct event_queue audio_queue NOCACHEBSS_ATTR
;
267 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR
;
268 static long audio_stack
[(DEFAULT_STACK_SIZE
+ 0x1000)/sizeof(long)];
269 static const char audio_thread_name
[] = "audio";
271 static void audio_thread(void);
272 static void audio_initiate_track_change(long direction
);
273 static bool audio_have_tracks(void);
274 static void audio_reset_buffer(void);
277 extern struct codec_api ci
;
278 static struct event_queue codec_queue NOCACHEBSS_ATTR
;
279 static struct queue_sender_list codec_queue_sender_list
;
280 static long codec_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
282 static const char codec_thread_name
[] = "codec";
283 struct thread_entry
*codec_thread_p
; /* For modifying thread priority later. */
285 static volatile int current_codec IDATA_ATTR
; /* Current codec (normal/voice) */
288 #ifdef PLAYBACK_VOICE
290 extern struct codec_api ci_voice
;
292 static struct thread_entry
*voice_thread_p
= NULL
;
293 static struct event_queue voice_queue NOCACHEBSS_ATTR
;
294 static long voice_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
295 IBSS_ATTR_VOICE_STACK
;
296 static const char voice_thread_name
[] = "voice codec";
298 /* Voice codec swapping control */
299 extern unsigned char codecbuf
[]; /* DRAM codec swap buffer */
302 /* IRAM codec swap buffer for sim*/
303 static unsigned char sim_iram
[CODEC_IRAM_SIZE
];
304 #undef CODEC_IRAM_ORIGIN
305 #define CODEC_IRAM_ORIGIN sim_iram
308 /* iram_buf and dram_buf are either both NULL or both non-NULL */
309 /* Pointer to IRAM buffer for codec swapping */
310 static unsigned char *iram_buf
= NULL
;
311 /* Pointer to DRAM buffer for codec swapping */
312 static unsigned char *dram_buf
= NULL
;
313 /* Parity of swap_codec calls - needed because one codec swapping itself in
314 automatically swaps in the other and the swap when unlocking should not
315 happen if the parity is even.
317 static bool swap_codec_parity NOCACHEBSS_ATTR
= false; /* true=odd, false=even */
318 /* Locking to control which codec (normal/voice) is running */
319 static struct semaphore sem_codecthread NOCACHEBSS_ATTR
;
320 static struct event event_codecthread NOCACHEBSS_ATTR
;
323 static volatile bool voice_thread_start
= false; /* Triggers voice playback (A/V) */
324 static volatile bool voice_is_playing NOCACHEBSS_ATTR
= false; /* Is voice currently playing? (V) */
325 static volatile bool voice_codec_loaded NOCACHEBSS_ATTR
= false; /* Is voice codec loaded (V/A-) */
326 static unsigned char *voicebuf
= NULL
;
327 static size_t voice_remaining
= 0;
330 /* Voice IRAM has been stolen for other use */
331 static bool voice_iram_stolen
= false;
334 static void (*voice_getmore
)(unsigned char** start
, size_t* size
) = NULL
;
337 void (*callback
)(unsigned char **start
, size_t* size
);
341 static void voice_thread(void);
342 static void voice_stop(void);
344 #endif /* PLAYBACK_VOICE */
347 /* --- Helper functions --- */
349 struct mp3entry
*bufgetid3(int handle_id
)
354 struct mp3entry
*id3
;
355 ssize_t ret
= bufgetdata(handle_id
, 0, (void *)&id3
);
357 if (ret
< 0 || ret
!= sizeof(struct mp3entry
))
363 void *bufgetcodec(struct track_info
*track
)
366 ssize_t ret
= bufgetdata(track
->codec_hid
, track
->codecsize
, &ptr
);
369 request_buffer_handle(CUR_TI
->audio_hid
);
374 ret
= bufgetdata(track
->codec_hid
, track
->codecsize
, &ptr
);
383 void clear_track_info(struct track_info
*track
)
388 if (track
->codec_hid
> 0) {
389 bufclose(track
->codec_hid
);
392 if (track
->id3_hid
> 0) {
393 bufclose(track
->id3_hid
);
396 if (track
->audio_hid
> 0) {
397 bufclose(track
->audio_hid
);
400 memset(track
, 0, sizeof(struct track_info
));
403 /* --- External interfaces --- */
405 void mp3_play_data(const unsigned char* start
, int size
,
406 void (*get_more
)(unsigned char** start
, size_t* size
))
408 #ifdef PLAYBACK_VOICE
409 static struct voice_info voice_clip
;
410 voice_clip
.callback
= get_more
;
411 voice_clip
.buf
= (unsigned char*)start
;
412 voice_clip
.size
= size
;
413 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
414 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
415 LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
416 queue_post(&voice_queue
, Q_VOICE_PLAY
, (intptr_t)&voice_clip
);
417 voice_thread_start
= true;
426 void mp3_play_stop(void)
428 #ifdef PLAYBACK_VOICE
429 queue_remove_from_head(&voice_queue
, Q_VOICE_STOP
);
430 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
431 queue_post(&voice_queue
, Q_VOICE_STOP
, 1);
435 void mp3_play_pause(bool play
)
441 bool mp3_is_playing(void)
443 #ifdef PLAYBACK_VOICE
444 return voice_is_playing
;
450 /* If voice could be swapped out - wait for it to return
451 * Used by buffer claming functions.
453 static void wait_for_voice_swap_in(void)
455 #ifdef PLAYBACK_VOICE
456 if (NULL
== iram_buf
)
459 event_wait(&event_codecthread
, STATE_NONSIGNALED
);
460 #endif /* PLAYBACK_VOICE */
463 /* This sends a stop message and the audio thread will dump all it's
464 subsequenct messages */
465 static void audio_hard_stop(void)
468 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
469 queue_send(&audio_queue
, Q_AUDIO_STOP
, 1);
472 unsigned char *audio_get_buffer(bool talk_buf
, size_t *buffer_size
)
474 unsigned char *buf
, *end
;
476 if (audio_is_initialized
)
479 wait_for_voice_swap_in();
480 #ifdef PLAYBACK_VOICE
484 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
486 if (buffer_size
== NULL
)
488 /* Special case for talk_init to use since it already knows it's
490 buffer_state
= BUFFER_STATE_TRASHED
;
494 if (talk_buf
|| buffer_state
== BUFFER_STATE_TRASHED
495 || !talk_voice_required())
497 logf("get buffer: talk, audio");
498 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
499 the talk buffer is not needed because voice isn't being used, or
500 could be BUFFER_STATE_TRASHED already. If state is
501 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
502 without the caller knowing what's going on. Changing certain settings
503 may move it to a worse condition but the memory in use by something
504 else will remain undisturbed.
506 if (buffer_state
!= BUFFER_STATE_TRASHED
)
509 buffer_state
= BUFFER_STATE_TRASHED
;
517 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
518 still BUFFER_STATE_INITIALIZED */
519 /* Skip talk buffer and move pcm buffer to end to maximize available
520 contiguous memory - no audio running means voice will not need the
522 logf("get buffer: audio");
523 buf
= audiobuf
+ talk_get_bufsize();
524 end
= audiobufend
- pcmbuf_init(audiobufend
);
525 buffer_state
= BUFFER_STATE_VOICED_ONLY
;
528 *buffer_size
= end
- buf
;
534 void audio_iram_steal(void)
536 /* We need to stop audio playback in order to use codec IRAM */
539 #ifdef PLAYBACK_VOICE
540 if (NULL
!= iram_buf
)
542 /* Can't already be stolen */
543 if (voice_iram_stolen
)
546 /* Must wait for voice to be current again if it is swapped which
547 would cause the caller's buffer to get clobbered when voice locks
548 and runs - we'll wait for it to lock and yield again then make sure
549 the ride has come to a complete stop */
550 wait_for_voice_swap_in();
553 /* Save voice IRAM but just memcpy - safe to do here since voice
554 is current and no audio codec is loaded */
555 memcpy(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
556 voice_iram_stolen
= true;
560 /* Nothing much to do if no voice */
561 voice_iram_stolen
= false;
565 #endif /* IRAM_STEAL */
567 #ifdef HAVE_RECORDING
568 unsigned char *audio_get_recording_buffer(size_t *buffer_size
)
570 /* Don't allow overwrite of voice swap area or we'll trash the
571 swapped-out voice codec but can use whole thing if none */
574 /* Stop audio and voice. Wait for voice to swap in and be clear
575 of pending events to ensure trouble-free operation of encoders */
577 wait_for_voice_swap_in();
578 #ifdef PLAYBACK_VOICE
583 #ifdef PLAYBACK_VOICE
584 /* If no dram_buf, swap space not used and recording gets more
585 memory. Codec swap areas will remain unaffected by the next init
586 since they're allocated at the end of the buffer and their sizes
587 don't change between calls */
590 #endif /* PLAYBACK_VOICE */
593 buffer_state
= BUFFER_STATE_TRASHED
;
595 *buffer_size
= end
- audiobuf
;
597 return (unsigned char *)audiobuf
;
600 bool audio_load_encoder(int afmt
)
603 const char *enc_fn
= get_codec_filename(afmt
| CODEC_TYPE_ENCODER
);
607 audio_remove_encoder();
608 ci
.enc_codec_loaded
= 0; /* clear any previous error condition */
610 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
611 queue_post(&codec_queue
, Q_ENCODER_LOAD_DISK
, (intptr_t)enc_fn
);
613 while (ci
.enc_codec_loaded
== 0)
616 logf("codec loaded: %d", ci
.enc_codec_loaded
);
618 return ci
.enc_codec_loaded
> 0;
623 } /* audio_load_encoder */
625 void audio_remove_encoder(void)
628 /* force encoder codec unload (if currently loaded) */
629 if (ci
.enc_codec_loaded
<= 0)
632 ci
.stop_encoder
= true;
633 while (ci
.enc_codec_loaded
> 0)
636 } /* audio_remove_encoder */
638 #endif /* HAVE_RECORDING */
640 struct mp3entry
* audio_current_track(void)
642 const char *filename
;
644 static struct mp3entry temp_id3
;
646 int offset
= ci
.new_track
+ wps_offset
;
648 cur_idx
= track_ridx
+ offset
;
649 cur_idx
&= MAX_TRACK_MASK
;
651 if (cur_idx
== track_ridx
&& *curtrack_id3
.path
)
652 return &curtrack_id3
;
653 else if (offset
== -1 && *prevtrack_id3
.path
)
654 return &prevtrack_id3
;
655 else if (tracks
[cur_idx
].id3_hid
> 0)
656 return bufgetid3(tracks
[cur_idx
].id3_hid
);
658 memset(&temp_id3
, 0, sizeof(struct mp3entry
));
660 filename
= playlist_peek(0);
662 filename
= "No file!";
664 #ifdef HAVE_TC_RAMCACHE
665 if (tagcache_fill_tags(&temp_id3
, filename
))
669 p
= strrchr(filename
, '/');
675 strncpy(temp_id3
.path
, p
, sizeof(temp_id3
.path
)-1);
676 temp_id3
.title
= &temp_id3
.path
[0];
681 struct mp3entry
* audio_next_track(void)
683 int next_idx
= track_ridx
;
685 if (!audio_have_tracks())
688 if (wps_offset
== -1 && *prevtrack_id3
.path
)
689 return &curtrack_id3
;
692 next_idx
&= MAX_TRACK_MASK
;
694 if (tracks
[next_idx
].id3_hid
<= 0)
697 return &nexttrack_id3
;
700 bool audio_has_changed_track(void)
704 track_changed
= false;
711 void audio_play(long offset
)
715 #ifdef PLAYBACK_VOICE
716 /* Truncate any existing voice output so we don't have spelling
717 * etc. over the first part of the played track */
722 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset
);
723 /* Don't return until playback has actually started */
724 queue_send(&audio_queue
, Q_AUDIO_PLAY
, offset
);
727 void audio_stop(void)
730 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
731 /* Don't return until playback has actually stopped */
732 queue_send(&audio_queue
, Q_AUDIO_STOP
, 0);
735 void audio_pause(void)
737 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
738 /* Don't return until playback has actually paused */
739 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, true);
742 void audio_resume(void)
744 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
745 /* Don't return until playback has actually resumed */
746 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, false);
749 void audio_next(void)
751 if (playlist_check(ci
.new_track
+ wps_offset
+ 1))
753 if (global_settings
.beep
)
754 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
756 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
757 queue_post(&audio_queue
, Q_AUDIO_SKIP
, 1);
758 /* Update wps while our message travels inside deep playback queues. */
760 track_changed
= true;
764 /* No more tracks. */
765 if (global_settings
.beep
)
766 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
770 void audio_prev(void)
772 if (playlist_check(ci
.new_track
+ wps_offset
- 1))
774 if (global_settings
.beep
)
775 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
777 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
778 queue_post(&audio_queue
, Q_AUDIO_SKIP
, -1);
779 /* Update wps while our message travels inside deep playback queues. */
781 track_changed
= true;
785 /* No more tracks. */
786 if (global_settings
.beep
)
787 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
791 void audio_next_dir(void)
793 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
794 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, 1);
797 void audio_prev_dir(void)
799 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
800 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, -1);
803 void audio_pre_ff_rewind(void)
805 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
806 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
809 void audio_ff_rewind(long newpos
)
811 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
812 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, newpos
);
815 void audio_flush_and_reload_tracks(void)
817 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
818 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
821 void audio_error_clear(void)
823 #ifdef AUDIO_HAVE_RECORDING
824 pcm_rec_error_clear();
828 int audio_status(void)
833 ret
|= AUDIO_STATUS_PLAY
;
836 ret
|= AUDIO_STATUS_PAUSE
;
838 #ifdef HAVE_RECORDING
839 /* Do this here for constitency with mpeg.c version */
840 ret
|= pcm_rec_status();
846 int audio_get_file_pos(void)
851 #ifndef HAVE_FLASH_STORAGE
852 void audio_set_buffer_margin(int setting
)
854 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
855 buffer_margin
= lookup
[setting
];
856 logf("buffer margin: %d", buffer_margin
);
857 set_filebuf_watermark(buffer_margin
);
861 /* Take nescessary steps to enable or disable the crossfade setting */
862 void audio_set_crossfade(int enable
)
868 /* Tell it the next setting to use */
869 pcmbuf_crossfade_enable(enable
);
871 /* Return if size hasn't changed or this is too early to determine
872 which in the second case there's no way we could be playing
874 if (pcmbuf_is_same_size())
876 /* This function is a copout and just syncs some variables -
877 to be removed at a later date */
878 pcmbuf_crossfade_enable_finished();
883 was_playing
= playing
;
885 /* Playback has to be stopped before changing the buffer size */
888 /* Store the track resume position */
889 offset
= curtrack_id3
.offset
;
890 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK
));
893 /* Blast it - audio buffer will have to be setup again next time
895 audio_get_buffer(true, &size
);
897 /* Restart playback if audio was running previously */
902 /* --- Routines called from multiple threads --- */
903 static void set_current_codec(int codec_idx
)
905 current_codec
= codec_idx
;
906 dsp_configure(DSP_SWITCH_CODEC
, codec_idx
);
909 #ifdef PLAYBACK_VOICE
910 static void swap_codec(void)
914 /* Swap nothing if no swap buffers exist */
915 if (dram_buf
== NULL
)
917 logf("swap: no swap buffers");
921 my_codec
= current_codec
;
923 logf("swapping out codec: %d", my_codec
);
925 /* Invert this when a codec thread enters and leaves */
926 swap_codec_parity
= !swap_codec_parity
;
928 /* If this is true, an odd number of calls has occurred and there's
929 no codec thread waiting to swap us out when it locks and runs. This
930 occurs when playback is stopped or when just starting playback and
931 the audio thread is loading a codec; parities should always be even
932 on entry when a thread calls this during playback */
933 if (swap_codec_parity
)
935 /* Save our current IRAM and DRAM */
937 if (voice_iram_stolen
)
939 logf("swap: iram restore");
940 voice_iram_stolen
= false;
941 /* Don't swap trashed data into buffer as the voice IRAM will
942 already be swapped out - should _always_ be the case if
943 voice_iram_stolen is true since the voice has been swapped
945 if (my_codec
== CODEC_IDX_VOICE
)
947 logf("voice iram already swapped");
953 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
959 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
960 /* No cache invalidation needed; it will be done in codec_load_ram
961 or we won't be here otherwise */
964 /* Release my semaphore */
965 semaphore_release(&sem_codecthread
);
966 logf("unlocked: %d", my_codec
);
968 /* Wait for other codec */
969 event_wait(&event_codecthread
,
970 (my_codec
== CODEC_IDX_AUDIO
) ? STATE_NONSIGNALED
: STATE_SIGNALED
);
972 /* Wait for other codec to unlock */
973 logf("waiting for lock: %d", my_codec
);
974 semaphore_wait(&sem_codecthread
);
977 set_current_codec(my_codec
);
978 event_set_state(&event_codecthread
,
979 (my_codec
== CODEC_IDX_AUDIO
) ? STATE_SIGNALED
: STATE_NONSIGNALED
);
981 /* Reload our IRAM and DRAM */
982 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
983 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
986 /* Flip parity again */
987 swap_codec_parity
= !swap_codec_parity
;
989 logf("resuming codec: %d", my_codec
);
992 /* This function is meant to be used by the buffer stealing functions to
993 ensure the codec is no longer active and so voice will be swapped-in
994 before it is called */
995 static void voice_stop(void)
997 /* Must have a voice codec loaded or we'll hang forever here */
998 if (!voice_codec_loaded
)
1001 talk_force_shutup();
1003 /* Loop until voice empties it's queue, stops and picks up on the new
1004 track; the voice thread must be stopped and waiting for messages
1005 outside the codec */
1006 while (voice_is_playing
|| !queue_empty(&voice_queue
) ||
1014 /* Is voice still speaking */
1015 /* Unfortunately only reliable when music is not also playing. */
1016 static bool is_voice_speaking(void)
1018 return is_voice_queued()
1020 || (!playing
&& pcm_is_playing());
1023 #endif /* PLAYBACK_VOICE */
1025 /* Wait for voice to finish speaking. */
1026 /* Also only reliable when music is not also playing. */
1027 void voice_wait(void)
1029 #ifdef PLAYBACK_VOICE
1030 while (is_voice_speaking())
1035 static void set_filebuf_watermark(int seconds
)
1040 return; /* Audio buffers not yet set up */
1042 bytes
= MAX(curtrack_id3
.bitrate
* seconds
* (1000/8), conf_watermark
);
1043 bytes
= MIN(bytes
, filebuflen
/ 2);
1044 conf_watermark
= bytes
;
1047 const char * get_codec_filename(int cod_spec
)
1051 #ifdef HAVE_RECORDING
1052 /* Can choose decoder or encoder if one available */
1053 int type
= cod_spec
& CODEC_TYPE_MASK
;
1054 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
1056 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
1057 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
1059 fname
= (type
== CODEC_TYPE_ENCODER
) ?
1060 audio_formats
[afmt
].codec_enc_root_fn
:
1061 audio_formats
[afmt
].codec_root_fn
;
1064 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
1065 afmt
, fname
? fname
: "<unknown>");
1066 #else /* !HAVE_RECORDING */
1067 /* Always decoder */
1068 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
1069 cod_spec
= AFMT_UNKNOWN
;
1070 fname
= audio_formats
[cod_spec
].codec_root_fn
;
1071 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
1072 #endif /* HAVE_RECORDING */
1075 } /* get_codec_filename */
1078 /* --- Voice thread --- */
1080 #ifdef PLAYBACK_VOICE
1082 static bool voice_pcmbuf_insert_callback(
1083 const void *ch1
, const void *ch2
, int count
)
1085 const char *src
[2] = { ch1
, ch2
};
1089 int out_count
= dsp_output_count(count
);
1093 while ((dest
= pcmbuf_request_voice_buffer(
1094 &out_count
, playing
)) == NULL
)
1096 if (playing
&& audio_codec_loaded
)
1102 /* Get the real input_size for output_size bytes, guarding
1103 * against resampling buffer overflows. */
1104 inp_count
= dsp_input_count(out_count
);
1109 /* Input size has grown, no error, just don't write more than length */
1110 if (inp_count
> count
)
1113 out_count
= dsp_process(dest
, src
, inp_count
);
1120 pcmbuf_mix_voice(out_count
);
1121 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
1126 pcmbuf_write_complete(out_count
);
1132 } /* voice_pcmbuf_insert_callback */
1134 static void* voice_get_memory_callback(size_t *size
)
1136 /* Voice should have no use for this. If it did, we'd have to
1137 swap the malloc buffer as well. */
1142 static void voice_set_elapsed_callback(unsigned int value
)
1147 static void voice_set_offset_callback(size_t value
)
1152 static void voice_configure_callback(int setting
, intptr_t value
)
1154 if (!dsp_configure(setting
, value
))
1156 logf("Illegal key:%d", setting
);
1160 static size_t voice_filebuf_callback(void *ptr
, size_t size
)
1168 /* Handle Q_VOICE_STOP and part of SYS_USB_CONNECTED */
1169 static bool voice_on_voice_stop(bool aborting
, size_t *realsize
)
1171 if (aborting
&& !playing
)
1173 /* Aborting: Slight hack - flush PCM buffer if
1174 only being used for voice */
1178 if (voice_is_playing
)
1180 /* Clear the current buffer */
1181 voice_is_playing
= false;
1182 voice_getmore
= NULL
;
1183 voice_remaining
= 0;
1186 /* Cancel any automatic boost if no more clips requested. */
1187 if (!playing
|| !voice_thread_start
)
1190 /* Force the codec to think it's changing tracks */
1191 ci_voice
.new_track
= 1;
1194 return true; /* Yes, change tracks */
1200 static void* voice_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1202 struct queue_event ev
;
1204 if (ci_voice
.new_track
)
1212 if (voice_is_playing
|| playing
)
1214 queue_wait_w_tmo(&voice_queue
, &ev
, 0);
1215 if (!voice_is_playing
&& ev
.id
== SYS_TIMEOUT
)
1216 ev
.id
= Q_AUDIO_PLAY
;
1220 queue_wait(&voice_queue
, &ev
);
1225 LOGFQUEUE("voice < Q_AUDIO_PLAY");
1228 if (audio_codec_loaded
)
1234 #ifdef AUDIO_HAVE_RECORDING
1235 case Q_ENCODER_RECORD
:
1236 LOGFQUEUE("voice < Q_ENCODER_RECORD");
1242 LOGFQUEUE("voice < Q_VOICE_STOP");
1243 if (voice_on_voice_stop(ev
.data
, realsize
))
1247 case SYS_USB_CONNECTED
:
1249 LOGFQUEUE("voice < SYS_USB_CONNECTED");
1250 bool change_tracks
= voice_on_voice_stop(ev
.data
, realsize
);
1251 /* Voice is obviously current so let us swap ourselves away if
1252 playing so audio may stop itself - audio_codec_loaded can
1253 only be true in this case if we're here even if the codec
1254 is only about to load */
1255 if (audio_codec_loaded
)
1257 /* Playback should be finished by now - ack and wait */
1258 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
1259 usb_wait_for_disconnect(&voice_queue
);
1266 LOGFQUEUE("voice < Q_VOICE_PLAY");
1267 if (!voice_is_playing
)
1269 /* Set up new voice data */
1270 struct voice_info
*voice_data
;
1272 if (voice_iram_stolen
)
1274 /* Voice is the first to run again and is currently
1276 logf("voice: iram restore");
1277 memcpy(CODEC_IRAM_ORIGIN
, iram_buf
, CODEC_IRAM_SIZE
);
1278 voice_iram_stolen
= false;
1281 /* Must reset the buffer before any playback begins if
1283 if (buffer_state
== BUFFER_STATE_TRASHED
)
1284 audio_reset_buffer();
1286 voice_is_playing
= true;
1287 trigger_cpu_boost();
1288 voice_data
= (struct voice_info
*)ev
.data
;
1289 voice_remaining
= voice_data
->size
;
1290 voicebuf
= voice_data
->buf
;
1291 voice_getmore
= voice_data
->callback
;
1293 goto voice_play_clip
; /* To exit both switch and while */
1296 LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
1297 goto voice_play_clip
;
1300 LOGFQUEUE("voice < default");
1306 if (voice_remaining
== 0 || voicebuf
== NULL
)
1309 voice_getmore((unsigned char **)&voicebuf
, &voice_remaining
);
1311 /* If this clip is done */
1312 if (voice_remaining
== 0)
1314 LOGFQUEUE("voice > voice Q_VOICE_STOP");
1315 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
1316 /* Force pcm playback. */
1317 if (!pcm_is_playing())
1318 pcmbuf_play_start();
1322 *realsize
= MIN(voice_remaining
, reqsize
);
1328 } /* voice_request_buffer_callback */
1330 static void voice_advance_buffer_callback(size_t amount
)
1332 amount
= MIN(amount
, voice_remaining
);
1334 voice_remaining
-= amount
;
1337 static void voice_advance_buffer_loc_callback(void *ptr
)
1339 size_t amount
= (size_t)ptr
- (size_t)voicebuf
;
1341 voice_advance_buffer_callback(amount
);
1344 static off_t
voice_mp3_get_filepos_callback(int newtime
)
1351 static void voice_do_nothing(void)
1356 static bool voice_seek_buffer_callback(size_t newpos
)
1363 static bool voice_request_next_track_callback(void)
1365 ci_voice
.new_track
= 0;
1369 static void voice_thread(void)
1371 logf("Loading voice codec");
1372 voice_codec_loaded
= true;
1373 semaphore_wait(&sem_codecthread
);
1374 event_set_state(&event_codecthread
, false);
1375 set_current_codec(CODEC_IDX_VOICE
);
1376 dsp_configure(DSP_RESET
, 0);
1377 voice_remaining
= 0;
1378 voice_getmore
= NULL
;
1380 /* FIXME: If we being starting the voice thread without reboot, the
1381 voice_queue could be full of old stuff and we must flush it. */
1382 codec_load_file(get_codec_filename(AFMT_MPA_L3
), &ci_voice
);
1384 logf("Voice codec finished");
1385 voice_codec_loaded
= false;
1386 voice_thread_p
= NULL
;
1387 semaphore_release(&sem_codecthread
);
1388 } /* voice_thread */
1390 #endif /* PLAYBACK_VOICE */
1392 /* --- Codec thread --- */
1393 static bool codec_pcmbuf_insert_callback(
1394 const void *ch1
, const void *ch2
, int count
)
1396 const char *src
[2] = { ch1
, ch2
};
1400 int out_count
= dsp_output_count(count
);
1404 /* Prevent audio from a previous track from playing */
1405 if (ci
.new_track
|| ci
.stop_codec
)
1408 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
1411 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
1415 /* Get the real input_size for output_size bytes, guarding
1416 * against resampling buffer overflows. */
1417 inp_count
= dsp_input_count(out_count
);
1422 /* Input size has grown, no error, just don't write more than length */
1423 if (inp_count
> count
)
1426 out_count
= dsp_process(dest
, src
, inp_count
);
1431 pcmbuf_write_complete(out_count
);
1433 #ifdef PLAYBACK_VOICE
1434 if ((voice_is_playing
|| voice_thread_start
)
1435 && pcm_is_playing() && voice_codec_loaded
&&
1436 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1438 voice_thread_start
= false;
1447 } /* codec_pcmbuf_insert_callback */
1449 static void* codec_get_memory_callback(size_t *size
)
1451 *size
= MALLOC_BUFSIZE
;
1455 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
1456 static void codec_pcmbuf_position_callback(size_t size
)
1458 /* This is called from an ISR, so be quick */
1459 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
1460 prevtrack_id3
.elapsed
;
1462 if (time
>= prevtrack_id3
.length
)
1464 pcmbuf_set_position_callback(NULL
);
1465 prevtrack_id3
.elapsed
= prevtrack_id3
.length
;
1468 prevtrack_id3
.elapsed
= time
;
1471 static void codec_set_elapsed_callback(unsigned int value
)
1473 unsigned int latency
;
1477 #ifdef AB_REPEAT_ENABLE
1478 ab_position_report(value
);
1481 latency
= pcmbuf_get_latency();
1482 if (value
< latency
)
1483 curtrack_id3
.elapsed
= 0;
1484 else if (value
- latency
> curtrack_id3
.elapsed
||
1485 value
- latency
< curtrack_id3
.elapsed
- 2)
1487 curtrack_id3
.elapsed
= value
- latency
;
1491 static void codec_set_offset_callback(size_t value
)
1493 unsigned int latency
;
1498 latency
= pcmbuf_get_latency() * curtrack_id3
.bitrate
/ 8;
1499 if (value
< latency
)
1500 curtrack_id3
.offset
= 0;
1502 curtrack_id3
.offset
= value
- latency
;
1505 static void codec_advance_buffer_counters(size_t amount
)
1507 bufadvance(CUR_TI
->audio_hid
, amount
);
1508 ci
.curpos
+= amount
;
1511 /* copy up-to size bytes into ptr and return the actual size copied */
1512 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
1516 if (ci
.stop_codec
|| !playing
)
1519 copy_n
= bufread(CUR_TI
->audio_hid
, size
, ptr
);
1521 /* Nothing requested OR nothing left */
1528 request_buffer_handle(CUR_TI
->audio_hid
);
1531 /* Let the disk buffer catch fill until enough data is available */
1532 while (copy_n
== -2)
1536 if (ci
.stop_codec
|| ci
.new_track
)
1539 copy_n
= bufread(CUR_TI
->audio_hid
, size
, ptr
);
1542 /* Update read and other position pointers */
1543 codec_advance_buffer_counters(copy_n
);
1545 /* Return the actual amount of data copied to the buffer */
1547 } /* codec_filebuf_callback */
1549 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1551 size_t copy_n
= reqsize
;
1561 ret
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, &ptr
);
1563 copy_n
= MIN((size_t)ret
, reqsize
);
1573 request_buffer_handle(CUR_TI
->audio_hid
);
1576 /* Let the disk buffer catch fill until enough data is available */
1581 if (ci
.stop_codec
|| ci
.new_track
)
1586 ret
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, &ptr
);
1588 copy_n
= MIN((size_t)ret
, reqsize
);
1593 } /* codec_request_buffer_callback */
1595 static int get_codec_base_type(int type
)
1607 static void codec_advance_buffer_callback(size_t amount
)
1609 codec_advance_buffer_counters(amount
);
1610 codec_set_offset_callback(ci
.curpos
);
1613 static void codec_advance_buffer_loc_callback(void *ptr
)
1615 size_t amount
= get_offset(CUR_TI
->audio_hid
, ptr
);
1617 codec_advance_buffer_callback(amount
);
1620 /* Copied from mpeg.c. Should be moved somewhere else. */
1621 static int codec_get_file_pos(void)
1624 struct mp3entry
*id3
= audio_current_track();
1630 /* Use the TOC to find the new position */
1631 unsigned int percent
, remainder
;
1632 int curtoc
, nexttoc
, plen
;
1634 percent
= (id3
->elapsed
*100)/id3
->length
;
1638 curtoc
= id3
->toc
[percent
];
1641 nexttoc
= id3
->toc
[percent
+1];
1645 pos
= (id3
->filesize
/256)*curtoc
;
1647 /* Use the remainder to get a more accurate position */
1648 remainder
= (id3
->elapsed
*100)%id3
->length
;
1649 remainder
= (remainder
*100)/id3
->length
;
1650 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1651 pos
+= (plen
/100)*remainder
;
1655 /* No TOC exists, estimate the new position */
1656 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1657 (id3
->elapsed
/ 1000);
1660 else if (id3
->bitrate
)
1661 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1665 pos
+= id3
->first_frame_offset
;
1667 /* Don't seek right to the end of the file so that we can
1668 transition properly to the next song */
1669 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1670 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1675 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1679 curtrack_id3
.elapsed
= newtime
;
1680 newpos
= codec_get_file_pos();
1685 static void codec_seek_complete_callback(void)
1687 logf("seek_complete");
1688 if (pcm_is_paused())
1690 /* If this is not a seamless seek, clear the buffer */
1692 dsp_configure(DSP_FLUSH
, 0);
1694 /* If playback was not 'deliberately' paused, unpause now */
1696 pcmbuf_pause(false);
1701 static bool codec_seek_buffer_callback(size_t newpos
)
1703 logf("codec_seek_buffer_callback");
1705 int ret
= bufseek(CUR_TI
->audio_hid
, newpos
);
1715 static void codec_configure_callback(int setting
, intptr_t value
)
1718 case CODEC_SET_FILEBUF_WATERMARK
:
1719 conf_watermark
= value
;
1720 set_filebuf_watermark(buffer_margin
);
1723 case CODEC_SET_FILEBUF_CHUNKSIZE
:
1724 conf_filechunk
= value
;
1727 case CODEC_SET_FILEBUF_PRESEEK
:
1728 conf_preseek
= value
;
1732 if (!dsp_configure(setting
, value
)) { logf("Illegal key:%d", setting
); }
1736 static void codec_track_changed(void)
1738 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1739 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1742 static void codec_pcmbuf_track_changed_callback(void)
1744 DEBUGF("codec_pcmbuf_track_changed_callback\n");
1745 pcmbuf_set_position_callback(NULL
);
1746 codec_track_changed();
1749 static void codec_discard_codec_callback(void)
1751 if (CUR_TI
->codec_hid
> 0)
1753 bufclose(CUR_TI
->codec_hid
);
1754 CUR_TI
->codec_hid
= 0;
1755 CUR_TI
->codecsize
= 0;
1759 static inline void codec_gapless_track_change(void) {
1760 /* callback keeps the progress bar moving while the pcmbuf empties */
1761 pcmbuf_set_position_callback(codec_pcmbuf_position_callback
);
1762 /* set the pcmbuf callback for when the track really changes */
1763 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1766 static inline void codec_crossfade_track_change(void) {
1767 /* Initiate automatic crossfade mode */
1768 pcmbuf_crossfade_init(false);
1769 /* Notify the wps that the track change starts now */
1770 codec_track_changed();
1773 static void codec_track_skip_done(bool was_manual
)
1775 int crossfade_mode
= global_settings
.crossfade
;
1777 /* Manual track change (always crossfade or flush audio). */
1780 pcmbuf_crossfade_init(true);
1781 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1782 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1784 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1785 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1786 && crossfade_mode
!= CROSSFADE_ENABLE_TRACKSKIP
)
1788 if (crossfade_mode
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1790 if (global_settings
.playlist_shuffle
)
1791 /* shuffle mode is on, so crossfade: */
1792 codec_crossfade_track_change();
1794 /* shuffle mode is off, so do a gapless track change */
1795 codec_gapless_track_change();
1798 /* normal crossfade: */
1799 codec_crossfade_track_change();
1802 /* normal gapless playback. */
1803 codec_gapless_track_change();
1806 static bool codec_load_next_track(void)
1808 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1810 prev_track_elapsed
= curtrack_id3
.elapsed
;
1813 codec_seek_complete_callback();
1815 #ifdef AB_REPEAT_ENABLE
1816 ab_end_of_track_report();
1819 logf("Request new track");
1821 if (ci
.new_track
== 0)
1824 automatic_skip
= true;
1829 trigger_cpu_boost();
1830 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1831 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1836 case Q_CODEC_REQUEST_COMPLETE
:
1837 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1838 codec_track_skip_done(!automatic_skip
);
1841 case Q_CODEC_REQUEST_FAILED
:
1842 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1844 ci
.stop_codec
= true;
1848 LOGFQUEUE("codec |< default");
1849 ci
.stop_codec
= true;
1854 static bool codec_request_next_track_callback(void)
1858 if (ci
.stop_codec
|| !playing
)
1861 prev_codectype
= get_codec_base_type(curtrack_id3
.codectype
);
1863 if (!codec_load_next_track())
1866 /* Seek to the beginning of the new track because if the struct mp3entry was
1867 buffered, "elapsed" might not be zero (if the track has been played
1868 already but not unbuffered) */
1869 codec_seek_buffer_callback(0);
1871 /* Check if the next codec is the same file. */
1872 if (prev_codectype
== get_codec_base_type(curtrack_id3
.codectype
))
1874 logf("New track loaded");
1875 codec_discard_codec_callback();
1880 logf("New codec:%d/%d", curtrack_id3
.codectype
, prev_codectype
);
1885 static void codec_thread(void)
1887 struct queue_event ev
;
1893 queue_wait(&codec_queue
, &ev
);
1896 case Q_CODEC_LOAD_DISK
:
1897 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1898 queue_reply(&codec_queue
, 1);
1899 audio_codec_loaded
= true;
1900 #ifdef PLAYBACK_VOICE
1901 /* Don't sent messages to voice codec if it's already swapped
1902 out or it will never get this */
1903 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1905 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1906 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1908 semaphore_wait(&sem_codecthread
);
1909 event_set_state(&event_codecthread
, true);
1911 set_current_codec(CODEC_IDX_AUDIO
);
1912 ci
.stop_codec
= false;
1913 status
= codec_load_file((const char *)ev
.data
, &ci
);
1914 DEBUGF("codec_load = %d\n", status
);
1915 #ifdef PLAYBACK_VOICE
1916 semaphore_release(&sem_codecthread
);
1921 LOGFQUEUE("codec < Q_CODEC_LOAD");
1922 if (CUR_TI
->codec_hid
<= 0) {
1923 logf("Codec slot is empty!");
1924 /* Wait for the pcm buffer to go empty */
1925 while (pcm_is_playing())
1927 /* This must be set to prevent an infinite loop */
1928 ci
.stop_codec
= true;
1929 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1930 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
1934 audio_codec_loaded
= true;
1935 #ifdef PLAYBACK_VOICE
1936 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1938 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1939 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1941 semaphore_wait(&sem_codecthread
);
1942 event_set_state(&event_codecthread
, true);
1944 set_current_codec(CODEC_IDX_AUDIO
);
1945 ci
.stop_codec
= false;
1946 wrap
= (size_t)&filebuf
[filebuflen
] - (size_t)bufgetcodec(CUR_TI
);
1947 status
= codec_load_ram(bufgetcodec(CUR_TI
), CUR_TI
->codecsize
,
1948 &filebuf
[0], wrap
, &ci
);
1949 #ifdef PLAYBACK_VOICE
1950 semaphore_release(&sem_codecthread
);
1954 #ifdef AUDIO_HAVE_RECORDING
1955 case Q_ENCODER_LOAD_DISK
:
1956 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1957 audio_codec_loaded
= false; /* Not audio codec! */
1958 #ifdef PLAYBACK_VOICE
1959 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1961 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
1962 queue_post(&voice_queue
, Q_ENCODER_RECORD
, 0);
1964 semaphore_wait(&sem_codecthread
);
1965 event_set_state(&event_codecthread
, true);
1967 logf("loading encoder");
1968 set_current_codec(CODEC_IDX_AUDIO
);
1969 ci
.stop_encoder
= false;
1970 status
= codec_load_file((const char *)ev
.data
, &ci
);
1971 #ifdef PLAYBACK_VOICE
1972 semaphore_release(&sem_codecthread
);
1974 logf("encoder stopped");
1976 #endif /* AUDIO_HAVE_RECORDING */
1979 case SYS_USB_CONNECTED
:
1980 LOGFQUEUE("codec < SYS_USB_CONNECTED");
1981 queue_clear(&codec_queue
);
1982 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
1983 usb_wait_for_disconnect(&codec_queue
);
1988 LOGFQUEUE("codec < default");
1991 if (audio_codec_loaded
)
2000 audio_codec_loaded
= false;
2004 case Q_CODEC_LOAD_DISK
:
2006 LOGFQUEUE("codec < Q_CODEC_LOAD");
2009 if (ci
.new_track
|| status
!= CODEC_OK
)
2013 logf("Codec failure");
2014 gui_syncsplash(HZ
*2, "Codec failure");
2017 if (!codec_load_next_track())
2019 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2020 /* End of playlist */
2021 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2027 logf("Codec finished");
2030 /* Wait for the audio to stop playing before
2031 * triggering the WPS exit */
2032 while(pcm_is_playing())
2034 curtrack_id3
.elapsed
=
2035 curtrack_id3
.length
- pcmbuf_get_latency();
2038 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2039 /* End of playlist */
2040 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2045 if (CUR_TI
->codec_hid
> 0)
2047 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2048 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
2052 const char *codec_fn
=
2053 get_codec_filename(curtrack_id3
.codectype
);
2054 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2055 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
2056 (intptr_t)codec_fn
);
2061 #ifdef AUDIO_HAVE_RECORDING
2062 case Q_ENCODER_LOAD_DISK
:
2063 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2065 if (status
== CODEC_OK
)
2068 logf("Encoder failure");
2069 gui_syncsplash(HZ
*2, "Encoder failure");
2071 if (ci
.enc_codec_loaded
< 0)
2074 logf("Encoder failed to load");
2075 ci
.enc_codec_loaded
= -1;
2077 #endif /* AUDIO_HAVE_RECORDING */
2080 LOGFQUEUE("codec < default");
2087 /* --- Audio thread --- */
2089 static bool audio_have_tracks(void)
2091 return track_ridx
!= track_widx
|| CUR_TI
->filesize
;
2094 static bool audio_have_free_tracks(void)
2096 if (track_widx
< track_ridx
)
2097 return track_widx
+ 1 < track_ridx
;
2098 else if (track_ridx
== 0)
2099 return track_widx
< MAX_TRACK
- 1;
2104 int audio_track_count(void)
2106 if (audio_have_tracks())
2108 int relative_track_widx
= track_widx
;
2110 if (track_ridx
> track_widx
)
2111 relative_track_widx
+= MAX_TRACK
;
2113 return relative_track_widx
- track_ridx
+ 1;
2119 long audio_filebufused(void)
2121 return (long) bufused();
2124 static void audio_update_trackinfo(void)
2126 if (CUR_TI
->id3_hid
> 0)
2127 copy_mp3entry(&curtrack_id3
, bufgetid3(CUR_TI
->id3_hid
));
2129 CUR_TI
->taginfo_ready
= (CUR_TI
->id3_hid
> 0);
2131 int next_idx
= track_ridx
+ 1;
2132 next_idx
&= MAX_TRACK_MASK
;
2134 if (tracks
[next_idx
].id3_hid
> 0)
2135 copy_mp3entry(&nexttrack_id3
, bufgetid3(tracks
[next_idx
].id3_hid
));
2137 tracks
[next_idx
].taginfo_ready
= (tracks
[next_idx
].id3_hid
> 0);
2139 ci
.filesize
= CUR_TI
->filesize
;
2140 curtrack_id3
.elapsed
= 0;
2141 curtrack_id3
.offset
= 0;
2142 ci
.id3
= &curtrack_id3
;
2144 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2147 static void audio_clear_track_entries(bool clear_unbuffered
)
2149 int cur_idx
= track_widx
;
2152 logf("Clearing tracks:%d/%d, %d", track_ridx
, track_widx
, clear_unbuffered
);
2154 /* Loop over all tracks from write-to-read */
2158 cur_idx
&= MAX_TRACK_MASK
;
2160 if (cur_idx
== track_ridx
)
2163 /* If the track is buffered, conditionally clear/notify,
2164 * otherwise clear the track if that option is selected */
2165 if (tracks
[cur_idx
].event_sent
)
2169 /* If there is an unbuffer callback, call it, otherwise,
2170 * just clear the track */
2171 if (track_unbuffer_callback
&& tracks
[last_idx
].id3_hid
> 0)
2172 track_unbuffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), false);
2174 clear_track_info(&tracks
[last_idx
]);
2178 else if (clear_unbuffered
)
2179 clear_track_info(&tracks
[cur_idx
]);
2182 /* We clear the previous instance of a buffered track throughout
2183 * the above loop to facilitate 'last' detection. Clear/notify
2184 * the last track here */
2187 if (track_unbuffer_callback
&& tracks
[last_idx
].id3_hid
> 0)
2188 track_unbuffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), true);
2189 clear_track_info(&tracks
[last_idx
]);
2193 static void audio_release_tracks(void)
2197 logf("releasing all tracks");
2199 for(i
= 0; i
< MAX_TRACKS
; i
++)
2201 cur_idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
2202 clear_track_info(&tracks
[cur_idx
]);
2207 /* FIXME: This code should be made more generic and move to metadata.c */
2208 static void audio_strip_tags(void)
2211 static const unsigned char tag
[] = "TAG";
2212 static const unsigned char apetag
[] = "APETAGEX";
2215 size_t len
, version
;
2217 tag_idx
= RINGBUF_SUB(buf_widx
, 128);
2219 if (bufused() > 128 && tag_idx
> buf_ridx
)
2222 for(i
= 0;i
< 3;i
++)
2224 if(filebuf
[cur_idx
] != tag
[i
])
2227 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2230 /* Skip id3v1 tag */
2231 logf("Skipping ID3v1 tag");
2233 tracks
[track_widx
].available
-= 128;
2234 tracks
[track_widx
].filesize
-= 128;
2238 /* Check for APE tag (look for the APE tag footer) */
2239 tag_idx
= RINGBUF_SUB(buf_widx
, 32);
2241 if (bufused() > 32 && tag_idx
> buf_ridx
)
2244 for(i
= 0;i
< 8;i
++)
2246 if(filebuf
[cur_idx
] != apetag
[i
])
2249 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2252 /* Read the version and length from the footer */
2253 version
= filebuf
[tag_idx
+8] | (filebuf
[tag_idx
+9] << 8) |
2254 (filebuf
[tag_idx
+10] << 16) | (filebuf
[tag_idx
+11] << 24);
2255 len
= filebuf
[tag_idx
+12] | (filebuf
[tag_idx
+13] << 8) |
2256 (filebuf
[tag_idx
+14] << 16) | (filebuf
[tag_idx
+15] << 24);
2257 if (version
== 2000)
2258 len
+= 32; /* APEv2 has a 32 byte header */
2261 if (bufused() > len
)
2263 logf("Skipping APE tag (%ldB)", len
);
2264 buf_widx
= RINGBUF_SUB(buf_widx
, len
);
2265 tracks
[track_widx
].available
-= len
;
2266 tracks
[track_widx
].filesize
-= len
;
2272 static bool audio_loadcodec(bool start_play
)
2276 char codec_path
[MAX_PATH
]; /* Full path to codec */
2278 DEBUGF("audio_loadcodec(start_play = %s)\n", start_play
? "true" : "false");
2280 if (tracks
[track_widx
].id3_hid
<= 0) {
2281 DEBUGF("track ID3 info not ready\n");
2285 const char * codec_fn
=
2286 get_codec_filename(bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
);
2287 if (codec_fn
== NULL
)
2290 tracks
[track_widx
].codec_hid
= 0;
2294 /* Load the codec directly from disk and save some memory. */
2295 track_ridx
= track_widx
;
2296 ci
.filesize
= CUR_TI
->filesize
;
2297 ci
.id3
= &curtrack_id3
;
2298 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2300 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2301 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
2306 /* If we already have another track than this one buffered */
2307 if (track_widx
!= track_ridx
)
2309 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
2311 /* If the previous codec is the same as this one, there is no need
2312 * to put another copy of it on the file buffer */
2313 if (get_codec_base_type(
2314 bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
) ==
2315 get_codec_base_type(
2316 bufgetid3(tracks
[prev_track
].id3_hid
)->codectype
)
2317 && audio_codec_loaded
)
2319 logf("Reusing prev. codec");
2325 codec_get_full_path(codec_path
, codec_fn
);
2327 fd
= open(codec_path
, O_RDONLY
);
2330 logf("Codec doesn't exist!");
2334 tracks
[track_widx
].codecsize
= filesize(fd
);
2336 tracks
[track_widx
].codec_hid
= bufopen(codec_path
, 0, TYPE_CODEC
);
2337 if (tracks
[track_widx
].codec_hid
< 0)
2339 logf("Not enough space");
2345 logf("Loaded codec");
2350 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2351 static void audio_set_elapsed(struct mp3entry
* id3
)
2353 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
2354 id3
->offset
- id3
->first_frame_offset
: 0;
2357 if ( id3
->has_toc
) {
2358 /* calculate elapsed time using TOC */
2360 unsigned int remainder
, plen
, relpos
, nextpos
;
2362 /* find wich percent we're at */
2363 for (i
=0; i
<100; i
++ )
2364 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
2371 relpos
= id3
->toc
[i
];
2374 nextpos
= id3
->toc
[i
+1];
2378 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
2380 /* set time for this percent (divide before multiply to prevent
2381 overflow on long files. loss of precision is negligible on
2383 id3
->elapsed
= i
* (id3
->length
/ 100);
2385 /* calculate remainder time */
2386 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
2387 id3
->elapsed
+= (((remainder
* 100) / plen
) *
2388 (id3
->length
/ 10000));
2391 /* no TOC exists. set a rough estimate using average bitrate */
2392 int tpk
= id3
->length
/
2393 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
2395 id3
->elapsed
= offset
/ 1024 * tpk
;
2400 /* constant bitrate, use exact calculation */
2401 if (id3
->bitrate
!= 0)
2402 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
2406 /* Load one track by making the appropriate bufopen calls. Return true if
2407 everything required was loaded correctly, false if not. */
2408 static bool audio_load_track(int offset
, bool start_play
)
2413 int file_offset
= 0;
2414 struct mp3entry id3
;
2416 /* Stop buffer filling if there is no free track entries.
2417 Don't fill up the last track entry (we wan't to store next track
2419 if (!audio_have_free_tracks())
2421 logf("No free tracks");
2427 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
2428 /* Get track name from current playlist read position. */
2429 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
2431 /* Handle broken playlists. */
2432 fd
= open(trackname
, O_RDONLY
);
2435 logf("Open failed");
2436 /* Skip invalid entry from playlist. */
2437 playlist_skip_entry(NULL
, last_peek_offset
);
2445 logf("End-of-playlist");
2446 playlist_end
= true;
2450 tracks
[track_widx
].filesize
= filesize(fd
);
2452 /* Set default values */
2455 int last_codec
= current_codec
;
2457 set_current_codec(CODEC_IDX_AUDIO
);
2458 conf_watermark
= AUDIO_DEFAULT_WATERMARK
;
2459 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
2460 conf_preseek
= AUDIO_REBUFFER_GUESS_SIZE
;
2461 dsp_configure(DSP_RESET
, 0);
2462 set_current_codec(last_codec
);
2464 track_changed
= true;
2465 playlist_update_resume_info(audio_current_track());
2468 /* Get track metadata if we don't already have it. */
2469 if (tracks
[track_widx
].id3_hid
<= 0)
2471 if (get_metadata(&id3
, fd
, trackname
))
2473 tracks
[track_widx
].id3_hid
= bufalloc(&id3
, sizeof(struct mp3entry
),
2475 tracks
[track_widx
].taginfo_ready
= (tracks
[track_widx
].id3_hid
> 0);
2477 if (tracks
[track_widx
].id3_hid
<= 0)
2479 DEBUGF("failed to allocate space for metadata\n");
2485 if (track_widx
== track_ridx
)
2486 copy_mp3entry(&curtrack_id3
, &id3
);
2487 else if (track_widx
== ((track_ridx
+ 1) & MAX_TRACK_MASK
))
2488 copy_mp3entry(&nexttrack_id3
, &id3
);
2492 track_changed
= true;
2493 playlist_update_resume_info(audio_current_track());
2498 logf("mde:%s!",trackname
);
2500 /* Skip invalid entry from playlist. */
2501 playlist_skip_entry(NULL
, last_peek_offset
);
2502 tracks
[track_widx
].taginfo_ready
= false;
2511 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
2513 char cuepath
[MAX_PATH
];
2515 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
2517 if (look_for_cuesheet_file(trackname
, cuepath
) &&
2518 parse_cuesheet(cuepath
, cue
))
2520 strcpy((cue
)->audio_filename
, trackname
);
2522 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
2527 /* Load the codec. */
2528 if (!audio_loadcodec(start_play
))
2530 if (tracks
[track_widx
].codecsize
)
2532 /* No space for codec on buffer, not an error */
2533 tracks
[track_widx
].codecsize
= 0;
2537 /* This is an error condition, either no codec was found, or reading
2538 * the codec file failed part way through, either way, skip the track */
2539 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
2540 /* We should not use gui_syncplash from audio thread! */
2541 gui_syncsplash(HZ
*2, msgbuf
);
2542 /* Skip invalid entry from playlist. */
2543 playlist_skip_entry(NULL
, last_peek_offset
);
2544 tracks
[track_widx
].taginfo_ready
= false;
2548 struct mp3entry
*track_id3
;
2550 if (track_widx
== track_ridx
)
2551 track_id3
= &curtrack_id3
;
2552 else if (track_widx
== ((track_ridx
+ 1) & MAX_TRACK_MASK
))
2553 track_id3
= &nexttrack_id3
;
2555 track_id3
= bufgetid3(tracks
[track_widx
].id3_hid
);
2557 set_filebuf_watermark(buffer_margin
);
2558 track_id3
->elapsed
= 0;
2562 switch (track_id3
->codectype
) {
2566 file_offset
= offset
;
2567 track_id3
->offset
= offset
;
2568 audio_set_elapsed(track_id3
);
2573 file_offset
= offset
;
2574 track_id3
->offset
= offset
;
2575 track_id3
->elapsed
= track_id3
->length
/ 2;
2579 case AFMT_OGG_VORBIS
:
2587 track_id3
->offset
= offset
;
2592 logf("alt:%s", trackname
);
2594 tracks
[track_widx
].audio_hid
= bufopen(trackname
, file_offset
, TYPE_AUDIO
);
2596 if (tracks
[track_widx
].audio_hid
<= 0)
2601 request_buffer_handle(tracks
[track_widx
].audio_hid
);
2605 track_widx
&= MAX_TRACK_MASK
;
2610 /* Send callback events to notify about new tracks. */
2611 static void audio_generate_postbuffer_events(void)
2616 logf("Postbuffer:%d/%d",track_ridx
,track_widx
);
2618 if (audio_have_tracks())
2620 cur_idx
= track_ridx
;
2623 if (!tracks
[cur_idx
].event_sent
)
2625 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2627 /* Mark the event 'sent' even if we don't really send one */
2628 tracks
[last_idx
].event_sent
= true;
2629 if (track_buffer_callback
&& tracks
[last_idx
].id3_hid
> 0)
2630 track_buffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), false);
2634 if (cur_idx
== track_widx
)
2637 cur_idx
&= MAX_TRACK_MASK
;
2640 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2642 tracks
[last_idx
].event_sent
= true;
2643 if (track_buffer_callback
&& tracks
[last_idx
].id3_hid
> 0)
2644 track_buffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), true);
2649 static void low_buffer_callback(void)
2651 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
2652 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
2655 static void audio_fill_file_buffer(bool start_play
, size_t offset
)
2657 bool had_next_track
= audio_next_track() != NULL
;
2658 bool continue_buffering
;
2660 /* Must reset the buffer before use if trashed or voice only - voice
2661 file size shouldn't have changed so we can go straight from
2662 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
2663 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
2664 audio_reset_buffer();
2666 logf("Starting buffer fill");
2669 audio_clear_track_entries(false);
2671 /* Save the current resume position once. */
2672 playlist_update_resume_info(audio_current_track());
2675 continue_buffering
= audio_load_track(offset
, start_play
);
2679 } while (continue_buffering
);
2681 if (!had_next_track
&& audio_next_track())
2682 track_changed
= true;
2684 audio_generate_postbuffer_events();
2685 register_buffer_low_callback(low_buffer_callback
);
2688 static void audio_rebuffer(void)
2690 logf("Forcing rebuffer");
2692 clear_track_info(CUR_TI
);
2694 /* Reset track pointers */
2695 track_widx
= track_ridx
;
2696 audio_clear_track_entries(true);
2698 /* Just to make sure none were forgotten */
2699 audio_release_tracks();
2701 /* Fill the buffer */
2702 last_peek_offset
= -1;
2705 if (!CUR_TI
->taginfo_ready
)
2706 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
2708 audio_fill_file_buffer(false, 0);
2711 static int audio_check_new_track(void)
2713 DEBUGF("audio_check_new_track\n");
2715 int track_count
= audio_track_count();
2716 int old_track_ridx
= track_ridx
;
2722 if (playlist_next_dir(ci
.new_track
))
2730 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2731 return Q_CODEC_REQUEST_FAILED
;
2738 /* If the playlist isn't that big */
2739 if (!playlist_check(ci
.new_track
))
2741 if (ci
.new_track
>= 0)
2743 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2744 return Q_CODEC_REQUEST_FAILED
;
2746 /* Find the beginning backward if the user over-skips it */
2747 while (!playlist_check(++ci
.new_track
))
2748 if (ci
.new_track
>= 0)
2750 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2751 return Q_CODEC_REQUEST_FAILED
;
2754 /* Update the playlist */
2755 last_peek_offset
-= ci
.new_track
;
2757 if (!automatic_skip
&& playlist_next(ci
.new_track
) < 0)
2759 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2760 return Q_CODEC_REQUEST_FAILED
;
2766 new_playlist
= false;
2769 /* Save the old track */
2770 /* prev_ti = CUR_TI; */
2771 copy_mp3entry(&prevtrack_id3
, &curtrack_id3
);
2774 for (i
= 0; i
< ci
.new_track
; i
++)
2776 idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
2777 if (handleoffset(tracks
[idx
].audio_hid
) > 0)
2778 clear_track_info(&tracks
[idx
]);
2781 /* Move to the new track */
2782 track_ridx
+= ci
.new_track
;
2783 track_ridx
&= MAX_TRACK_MASK
;
2785 set_base_handle(CUR_TI
->audio_hid
);
2789 playlist_end
= false;
2790 wps_offset
= -ci
.new_track
;
2793 track_changed
= true;
2795 /* If it is not safe to even skip this many track entries */
2796 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
2803 forward
= ci
.new_track
> 0;
2806 /* If the target track is clearly not in memory */
2807 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
2813 /* The track may be in memory, see if it really is */
2816 int cur_idx
= track_ridx
;
2817 bool taginfo_ready
= true;
2818 bool wrap
= track_ridx
> old_track_ridx
;
2823 cur_idx
&= MAX_TRACK_MASK
;
2824 if (!(wrap
|| cur_idx
< old_track_ridx
))
2827 /* If we hit a track in between without valid tag info, bail */
2828 if (!tracks
[cur_idx
].taginfo_ready
)
2830 taginfo_ready
= false;
2841 audio_update_trackinfo();
2842 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2843 return Q_CODEC_REQUEST_COMPLETE
;
2846 void audio_set_track_buffer_event(void (*handler
)(struct mp3entry
*id3
,
2849 track_buffer_callback
= handler
;
2852 void audio_set_track_unbuffer_event(void (*handler
)(struct mp3entry
*id3
,
2855 track_unbuffer_callback
= handler
;
2858 void audio_set_track_changed_event(void (*handler
)(struct mp3entry
*id3
))
2860 track_changed_callback
= handler
;
2863 unsigned long audio_prev_elapsed(void)
2865 return prev_track_elapsed
;
2868 static void audio_stop_codec_flush(void)
2870 ci
.stop_codec
= true;
2873 while (audio_codec_loaded
)
2876 /* If the audio codec is not loaded any more, and the audio is still
2877 * playing, it is now and _only_ now safe to call this function from the
2879 if (pcm_is_playing())
2881 pcmbuf_pause(paused
);
2884 static void audio_stop_playback(void)
2886 /* If we were playing, save resume information */
2889 struct mp3entry
*id3
= NULL
;
2891 if (!playlist_end
|| !ci
.stop_codec
)
2893 /* Set this early, the outside code yields and may allow the codec
2894 to try to wait for a reply on a buffer wait */
2895 ci
.stop_codec
= true;
2896 id3
= audio_current_track();
2899 /* Save the current playing spot, or NULL if the playlist has ended */
2900 playlist_update_resume_info(id3
);
2902 prev_track_elapsed
= curtrack_id3
.elapsed
;
2904 /* Increment index so runtime info is saved in audio_clear_track_entries().
2905 * Done here, as audio_stop_playback() may be called more than once.
2906 * Don't update runtime unless playback is stopped because of end of playlist.
2907 * Updating runtime when manually stopping a tracks, can destroy autoscores
2913 track_ridx
&= MAX_TRACK_MASK
;
2918 audio_stop_codec_flush();
2921 /* Close all tracks */
2922 audio_release_tracks();
2924 /* Mark all entries null. */
2925 audio_clear_track_entries(false);
2927 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
2928 memset(&nexttrack_id3
, 0, sizeof(struct mp3entry
));
2931 static void audio_play_start(size_t offset
)
2933 #if INPUT_SRC_CAPS != 0
2934 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
2935 audio_set_output_source(AUDIO_SRC_PLAYBACK
);
2938 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2940 audio_stop_codec_flush();
2942 track_changed
= true;
2943 playlist_end
= false;
2951 sound_set_volume(global_settings
.volume
);
2952 track_widx
= track_ridx
= 0;
2954 /* Mark all entries null. */
2955 memset(tracks
, 0, sizeof(struct track_info
) * MAX_TRACK
);
2957 last_peek_offset
= -1;
2959 /* Officially playing */
2960 queue_reply(&audio_queue
, 1);
2962 audio_fill_file_buffer(true, offset
);
2964 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2965 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
2969 /* Invalidates all but currently playing track. */
2970 static void audio_invalidate_tracks(void)
2972 if (audio_have_tracks())
2974 last_peek_offset
= 0;
2975 playlist_end
= false;
2976 track_widx
= track_ridx
;
2978 /* Mark all other entries null (also buffered wrong metadata). */
2979 audio_clear_track_entries(true);
2981 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
2983 audio_fill_file_buffer(false, 0);
2987 static void audio_new_playlist(void)
2989 /* Prepare to start a new fill from the beginning of the playlist */
2990 last_peek_offset
= -1;
2991 if (audio_have_tracks())
2994 skipped_during_pause
= true;
2995 playlist_end
= false;
2996 track_widx
= track_ridx
;
2997 audio_clear_track_entries(true);
3000 track_widx
&= MAX_TRACK_MASK
;
3002 /* Mark the current track as invalid to prevent skipping back to it */
3003 CUR_TI
->taginfo_ready
= false;
3006 /* Signal the codec to initiate a track change forward */
3007 new_playlist
= true;
3010 /* Officially playing */
3011 queue_reply(&audio_queue
, 1);
3013 audio_fill_file_buffer(false, 0);
3016 static void audio_initiate_track_change(long direction
)
3018 playlist_end
= false;
3019 ci
.new_track
+= direction
;
3020 wps_offset
-= direction
;
3022 skipped_during_pause
= true;
3025 static void audio_initiate_dir_change(long direction
)
3027 playlist_end
= false;
3029 ci
.new_track
= direction
;
3031 skipped_during_pause
= true;
3035 * Layout audio buffer as follows - iram buffer depends on target:
3036 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
3038 static void audio_reset_buffer(void)
3040 /* see audio_get_recording_buffer if this is modified */
3041 logf("audio_reset_buffer");
3043 /* If the setup of anything allocated before the file buffer is
3044 changed, do check the adjustments after the buffer_alloc call
3045 as it will likely be affected and need sliding over */
3047 /* Initially set up file buffer as all space available */
3048 malloc_buf
= audiobuf
+ talk_get_bufsize();
3049 /* Align the malloc buf to line size. Especially important to cf
3050 targets that do line reads/writes. */
3051 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
3052 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
3053 filebuflen
= audiobufend
- filebuf
;
3055 /* Allow for codec swap space at end of audio buffer */
3056 if (talk_voice_required())
3058 /* Layout of swap buffer:
3059 * #ifdef IRAM_STEAL (dedicated iram_buf):
3060 * |iram_buf|...audiobuf...|dram_buf|audiobufend
3062 * audiobuf...|dram_buf|iram_buf|audiobufend
3064 #ifdef PLAYBACK_VOICE
3065 /* Check for an absolutely nasty situation which should never,
3066 ever happen - frankly should just panic */
3067 if (voice_codec_loaded
&& current_codec
!= CODEC_IDX_VOICE
)
3069 logf("buffer reset with voice swapped");
3071 /* line align length which line aligns the calculations below since
3072 all sizes are also at least line aligned - needed for memswap128 */
3075 filebuflen
-= CODEC_SIZE
;
3077 filebuflen
-= CODEC_SIZE
+ CODEC_IRAM_SIZE
;
3079 /* Allocate buffers for swapping voice <=> audio */
3080 /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
3081 and out of the way of buffer usage or else a call to audio_get_buffer
3082 and subsequent buffer use might trash the swap space. A plugin
3083 initializing IRAM after getting the full buffer would present similar
3084 problem. Options include: failing the request if the other buffer
3085 has been obtained already or never allowing use of the voice IRAM
3086 buffer within the audio buffer. Using buffer_alloc basically
3087 implements the second in a more convenient way. */
3088 dram_buf
= filebuf
+ filebuflen
;
3091 /* Allocate voice IRAM swap buffer once */
3092 if (iram_buf
== NULL
)
3094 iram_buf
= buffer_alloc(CODEC_IRAM_SIZE
);
3095 /* buffer_alloc moves audiobuf; this is safe because only the end
3096 * has been touched so far in this function and the address of
3097 * filebuf + filebuflen is not changed */
3098 malloc_buf
+= CODEC_IRAM_SIZE
;
3099 filebuf
+= CODEC_IRAM_SIZE
;
3100 filebuflen
-= CODEC_IRAM_SIZE
;
3103 /* Allocate iram_buf after dram_buf */
3104 iram_buf
= dram_buf
+ CODEC_SIZE
;
3105 #endif /* IRAM_STEAL */
3106 #endif /* PLAYBACK_VOICE */
3110 #ifdef PLAYBACK_VOICE
3111 /* No swap buffers needed */
3117 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
3118 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
3120 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
3121 will already be line aligned */
3124 /* Set the high watermark as 75% full...or 25% empty :) */
3126 high_watermark
= 3*filebuflen
/ 4;
3129 /* Clear any references to the file buffer */
3130 buffer_state
= BUFFER_STATE_INITIALIZED
;
3132 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
3133 /* Make sure everything adds up - yes, some info is a bit redundant but
3134 aids viewing and the sumation of certain variables should add up to
3135 the location of others. */
3138 unsigned char * pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
3139 logf("mabuf: %08X", (unsigned)malloc_buf
);
3140 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
3141 logf("fbuf: %08X", (unsigned)filebuf
);
3142 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
3143 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
3144 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
3145 logf("pcmb: %08X", (unsigned)pcmbuf
);
3146 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
3149 logf("dramb: %08X", (unsigned)dram_buf
);
3150 logf("drambe: %08X", (unsigned)(dram_buf
+ CODEC_SIZE
));
3154 logf("iramb: %08X", (unsigned)iram_buf
);
3155 logf("irambe: %08X", (unsigned)(iram_buf
+ CODEC_IRAM_SIZE
));
3161 static void audio_thread(void)
3163 struct queue_event ev
;
3167 #ifdef PLAYBACK_VOICE
3168 /* Unlock semaphore that init stage locks before creating this thread */
3169 semaphore_release(&sem_codecthread
);
3171 /* Buffers must be set up by now - should panic - really */
3172 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
3174 logf("audio_thread start: no buffer");
3177 /* Have to wait for voice to load up or else the codec swap will be
3178 invalid when an audio codec is loaded */
3179 wait_for_voice_swap_in();
3184 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
3187 case Q_AUDIO_FILL_BUFFER
:
3188 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3189 if (!playing
|| playlist_end
|| ci
.stop_codec
)
3191 audio_fill_file_buffer(false, 0);
3195 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3196 if (playing
&& ev
.data
<= 0)
3197 audio_new_playlist();
3200 audio_stop_playback();
3201 audio_play_start((size_t)ev
.data
);
3206 LOGFQUEUE("audio < Q_AUDIO_STOP");
3208 audio_stop_playback();
3210 queue_clear(&audio_queue
);
3214 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3215 if (!(bool) ev
.data
&& skipped_during_pause
&& !pcmbuf_is_crossfade_active())
3216 pcmbuf_play_stop(); /* Flush old track on resume after skip */
3217 skipped_during_pause
= false;
3220 pcmbuf_pause((bool)ev
.data
);
3221 paused
= (bool)ev
.data
;
3225 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3226 audio_initiate_track_change((long)ev
.data
);
3229 case Q_AUDIO_PRE_FF_REWIND
:
3230 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3236 case Q_AUDIO_FF_REWIND
:
3237 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3240 ci
.seek_time
= (long)ev
.data
+1;
3243 case Q_AUDIO_CHECK_NEW_TRACK
:
3244 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3245 queue_reply(&audio_queue
, audio_check_new_track());
3248 case Q_AUDIO_DIR_SKIP
:
3249 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3250 playlist_end
= false;
3251 audio_initiate_dir_change(ev
.data
);
3255 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3256 audio_invalidate_tracks();
3259 case Q_AUDIO_TRACK_CHANGED
:
3260 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3263 playlist_next(-wps_offset
);
3265 automatic_skip
= false;
3266 prevtrack_id3
.path
[0] = 0;
3268 if (track_changed_callback
)
3269 track_changed_callback(&curtrack_id3
);
3270 track_changed
= true;
3271 playlist_update_resume_info(audio_current_track());
3275 case SYS_USB_CONNECTED
:
3276 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3278 audio_stop_playback();
3279 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
3280 usb_wait_for_disconnect(&audio_queue
);
3285 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3289 //LOGFQUEUE("audio < default");
3295 #ifdef ROCKBOX_HAS_LOGF
3296 static void audio_test_track_changed_event(struct mp3entry
*id3
)
3300 logf("tce:%s", id3
->path
);
3304 /* Initialize the audio system - called from init() in main.c.
3305 * Last function because of all the references to internal symbols
3307 void audio_init(void)
3309 #ifdef PLAYBACK_VOICE
3310 static bool voicetagtrue
= true;
3311 static struct mp3entry id3_voice
;
3312 struct thread_entry
*voice_thread_p
= NULL
;
3314 struct thread_entry
*audio_thread_p
;
3316 /* Can never do this twice */
3317 if (audio_is_initialized
)
3319 logf("audio: already initialized");
3323 logf("audio: initializing");
3325 /* Initialize queues before giving control elsewhere in case it likes
3326 to send messages. Thread creation will be delayed however so nothing
3327 starts running until ready if something yields such as talk_init. */
3328 #ifdef PLAYBACK_VOICE
3329 /* Take ownership of lock to prevent playback of anything before audio
3330 hardware is initialized - audio thread unlocks it after final init
3332 semaphore_init(&sem_codecthread
, 1, 0);
3333 event_init(&event_codecthread
, EVENT_MANUAL
| STATE_SIGNALED
);
3335 queue_init(&audio_queue
, true);
3336 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
3337 queue_init(&codec_queue
, true);
3338 queue_enable_queue_send(&codec_queue
, &codec_queue_sender_list
);
3342 #ifdef ROCKBOX_HAS_LOGF
3343 audio_set_track_changed_event(audio_test_track_changed_event
);
3346 /* Initialize codec api. */
3347 ci
.read_filebuf
= codec_filebuf_callback
;
3348 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
3349 ci
.get_codec_memory
= codec_get_memory_callback
;
3350 ci
.request_buffer
= codec_request_buffer_callback
;
3351 ci
.advance_buffer
= codec_advance_buffer_callback
;
3352 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
3353 ci
.request_next_track
= codec_request_next_track_callback
;
3354 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
3355 ci
.seek_buffer
= codec_seek_buffer_callback
;
3356 ci
.seek_complete
= codec_seek_complete_callback
;
3357 ci
.set_elapsed
= codec_set_elapsed_callback
;
3358 ci
.set_offset
= codec_set_offset_callback
;
3359 ci
.configure
= codec_configure_callback
;
3360 ci
.discard_codec
= codec_discard_codec_callback
;
3362 /* Initialize voice codec api. */
3363 #ifdef PLAYBACK_VOICE
3364 memcpy(&ci_voice
, &ci
, sizeof(ci_voice
));
3365 memset(&id3_voice
, 0, sizeof(id3_voice
));
3366 ci_voice
.read_filebuf
= voice_filebuf_callback
;
3367 ci_voice
.pcmbuf_insert
= voice_pcmbuf_insert_callback
;
3368 ci_voice
.get_codec_memory
= voice_get_memory_callback
;
3369 ci_voice
.request_buffer
= voice_request_buffer_callback
;
3370 ci_voice
.advance_buffer
= voice_advance_buffer_callback
;
3371 ci_voice
.advance_buffer_loc
= voice_advance_buffer_loc_callback
;
3372 ci_voice
.request_next_track
= voice_request_next_track_callback
;
3373 ci_voice
.mp3_get_filepos
= voice_mp3_get_filepos_callback
;
3374 ci_voice
.seek_buffer
= voice_seek_buffer_callback
;
3375 ci_voice
.seek_complete
= voice_do_nothing
;
3376 ci_voice
.set_elapsed
= voice_set_elapsed_callback
;
3377 ci_voice
.set_offset
= voice_set_offset_callback
;
3378 ci_voice
.configure
= voice_configure_callback
;
3379 ci_voice
.discard_codec
= voice_do_nothing
;
3380 ci_voice
.taginfo_ready
= &voicetagtrue
;
3381 ci_voice
.id3
= &id3_voice
;
3382 id3_voice
.frequency
= 11200;
3383 id3_voice
.length
= 1000000L;
3386 /* initialize the buffer */
3389 /* audio_reset_buffer must to know the size of voice buffer so init
3393 codec_thread_p
= create_thread(
3394 codec_thread
, codec_stack
, sizeof(codec_stack
),
3395 CREATE_THREAD_FROZEN
,
3396 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
3399 audio_thread_p
= create_thread(audio_thread
, audio_stack
,
3400 sizeof(audio_stack
), CREATE_THREAD_FROZEN
,
3401 audio_thread_name
IF_PRIO(, PRIORITY_BACKGROUND
)
3404 #ifdef PLAYBACK_VOICE
3405 /* TODO: Change this around when various speech codecs can be used */
3406 if (talk_voice_required())
3408 logf("Starting voice codec");
3409 queue_init(&voice_queue
, true);
3410 voice_thread_p
= create_thread(voice_thread
, voice_stack
,
3411 sizeof(voice_stack
), CREATE_THREAD_FROZEN
,
3413 IF_PRIO(, PRIORITY_PLAYBACK
) IF_COP(, CPU
));
3417 /* Set crossfade setting for next buffer init which should be about... */
3418 pcmbuf_crossfade_enable(global_settings
.crossfade
);
3420 /* ...now! Set up the buffers */
3421 audio_reset_buffer();
3423 buffering_init(filebuf
, filebuflen
);
3425 /* Probably safe to say */
3426 audio_is_initialized
= true;
3428 sound_settings_apply();
3430 eq_hw_enable(global_settings
.eq_hw_enabled
);
3432 #ifndef HAVE_FLASH_STORAGE
3433 audio_set_buffer_margin(global_settings
.buffer_margin
);
3436 /* it's safe to let the threads run now */
3437 thread_thaw(codec_thread_p
);
3438 #ifdef PLAYBACK_VOICE
3440 thread_thaw(voice_thread_p
);
3442 thread_thaw(audio_thread_p
);