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 /* default point to start buffer refill */
92 #define AUDIO_DEFAULT_WATERMARK (1024*512)
93 /* amount of data to read in one read() call */
94 #define AUDIO_DEFAULT_FILECHUNK (1024*32)
95 /* amount of guess-space to allow for codecs that must hunt and peck
96 * for their correct seeek target, 32k seems a good size */
97 #define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
99 /* Define LOGF_ENABLE to enable logf output in this file */
100 /*#define LOGF_ENABLE*/
103 /* macros to enable logf for queues
104 logging on SYS_TIMEOUT can be disabled */
106 /* Define this for logf output of all queuing except SYS_TIMEOUT */
107 #define PLAYBACK_LOGQUEUES
108 /* Define this to logf SYS_TIMEOUT messages */
109 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
112 #ifdef PLAYBACK_LOGQUEUES
113 #define LOGFQUEUE logf
115 #define LOGFQUEUE(...)
118 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
119 #define LOGFQUEUE_SYS_TIMEOUT logf
121 #define LOGFQUEUE_SYS_TIMEOUT(...)
125 /* Define one constant that includes recording related functionality */
126 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
127 #define AUDIO_HAVE_RECORDING
135 Q_AUDIO_PRE_FF_REWIND
,
137 Q_AUDIO_CHECK_NEW_TRACK
,
139 Q_AUDIO_TRACK_CHANGED
,
143 Q_CODEC_REQUEST_COMPLETE
,
144 Q_CODEC_REQUEST_FAILED
,
152 #ifdef AUDIO_HAVE_RECORDING
158 /* As defined in plugins/lib/xxx2wav.h */
160 #define MALLOC_BUFSIZE (512*1024)
161 #define GUARD_BUFSIZE (32*1024)
163 #define MALLOC_BUFSIZE (100*1024)
164 #define GUARD_BUFSIZE (8*1024)
167 /* As defined in plugin.lds */
169 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
170 #define CODEC_IRAM_SIZE ((size_t)0xc000)
171 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
172 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
173 #define CODEC_IRAM_SIZE ((size_t)0x10000)
175 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
176 #define CODEC_IRAM_SIZE ((size_t)0xc000)
179 #ifndef IBSS_ATTR_VOICE_STACK
180 #define IBSS_ATTR_VOICE_STACK IBSS_ATTR
183 bool audio_is_initialized
= false;
185 /* Variables are commented with the threads that use them: *
186 * A=audio, C=codec, V=voice. A suffix of - indicates that *
187 * the variable is read but not updated on that thread. */
188 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
190 /* Main state control */
191 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR
= false; /* Codec loaded? (C/A-) */
192 static volatile bool playing NOCACHEBSS_ATTR
= false; /* Is audio playing? (A) */
193 static volatile bool paused NOCACHEBSS_ATTR
= false; /* Is audio paused? (A/C-) */
195 /* Ring buffer where compressed audio and codecs are loaded */
196 static unsigned char *filebuf
= NULL
; /* Start of buffer (A/C-) */
197 static unsigned char *malloc_buf
= NULL
; /* Start of malloc buffer (A/C-) */
198 /* FIXME: make filebuflen static */
199 size_t filebuflen
= 0; /* Size of buffer (A/C-) */
200 /* FIXME: make buf_ridx (C/A-) */
202 /* Possible arrangements of the buffer */
203 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
204 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
205 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
206 static int buffer_state
= BUFFER_STATE_TRASHED
; /* Buffer state */
208 static struct mp3entry prevtrack_id3
;
209 static struct mp3entry curtrack_id3
;
210 static struct mp3entry nexttrack_id3
;
212 /* Track info structure about songs in the file buffer (A/C-) */
214 int audio_hid
; /* The ID for the track's buffer handle */
215 int id3_hid
; /* The ID for the track's metadata handle */
216 int codec_hid
; /* The ID for the track's codec handle */
218 size_t filesize
; /* File total length */
220 bool taginfo_ready
; /* Is metadata read */
222 bool event_sent
; /* Was this track's buffered event sent */
225 static struct track_info tracks
[MAX_TRACK
];
226 static volatile int track_ridx
= 0; /* Track being decoded (A/C-) */
227 static int track_widx
= 0; /* Track being buffered (A) */
229 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
231 /* Set by the audio thread when the current track information has updated
232 * and the WPS may need to update its cached information */
233 static bool track_changed
= false;
235 /* Information used only for filling the buffer */
236 /* Playlist steps from playing track to next track to be buffered (A) */
237 static int last_peek_offset
= 0;
239 /* Scrobbler support */
240 static unsigned long prev_track_elapsed
= 0; /* Previous track elapsed time (C/A-)*/
242 /* Track change controls */
243 static bool automatic_skip
= false; /* Who initiated in-progress skip? (C/A-) */
244 static bool playlist_end
= false; /* Has the current playlist ended? (A) */
245 static bool dir_skip
= false; /* Is a directory skip pending? (A) */
246 static bool new_playlist
= false; /* Are we starting a new playlist? (A) */
247 static int wps_offset
= 0; /* Pending track change offset, to keep WPS responsive (A) */
248 static bool skipped_during_pause
= false; /* Do we need to clear the PCM buffer when playback resumes (A) */
250 /* Callbacks which applications or plugins may set */
251 /* When the playing track has changed from the user's perspective */
252 void (*track_changed_callback
)(struct mp3entry
*id3
) = NULL
;
253 /* When a track has been buffered */
254 void (*track_buffer_callback
)(struct mp3entry
*id3
) = NULL
;
255 /* When a track's buffer has been overwritten or cleared */
256 void (*track_unbuffer_callback
)(struct mp3entry
*id3
) = NULL
;
258 static size_t buffer_margin
= 0; /* Buffer margin aka anti-skip buffer (A/C-) */
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
, size_t max
);
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 static 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 static bool clear_track_info(struct track_info
*track
)
368 if (track
->codec_hid
> 0) {
369 if (bufclose(track
->codec_hid
))
370 track
->codec_hid
= 0;
375 if (track
->id3_hid
> 0) {
376 if (bufclose(track
->id3_hid
))
382 if (track
->audio_hid
> 0) {
383 if (bufclose(track
->audio_hid
))
384 track
->audio_hid
= 0;
389 memset(track
, 0, sizeof(struct track_info
));
393 /* --- External interfaces --- */
395 void mp3_play_data(const unsigned char* start
, int size
,
396 void (*get_more
)(unsigned char** start
, size_t* size
))
398 #ifdef PLAYBACK_VOICE
399 static struct voice_info voice_clip
;
400 voice_clip
.callback
= get_more
;
401 voice_clip
.buf
= (unsigned char*)start
;
402 voice_clip
.size
= size
;
403 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
404 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
405 LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
406 queue_post(&voice_queue
, Q_VOICE_PLAY
, (intptr_t)&voice_clip
);
407 voice_thread_start
= true;
416 void mp3_play_stop(void)
418 #ifdef PLAYBACK_VOICE
419 queue_remove_from_head(&voice_queue
, Q_VOICE_STOP
);
420 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
421 queue_post(&voice_queue
, Q_VOICE_STOP
, 1);
425 void mp3_play_pause(bool play
)
431 bool mp3_is_playing(void)
433 #ifdef PLAYBACK_VOICE
434 return voice_is_playing
;
440 /* If voice could be swapped out - wait for it to return
441 * Used by buffer claming functions.
443 static void wait_for_voice_swap_in(void)
445 #ifdef PLAYBACK_VOICE
446 if (NULL
== iram_buf
)
449 event_wait(&event_codecthread
, STATE_NONSIGNALED
);
450 #endif /* PLAYBACK_VOICE */
453 /* This sends a stop message and the audio thread will dump all it's
454 subsequenct messages */
455 static void audio_hard_stop(void)
458 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
459 queue_send(&audio_queue
, Q_AUDIO_STOP
, 1);
462 unsigned char *audio_get_buffer(bool talk_buf
, size_t *buffer_size
)
464 unsigned char *buf
, *end
;
466 if (audio_is_initialized
)
469 wait_for_voice_swap_in();
470 #ifdef PLAYBACK_VOICE
474 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
476 if (buffer_size
== NULL
)
478 /* Special case for talk_init to use since it already knows it's
480 buffer_state
= BUFFER_STATE_TRASHED
;
484 if (talk_buf
|| buffer_state
== BUFFER_STATE_TRASHED
485 || !talk_voice_required())
487 logf("get buffer: talk, audio");
488 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
489 the talk buffer is not needed because voice isn't being used, or
490 could be BUFFER_STATE_TRASHED already. If state is
491 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
492 without the caller knowing what's going on. Changing certain settings
493 may move it to a worse condition but the memory in use by something
494 else will remain undisturbed.
496 if (buffer_state
!= BUFFER_STATE_TRASHED
)
499 buffer_state
= BUFFER_STATE_TRASHED
;
507 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
508 still BUFFER_STATE_INITIALIZED */
509 /* Skip talk buffer and move pcm buffer to end to maximize available
510 contiguous memory - no audio running means voice will not need the
512 logf("get buffer: audio");
513 buf
= audiobuf
+ talk_get_bufsize();
514 end
= audiobufend
- pcmbuf_init(audiobufend
);
515 buffer_state
= BUFFER_STATE_VOICED_ONLY
;
518 *buffer_size
= end
- buf
;
524 void audio_iram_steal(void)
526 /* We need to stop audio playback in order to use codec IRAM */
529 #ifdef PLAYBACK_VOICE
530 if (NULL
!= iram_buf
)
532 /* Can't already be stolen */
533 if (voice_iram_stolen
)
536 /* Must wait for voice to be current again if it is swapped which
537 would cause the caller's buffer to get clobbered when voice locks
538 and runs - we'll wait for it to lock and yield again then make sure
539 the ride has come to a complete stop */
540 wait_for_voice_swap_in();
543 /* Save voice IRAM but just memcpy - safe to do here since voice
544 is current and no audio codec is loaded */
545 memcpy(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
546 voice_iram_stolen
= true;
550 /* Nothing much to do if no voice */
551 voice_iram_stolen
= false;
555 #endif /* IRAM_STEAL */
557 #ifdef HAVE_RECORDING
558 unsigned char *audio_get_recording_buffer(size_t *buffer_size
)
560 /* Don't allow overwrite of voice swap area or we'll trash the
561 swapped-out voice codec but can use whole thing if none */
564 /* Stop audio and voice. Wait for voice to swap in and be clear
565 of pending events to ensure trouble-free operation of encoders */
567 wait_for_voice_swap_in();
568 #ifdef PLAYBACK_VOICE
573 #ifdef PLAYBACK_VOICE
574 /* If no dram_buf, swap space not used and recording gets more
575 memory. Codec swap areas will remain unaffected by the next init
576 since they're allocated at the end of the buffer and their sizes
577 don't change between calls */
580 #endif /* PLAYBACK_VOICE */
583 buffer_state
= BUFFER_STATE_TRASHED
;
585 *buffer_size
= end
- audiobuf
;
587 return (unsigned char *)audiobuf
;
590 bool audio_load_encoder(int afmt
)
593 const char *enc_fn
= get_codec_filename(afmt
| CODEC_TYPE_ENCODER
);
597 audio_remove_encoder();
598 ci
.enc_codec_loaded
= 0; /* clear any previous error condition */
600 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
601 queue_post(&codec_queue
, Q_ENCODER_LOAD_DISK
, (intptr_t)enc_fn
);
603 while (ci
.enc_codec_loaded
== 0)
606 logf("codec loaded: %d", ci
.enc_codec_loaded
);
608 return ci
.enc_codec_loaded
> 0;
613 } /* audio_load_encoder */
615 void audio_remove_encoder(void)
618 /* force encoder codec unload (if currently loaded) */
619 if (ci
.enc_codec_loaded
<= 0)
622 ci
.stop_encoder
= true;
623 while (ci
.enc_codec_loaded
> 0)
626 } /* audio_remove_encoder */
628 #endif /* HAVE_RECORDING */
630 struct mp3entry
* audio_current_track(void)
632 const char *filename
;
634 static struct mp3entry temp_id3
;
636 int offset
= ci
.new_track
+ wps_offset
;
638 cur_idx
= track_ridx
+ offset
;
639 cur_idx
&= MAX_TRACK_MASK
;
641 if (cur_idx
== track_ridx
&& *curtrack_id3
.path
)
642 return &curtrack_id3
;
643 else if (offset
== -1 && *prevtrack_id3
.path
)
644 return &prevtrack_id3
;
645 else if (tracks
[cur_idx
].id3_hid
> 0)
646 return bufgetid3(tracks
[cur_idx
].id3_hid
);
648 memset(&temp_id3
, 0, sizeof(struct mp3entry
));
650 filename
= playlist_peek(0);
652 filename
= "No file!";
654 #ifdef HAVE_TC_RAMCACHE
655 if (tagcache_fill_tags(&temp_id3
, filename
))
659 p
= strrchr(filename
, '/');
665 strncpy(temp_id3
.path
, p
, sizeof(temp_id3
.path
)-1);
666 temp_id3
.title
= &temp_id3
.path
[0];
671 struct mp3entry
* audio_next_track(void)
673 int next_idx
= track_ridx
;
675 if (!audio_have_tracks())
678 if (wps_offset
== -1 && *prevtrack_id3
.path
)
679 return &curtrack_id3
;
682 next_idx
&= MAX_TRACK_MASK
;
684 if (tracks
[next_idx
].id3_hid
<= 0)
687 return &nexttrack_id3
;
690 bool audio_has_changed_track(void)
694 track_changed
= false;
701 void audio_play(long offset
)
705 #ifdef PLAYBACK_VOICE
706 /* Truncate any existing voice output so we don't have spelling
707 * etc. over the first part of the played track */
712 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset
);
713 /* Don't return until playback has actually started */
714 queue_send(&audio_queue
, Q_AUDIO_PLAY
, offset
);
717 void audio_stop(void)
720 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
721 /* Don't return until playback has actually stopped */
722 queue_send(&audio_queue
, Q_AUDIO_STOP
, 0);
725 void audio_pause(void)
727 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
728 /* Don't return until playback has actually paused */
729 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, true);
732 void audio_resume(void)
734 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
735 /* Don't return until playback has actually resumed */
736 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, false);
739 void audio_next(void)
741 if (playlist_check(ci
.new_track
+ wps_offset
+ 1))
743 if (global_settings
.beep
)
744 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
746 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
747 queue_post(&audio_queue
, Q_AUDIO_SKIP
, 1);
748 /* Update wps while our message travels inside deep playback queues. */
750 track_changed
= true;
754 /* No more tracks. */
755 if (global_settings
.beep
)
756 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
760 void audio_prev(void)
762 if (playlist_check(ci
.new_track
+ wps_offset
- 1))
764 if (global_settings
.beep
)
765 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
767 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
768 queue_post(&audio_queue
, Q_AUDIO_SKIP
, -1);
769 /* Update wps while our message travels inside deep playback queues. */
771 track_changed
= true;
775 /* No more tracks. */
776 if (global_settings
.beep
)
777 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
781 void audio_next_dir(void)
783 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
784 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, 1);
787 void audio_prev_dir(void)
789 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
790 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, -1);
793 void audio_pre_ff_rewind(void)
795 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
796 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
799 void audio_ff_rewind(long newpos
)
801 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
802 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, newpos
);
805 void audio_flush_and_reload_tracks(void)
807 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
808 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
811 void audio_error_clear(void)
813 #ifdef AUDIO_HAVE_RECORDING
814 pcm_rec_error_clear();
818 int audio_status(void)
823 ret
|= AUDIO_STATUS_PLAY
;
826 ret
|= AUDIO_STATUS_PAUSE
;
828 #ifdef HAVE_RECORDING
829 /* Do this here for constitency with mpeg.c version */
830 ret
|= pcm_rec_status();
836 int audio_get_file_pos(void)
841 #ifndef HAVE_FLASH_STORAGE
842 void audio_set_buffer_margin(int setting
)
844 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
845 buffer_margin
= lookup
[setting
];
846 logf("buffer margin: %ld", buffer_margin
);
847 set_filebuf_watermark(buffer_margin
, 0);
851 /* Take nescessary steps to enable or disable the crossfade setting */
852 void audio_set_crossfade(int enable
)
858 /* Tell it the next setting to use */
859 pcmbuf_crossfade_enable(enable
);
861 /* Return if size hasn't changed or this is too early to determine
862 which in the second case there's no way we could be playing
864 if (pcmbuf_is_same_size())
866 /* This function is a copout and just syncs some variables -
867 to be removed at a later date */
868 pcmbuf_crossfade_enable_finished();
873 was_playing
= playing
;
875 /* Playback has to be stopped before changing the buffer size */
878 /* Store the track resume position */
879 offset
= curtrack_id3
.offset
;
880 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK
));
883 /* Blast it - audio buffer will have to be setup again next time
885 audio_get_buffer(true, &size
);
887 /* Restart playback if audio was running previously */
892 /* --- Routines called from multiple threads --- */
893 static void set_current_codec(int codec_idx
)
895 current_codec
= codec_idx
;
896 dsp_configure(DSP_SWITCH_CODEC
, codec_idx
);
899 #ifdef PLAYBACK_VOICE
900 static void swap_codec(void)
904 /* Swap nothing if no swap buffers exist */
905 if (dram_buf
== NULL
)
907 logf("swap: no swap buffers");
911 my_codec
= current_codec
;
913 logf("swapping out codec: %d", my_codec
);
915 /* Invert this when a codec thread enters and leaves */
916 swap_codec_parity
= !swap_codec_parity
;
918 /* If this is true, an odd number of calls has occurred and there's
919 no codec thread waiting to swap us out when it locks and runs. This
920 occurs when playback is stopped or when just starting playback and
921 the audio thread is loading a codec; parities should always be even
922 on entry when a thread calls this during playback */
923 if (swap_codec_parity
)
925 /* Save our current IRAM and DRAM */
927 if (voice_iram_stolen
)
929 logf("swap: iram restore");
930 voice_iram_stolen
= false;
931 /* Don't swap trashed data into buffer as the voice IRAM will
932 already be swapped out - should _always_ be the case if
933 voice_iram_stolen is true since the voice has been swapped
935 if (my_codec
== CODEC_IDX_VOICE
)
937 logf("voice iram already swapped");
943 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
949 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
950 /* No cache invalidation needed; it will be done in codec_load_ram
951 or we won't be here otherwise */
954 /* Release my semaphore */
955 semaphore_release(&sem_codecthread
);
956 logf("unlocked: %d", my_codec
);
958 /* Wait for other codec */
959 event_wait(&event_codecthread
,
960 (my_codec
== CODEC_IDX_AUDIO
) ? STATE_NONSIGNALED
: STATE_SIGNALED
);
962 /* Wait for other codec to unlock */
963 logf("waiting for lock: %d", my_codec
);
964 semaphore_wait(&sem_codecthread
);
967 set_current_codec(my_codec
);
968 event_set_state(&event_codecthread
,
969 (my_codec
== CODEC_IDX_AUDIO
) ? STATE_SIGNALED
: STATE_NONSIGNALED
);
971 /* Reload our IRAM and DRAM */
972 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
973 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
976 /* Flip parity again */
977 swap_codec_parity
= !swap_codec_parity
;
979 logf("resuming codec: %d", my_codec
);
982 /* This function is meant to be used by the buffer stealing functions to
983 ensure the codec is no longer active and so voice will be swapped-in
984 before it is called */
985 static void voice_stop(void)
987 /* Must have a voice codec loaded or we'll hang forever here */
988 if (!voice_codec_loaded
)
993 /* Loop until voice empties it's queue, stops and picks up on the new
994 track; the voice thread must be stopped and waiting for messages
996 while (voice_is_playing
|| !queue_empty(&voice_queue
) ||
1004 /* Is voice still speaking */
1005 /* Unfortunately only reliable when music is not also playing. */
1006 static bool is_voice_speaking(void)
1008 return is_voice_queued()
1010 || (!playing
&& pcm_is_playing());
1013 #endif /* PLAYBACK_VOICE */
1015 /* Wait for voice to finish speaking. */
1016 /* Also only reliable when music is not also playing. */
1017 void voice_wait(void)
1019 #ifdef PLAYBACK_VOICE
1020 while (is_voice_speaking())
1025 static void set_filebuf_watermark(int seconds
, size_t max
)
1030 return; /* Audio buffers not yet set up */
1032 bytes
= seconds
?MAX(curtrack_id3
.bitrate
* seconds
* (1000/8), max
):max
;
1033 bytes
= MIN(bytes
, filebuflen
/ 2);
1034 buf_set_conf(BUFFERING_SET_WATERMARK
, bytes
);
1037 const char * get_codec_filename(int cod_spec
)
1041 #ifdef HAVE_RECORDING
1042 /* Can choose decoder or encoder if one available */
1043 int type
= cod_spec
& CODEC_TYPE_MASK
;
1044 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
1046 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
1047 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
1049 fname
= (type
== CODEC_TYPE_ENCODER
) ?
1050 audio_formats
[afmt
].codec_enc_root_fn
:
1051 audio_formats
[afmt
].codec_root_fn
;
1054 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
1055 afmt
, fname
? fname
: "<unknown>");
1056 #else /* !HAVE_RECORDING */
1057 /* Always decoder */
1058 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
1059 cod_spec
= AFMT_UNKNOWN
;
1060 fname
= audio_formats
[cod_spec
].codec_root_fn
;
1061 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
1062 #endif /* HAVE_RECORDING */
1065 } /* get_codec_filename */
1068 /* --- Voice thread --- */
1070 #ifdef PLAYBACK_VOICE
1072 static bool voice_pcmbuf_insert_callback(
1073 const void *ch1
, const void *ch2
, int count
)
1075 const char *src
[2] = { ch1
, ch2
};
1079 int out_count
= dsp_output_count(count
);
1083 while ((dest
= pcmbuf_request_voice_buffer(
1084 &out_count
, playing
)) == NULL
)
1086 if (playing
&& audio_codec_loaded
)
1092 /* Get the real input_size for output_size bytes, guarding
1093 * against resampling buffer overflows. */
1094 inp_count
= dsp_input_count(out_count
);
1099 /* Input size has grown, no error, just don't write more than length */
1100 if (inp_count
> count
)
1103 out_count
= dsp_process(dest
, src
, inp_count
);
1110 pcmbuf_mix_voice(out_count
);
1111 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
1116 pcmbuf_write_complete(out_count
);
1122 } /* voice_pcmbuf_insert_callback */
1124 static void* voice_get_memory_callback(size_t *size
)
1126 /* Voice should have no use for this. If it did, we'd have to
1127 swap the malloc buffer as well. */
1132 static void voice_set_elapsed_callback(unsigned int value
)
1137 static void voice_set_offset_callback(size_t value
)
1142 static void voice_configure_callback(int setting
, intptr_t value
)
1144 if (!dsp_configure(setting
, value
))
1146 logf("Illegal key:%d", setting
);
1150 static size_t voice_filebuf_callback(void *ptr
, size_t size
)
1158 /* Handle Q_VOICE_STOP and part of SYS_USB_CONNECTED */
1159 static bool voice_on_voice_stop(bool aborting
, size_t *realsize
)
1161 if (aborting
&& !playing
)
1163 /* Aborting: Slight hack - flush PCM buffer if
1164 only being used for voice */
1168 if (voice_is_playing
)
1170 /* Clear the current buffer */
1171 voice_is_playing
= false;
1172 voice_getmore
= NULL
;
1173 voice_remaining
= 0;
1176 /* Cancel any automatic boost if no more clips requested. */
1177 if (!playing
|| !voice_thread_start
)
1180 /* Force the codec to think it's changing tracks */
1181 ci_voice
.new_track
= 1;
1184 return true; /* Yes, change tracks */
1190 static void* voice_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1192 struct queue_event ev
;
1194 if (ci_voice
.new_track
)
1202 if (voice_is_playing
|| playing
)
1204 queue_wait_w_tmo(&voice_queue
, &ev
, 0);
1205 if (!voice_is_playing
&& ev
.id
== SYS_TIMEOUT
)
1206 ev
.id
= Q_AUDIO_PLAY
;
1210 queue_wait(&voice_queue
, &ev
);
1215 LOGFQUEUE("voice < Q_AUDIO_PLAY");
1218 if (audio_codec_loaded
)
1224 #ifdef AUDIO_HAVE_RECORDING
1225 case Q_ENCODER_RECORD
:
1226 LOGFQUEUE("voice < Q_ENCODER_RECORD");
1232 LOGFQUEUE("voice < Q_VOICE_STOP");
1233 if (voice_on_voice_stop(ev
.data
, realsize
))
1238 LOGFQUEUE("voice < Q_VOICE_PLAY");
1239 if (!voice_is_playing
)
1241 /* Set up new voice data */
1242 struct voice_info
*voice_data
;
1244 if (voice_iram_stolen
)
1246 /* Voice is the first to run again and is currently
1248 logf("voice: iram restore");
1249 memcpy(CODEC_IRAM_ORIGIN
, iram_buf
, CODEC_IRAM_SIZE
);
1250 voice_iram_stolen
= false;
1253 /* Must reset the buffer before any playback begins if
1255 if (buffer_state
== BUFFER_STATE_TRASHED
)
1256 audio_reset_buffer();
1258 voice_is_playing
= true;
1259 trigger_cpu_boost();
1260 voice_data
= (struct voice_info
*)ev
.data
;
1261 voice_remaining
= voice_data
->size
;
1262 voicebuf
= voice_data
->buf
;
1263 voice_getmore
= voice_data
->callback
;
1265 goto voice_play_clip
; /* To exit both switch and while */
1268 LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
1269 goto voice_play_clip
;
1272 LOGFQUEUE("voice < default");
1278 if (voice_remaining
== 0 || voicebuf
== NULL
)
1281 voice_getmore((unsigned char **)&voicebuf
, &voice_remaining
);
1283 /* If this clip is done */
1284 if (voice_remaining
== 0)
1286 LOGFQUEUE("voice > voice Q_VOICE_STOP");
1287 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
1288 /* Force pcm playback. */
1289 if (!pcm_is_playing())
1290 pcmbuf_play_start();
1294 *realsize
= MIN(voice_remaining
, reqsize
);
1300 } /* voice_request_buffer_callback */
1302 static void voice_advance_buffer_callback(size_t amount
)
1304 amount
= MIN(amount
, voice_remaining
);
1306 voice_remaining
-= amount
;
1309 static void voice_advance_buffer_loc_callback(void *ptr
)
1311 size_t amount
= (size_t)ptr
- (size_t)voicebuf
;
1313 voice_advance_buffer_callback(amount
);
1316 static off_t
voice_mp3_get_filepos_callback(int newtime
)
1323 static void voice_do_nothing(void)
1328 static bool voice_seek_buffer_callback(size_t newpos
)
1335 static bool voice_request_next_track_callback(void)
1337 ci_voice
.new_track
= 0;
1341 static void voice_thread(void)
1343 logf("Loading voice codec");
1344 voice_codec_loaded
= true;
1345 semaphore_wait(&sem_codecthread
);
1346 event_set_state(&event_codecthread
, STATE_NONSIGNALED
);
1347 set_current_codec(CODEC_IDX_VOICE
);
1348 dsp_configure(DSP_RESET
, 0);
1349 voice_remaining
= 0;
1350 voice_getmore
= NULL
;
1352 /* FIXME: If we being starting the voice thread without reboot, the
1353 voice_queue could be full of old stuff and we must flush it. */
1354 codec_load_file(get_codec_filename(AFMT_MPA_L3
), &ci_voice
);
1356 logf("Voice codec finished");
1357 voice_codec_loaded
= false;
1358 voice_thread_p
= NULL
;
1359 semaphore_release(&sem_codecthread
);
1360 } /* voice_thread */
1362 #endif /* PLAYBACK_VOICE */
1364 /* --- Codec thread --- */
1365 static bool codec_pcmbuf_insert_callback(
1366 const void *ch1
, const void *ch2
, int count
)
1368 const char *src
[2] = { ch1
, ch2
};
1372 int out_count
= dsp_output_count(count
);
1376 /* Prevent audio from a previous track from playing */
1377 if (ci
.new_track
|| ci
.stop_codec
)
1380 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
1383 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
1387 /* Get the real input_size for output_size bytes, guarding
1388 * against resampling buffer overflows. */
1389 inp_count
= dsp_input_count(out_count
);
1394 /* Input size has grown, no error, just don't write more than length */
1395 if (inp_count
> count
)
1398 out_count
= dsp_process(dest
, src
, inp_count
);
1403 pcmbuf_write_complete(out_count
);
1405 #ifdef PLAYBACK_VOICE
1406 if ((voice_is_playing
|| voice_thread_start
)
1407 && pcm_is_playing() && voice_codec_loaded
&&
1408 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1410 voice_thread_start
= false;
1419 } /* codec_pcmbuf_insert_callback */
1421 static void* codec_get_memory_callback(size_t *size
)
1423 *size
= MALLOC_BUFSIZE
;
1427 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
1428 static void codec_pcmbuf_position_callback(size_t size
)
1430 /* This is called from an ISR, so be quick */
1431 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
1432 prevtrack_id3
.elapsed
;
1434 if (time
>= prevtrack_id3
.length
)
1436 pcmbuf_set_position_callback(NULL
);
1437 prevtrack_id3
.elapsed
= prevtrack_id3
.length
;
1440 prevtrack_id3
.elapsed
= time
;
1443 static void codec_set_elapsed_callback(unsigned int value
)
1445 unsigned int latency
;
1449 #ifdef AB_REPEAT_ENABLE
1450 ab_position_report(value
);
1453 latency
= pcmbuf_get_latency();
1454 if (value
< latency
)
1455 curtrack_id3
.elapsed
= 0;
1456 else if (value
- latency
> curtrack_id3
.elapsed
||
1457 value
- latency
< curtrack_id3
.elapsed
- 2)
1459 curtrack_id3
.elapsed
= value
- latency
;
1463 static void codec_set_offset_callback(size_t value
)
1465 unsigned int latency
;
1470 latency
= pcmbuf_get_latency() * curtrack_id3
.bitrate
/ 8;
1471 if (value
< latency
)
1472 curtrack_id3
.offset
= 0;
1474 curtrack_id3
.offset
= value
- latency
;
1477 static void codec_advance_buffer_counters(size_t amount
)
1479 bufadvance(CUR_TI
->audio_hid
, amount
);
1480 ci
.curpos
+= amount
;
1483 /* copy up-to size bytes into ptr and return the actual size copied */
1484 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
1488 if (ci
.stop_codec
|| !playing
)
1491 copy_n
= bufread(CUR_TI
->audio_hid
, size
, ptr
);
1493 /* Nothing requested OR nothing left */
1497 /* Update read and other position pointers */
1498 codec_advance_buffer_counters(copy_n
);
1500 /* Return the actual amount of data copied to the buffer */
1502 } /* codec_filebuf_callback */
1504 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1506 size_t copy_n
= reqsize
;
1516 ret
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, &ptr
);
1518 copy_n
= MIN((size_t)ret
, reqsize
);
1529 } /* codec_request_buffer_callback */
1531 static int get_codec_base_type(int type
)
1543 static void codec_advance_buffer_callback(size_t amount
)
1545 codec_advance_buffer_counters(amount
);
1546 codec_set_offset_callback(ci
.curpos
);
1549 static void codec_advance_buffer_loc_callback(void *ptr
)
1551 size_t amount
= buf_get_offset(CUR_TI
->audio_hid
, ptr
);
1552 codec_advance_buffer_callback(amount
);
1555 /* Copied from mpeg.c. Should be moved somewhere else. */
1556 static int codec_get_file_pos(void)
1559 struct mp3entry
*id3
= audio_current_track();
1565 /* Use the TOC to find the new position */
1566 unsigned int percent
, remainder
;
1567 int curtoc
, nexttoc
, plen
;
1569 percent
= (id3
->elapsed
*100)/id3
->length
;
1573 curtoc
= id3
->toc
[percent
];
1576 nexttoc
= id3
->toc
[percent
+1];
1580 pos
= (id3
->filesize
/256)*curtoc
;
1582 /* Use the remainder to get a more accurate position */
1583 remainder
= (id3
->elapsed
*100)%id3
->length
;
1584 remainder
= (remainder
*100)/id3
->length
;
1585 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1586 pos
+= (plen
/100)*remainder
;
1590 /* No TOC exists, estimate the new position */
1591 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1592 (id3
->elapsed
/ 1000);
1595 else if (id3
->bitrate
)
1596 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1600 pos
+= id3
->first_frame_offset
;
1602 /* Don't seek right to the end of the file so that we can
1603 transition properly to the next song */
1604 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1605 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1610 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1614 curtrack_id3
.elapsed
= newtime
;
1615 newpos
= codec_get_file_pos();
1620 static void codec_seek_complete_callback(void)
1622 logf("seek_complete");
1623 if (pcm_is_paused())
1625 /* If this is not a seamless seek, clear the buffer */
1627 dsp_configure(DSP_FLUSH
, 0);
1629 /* If playback was not 'deliberately' paused, unpause now */
1631 pcmbuf_pause(false);
1636 static bool codec_seek_buffer_callback(size_t newpos
)
1638 logf("codec_seek_buffer_callback");
1640 int ret
= bufseek(CUR_TI
->audio_hid
, newpos
);
1650 static void codec_configure_callback(int setting
, intptr_t value
)
1653 case CODEC_SET_FILEBUF_WATERMARK
:
1654 set_filebuf_watermark(buffer_margin
, value
);
1657 case CODEC_SET_FILEBUF_CHUNKSIZE
:
1658 buf_set_conf(BUFFERING_SET_CHUNKSIZE
, value
);
1661 case CODEC_SET_FILEBUF_PRESEEK
:
1662 buf_set_conf(BUFFERING_SET_PRESEEK
, value
);
1666 if (!dsp_configure(setting
, value
)) { logf("Illegal key:%d", setting
); }
1670 static void codec_track_changed(void)
1672 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1673 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1676 static void codec_pcmbuf_track_changed_callback(void)
1678 pcmbuf_set_position_callback(NULL
);
1679 codec_track_changed();
1682 static void codec_discard_codec_callback(void)
1684 if (CUR_TI
->codec_hid
> 0)
1686 bufclose(CUR_TI
->codec_hid
);
1687 CUR_TI
->codec_hid
= 0;
1691 static inline void codec_gapless_track_change(void)
1693 /* callback keeps the progress bar moving while the pcmbuf empties */
1694 pcmbuf_set_position_callback(codec_pcmbuf_position_callback
);
1695 /* set the pcmbuf callback for when the track really changes */
1696 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1699 static inline void codec_crossfade_track_change(void)
1701 /* Initiate automatic crossfade mode */
1702 pcmbuf_crossfade_init(false);
1703 /* Notify the wps that the track change starts now */
1704 codec_track_changed();
1707 static void codec_track_skip_done(bool was_manual
)
1709 /* Manual track change (always crossfade or flush audio). */
1712 pcmbuf_crossfade_init(true);
1713 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1714 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1716 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1717 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1718 && global_settings
.crossfade
!= CROSSFADE_ENABLE_TRACKSKIP
)
1720 if (global_settings
.crossfade
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1722 if (global_settings
.playlist_shuffle
)
1723 /* shuffle mode is on, so crossfade: */
1724 codec_crossfade_track_change();
1726 /* shuffle mode is off, so do a gapless track change */
1727 codec_gapless_track_change();
1730 /* normal crossfade: */
1731 codec_crossfade_track_change();
1734 /* normal gapless playback. */
1735 codec_gapless_track_change();
1738 static bool codec_load_next_track(void)
1740 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1742 prev_track_elapsed
= curtrack_id3
.elapsed
;
1745 codec_seek_complete_callback();
1747 #ifdef AB_REPEAT_ENABLE
1748 ab_end_of_track_report();
1751 logf("Request new track");
1753 if (ci
.new_track
== 0)
1756 automatic_skip
= true;
1761 trigger_cpu_boost();
1762 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1763 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1768 case Q_CODEC_REQUEST_COMPLETE
:
1769 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1770 codec_track_skip_done(!automatic_skip
);
1773 case Q_CODEC_REQUEST_FAILED
:
1774 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1776 ci
.stop_codec
= true;
1780 LOGFQUEUE("codec |< default");
1781 ci
.stop_codec
= true;
1786 static bool codec_request_next_track_callback(void)
1790 if (ci
.stop_codec
|| !playing
)
1793 prev_codectype
= get_codec_base_type(curtrack_id3
.codectype
);
1795 if (!codec_load_next_track())
1798 /* Seek to the beginning of the new track because if the struct mp3entry was
1799 buffered, "elapsed" might not be zero (if the track has been played
1800 already but not unbuffered) */
1801 codec_seek_buffer_callback(0);
1803 /* Check if the next codec is the same file. */
1804 if (prev_codectype
== get_codec_base_type(curtrack_id3
.codectype
))
1806 logf("New track loaded");
1807 codec_discard_codec_callback();
1812 logf("New codec:%d/%d", curtrack_id3
.codectype
, prev_codectype
);
1817 static void codec_thread(void)
1819 struct queue_event ev
;
1824 queue_wait(&codec_queue
, &ev
);
1827 case Q_CODEC_LOAD_DISK
:
1828 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1829 queue_reply(&codec_queue
, 1);
1830 audio_codec_loaded
= true;
1831 #ifdef PLAYBACK_VOICE
1832 /* Don't sent messages to voice codec if it's already swapped
1833 out or it will never get this */
1834 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1836 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1837 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1839 semaphore_wait(&sem_codecthread
);
1840 event_set_state(&event_codecthread
, STATE_SIGNALED
);
1842 set_current_codec(CODEC_IDX_AUDIO
);
1843 ci
.stop_codec
= false;
1844 status
= codec_load_file((const char *)ev
.data
, &ci
);
1845 #ifdef PLAYBACK_VOICE
1846 semaphore_release(&sem_codecthread
);
1851 LOGFQUEUE("codec < Q_CODEC_LOAD");
1852 if (CUR_TI
->codec_hid
<= 0) {
1853 logf("Codec slot is empty!");
1854 /* Wait for the pcm buffer to go empty */
1855 while (pcm_is_playing())
1857 /* This must be set to prevent an infinite loop */
1858 ci
.stop_codec
= true;
1859 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1860 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
1864 audio_codec_loaded
= true;
1865 #ifdef PLAYBACK_VOICE
1866 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1868 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1869 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1871 semaphore_wait(&sem_codecthread
);
1872 event_set_state(&event_codecthread
, STATE_SIGNALED
);
1874 set_current_codec(CODEC_IDX_AUDIO
);
1875 ci
.stop_codec
= false;
1876 status
= codec_load_buf(CUR_TI
->codec_hid
, &ci
);
1877 #ifdef PLAYBACK_VOICE
1878 semaphore_release(&sem_codecthread
);
1882 #ifdef AUDIO_HAVE_RECORDING
1883 case Q_ENCODER_LOAD_DISK
:
1884 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1885 audio_codec_loaded
= false; /* Not audio codec! */
1886 #ifdef PLAYBACK_VOICE
1887 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1889 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
1890 queue_post(&voice_queue
, Q_ENCODER_RECORD
, 0);
1892 semaphore_wait(&sem_codecthread
);
1893 event_set_state(&event_codecthread
, STATE_SIGNALED
);
1895 logf("loading encoder");
1896 set_current_codec(CODEC_IDX_AUDIO
);
1897 ci
.stop_encoder
= false;
1898 status
= codec_load_file((const char *)ev
.data
, &ci
);
1899 #ifdef PLAYBACK_VOICE
1900 semaphore_release(&sem_codecthread
);
1902 logf("encoder stopped");
1904 #endif /* AUDIO_HAVE_RECORDING */
1907 LOGFQUEUE("codec < default");
1910 if (audio_codec_loaded
)
1919 audio_codec_loaded
= false;
1923 case Q_CODEC_LOAD_DISK
:
1925 LOGFQUEUE("codec < Q_CODEC_LOAD");
1928 if (ci
.new_track
|| status
!= CODEC_OK
)
1932 logf("Codec failure");
1933 gui_syncsplash(HZ
*2, "Codec failure");
1936 if (!codec_load_next_track())
1938 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1939 /* End of playlist */
1940 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1946 logf("Codec finished");
1949 /* Wait for the audio to stop playing before
1950 * triggering the WPS exit */
1951 while(pcm_is_playing())
1953 curtrack_id3
.elapsed
=
1954 curtrack_id3
.length
- pcmbuf_get_latency();
1957 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1958 /* End of playlist */
1959 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1964 if (CUR_TI
->codec_hid
> 0)
1966 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1967 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
1971 const char *codec_fn
=
1972 get_codec_filename(curtrack_id3
.codectype
);
1973 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1974 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
1975 (intptr_t)codec_fn
);
1980 #ifdef AUDIO_HAVE_RECORDING
1981 case Q_ENCODER_LOAD_DISK
:
1982 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1984 if (status
== CODEC_OK
)
1987 logf("Encoder failure");
1988 gui_syncsplash(HZ
*2, "Encoder failure");
1990 if (ci
.enc_codec_loaded
< 0)
1993 logf("Encoder failed to load");
1994 ci
.enc_codec_loaded
= -1;
1996 #endif /* AUDIO_HAVE_RECORDING */
1999 LOGFQUEUE("codec < default");
2006 /* --- Audio thread --- */
2008 static bool audio_have_tracks(void)
2010 return track_ridx
!= track_widx
|| CUR_TI
->filesize
;
2013 static bool audio_have_free_tracks(void)
2015 if (track_widx
< track_ridx
)
2016 return track_widx
+ 1 < track_ridx
;
2017 else if (track_ridx
== 0)
2018 return track_widx
< MAX_TRACK
- 1;
2023 int audio_track_count(void)
2025 if (audio_have_tracks())
2027 int relative_track_widx
= track_widx
;
2029 if (track_ridx
> track_widx
)
2030 relative_track_widx
+= MAX_TRACK
;
2032 return relative_track_widx
- track_ridx
+ 1;
2038 long audio_filebufused(void)
2040 return (long) buf_used();
2043 static void audio_update_trackinfo(void)
2045 if (CUR_TI
->id3_hid
> 0)
2046 copy_mp3entry(&curtrack_id3
, bufgetid3(CUR_TI
->id3_hid
));
2048 CUR_TI
->taginfo_ready
= (CUR_TI
->id3_hid
> 0);
2050 int next_idx
= track_ridx
+ 1;
2051 next_idx
&= MAX_TRACK_MASK
;
2053 if (tracks
[next_idx
].id3_hid
> 0)
2054 copy_mp3entry(&nexttrack_id3
, bufgetid3(tracks
[next_idx
].id3_hid
));
2056 tracks
[next_idx
].taginfo_ready
= (tracks
[next_idx
].id3_hid
> 0);
2058 ci
.filesize
= CUR_TI
->filesize
;
2059 curtrack_id3
.elapsed
= 0;
2060 curtrack_id3
.offset
= 0;
2061 ci
.id3
= &curtrack_id3
;
2063 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2066 static void low_buffer_callback(void)
2068 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
2069 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
2072 static void audio_clear_track_entries(bool clear_unbuffered
)
2074 int cur_idx
= track_widx
;
2076 logf("Clearing tracks:%d/%d, %d", track_ridx
, track_widx
, clear_unbuffered
);
2078 /* This function is always called in association with a stop or a rebuffer,
2079 * we will reregister the callback at the end of a rebuffer if needed */
2080 unregister_buffer_low_callback(low_buffer_callback
);
2082 /* Loop over all tracks from write-to-read */
2086 cur_idx
&= MAX_TRACK_MASK
;
2088 if (cur_idx
== track_ridx
)
2091 /* If the track is buffered, conditionally clear/notify,
2092 * otherwise clear the track if that option is selected */
2093 if (tracks
[cur_idx
].event_sent
)
2095 /* If there is an unbuffer callback, call it, otherwise,
2096 * just clear the track */
2097 if (track_unbuffer_callback
&& tracks
[cur_idx
].id3_hid
> 0)
2098 track_unbuffer_callback(bufgetid3(tracks
[cur_idx
].id3_hid
));
2100 clear_track_info(&tracks
[cur_idx
]);
2102 else if (clear_unbuffered
)
2103 clear_track_info(&tracks
[cur_idx
]);
2107 static bool audio_release_tracks(void)
2111 logf("releasing all tracks");
2113 for(i
= 0; i
< MAX_TRACKS
; i
++)
2115 cur_idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
2116 if (!clear_track_info(&tracks
[cur_idx
]))
2123 static bool audio_loadcodec(bool start_play
)
2126 char codec_path
[MAX_PATH
]; /* Full path to codec */
2128 if (tracks
[track_widx
].id3_hid
<= 0) {
2132 const char * codec_fn
=
2133 get_codec_filename(bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
);
2134 if (codec_fn
== NULL
)
2137 tracks
[track_widx
].codec_hid
= false;
2141 /* Load the codec directly from disk and save some memory. */
2142 track_ridx
= track_widx
;
2143 ci
.filesize
= CUR_TI
->filesize
;
2144 ci
.id3
= &curtrack_id3
;
2145 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2147 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2148 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
2153 /* If we already have another track than this one buffered */
2154 if (track_widx
!= track_ridx
)
2156 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
2158 /* If the previous codec is the same as this one, there is no need
2159 * to put another copy of it on the file buffer */
2160 if (get_codec_base_type(
2161 bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
) ==
2162 get_codec_base_type(
2163 bufgetid3(tracks
[prev_track
].id3_hid
)->codectype
)
2164 && audio_codec_loaded
)
2166 logf("Reusing prev. codec");
2172 codec_get_full_path(codec_path
, codec_fn
);
2174 tracks
[track_widx
].codec_hid
= bufopen(codec_path
, 0, TYPE_CODEC
);
2175 if (tracks
[track_widx
].codec_hid
< 0)
2178 logf("Loaded codec");
2183 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2184 static void audio_set_elapsed(struct mp3entry
* id3
)
2186 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
2187 id3
->offset
- id3
->first_frame_offset
: 0;
2190 if ( id3
->has_toc
) {
2191 /* calculate elapsed time using TOC */
2193 unsigned int remainder
, plen
, relpos
, nextpos
;
2195 /* find wich percent we're at */
2196 for (i
=0; i
<100; i
++ )
2197 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
2204 relpos
= id3
->toc
[i
];
2207 nextpos
= id3
->toc
[i
+1];
2211 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
2213 /* set time for this percent (divide before multiply to prevent
2214 overflow on long files. loss of precision is negligible on
2216 id3
->elapsed
= i
* (id3
->length
/ 100);
2218 /* calculate remainder time */
2219 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
2220 id3
->elapsed
+= (((remainder
* 100) / plen
) *
2221 (id3
->length
/ 10000));
2224 /* no TOC exists. set a rough estimate using average bitrate */
2225 int tpk
= id3
->length
/
2226 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
2228 id3
->elapsed
= offset
/ 1024 * tpk
;
2233 /* constant bitrate, use exact calculation */
2234 if (id3
->bitrate
!= 0)
2235 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
2239 /* Load one track by making the appropriate bufopen calls. Return true if
2240 everything required was loaded correctly, false if not. */
2241 static bool audio_load_track(int offset
, bool start_play
)
2246 int file_offset
= 0;
2247 struct mp3entry id3
;
2249 /* Stop buffer filling if there is no free track entries.
2250 Don't fill up the last track entry (we wan't to store next track
2252 if (!audio_have_free_tracks())
2254 logf("No free tracks");
2260 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
2261 /* Get track name from current playlist read position. */
2262 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
2264 /* Handle broken playlists. */
2265 fd
= open(trackname
, O_RDONLY
);
2268 logf("Open failed");
2269 /* Skip invalid entry from playlist. */
2270 playlist_skip_entry(NULL
, last_peek_offset
);
2278 logf("End-of-playlist");
2279 playlist_end
= true;
2283 tracks
[track_widx
].filesize
= filesize(fd
);
2285 /* Set default values */
2288 int last_codec
= current_codec
;
2290 set_current_codec(CODEC_IDX_AUDIO
);
2291 buf_set_conf(BUFFERING_SET_WATERMARK
, AUDIO_DEFAULT_WATERMARK
);
2292 buf_set_conf(BUFFERING_SET_CHUNKSIZE
, AUDIO_DEFAULT_FILECHUNK
);
2293 buf_set_conf(BUFFERING_SET_PRESEEK
, AUDIO_REBUFFER_GUESS_SIZE
);
2294 dsp_configure(DSP_RESET
, 0);
2295 set_current_codec(last_codec
);
2297 track_changed
= true;
2298 playlist_update_resume_info(audio_current_track());
2301 /* Get track metadata if we don't already have it. */
2302 if (tracks
[track_widx
].id3_hid
<= 0)
2304 if (get_metadata(&id3
, fd
, trackname
))
2306 tracks
[track_widx
].id3_hid
= bufalloc(&id3
, sizeof(struct mp3entry
),
2308 tracks
[track_widx
].taginfo_ready
= (tracks
[track_widx
].id3_hid
> 0);
2310 if (tracks
[track_widx
].id3_hid
<= 0)
2317 if (track_widx
== track_ridx
)
2318 copy_mp3entry(&curtrack_id3
, &id3
);
2319 else if (track_widx
== ((track_ridx
+ 1) & MAX_TRACK_MASK
))
2320 copy_mp3entry(&nexttrack_id3
, &id3
);
2324 track_changed
= true;
2325 playlist_update_resume_info(audio_current_track());
2330 logf("mde:%s!",trackname
);
2332 /* Skip invalid entry from playlist. */
2333 playlist_skip_entry(NULL
, last_peek_offset
);
2334 tracks
[track_widx
].taginfo_ready
= false;
2344 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
2346 char cuepath
[MAX_PATH
];
2348 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
2350 if (look_for_cuesheet_file(trackname
, cuepath
) &&
2351 parse_cuesheet(cuepath
, cue
))
2353 strcpy((cue
)->audio_filename
, trackname
);
2355 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
2360 /* Load the codec. */
2361 if (!audio_loadcodec(start_play
))
2363 if (tracks
[track_widx
].codec_hid
== ERR_BUFFER_FULL
)
2365 /* No space for codec on buffer, not an error */
2369 /* This is an error condition, either no codec was found, or reading
2370 * the codec file failed part way through, either way, skip the track */
2371 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
2372 /* We should not use gui_syncplash from audio thread! */
2373 gui_syncsplash(HZ
*2, msgbuf
);
2374 /* Skip invalid entry from playlist. */
2375 playlist_skip_entry(NULL
, last_peek_offset
);
2376 tracks
[track_widx
].taginfo_ready
= false;
2380 struct mp3entry
*track_id3
;
2382 if (track_widx
== track_ridx
)
2383 track_id3
= &curtrack_id3
;
2384 else if (track_widx
== ((track_ridx
+ 1) & MAX_TRACK_MASK
))
2385 track_id3
= &nexttrack_id3
;
2387 track_id3
= bufgetid3(tracks
[track_widx
].id3_hid
);
2389 #ifndef HAVE_FLASH_STORAGE
2390 set_filebuf_watermark(buffer_margin
, 0);
2392 track_id3
->elapsed
= 0;
2394 enum data_type type
= TYPE_PACKET_AUDIO
;
2396 switch (track_id3
->codectype
) {
2401 file_offset
= offset
;
2402 track_id3
->offset
= offset
;
2403 audio_set_elapsed(track_id3
);
2410 file_offset
= offset
;
2411 track_id3
->offset
= offset
;
2412 track_id3
->elapsed
= track_id3
->length
/ 2;
2417 case AFMT_OGG_VORBIS
:
2426 track_id3
->offset
= offset
;
2432 logf("Loading atomic %d",track_id3
->codectype
);
2433 type
= TYPE_ATOMIC_AUDIO
;
2437 logf("alt:%s", trackname
);
2439 tracks
[track_widx
].audio_hid
= bufopen(trackname
, file_offset
, type
);
2441 if (tracks
[track_widx
].audio_hid
<= 0)
2446 buf_request_buffer_handle(tracks
[track_widx
].audio_hid
);
2450 track_widx
&= MAX_TRACK_MASK
;
2455 /* Send callback events to notify about new tracks. */
2456 static void audio_generate_postbuffer_events(void)
2460 logf("Postbuffer:%d/%d",track_ridx
,track_widx
);
2462 if (audio_have_tracks())
2464 cur_idx
= track_ridx
;
2467 if (!tracks
[cur_idx
].event_sent
)
2469 /* Mark the event 'sent' even if we don't really send one */
2470 tracks
[cur_idx
].event_sent
= true;
2471 if (track_buffer_callback
&& tracks
[cur_idx
].id3_hid
> 0)
2472 track_buffer_callback(bufgetid3(tracks
[cur_idx
].id3_hid
));
2474 if (cur_idx
== track_widx
)
2477 cur_idx
&= MAX_TRACK_MASK
;
2482 static void audio_fill_file_buffer(bool start_play
, size_t offset
)
2484 struct queue_event ev
;
2485 bool had_next_track
= audio_next_track() != NULL
;
2486 bool continue_buffering
;
2488 /* Must reset the buffer before use if trashed or voice only - voice
2489 file size shouldn't have changed so we can go straight from
2490 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
2491 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
2492 audio_reset_buffer();
2494 logf("Starting buffer fill");
2497 audio_clear_track_entries(false);
2499 /* Save the current resume position once. */
2500 playlist_update_resume_info(audio_current_track());
2503 continue_buffering
= audio_load_track(offset
, start_play
);
2507 if (queue_peek(&audio_queue
, &ev
)) {
2508 if (ev
.id
!= Q_AUDIO_FILL_BUFFER
)
2510 /* There's a message in the queue. break the loop to treat it,
2511 and go back to filling after that. */
2512 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
2513 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
2517 } while (continue_buffering
);
2519 if (!had_next_track
&& audio_next_track())
2520 track_changed
= true;
2522 audio_generate_postbuffer_events();
2524 if (!continue_buffering
)
2525 register_buffer_low_callback(low_buffer_callback
);
2528 static void audio_rebuffer(void)
2530 logf("Forcing rebuffer");
2532 clear_track_info(CUR_TI
);
2534 /* Reset track pointers */
2535 track_widx
= track_ridx
;
2536 audio_clear_track_entries(true);
2538 /* Fill the buffer */
2539 last_peek_offset
= -1;
2542 if (!CUR_TI
->taginfo_ready
)
2543 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
2545 audio_fill_file_buffer(false, 0);
2548 static int audio_check_new_track(void)
2550 int track_count
= audio_track_count();
2551 int old_track_ridx
= track_ridx
;
2557 if (playlist_next_dir(ci
.new_track
))
2565 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2566 return Q_CODEC_REQUEST_FAILED
;
2573 /* If the playlist isn't that big */
2574 if (!playlist_check(ci
.new_track
))
2576 if (ci
.new_track
>= 0)
2578 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2579 return Q_CODEC_REQUEST_FAILED
;
2581 /* Find the beginning backward if the user over-skips it */
2582 while (!playlist_check(++ci
.new_track
))
2583 if (ci
.new_track
>= 0)
2585 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2586 return Q_CODEC_REQUEST_FAILED
;
2589 /* Update the playlist */
2590 last_peek_offset
-= ci
.new_track
;
2592 if (playlist_next(ci
.new_track
) < 0)
2594 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2595 return Q_CODEC_REQUEST_FAILED
;
2601 new_playlist
= false;
2604 /* Save the old track */
2605 copy_mp3entry(&prevtrack_id3
, &curtrack_id3
);
2608 for (i
= 0; i
< ci
.new_track
; i
++)
2610 idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
2611 if (buf_handle_offset(tracks
[idx
].audio_hid
) > 0)
2612 clear_track_info(&tracks
[idx
]);
2615 /* Move to the new track */
2616 track_ridx
+= ci
.new_track
;
2617 track_ridx
&= MAX_TRACK_MASK
;
2619 buf_set_base_handle(CUR_TI
->audio_hid
);
2623 playlist_end
= false;
2624 wps_offset
= -ci
.new_track
;
2627 track_changed
= true;
2629 /* If it is not safe to even skip this many track entries */
2630 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
2637 forward
= ci
.new_track
> 0;
2640 /* If the target track is clearly not in memory */
2641 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
2647 /* When skipping backwards, it is possible that we've found a track that's
2648 * buffered, but which is around the track-wrap and therefor not the track
2649 * we are looking for */
2652 int cur_idx
= track_ridx
;
2653 bool taginfo_ready
= true;
2654 /* We've wrapped the buffer backwards if new > old */
2655 bool wrap
= track_ridx
> old_track_ridx
;
2660 cur_idx
&= MAX_TRACK_MASK
;
2662 /* if we've advanced past the wrap when cur_idx is zeroed */
2666 /* if we aren't still on the wrap and we've caught the old track */
2667 if (!(wrap
|| cur_idx
< old_track_ridx
))
2670 /* If we hit a track in between without valid tag info, bail */
2671 if (!tracks
[cur_idx
].taginfo_ready
)
2673 taginfo_ready
= false;
2684 audio_update_trackinfo();
2685 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2686 return Q_CODEC_REQUEST_COMPLETE
;
2689 void audio_set_track_buffer_event(void (*handler
)(struct mp3entry
*id3
))
2691 track_buffer_callback
= handler
;
2694 void audio_set_track_unbuffer_event(void (*handler
)(struct mp3entry
*id3
))
2696 track_unbuffer_callback
= handler
;
2699 void audio_set_track_changed_event(void (*handler
)(struct mp3entry
*id3
))
2701 track_changed_callback
= handler
;
2704 unsigned long audio_prev_elapsed(void)
2706 return prev_track_elapsed
;
2709 static void audio_stop_codec_flush(void)
2711 ci
.stop_codec
= true;
2714 while (audio_codec_loaded
)
2717 /* If the audio codec is not loaded any more, and the audio is still
2718 * playing, it is now and _only_ now safe to call this function from the
2720 if (pcm_is_playing())
2722 pcmbuf_pause(paused
);
2725 static void audio_stop_playback(void)
2727 /* If we were playing, save resume information */
2730 struct mp3entry
*id3
= NULL
;
2732 if (!playlist_end
|| !ci
.stop_codec
)
2734 /* Set this early, the outside code yields and may allow the codec
2735 to try to wait for a reply on a buffer wait */
2736 ci
.stop_codec
= true;
2737 id3
= audio_current_track();
2740 /* Save the current playing spot, or NULL if the playlist has ended */
2741 playlist_update_resume_info(id3
);
2743 prev_track_elapsed
= curtrack_id3
.elapsed
;
2745 /* Increment index so runtime info is saved in audio_clear_track_entries().
2746 * Done here, as audio_stop_playback() may be called more than once.
2747 * Don't update runtime unless playback is stopped because of end of playlist.
2748 * Updating runtime when manually stopping a tracks, can destroy autoscores
2754 track_ridx
&= MAX_TRACK_MASK
;
2759 audio_stop_codec_flush();
2762 /* Mark all entries null. */
2763 audio_clear_track_entries(false);
2765 /* Close all tracks */
2766 audio_release_tracks();
2768 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
2769 memset(&nexttrack_id3
, 0, sizeof(struct mp3entry
));
2772 static void audio_play_start(size_t offset
)
2774 #if INPUT_SRC_CAPS != 0
2775 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
2776 audio_set_output_source(AUDIO_SRC_PLAYBACK
);
2779 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2781 audio_stop_codec_flush();
2783 track_changed
= true;
2784 playlist_end
= false;
2792 sound_set_volume(global_settings
.volume
);
2793 track_widx
= track_ridx
= 0;
2795 /* Mark all entries null. */
2796 memset(tracks
, 0, sizeof(struct track_info
) * MAX_TRACK
);
2798 last_peek_offset
= -1;
2800 /* Officially playing */
2801 queue_reply(&audio_queue
, 1);
2803 audio_fill_file_buffer(true, offset
);
2805 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2806 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
2810 /* Invalidates all but currently playing track. */
2811 static void audio_invalidate_tracks(void)
2813 if (audio_have_tracks())
2815 last_peek_offset
= 0;
2816 playlist_end
= false;
2817 track_widx
= track_ridx
;
2819 /* Mark all other entries null (also buffered wrong metadata). */
2820 audio_clear_track_entries(true);
2822 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
2824 audio_fill_file_buffer(false, 0);
2828 static void audio_new_playlist(void)
2830 /* Prepare to start a new fill from the beginning of the playlist */
2831 last_peek_offset
= -1;
2832 if (audio_have_tracks())
2835 skipped_during_pause
= true;
2836 playlist_end
= false;
2837 track_widx
= track_ridx
;
2838 audio_clear_track_entries(true);
2841 track_widx
&= MAX_TRACK_MASK
;
2843 /* Mark the current track as invalid to prevent skipping back to it */
2844 CUR_TI
->taginfo_ready
= false;
2847 /* Signal the codec to initiate a track change forward */
2848 new_playlist
= true;
2851 /* Officially playing */
2852 queue_reply(&audio_queue
, 1);
2854 audio_fill_file_buffer(false, 0);
2857 static void audio_initiate_track_change(long direction
)
2859 playlist_end
= false;
2860 ci
.new_track
+= direction
;
2861 wps_offset
-= direction
;
2863 skipped_during_pause
= true;
2866 static void audio_initiate_dir_change(long direction
)
2868 playlist_end
= false;
2870 ci
.new_track
= direction
;
2872 skipped_during_pause
= true;
2876 * Layout audio buffer as follows - iram buffer depends on target:
2877 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
2879 static void audio_reset_buffer(void)
2881 /* see audio_get_recording_buffer if this is modified */
2882 logf("audio_reset_buffer");
2884 /* If the setup of anything allocated before the file buffer is
2885 changed, do check the adjustments after the buffer_alloc call
2886 as it will likely be affected and need sliding over */
2888 /* Initially set up file buffer as all space available */
2889 malloc_buf
= audiobuf
+ talk_get_bufsize();
2890 /* Align the malloc buf to line size. Especially important to cf
2891 targets that do line reads/writes. */
2892 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
2893 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
2894 filebuflen
= audiobufend
- filebuf
;
2896 /* Allow for codec swap space at end of audio buffer */
2897 if (talk_voice_required())
2899 /* Layout of swap buffer:
2900 * #ifdef IRAM_STEAL (dedicated iram_buf):
2901 * |iram_buf|...audiobuf...|dram_buf|audiobufend
2903 * audiobuf...|dram_buf|iram_buf|audiobufend
2905 #ifdef PLAYBACK_VOICE
2906 /* Check for an absolutely nasty situation which should never,
2907 ever happen - frankly should just panic */
2908 if (voice_codec_loaded
&& current_codec
!= CODEC_IDX_VOICE
)
2910 logf("buffer reset with voice swapped");
2912 /* line align length which line aligns the calculations below since
2913 all sizes are also at least line aligned - needed for memswap128 */
2916 filebuflen
-= CODEC_SIZE
;
2918 filebuflen
-= CODEC_SIZE
+ CODEC_IRAM_SIZE
;
2920 /* Allocate buffers for swapping voice <=> audio */
2921 /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
2922 and out of the way of buffer usage or else a call to audio_get_buffer
2923 and subsequent buffer use might trash the swap space. A plugin
2924 initializing IRAM after getting the full buffer would present similar
2925 problem. Options include: failing the request if the other buffer
2926 has been obtained already or never allowing use of the voice IRAM
2927 buffer within the audio buffer. Using buffer_alloc basically
2928 implements the second in a more convenient way. */
2929 dram_buf
= filebuf
+ filebuflen
;
2932 /* Allocate voice IRAM swap buffer once */
2933 if (iram_buf
== NULL
)
2935 iram_buf
= buffer_alloc(CODEC_IRAM_SIZE
);
2936 /* buffer_alloc moves audiobuf; this is safe because only the end
2937 * has been touched so far in this function and the address of
2938 * filebuf + filebuflen is not changed */
2939 malloc_buf
+= CODEC_IRAM_SIZE
;
2940 filebuf
+= CODEC_IRAM_SIZE
;
2941 filebuflen
-= CODEC_IRAM_SIZE
;
2944 /* Allocate iram_buf after dram_buf */
2945 iram_buf
= dram_buf
+ CODEC_SIZE
;
2946 #endif /* IRAM_STEAL */
2947 #endif /* PLAYBACK_VOICE */
2951 #ifdef PLAYBACK_VOICE
2952 /* No swap buffers needed */
2958 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
2959 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
2961 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
2962 will already be line aligned */
2965 buffering_reset(filebuf
, filebuflen
);
2967 /* Clear any references to the file buffer */
2968 buffer_state
= BUFFER_STATE_INITIALIZED
;
2970 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
2971 /* Make sure everything adds up - yes, some info is a bit redundant but
2972 aids viewing and the sumation of certain variables should add up to
2973 the location of others. */
2976 unsigned char * pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
2977 logf("mabuf: %08X", (unsigned)malloc_buf
);
2978 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
2979 logf("fbuf: %08X", (unsigned)filebuf
);
2980 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
2981 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
2982 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
2983 logf("pcmb: %08X", (unsigned)pcmbuf
);
2984 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
2987 logf("dramb: %08X", (unsigned)dram_buf
);
2988 logf("drambe: %08X", (unsigned)(dram_buf
+ CODEC_SIZE
));
2992 logf("iramb: %08X", (unsigned)iram_buf
);
2993 logf("irambe: %08X", (unsigned)(iram_buf
+ CODEC_IRAM_SIZE
));
2999 static void audio_thread(void)
3001 struct queue_event ev
;
3005 #ifdef PLAYBACK_VOICE
3006 /* Unlock semaphore that init stage locks before creating this thread */
3007 semaphore_release(&sem_codecthread
);
3009 /* Buffers must be set up by now - should panic - really */
3010 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
3012 logf("audio_thread start: no buffer");
3015 /* Have to wait for voice to load up or else the codec swap will be
3016 invalid when an audio codec is loaded */
3017 wait_for_voice_swap_in();
3022 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
3025 case Q_AUDIO_FILL_BUFFER
:
3026 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3027 if (!playing
|| playlist_end
|| ci
.stop_codec
)
3029 audio_fill_file_buffer(false, 0);
3033 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3034 if (playing
&& ev
.data
<= 0)
3035 audio_new_playlist();
3038 audio_stop_playback();
3039 audio_play_start((size_t)ev
.data
);
3044 LOGFQUEUE("audio < Q_AUDIO_STOP");
3046 audio_stop_playback();
3048 queue_clear(&audio_queue
);
3052 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3053 if (!(bool) ev
.data
&& skipped_during_pause
&& !pcmbuf_is_crossfade_active())
3054 pcmbuf_play_stop(); /* Flush old track on resume after skip */
3055 skipped_during_pause
= false;
3058 pcmbuf_pause((bool)ev
.data
);
3059 paused
= (bool)ev
.data
;
3063 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3064 audio_initiate_track_change((long)ev
.data
);
3067 case Q_AUDIO_PRE_FF_REWIND
:
3068 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3074 case Q_AUDIO_FF_REWIND
:
3075 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3078 ci
.seek_time
= (long)ev
.data
+1;
3081 case Q_AUDIO_CHECK_NEW_TRACK
:
3082 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3083 queue_reply(&audio_queue
, audio_check_new_track());
3086 case Q_AUDIO_DIR_SKIP
:
3087 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3088 playlist_end
= false;
3089 audio_initiate_dir_change(ev
.data
);
3093 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3094 audio_invalidate_tracks();
3097 case Q_AUDIO_TRACK_CHANGED
:
3098 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3102 automatic_skip
= false;
3104 prevtrack_id3
.path
[0] = 0;
3105 if (track_changed_callback
)
3106 track_changed_callback(&curtrack_id3
);
3107 track_changed
= true;
3108 playlist_update_resume_info(audio_current_track());
3112 case SYS_USB_CONNECTED
:
3113 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3115 audio_stop_playback();
3116 #ifdef PLAYBACK_VOICE
3117 wait_for_voice_swap_in();
3120 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
3121 usb_wait_for_disconnect(&audio_queue
);
3123 /* Mark all entries null. */
3124 audio_clear_track_entries(false);
3126 /* release tracks to make sure all handles are closed */
3127 audio_release_tracks();
3132 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3136 LOGFQUEUE("audio < default");
3142 #ifdef ROCKBOX_HAS_LOGF
3143 static void audio_test_track_changed_event(struct mp3entry
*id3
)
3147 logf("tce:%s", id3
->path
);
3151 /* Initialize the audio system - called from init() in main.c.
3152 * Last function because of all the references to internal symbols
3154 void audio_init(void)
3156 #ifdef PLAYBACK_VOICE
3157 static bool voicetagtrue
= true;
3158 static struct mp3entry id3_voice
;
3159 struct thread_entry
*voice_thread_p
= NULL
;
3161 struct thread_entry
*audio_thread_p
;
3163 /* Can never do this twice */
3164 if (audio_is_initialized
)
3166 logf("audio: already initialized");
3170 logf("audio: initializing");
3172 /* Initialize queues before giving control elsewhere in case it likes
3173 to send messages. Thread creation will be delayed however so nothing
3174 starts running until ready if something yields such as talk_init. */
3175 #ifdef PLAYBACK_VOICE
3176 /* Take ownership of lock to prevent playback of anything before audio
3177 hardware is initialized - audio thread unlocks it after final init
3179 semaphore_init(&sem_codecthread
, 1, 0);
3180 event_init(&event_codecthread
, EVENT_MANUAL
| STATE_SIGNALED
);
3182 queue_init(&audio_queue
, true);
3183 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
3184 queue_init(&codec_queue
, false);
3185 queue_enable_queue_send(&codec_queue
, &codec_queue_sender_list
);
3189 #ifdef ROCKBOX_HAS_LOGF
3190 audio_set_track_changed_event(audio_test_track_changed_event
);
3193 /* Initialize codec api. */
3194 ci
.read_filebuf
= codec_filebuf_callback
;
3195 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
3196 ci
.get_codec_memory
= codec_get_memory_callback
;
3197 ci
.request_buffer
= codec_request_buffer_callback
;
3198 ci
.advance_buffer
= codec_advance_buffer_callback
;
3199 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
3200 ci
.request_next_track
= codec_request_next_track_callback
;
3201 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
3202 ci
.seek_buffer
= codec_seek_buffer_callback
;
3203 ci
.seek_complete
= codec_seek_complete_callback
;
3204 ci
.set_elapsed
= codec_set_elapsed_callback
;
3205 ci
.set_offset
= codec_set_offset_callback
;
3206 ci
.configure
= codec_configure_callback
;
3207 ci
.discard_codec
= codec_discard_codec_callback
;
3209 /* Initialize voice codec api. */
3210 #ifdef PLAYBACK_VOICE
3211 memcpy(&ci_voice
, &ci
, sizeof(ci_voice
));
3212 memset(&id3_voice
, 0, sizeof(id3_voice
));
3213 ci_voice
.read_filebuf
= voice_filebuf_callback
;
3214 ci_voice
.pcmbuf_insert
= voice_pcmbuf_insert_callback
;
3215 ci_voice
.get_codec_memory
= voice_get_memory_callback
;
3216 ci_voice
.request_buffer
= voice_request_buffer_callback
;
3217 ci_voice
.advance_buffer
= voice_advance_buffer_callback
;
3218 ci_voice
.advance_buffer_loc
= voice_advance_buffer_loc_callback
;
3219 ci_voice
.request_next_track
= voice_request_next_track_callback
;
3220 ci_voice
.mp3_get_filepos
= voice_mp3_get_filepos_callback
;
3221 ci_voice
.seek_buffer
= voice_seek_buffer_callback
;
3222 ci_voice
.seek_complete
= voice_do_nothing
;
3223 ci_voice
.set_elapsed
= voice_set_elapsed_callback
;
3224 ci_voice
.set_offset
= voice_set_offset_callback
;
3225 ci_voice
.configure
= voice_configure_callback
;
3226 ci_voice
.discard_codec
= voice_do_nothing
;
3227 ci_voice
.taginfo_ready
= &voicetagtrue
;
3228 ci_voice
.id3
= &id3_voice
;
3229 id3_voice
.frequency
= 11200;
3230 id3_voice
.length
= 1000000L;
3233 /* initialize the buffer */
3236 /* audio_reset_buffer must to know the size of voice buffer so init
3240 codec_thread_p
= create_thread(
3241 codec_thread
, codec_stack
, sizeof(codec_stack
),
3242 CREATE_THREAD_FROZEN
,
3243 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
3246 audio_thread_p
= create_thread(audio_thread
, audio_stack
,
3247 sizeof(audio_stack
), CREATE_THREAD_FROZEN
,
3248 audio_thread_name
IF_PRIO(, PRIORITY_BACKGROUND
)
3251 #ifdef PLAYBACK_VOICE
3252 /* TODO: Change this around when various speech codecs can be used */
3253 if (talk_voice_required())
3255 logf("Starting voice codec");
3256 queue_init(&voice_queue
, false);
3257 voice_thread_p
= create_thread(voice_thread
, voice_stack
,
3258 sizeof(voice_stack
), CREATE_THREAD_FROZEN
,
3260 IF_PRIO(, PRIORITY_PLAYBACK
) IF_COP(, CPU
));
3264 /* Set crossfade setting for next buffer init which should be about... */
3265 pcmbuf_crossfade_enable(global_settings
.crossfade
);
3267 /* initialize the buffering system */
3270 /* ...now! Set up the buffers */
3271 audio_reset_buffer();
3273 /* Probably safe to say */
3274 audio_is_initialized
= true;
3276 sound_settings_apply();
3278 eq_hw_enable(global_settings
.eq_hw_enabled
);
3280 #ifndef HAVE_FLASH_STORAGE
3281 audio_set_buffer_margin(global_settings
.buffer_margin
);
3284 /* it's safe to let the threads run now */
3285 thread_thaw(codec_thread_p
);
3286 #ifdef PLAYBACK_VOICE
3288 thread_thaw(voice_thread_p
);
3290 thread_thaw(audio_thread_p
);