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 */
48 #include "mp3_playback.h"
51 #include "main_menu.h"
57 #include "pcm_playback.h"
58 #include "pcm_record.h"
65 #ifdef HAVE_LCD_BITMAP
67 #include "peakmeter.h"
79 #include "recording.h"
82 #define PLAYBACK_VOICE
85 /* default point to start buffer refill */
86 #define AUDIO_DEFAULT_WATERMARK (1024*512)
87 /* amount of data to read in one read() call */
88 #define AUDIO_DEFAULT_FILECHUNK (1024*32)
89 /* point at which the file buffer will fight for CPU time */
90 #define AUDIO_FILEBUF_CRITICAL (1024*128)
91 /* amount of guess-space to allow for codecs that must hunt and peck
92 * for their correct seeek target, 32k seems a good size */
93 #define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
95 /* macros to enable logf for queues */
97 #define PLAYBACK_LOGQUEUES /* Define this for logf output of all queuing */
100 #ifdef PLAYBACK_LOGQUEUES
101 #define LOGFQUEUE(s) logf("%s", s)
111 Q_AUDIO_PRE_FF_REWIND
,
113 Q_AUDIO_REBUFFER_SEEK
,
114 Q_AUDIO_CHECK_NEW_TRACK
,
116 Q_AUDIO_TRACK_CHANGED
,
118 Q_AUDIO_NEW_PLAYLIST
,
122 Q_CODEC_REQUEST_PENDING
,
123 Q_CODEC_REQUEST_COMPLETE
,
124 Q_CODEC_REQUEST_FAILED
,
132 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
138 /* As defined in plugins/lib/xxx2wav.h */
140 #define MALLOC_BUFSIZE (512*1024)
141 #define GUARD_BUFSIZE (32*1024)
143 #define MALLOC_BUFSIZE (100*1024)
144 #define GUARD_BUFSIZE (8*1024)
147 /* As defined in plugin.lds */
148 #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002
149 #define CODEC_IRAM_ORIGIN 0x4000c000
150 #elif defined(IAUDIO_X5)
151 #define CODEC_IRAM_ORIGIN 0x10014000
153 #define CODEC_IRAM_ORIGIN 0x1000c000
155 #define CODEC_IRAM_SIZE 0xc000
158 extern bool audio_is_initialized
;
160 static bool audio_is_initialized
= false;
164 /* Variables are commented with the threads that use them: *
165 * A=audio, C=codec, V=voice. A suffix of - indicates that *
166 * the variable is read but not updated on that thread. */
168 /* Main state control */
169 static struct event_queue codec_callback_queue
; /* Queue for codec callback responses */
170 static volatile bool audio_codec_loaded
; /* Is codec loaded? (C/A-) */
171 static volatile bool playing
; /* Is audio playing? (A) */
172 static volatile bool paused
; /* Is audio paused? (A/C-) */
173 static volatile bool filling IDATA_ATTR
; /* Is file buffer currently being refilled? (A/C-) */
175 /* Ring buffer where tracks and codecs are loaded */
176 static char *filebuf
; /* Pointer to start of ring buffer (A/C-) */
177 size_t filebuflen
; /* Total size of the ring buffer FIXME: make static (A/C-)*/
178 static volatile size_t buf_ridx IDATA_ATTR
; /* Ring buffer read position (A/C) FIXME? should be (C/A-) */
179 static volatile size_t buf_widx IDATA_ATTR
; /* Ring buffer read position (A/C-) */
181 #define RINGBUF_ADD(p,v) ((p+v)<filebuflen ? p+v : p+v-filebuflen)
182 #define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+filebuflen-v)
183 #define RINGBUF_ADD_CROSS(p1,v,p2) ((p1<p2)?(int)(p1+v)-(int)p2:(int)(p1+v-p2)-(int)filebuflen)
184 #define FILEBUFUSED RINGBUF_SUB(buf_widx, buf_ridx) /* Bytes available in the buffer */
186 /* Track info buffer */
187 static struct track_info tracks
[MAX_TRACK
]; /* Track info structure about songs in the file buffer (A/C-) */
188 static volatile int track_ridx
; /* Track being decoded (A/C-) */
189 static int track_widx
; /* Track being buffered (A) */
190 static bool track_changed
; /* Set to indicate track has changed (A) */
191 static struct track_info
*prev_ti
; /* Pointer to previous track played info (A/C-) */
193 #define CUR_TI (&tracks[track_ridx]) /* Pointer to current track playing info (A/C-) */
195 /* Audio buffering controls */
196 static int last_peek_offset
; /* Step count to the next unbuffered track (A) */
197 static int current_fd
; /* Partially loaded track file handle to continue buffering (A) */
199 /* Scrobbler support */
200 static unsigned long prev_track_elapsed
; /* Previous track elapsed time (C/A-) */
202 /* Track change controls */
203 static bool automatic_skip
= false; /* Was the skip being executed manual or automatic? (C/A-) */
204 static bool playlist_end
= false; /* Have we reached end of the current playlist? (A) */
205 static bool dir_skip
= false; /* Is a directory skip pending? (A) */
206 static bool new_playlist
= false; /* Are we starting a new playlist? (A) */
207 static int wps_offset
= 0; /* Pending track change offset, to keep WPS responsive (A) */
210 void (*track_changed_callback
)(struct mp3entry
*id3
); /* ...when current track has really changed */
211 void (*track_buffer_callback
)(struct mp3entry
*id3
, bool last_track
); /* ...when track has been buffered */
212 void (*track_unbuffer_callback
)(struct mp3entry
*id3
, bool last_track
); /* ...when track is being unbuffered */
215 static size_t conf_watermark
; /* Low water mark (A/C) FIXME */
216 static size_t conf_filechunk
; /* Largest chunk the codec accepts (A/C) FIXME */
217 static size_t conf_preseek
; /* Codec pre-seek margin (A/C) FIXME */
218 static size_t buffer_margin
; /* Buffer margin aka anti-skip buffer (A/C-) */
219 static bool v1first
= false; /* ID3 data control, true if V1 then V2 (A) */
221 /* Multiple threads */
222 static const char *get_codec_filename(int enc_spec
); /* Returns codec filename (A-/C-/V-) */
223 static void set_filebuf_watermark(int seconds
); /* Set low watermark (A/C) FIXME */
226 static struct event_queue audio_queue
;
227 static long audio_stack
[(DEFAULT_STACK_SIZE
+ 0x1000)/sizeof(long)];
228 static const char audio_thread_name
[] = "audio";
230 static void audio_thread(void);
231 static void audio_initiate_track_change(long direction
);
232 static bool audio_have_tracks(void);
233 static void audio_reset_buffer(void);
236 extern struct codec_api ci
;
237 static struct event_queue codec_queue
;
238 static long codec_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
240 static const char codec_thread_name
[] = "codec";
241 struct thread_entry
*codec_thread_p
; /* For modifying thread priority later. */
243 volatile int current_codec IDATA_ATTR
; /* Current codec (normal/voice) */
246 #ifdef PLAYBACK_VOICE
248 extern struct codec_api ci_voice
;
250 static struct thread_entry
*voice_thread_p
= NULL
;
251 static struct event_queue voice_queue
;
252 static long voice_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
254 static const char voice_thread_name
[] = "voice codec";
256 /* Voice codec swapping control */
257 extern unsigned char codecbuf
[]; /* DRAM codec swap buffer */
260 static unsigned char sim_iram
[CODEC_IRAM_SIZE
]; /* IRAM codec swap buffer for sim*/
261 #undef CODEC_IRAM_ORIGIN
262 #define CODEC_IRAM_ORIGIN sim_iram
265 static unsigned char *iram_buf
[2]; /* Ptr to IRAM buffers for normal/voice codecs */
266 static unsigned char *dram_buf
[2]; /* Ptr to DRAM buffers for normal/voice codecs */
267 static struct mutex mutex_codecthread
; /* Mutex to control which codec (normal/voice) is running */
270 static volatile bool voice_thread_start
; /* Set to trigger voice playback (A/V) */
271 static volatile bool voice_is_playing
; /* Is voice currently playing? (V) */
272 static volatile bool voice_codec_loaded
; /* Is voice codec loaded (V/A-) */
273 static char *voicebuf
;
274 static size_t voice_remaining
;
276 static void (*voice_getmore
)(unsigned char** start
, int* size
);
279 void (*callback
)(unsigned char **start
, int *size
);
283 static void voice_thread(void);
285 #endif /* PLAYBACK_VOICE */
287 /* --- External interfaces --- */
289 void mp3_play_data(const unsigned char* start
, int size
,
290 void (*get_more
)(unsigned char** start
, int* size
))
292 #ifdef PLAYBACK_VOICE
293 static struct voice_info voice_clip
;
294 voice_clip
.callback
= get_more
;
295 voice_clip
.buf
= (char *)start
;
296 voice_clip
.size
= size
;
297 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
298 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
299 LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
300 queue_post(&voice_queue
, Q_VOICE_PLAY
, &voice_clip
);
301 voice_thread_start
= true;
310 void mp3_play_stop(void)
312 #ifdef PLAYBACK_VOICE
313 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
314 queue_post(&voice_queue
, Q_VOICE_STOP
, (void *)1);
318 bool mp3_pause_done(void)
320 return pcm_is_paused();
323 void mpeg_id3_options(bool _v1first
)
328 void audio_load_encoder(int enc_id
)
330 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
331 const char *enc_fn
= get_codec_filename(enc_id
| CODEC_TYPE_ENCODER
);
335 audio_remove_encoder();
337 LOGFQUEUE("audio > codec Q_ENCODER_LOAD_DISK");
338 queue_post(&codec_queue
, Q_ENCODER_LOAD_DISK
, (void *)enc_fn
);
340 while (!ci
.enc_codec_loaded
)
345 } /* audio_load_encoder */
347 void audio_remove_encoder(void)
349 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
350 /* force encoder codec unload (if previously loaded) */
351 if (!ci
.enc_codec_loaded
)
354 ci
.stop_codec
= true;
355 while (ci
.enc_codec_loaded
)
358 } /* audio_remove_encoder */
360 struct mp3entry
* audio_current_track(void)
362 const char *filename
;
364 static struct mp3entry temp_id3
;
366 int offset
= ci
.new_track
+ wps_offset
;
368 cur_idx
= track_ridx
+ offset
;
369 cur_idx
&= MAX_TRACK_MASK
;
371 if (tracks
[cur_idx
].taginfo_ready
)
372 return &tracks
[cur_idx
].id3
;
374 memset(&temp_id3
, 0, sizeof(struct mp3entry
));
376 filename
= playlist_peek(offset
);
378 filename
= "No file!";
380 #ifdef HAVE_TC_RAMCACHE
381 if (tagcache_fill_tags(&temp_id3
, filename
))
385 p
= strrchr(filename
, '/');
391 strncpy(temp_id3
.path
, p
, sizeof(temp_id3
.path
)-1);
392 temp_id3
.title
= &temp_id3
.path
[0];
397 struct mp3entry
* audio_next_track(void)
399 int next_idx
= track_ridx
;
401 if (!audio_have_tracks())
405 next_idx
&= MAX_TRACK_MASK
;
407 if (!tracks
[next_idx
].taginfo_ready
)
410 return &tracks
[next_idx
].id3
;
413 bool audio_has_changed_track(void)
417 track_changed
= false;
424 void audio_play(long offset
)
428 #ifdef PLAYBACK_VOICE
429 /* Truncate any existing voice output so we don't have spelling
430 * etc. over the first part of the played track */
431 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
432 queue_post(&voice_queue
, Q_VOICE_STOP
, (void *)1);
436 if (playing
&& offset
<= 0)
438 LOGFQUEUE("audio > audio Q_AUDIO_NEW_PLAYLIST");
439 queue_post(&audio_queue
, Q_AUDIO_NEW_PLAYLIST
, 0);
443 LOGFQUEUE("audio > audio Q_AUDIO_STOP");
444 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
445 LOGFQUEUE("audio > audio Q_AUDIO_PLAY");
446 queue_post(&audio_queue
, Q_AUDIO_PLAY
, (void *)offset
);
449 /* Don't return until playback has actually started */
454 void audio_stop(void)
457 LOGFQUEUE("audio > audio Q_AUDIO_STOP");
458 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
460 /* Don't return until playback has actually stopped */
465 void audio_pause(void)
467 LOGFQUEUE("audio > audio Q_AUDIO_PAUSE");
468 queue_post(&audio_queue
, Q_AUDIO_PAUSE
, (void *)true);
471 void audio_resume(void)
473 LOGFQUEUE("audio > audio Q_AUDIO_PAUSE resume");
474 queue_post(&audio_queue
, Q_AUDIO_PAUSE
, (void *)false);
477 void audio_next(void)
479 if (playlist_check(ci
.new_track
+ wps_offset
+ 1))
481 if (global_settings
.beep
)
482 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
484 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
485 queue_post(&audio_queue
, Q_AUDIO_SKIP
, (void *)1);
486 /* Keep wps fast while our message travels inside deep playback queues. */
488 track_changed
= true;
492 /* No more tracks. */
493 if (global_settings
.beep
)
494 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
498 void audio_prev(void)
500 if (playlist_check(ci
.new_track
+ wps_offset
- 1))
502 if (global_settings
.beep
)
503 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
505 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
506 queue_post(&audio_queue
, Q_AUDIO_SKIP
, (void *)-1);
507 /* Keep wps fast while our message travels inside deep playback queues. */
509 track_changed
= true;
513 /* No more tracks. */
514 if (global_settings
.beep
)
515 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
519 void audio_next_dir(void)
521 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
522 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, (void *)1);
525 void audio_prev_dir(void)
527 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
528 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, (void *)-1);
531 void audio_pre_ff_rewind(void)
533 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
534 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
537 void audio_ff_rewind(long newpos
)
539 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
540 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, (int *)newpos
);
543 void audio_flush_and_reload_tracks(void)
545 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
546 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
549 void audio_error_clear(void)
553 int audio_status(void)
558 ret
|= AUDIO_STATUS_PLAY
;
561 ret
|= AUDIO_STATUS_PAUSE
;
563 #ifdef HAVE_RECORDING
564 /* Do this here for constitency with mpeg.c version */
565 ret
|= pcm_rec_status();
571 bool audio_query_poweroff(void)
573 return !(playing
&& paused
);
576 int audio_get_file_pos(void)
581 void audio_set_buffer_margin(int setting
)
583 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
584 buffer_margin
= lookup
[setting
];
585 logf("buffer margin: %ds", buffer_margin
);
586 set_filebuf_watermark(buffer_margin
);
589 /* Set crossfade & PCM buffer length. */
590 void audio_set_crossfade(int enable
)
593 bool was_playing
= (playing
&& audio_is_initialized
);
600 return; /* Audio buffers not yet set up */
604 seconds
= global_settings
.crossfade_fade_out_delay
605 + global_settings
.crossfade_fade_out_duration
;
607 /* Buffer has to be at least 2s long. */
609 logf("buf len: %d", seconds
);
610 size
= seconds
* (NATIVE_FREQUENCY
*4);
613 size
= NATIVE_FREQUENCY
*2;
615 if (pcmbuf_get_bufsize() == size
)
620 /* Store the track resume position */
621 offset
= CUR_TI
->id3
.offset
;
623 /* Playback has to be stopped before changing the buffer size. */
624 gui_syncsplash(0, true, (char *)str(LANG_RESTARTING_PLAYBACK
));
625 LOGFQUEUE("audio > audio Q_AUDIO_STOP");
626 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
627 while (audio_codec_loaded
)
633 /* Re-initialize audio system. */
635 pcmbuf_crossfade_enable(enable
);
636 audio_reset_buffer();
637 logf("abuf:%dB", pcmbuf_get_bufsize());
638 logf("fbuf:%dB", filebuflen
);
642 /* Restart playback. */
645 LOGFQUEUE("audio > audio Q_AUDIO_PLAY");
646 queue_post(&audio_queue
, Q_AUDIO_PLAY
, (void *)offset
);
648 /* Wait for the playback to start again (and display the splash
649 screen during that period. */
655 void audio_preinit(void)
657 logf("playback system pre-init");
660 current_codec
= CODEC_IDX_AUDIO
;
663 audio_codec_loaded
= false;
664 #ifdef PLAYBACK_VOICE
665 voice_is_playing
= false;
666 voice_thread_start
= false;
667 voice_codec_loaded
= false;
669 track_changed
= false;
671 track_buffer_callback
= NULL
;
672 track_unbuffer_callback
= NULL
;
673 track_changed_callback
= NULL
;
674 track_ridx
= 0; /* Just to prevent CUR_TI from being anything random. */
675 prev_ti
= &tracks
[MAX_TRACK
-1]; /* And prevent prev_ti being random too */
677 mutex_init(&mutex_codecthread
);
679 queue_init(&audio_queue
, true);
680 queue_init(&codec_queue
, true);
681 /* create a private queue */
682 queue_init(&codec_callback_queue
, false);
684 create_thread(audio_thread
, audio_stack
, sizeof(audio_stack
),
685 audio_thread_name
IF_PRIO(, PRIORITY_BUFFERING
));
688 void audio_init(void)
690 LOGFQUEUE("audio > audio Q_AUDIO_POSTINIT");
691 queue_post(&audio_queue
, Q_AUDIO_POSTINIT
, 0);
694 void voice_init(void)
696 #ifdef PLAYBACK_VOICE
698 return; /* Audio buffers not yet set up */
703 if (!talk_voice_required())
706 logf("Starting voice codec");
707 queue_init(&voice_queue
, true);
708 voice_thread_p
= create_thread(voice_thread
, voice_stack
,
709 sizeof(voice_stack
), voice_thread_name
710 IF_PRIO(, PRIORITY_PLAYBACK
));
712 while (!voice_codec_loaded
)
717 void voice_stop(void)
719 #ifdef PLAYBACK_VOICE
720 /* Messages should not be posted to voice codec queue unless it is the
721 current codec or deadlocks happen.
723 if (current_codec
!= CODEC_IDX_VOICE
)
726 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
727 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
728 while (voice_is_playing
)
737 /* --- Routines called from multiple threads --- */
739 #ifdef PLAYBACK_VOICE
740 static void swap_codec(void)
742 int my_codec
= current_codec
;
744 logf("swapping out codec:%d", my_codec
);
746 /* Save our current IRAM and DRAM */
747 memcpy(iram_buf
[my_codec
], (unsigned char *)CODEC_IRAM_ORIGIN
,
749 memcpy(dram_buf
[my_codec
], codecbuf
, CODEC_SIZE
);
751 /* Release my semaphore */
752 mutex_unlock(&mutex_codecthread
);
754 /* Loop until the other codec has locked and run */
756 /* Release my semaphore and force a task switch. */
758 } while (my_codec
== current_codec
);
760 /* Wait for other codec to unlock */
761 mutex_lock(&mutex_codecthread
);
764 current_codec
= my_codec
;
766 /* Reload our IRAM and DRAM */
767 memcpy((unsigned char *)CODEC_IRAM_ORIGIN
, iram_buf
[my_codec
],
770 memcpy(codecbuf
, dram_buf
[my_codec
], CODEC_SIZE
);
772 logf("resuming codec:%d", my_codec
);
776 static void set_filebuf_watermark(int seconds
)
780 if (current_codec
== CODEC_IDX_VOICE
)
784 return; /* Audio buffers not yet set up */
786 bytes
= MAX(CUR_TI
->id3
.bitrate
* seconds
* (1000/8), conf_watermark
);
787 bytes
= MIN(bytes
, filebuflen
/ 2);
788 conf_watermark
= bytes
;
791 static const char * get_codec_filename(int enc_spec
)
794 int type
= enc_spec
& CODEC_TYPE_MASK
;
795 int afmt
= enc_spec
& CODEC_AFMT_MASK
;
797 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
798 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
800 fname
= (type
== CODEC_TYPE_DECODER
) ?
801 audio_formats
[afmt
].codec_fn
: audio_formats
[afmt
].codec_enc_fn
;
804 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
805 afmt
, fname
? fname
: "<unknown>");
808 } /* get_codec_filename */
811 /* --- Voice thread --- */
813 #ifdef PLAYBACK_VOICE
815 static bool voice_pcmbuf_insert_split_callback(
816 const void *ch1
, const void *ch2
, size_t length
)
826 if (dsp_stereo_mode() == STEREO_NONINTERLEAVED
)
827 length
*= 2; /* Length is per channel */
831 long est_output_size
= dsp_output_size(length
);
833 while ((dest
= pcmbuf_request_voice_buffer(est_output_size
,
834 &output_size
, playing
)) == NULL
)
836 if (playing
&& audio_codec_loaded
)
842 /* Get the real input_size for output_size bytes, guarding
843 * against resampling buffer overflows. */
844 input_size
= dsp_input_size(output_size
);
848 DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld<=0\n",
849 output_size
, length
, input_size
);
850 /* If this happens, there are samples of codec data that don't
851 * become a number of pcm samples, and something is broken */
855 /* Input size has grown, no error, just don't write more than length */
856 if ((size_t)input_size
> length
)
859 output_size
= dsp_process(dest
, src
, input_size
);
863 pcmbuf_mix_voice(output_size
);
864 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) && audio_codec_loaded
)
868 pcmbuf_write_complete(output_size
);
870 length
-= input_size
;
874 } /* voice_pcmbuf_insert_split_callback */
876 static bool voice_pcmbuf_insert_callback(const char *buf
, size_t length
)
878 /* TODO: The audiobuffer API should probably be updated, and be based on
879 * pcmbuf_insert_split(). */
880 long real_length
= length
;
882 if (dsp_stereo_mode() == STEREO_NONINTERLEAVED
)
883 length
/= 2; /* Length is per channel */
885 /* Second channel is only used for non-interleaved stereo. */
886 return voice_pcmbuf_insert_split_callback(buf
, buf
+ (real_length
/ 2),
890 static void* voice_get_memory_callback(size_t *size
)
896 static void voice_set_elapsed_callback(unsigned int value
)
901 static void voice_set_offset_callback(size_t value
)
906 static size_t voice_filebuf_callback(void *ptr
, size_t size
)
914 static void* voice_request_buffer_callback(size_t *realsize
, size_t reqsize
)
918 if (ci_voice
.new_track
)
926 if (voice_is_playing
|| playing
)
927 queue_wait_w_tmo(&voice_queue
, &ev
, 0);
929 queue_wait(&voice_queue
, &ev
);
930 if (!voice_is_playing
)
932 if (ev
.id
== SYS_TIMEOUT
)
933 ev
.id
= Q_AUDIO_PLAY
;
938 LOGFQUEUE("voice < Q_AUDIO_PLAY");
941 if (audio_codec_loaded
)
947 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
948 case Q_ENCODER_RECORD
:
949 LOGFQUEUE("voice < Q_ENCODER_RECORD");
955 LOGFQUEUE("voice < Q_VOICE_STOP");
956 if (ev
.data
== (void *)1 && !playing
&& pcm_is_playing())
957 /* Aborting: Slight hack - flush PCM buffer if
958 only being used for voice */
960 if (voice_is_playing
)
962 /* Clear the current buffer */
963 voice_is_playing
= false;
964 voice_getmore
= NULL
;
968 /* Force the codec to think it's changing tracks */
969 ci_voice
.new_track
= 1;
976 case SYS_USB_CONNECTED
:
977 LOGFQUEUE("voice < SYS_USB_CONNECTED");
978 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
979 if (audio_codec_loaded
)
981 usb_wait_for_disconnect(&voice_queue
);
985 LOGFQUEUE("voice < Q_VOICE_PLAY");
986 if (!voice_is_playing
)
988 /* Set up new voice data */
989 struct voice_info
*voice_data
;
990 voice_is_playing
= true;
992 voice_data
= ev
.data
;
993 voice_remaining
= voice_data
->size
;
994 voicebuf
= voice_data
->buf
;
995 voice_getmore
= voice_data
->callback
;
997 goto voice_play_clip
;
1000 LOGFQUEUE("voice < SYS_TIMEOUT");
1001 goto voice_play_clip
;
1004 LOGFQUEUE("voice < default");
1010 if (voice_remaining
== 0 || voicebuf
== NULL
)
1013 voice_getmore((unsigned char **)&voicebuf
, (int *)&voice_remaining
);
1015 /* If this clip is done */
1016 if (voice_remaining
== 0)
1018 LOGFQUEUE("voice > voice Q_VOICE_STOP");
1019 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
1020 /* Force pcm playback. */
1021 if (!pcm_is_playing())
1022 pcmbuf_play_start();
1026 *realsize
= MIN(voice_remaining
, reqsize
);
1032 } /* voice_request_buffer_callback */
1034 static void voice_advance_buffer_callback(size_t amount
)
1036 amount
= MIN(amount
, voice_remaining
);
1038 voice_remaining
-= amount
;
1041 static void voice_advance_buffer_loc_callback(void *ptr
)
1043 size_t amount
= (size_t)ptr
- (size_t)voicebuf
;
1045 voice_advance_buffer_callback(amount
);
1048 static off_t
voice_mp3_get_filepos_callback(int newtime
)
1055 static void voice_do_nothing(void)
1060 static bool voice_seek_buffer_callback(size_t newpos
)
1067 static bool voice_request_next_track_callback(void)
1069 ci_voice
.new_track
= 0;
1073 static void voice_thread(void)
1077 logf("Loading voice codec");
1078 voice_codec_loaded
= true;
1079 mutex_lock(&mutex_codecthread
);
1080 current_codec
= CODEC_IDX_VOICE
;
1081 dsp_configure(DSP_RESET
, 0);
1082 voice_remaining
= 0;
1083 voice_getmore
= NULL
;
1085 codec_load_file(get_codec_filename(AFMT_MPA_L3
), &ci_voice
);
1087 logf("Voice codec finished");
1088 voice_codec_loaded
= false;
1089 mutex_unlock(&mutex_codecthread
);
1091 } /* voice_thread */
1093 #endif /* PLAYBACK_VOICE */
1095 /* --- Codec thread --- */
1097 static bool codec_pcmbuf_insert_split_callback(
1098 const void *ch1
, const void *ch2
, size_t length
)
1108 if (dsp_stereo_mode() == STEREO_NONINTERLEAVED
)
1109 length
*= 2; /* Length is per channel */
1113 long est_output_size
= dsp_output_size(length
);
1114 /* Prevent audio from a previous track from playing */
1115 if (ci
.new_track
|| ci
.stop_codec
)
1118 while ((dest
= pcmbuf_request_buffer(est_output_size
,
1119 &output_size
)) == NULL
)
1122 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
1126 /* Get the real input_size for output_size bytes, guarding
1127 * against resampling buffer overflows. */
1128 input_size
= dsp_input_size(output_size
);
1130 if (input_size
<= 0)
1132 DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld<=0\n",
1133 output_size
, length
, input_size
);
1134 /* If this happens, there are samples of codec data that don't
1135 * become a number of pcm samples, and something is broken */
1139 /* Input size has grown, no error, just don't write more than length */
1140 if ((size_t)input_size
> length
)
1141 input_size
= length
;
1143 output_size
= dsp_process(dest
, src
, input_size
);
1145 pcmbuf_write_complete(output_size
);
1147 #ifdef PLAYBACK_VOICE
1148 if ((voice_is_playing
|| voice_thread_start
)
1149 && pcm_is_playing() && voice_codec_loaded
&&
1150 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1152 voice_thread_start
= false;
1157 length
-= input_size
;
1161 } /* codec_pcmbuf_insert_split_callback */
1163 static bool codec_pcmbuf_insert_callback(const char *buf
, size_t length
)
1165 /* TODO: The audiobuffer API should probably be updated, and be based on
1166 * pcmbuf_insert_split(). */
1167 long real_length
= length
;
1169 if (dsp_stereo_mode() == STEREO_NONINTERLEAVED
)
1170 length
/= 2; /* Length is per channel */
1172 /* Second channel is only used for non-interleaved stereo. */
1173 return codec_pcmbuf_insert_split_callback(buf
, buf
+ (real_length
/ 2),
1177 static void* codec_get_memory_callback(size_t *size
)
1179 *size
= MALLOC_BUFSIZE
;
1180 return &audiobuf
[talk_get_bufsize()];
1183 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
1184 static void codec_pcmbuf_position_callback(size_t size
)
1186 /* This is called from an ISR, so be quick */
1187 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
1188 prev_ti
->id3
.elapsed
;
1190 if (time
>= prev_ti
->id3
.length
)
1192 pcmbuf_set_position_callback(NULL
);
1193 prev_ti
->id3
.elapsed
= prev_ti
->id3
.length
;
1196 prev_ti
->id3
.elapsed
= time
;
1199 static void codec_set_elapsed_callback(unsigned int value
)
1201 unsigned int latency
;
1205 #ifdef AB_REPEAT_ENABLE
1206 ab_position_report(value
);
1209 latency
= pcmbuf_get_latency();
1210 if (value
< latency
)
1211 CUR_TI
->id3
.elapsed
= 0;
1212 else if (value
- latency
> CUR_TI
->id3
.elapsed
||
1213 value
- latency
< CUR_TI
->id3
.elapsed
- 2)
1215 CUR_TI
->id3
.elapsed
= value
- latency
;
1219 static void codec_set_offset_callback(size_t value
)
1221 unsigned int latency
;
1226 latency
= pcmbuf_get_latency() * CUR_TI
->id3
.bitrate
/ 8;
1227 if (value
< latency
)
1228 CUR_TI
->id3
.offset
= 0;
1230 CUR_TI
->id3
.offset
= value
- latency
;
1233 static void codec_advance_buffer_counters(size_t amount
)
1235 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
1236 ci
.curpos
+= amount
;
1237 CUR_TI
->available
-= amount
;
1239 /* Start buffer filling as necessary. */
1240 if (!pcmbuf_is_lowdata() && !filling
)
1242 if (FILEBUFUSED
< conf_watermark
&& playing
&& !playlist_end
)
1244 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1245 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1250 /* copy up-to size bytes into ptr and return the actual size copied */
1251 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
1253 char *buf
= (char *)ptr
;
1257 if (ci
.stop_codec
|| !playing
)
1260 /* The ammount to copy is the lesser of the requested amount and the
1261 * amount left of the current track (both on disk and already loaded) */
1262 copy_n
= MIN(size
, CUR_TI
->available
+ CUR_TI
->filerem
);
1264 /* Nothing requested OR nothing left */
1268 /* Let the disk buffer catch fill until enough data is available */
1269 while (copy_n
> CUR_TI
->available
)
1273 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1274 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1278 if (ci
.stop_codec
|| ci
.new_track
)
1282 /* Copy as much as possible without wrapping */
1283 part_n
= MIN(copy_n
, filebuflen
- buf_ridx
);
1284 memcpy(buf
, &filebuf
[buf_ridx
], part_n
);
1285 /* Copy the rest in the case of a wrap */
1286 if (part_n
< copy_n
) {
1287 memcpy(&buf
[part_n
], &filebuf
[0], copy_n
- part_n
);
1290 /* Update read and other position pointers */
1291 codec_advance_buffer_counters(copy_n
);
1293 /* Return the actual amount of data copied to the buffer */
1295 } /* codec_filebuf_callback */
1297 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1299 size_t short_n
, copy_n
, buf_rem
;
1307 copy_n
= MIN(reqsize
, CUR_TI
->available
+ CUR_TI
->filerem
);
1314 while (copy_n
> CUR_TI
->available
)
1318 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1319 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1323 if (ci
.stop_codec
|| ci
.new_track
)
1330 /* How much is left at the end of the file buffer before wrap? */
1331 buf_rem
= filebuflen
- buf_ridx
;
1333 /* If we can't satisfy the request without wrapping */
1334 if (buf_rem
< copy_n
)
1336 /* How short are we? */
1337 short_n
= copy_n
- buf_rem
;
1339 /* If we can fudge it with the guardbuf */
1340 if (short_n
< GUARD_BUFSIZE
)
1341 memcpy(&filebuf
[filebuflen
], &filebuf
[0], short_n
);
1348 return (char *)&filebuf
[buf_ridx
];
1349 } /* codec_request_buffer_callback */
1351 static int get_codec_base_type(int type
)
1363 static void codec_advance_buffer_callback(size_t amount
)
1365 if (amount
> CUR_TI
->available
+ CUR_TI
->filerem
)
1366 amount
= CUR_TI
->available
+ CUR_TI
->filerem
;
1368 while (amount
> CUR_TI
->available
&& filling
)
1371 if (amount
> CUR_TI
->available
)
1375 LOGFQUEUE("codec > audio Q_AUDIO_REBUFFER_SEEK");
1376 queue_post(&audio_queue
,
1377 Q_AUDIO_REBUFFER_SEEK
, (void *)(ci
.curpos
+ amount
));
1379 queue_wait(&codec_callback_queue
, &ev
);
1382 case Q_CODEC_REQUEST_FAILED
:
1383 LOGFQUEUE("codec < Q_CODEC_REQUEST_FAILED");
1384 ci
.stop_codec
= true;
1387 case Q_CODEC_REQUEST_COMPLETE
:
1388 LOGFQUEUE("codec < Q_CODEC_REQUEST_COMPLETE");
1392 LOGFQUEUE("codec < default");
1393 ci
.stop_codec
= true;
1398 codec_advance_buffer_counters(amount
);
1400 codec_set_offset_callback(ci
.curpos
);
1403 static void codec_advance_buffer_loc_callback(void *ptr
)
1405 size_t amount
= (size_t)ptr
- (size_t)&filebuf
[buf_ridx
];
1407 codec_advance_buffer_callback(amount
);
1410 /* Copied from mpeg.c. Should be moved somewhere else. */
1411 static int codec_get_file_pos(void)
1414 struct mp3entry
*id3
= audio_current_track();
1420 /* Use the TOC to find the new position */
1421 unsigned int percent
, remainder
;
1422 int curtoc
, nexttoc
, plen
;
1424 percent
= (id3
->elapsed
*100)/id3
->length
;
1428 curtoc
= id3
->toc
[percent
];
1431 nexttoc
= id3
->toc
[percent
+1];
1435 pos
= (id3
->filesize
/256)*curtoc
;
1437 /* Use the remainder to get a more accurate position */
1438 remainder
= (id3
->elapsed
*100)%id3
->length
;
1439 remainder
= (remainder
*100)/id3
->length
;
1440 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1441 pos
+= (plen
/100)*remainder
;
1445 /* No TOC exists, estimate the new position */
1446 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1447 (id3
->elapsed
/ 1000);
1450 else if (id3
->bitrate
)
1451 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1455 /* Don't seek right to the end of the file so that we can
1456 transition properly to the next song */
1457 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1458 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1459 /* skip past id3v2 tag and other leading garbage */
1460 else if (pos
< (int)id3
->first_frame_offset
)
1461 pos
= id3
->first_frame_offset
;
1466 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1470 CUR_TI
->id3
.elapsed
= newtime
;
1471 newpos
= codec_get_file_pos();
1476 static void codec_seek_complete_callback(void)
1478 logf("seek_complete");
1479 if (pcm_is_paused())
1481 /* If this is not a seamless seek, clear the buffer */
1484 /* If playback was not 'deliberately' paused, unpause now */
1486 pcmbuf_pause(false);
1491 static bool codec_seek_buffer_callback(size_t newpos
)
1495 logf("codec_seek_buffer_callback");
1497 if (newpos
>= CUR_TI
->filesize
)
1498 newpos
= CUR_TI
->filesize
- 1;
1500 difference
= newpos
- ci
.curpos
;
1501 if (difference
>= 0)
1503 /* Seeking forward */
1504 logf("seek: +%d", difference
);
1505 codec_advance_buffer_callback(difference
);
1509 /* Seeking backward */
1510 difference
= -difference
;
1511 if (ci
.curpos
- difference
< 0)
1512 difference
= ci
.curpos
;
1514 /* We need to reload the song. */
1515 if (newpos
< CUR_TI
->start_pos
)
1519 LOGFQUEUE("codec > audio Q_AUDIO_REBUFFER_SEEK");
1520 queue_post(&audio_queue
, Q_AUDIO_REBUFFER_SEEK
, (void *)newpos
);
1522 queue_wait(&codec_callback_queue
, &ev
);
1525 case Q_CODEC_REQUEST_COMPLETE
:
1526 LOGFQUEUE("codec < Q_CODEC_REQUEST_COMPLETE");
1529 case Q_CODEC_REQUEST_FAILED
:
1530 LOGFQUEUE("codec < Q_CODEC_REQUEST_FAILED");
1531 ci
.stop_codec
= true;
1535 LOGFQUEUE("codec < default");
1540 /* Seeking inside buffer space. */
1541 logf("seek: -%d", difference
);
1542 CUR_TI
->available
+= difference
;
1543 buf_ridx
= RINGBUF_SUB(buf_ridx
, (unsigned)difference
);
1544 ci
.curpos
-= difference
;
1549 static void codec_configure_callback(int setting
, void *value
)
1552 case CODEC_SET_FILEBUF_WATERMARK
:
1553 conf_watermark
= (unsigned long)value
;
1554 set_filebuf_watermark(buffer_margin
);
1557 case CODEC_SET_FILEBUF_CHUNKSIZE
:
1558 conf_filechunk
= (unsigned long)value
;
1561 case CODEC_SET_FILEBUF_PRESEEK
:
1562 conf_preseek
= (unsigned long)value
;
1566 if (!dsp_configure(setting
, value
)) { logf("Illegal key:%d", setting
); }
1570 static void codec_track_changed(void)
1572 automatic_skip
= false;
1573 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1574 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1577 static void codec_pcmbuf_track_changed_callback(void)
1579 pcmbuf_set_position_callback(NULL
);
1580 codec_track_changed();
1583 static void codec_discard_codec_callback(void)
1585 if (CUR_TI
->has_codec
)
1587 CUR_TI
->has_codec
= false;
1588 buf_ridx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->codecsize
);
1592 /* Check if a buffer desync has happened, log it and stop playback. */
1593 if (buf_ridx
!= CUR_TI
->buf_idx
)
1595 int offset
= CUR_TI
->buf_idx
- buf_ridx
;
1596 size_t new_used
= FILEBUFUSED
- offset
;
1598 logf("Buf off :%d=%d-%d", offset
, CUR_TI
->buf_idx
, buf_ridx
);
1599 logf("Used off:%d",FILEBUFUSED
- new_used
);
1601 /* This is a fatal internal error and it's not safe to
1602 * continue playback. */
1603 ci
.stop_codec
= true;
1604 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1609 static void codec_track_skip_done(bool was_manual
)
1611 /* Manual track change (always crossfade or flush audio). */
1614 pcmbuf_crossfade_init(true);
1615 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1616 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1618 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1619 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1620 && global_settings
.crossfade
!= 2)
1622 pcmbuf_crossfade_init(false);
1623 codec_track_changed();
1625 /* Gapless playback. */
1628 pcmbuf_set_position_callback(codec_pcmbuf_position_callback
);
1629 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1633 static bool codec_load_next_track(void)
1637 prev_track_elapsed
= CUR_TI
->id3
.elapsed
;
1640 codec_seek_complete_callback();
1642 #ifdef AB_REPEAT_ENABLE
1643 ab_end_of_track_report();
1646 logf("Request new track");
1648 if (ci
.new_track
== 0)
1651 automatic_skip
= true;
1654 trigger_cpu_boost();
1655 LOGFQUEUE("codec > audio Q_AUDIO_CHECK_NEW_TRACK");
1656 queue_post(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1659 queue_wait(&codec_callback_queue
, &ev
);
1660 if (ev
.id
== Q_CODEC_REQUEST_PENDING
)
1662 if (!automatic_skip
)
1671 case Q_CODEC_REQUEST_COMPLETE
:
1672 LOGFQUEUE("codec < Q_CODEC_REQUEST_COMPLETE");
1673 codec_track_skip_done(!automatic_skip
);
1676 case Q_CODEC_REQUEST_FAILED
:
1677 LOGFQUEUE("codec < Q_CODEC_REQUEST_FAILED");
1679 ci
.stop_codec
= true;
1683 LOGFQUEUE("codec < default");
1684 ci
.stop_codec
= true;
1689 static bool codec_request_next_track_callback(void)
1693 if (ci
.stop_codec
|| !playing
)
1696 prev_codectype
= get_codec_base_type(CUR_TI
->id3
.codectype
);
1698 if (!codec_load_next_track())
1701 /* Check if the next codec is the same file. */
1702 if (prev_codectype
== get_codec_base_type(CUR_TI
->id3
.codectype
))
1704 logf("New track loaded");
1705 codec_discard_codec_callback();
1710 logf("New codec:%d/%d", CUR_TI
->id3
.codectype
, prev_codectype
);
1715 static void codec_thread(void)
1723 queue_wait(&codec_queue
, &ev
);
1726 case Q_CODEC_LOAD_DISK
:
1727 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1728 audio_codec_loaded
= true;
1729 #ifdef PLAYBACK_VOICE
1730 /* Don't sent messages to voice codec if it's not current */
1731 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1733 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1734 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1737 mutex_lock(&mutex_codecthread
);
1738 current_codec
= CODEC_IDX_AUDIO
;
1739 ci
.stop_codec
= false;
1740 status
= codec_load_file((const char *)ev
.data
, &ci
);
1741 mutex_unlock(&mutex_codecthread
);
1745 LOGFQUEUE("codec < Q_CODEC_LOAD");
1746 if (!CUR_TI
->has_codec
) {
1747 logf("Codec slot is empty!");
1748 /* Wait for the pcm buffer to go empty */
1749 while (pcm_is_playing())
1751 /* This must be set to prevent an infinite loop */
1752 ci
.stop_codec
= true;
1753 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1754 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
1758 audio_codec_loaded
= true;
1759 #ifdef PLAYBACK_VOICE
1760 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1762 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1763 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1766 mutex_lock(&mutex_codecthread
);
1767 current_codec
= CODEC_IDX_AUDIO
;
1768 ci
.stop_codec
= false;
1769 wrap
= (size_t)&filebuf
[filebuflen
] - (size_t)CUR_TI
->codecbuf
;
1770 status
= codec_load_ram(CUR_TI
->codecbuf
, CUR_TI
->codecsize
,
1771 &filebuf
[0], wrap
, &ci
);
1772 mutex_unlock(&mutex_codecthread
);
1775 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
1776 case Q_ENCODER_LOAD_DISK
:
1777 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1778 audio_codec_loaded
= false; /* Not audio codec! */
1779 #ifdef PLAYBACK_VOICE
1780 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1782 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
1783 queue_post(&voice_queue
, Q_ENCODER_RECORD
, NULL
);
1786 mutex_lock(&mutex_codecthread
);
1787 current_codec
= CODEC_IDX_AUDIO
;
1788 ci
.stop_codec
= false;
1789 status
= codec_load_file((const char *)ev
.data
, &ci
);
1790 mutex_unlock(&mutex_codecthread
);
1795 case SYS_USB_CONNECTED
:
1796 LOGFQUEUE("codec < SYS_USB_CONNECTED");
1797 queue_clear(&codec_queue
);
1798 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
1799 usb_wait_for_disconnect(&codec_queue
);
1804 LOGFQUEUE("codec < default");
1807 if (audio_codec_loaded
)
1815 audio_codec_loaded
= false;
1819 case Q_CODEC_LOAD_DISK
:
1821 LOGFQUEUE("codec < Q_CODEC_LOAD");
1824 if (ci
.new_track
|| status
!= CODEC_OK
)
1828 logf("Codec failure");
1829 gui_syncsplash(HZ
*2, true, "Codec failure");
1832 if (!codec_load_next_track())
1834 // queue_post(&codec_queue, Q_AUDIO_STOP, 0);
1835 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1836 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1842 logf("Codec finished");
1845 /* Wait for the audio to stop playing before
1846 * triggering the WPS exit */
1847 while(pcm_is_playing())
1849 CUR_TI
->id3
.elapsed
= CUR_TI
->id3
.length
- pcmbuf_get_latency();
1852 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1853 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1858 if (CUR_TI
->has_codec
)
1860 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1861 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
1865 const char *codec_fn
= get_codec_filename(CUR_TI
->id3
.codectype
);
1866 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1867 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
1874 LOGFQUEUE("codec < default");
1881 /* --- Audio thread --- */
1883 static bool audio_filebuf_is_lowdata(void)
1885 return FILEBUFUSED
< AUDIO_FILEBUF_CRITICAL
;
1888 static bool audio_have_tracks(void)
1890 return track_ridx
!= track_widx
|| CUR_TI
->filesize
;
1893 static bool audio_have_free_tracks(void)
1895 if (track_widx
< track_ridx
)
1896 return track_widx
+ 1 < track_ridx
;
1897 else if (track_ridx
== 0)
1898 return track_widx
< MAX_TRACK
- 1;
1903 int audio_track_count(void)
1905 if (audio_have_tracks())
1907 int relative_track_widx
= track_widx
;
1909 if (track_ridx
> track_widx
)
1910 relative_track_widx
+= MAX_TRACK
;
1912 return relative_track_widx
- track_ridx
+ 1;
1918 long audio_filebufused(void)
1920 return (long) FILEBUFUSED
;
1923 /* Count the data BETWEEN the selected tracks */
1924 static size_t audio_buffer_count_tracks(int from_track
, int to_track
)
1927 bool need_wrap
= to_track
< from_track
;
1931 if (++from_track
>= MAX_TRACK
)
1933 from_track
-= MAX_TRACK
;
1937 if (from_track
>= to_track
&& !need_wrap
)
1940 amount
+= tracks
[from_track
].codecsize
+ tracks
[from_track
].filesize
;
1945 static bool audio_buffer_wind_forward(int new_track_ridx
, int old_track_ridx
)
1949 /* Start with the remainder of the previously playing track */
1950 amount
= tracks
[old_track_ridx
].filesize
- ci
.curpos
;
1951 /* Then collect all data from tracks in between them */
1952 amount
+= audio_buffer_count_tracks(old_track_ridx
, new_track_ridx
);
1953 logf("bwf:%ldB", (long) amount
);
1955 if (amount
> FILEBUFUSED
)
1958 /* Wind the buffer to the beginning of the target track or its codec */
1959 buf_ridx
= RINGBUF_ADD(buf_ridx
, amount
);
1964 static bool audio_buffer_wind_backward(int new_track_ridx
, int old_track_ridx
)
1966 /* Available buffer data */
1968 /* Start with the previously playing track's data and our data */
1972 buf_back
= RINGBUF_SUB(buf_ridx
, buf_widx
);
1974 /* If we're not just resetting the current track */
1975 if (new_track_ridx
!= old_track_ridx
)
1977 /* Need to wind to before the old track's codec and our filesize */
1978 amount
+= tracks
[old_track_ridx
].codecsize
;
1979 amount
+= tracks
[new_track_ridx
].filesize
;
1981 /* Rewind the old track to its beginning */
1982 tracks
[old_track_ridx
].available
=
1983 tracks
[old_track_ridx
].filesize
- tracks
[old_track_ridx
].filerem
;
1986 /* If the codec was ever buffered */
1987 if (tracks
[new_track_ridx
].codecsize
)
1989 /* Add the codec to the needed size */
1990 amount
+= tracks
[new_track_ridx
].codecsize
;
1991 tracks
[new_track_ridx
].has_codec
= true;
1994 /* Then collect all data from tracks between new and old */
1995 amount
+= audio_buffer_count_tracks(new_track_ridx
, old_track_ridx
);
1997 /* Do we have space to make this skip? */
1998 if (amount
> buf_back
)
2001 logf("bwb:%ldB",amount
);
2003 /* Rewind the buffer to the beginning of the target track or its codec */
2004 buf_ridx
= RINGBUF_SUB(buf_ridx
, amount
);
2006 /* Reset to the beginning of the new track */
2007 tracks
[new_track_ridx
].available
= tracks
[new_track_ridx
].filesize
;
2012 static void audio_update_trackinfo(void)
2014 ci
.filesize
= CUR_TI
->filesize
;
2015 CUR_TI
->id3
.elapsed
= 0;
2016 CUR_TI
->id3
.offset
= 0;
2017 ci
.id3
= &CUR_TI
->id3
;
2019 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2022 /* Yield to codecs for as long as possible if they are in need of data
2023 * return true if the caller should break to let the audio thread process
2025 static bool audio_yield_codecs(void)
2029 if (!queue_empty(&audio_queue
))
2032 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
2033 && !ci
.stop_codec
&& playing
&& !audio_filebuf_is_lowdata())
2036 if (!queue_empty(&audio_queue
))
2043 static void audio_clear_track_entries(bool clear_unbuffered
)
2045 int cur_idx
= track_widx
;
2048 logf("Clearing tracks:%d/%d, %d", track_ridx
, track_widx
, clear_unbuffered
);
2050 /* Loop over all tracks from write-to-read */
2054 cur_idx
&= MAX_TRACK_MASK
;
2056 if (cur_idx
== track_ridx
)
2059 /* If the track is buffered, conditionally clear/notify,
2060 * otherwise clear the track if that option is selected */
2061 if (tracks
[cur_idx
].event_sent
)
2065 /* If there is an unbuffer callback, call it, otherwise,
2066 * just clear the track */
2067 if (track_unbuffer_callback
)
2068 track_unbuffer_callback(&tracks
[last_idx
].id3
, false);
2070 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2074 else if (clear_unbuffered
)
2075 memset(&tracks
[cur_idx
], 0, sizeof(struct track_info
));
2078 /* We clear the previous instance of a buffered track throughout
2079 * the above loop to facilitate 'last' detection. Clear/notify
2080 * the last track here */
2083 if (track_unbuffer_callback
)
2084 track_unbuffer_callback(&tracks
[last_idx
].id3
, true);
2085 memset(&tracks
[last_idx
], 0, sizeof(struct track_info
));
2089 /* FIXME: This code should be made more generic and move to metadata.c */
2090 static void audio_strip_id3v1_tag(void)
2093 static const unsigned char tag
[] = "TAG";
2097 tag_idx
= RINGBUF_SUB(buf_widx
, 128);
2099 if (FILEBUFUSED
> 128 && tag_idx
> buf_ridx
)
2102 for(i
= 0;i
< 3;i
++)
2104 if(filebuf
[cur_idx
] != tag
[i
])
2107 cur_idx
= RINGBUF_ADD(cur_idx
, 1);
2110 /* Skip id3v1 tag */
2111 logf("Skipping ID3v1 tag");
2113 tracks
[track_widx
].available
-= 128;
2114 tracks
[track_widx
].filesize
-= 128;
2118 /* Returns true if a whole file is read, false otherwise */
2119 static bool audio_read_file(size_t minimum
)
2121 bool ret_val
= false;
2123 /* If we're called and no file is open, this is an error */
2126 logf("Bad fd in arf");
2127 /* Give some hope of miraculous recovery by forcing a track reload */
2128 tracks
[track_widx
].filesize
= 0;
2129 /* Stop this buffering run */
2133 trigger_cpu_boost();
2134 while (tracks
[track_widx
].filerem
> 0)
2140 /* copy_n is the largest chunk that is safe to read */
2141 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2143 /* buf_widx == buf_ridx is defined as buffer empty, not buffer full */
2144 if (RINGBUF_ADD_CROSS(buf_widx
,copy_n
,buf_ridx
) >= 0)
2147 /* rc is the actual amount read */
2148 rc
= read(current_fd
, &filebuf
[buf_widx
], copy_n
);
2152 logf("File ended %dB early", tracks
[track_widx
].filerem
);
2153 tracks
[track_widx
].filesize
-= tracks
[track_widx
].filerem
;
2154 tracks
[track_widx
].filerem
= 0;
2158 /* How much of the playing track did we overwrite */
2159 if (buf_widx
== CUR_TI
->buf_idx
)
2161 /* Special handling; zero or full overlap? */
2162 if (track_widx
== track_ridx
&& CUR_TI
->available
== 0)
2168 overlap
= RINGBUF_ADD_CROSS(buf_widx
,rc
,CUR_TI
->buf_idx
);
2170 if ((unsigned)rc
> tracks
[track_widx
].filerem
)
2172 logf("Bad: rc-filerem=%d, fixing", rc
-tracks
[track_widx
].filerem
);
2173 tracks
[track_widx
].filesize
+= rc
- tracks
[track_widx
].filerem
;
2174 tracks
[track_widx
].filerem
= rc
;
2177 /* Advance buffer */
2178 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2179 tracks
[track_widx
].available
+= rc
;
2180 tracks
[track_widx
].filerem
-= rc
;
2182 /* If we write into the playing track, adjust it's buffer info */
2185 CUR_TI
->buf_idx
+= overlap
;
2186 CUR_TI
->start_pos
+= overlap
;
2189 /* For a rebuffer, fill at least this minimum */
2190 if (minimum
> (unsigned)rc
)
2192 /* Let the codec process up to the watermark */
2193 /* Break immediately if this is a quick buffer, or there is an event */
2194 else if (minimum
|| audio_yield_codecs())
2196 /* Exit quickly, but don't stop the overall buffering process */
2202 if (tracks
[track_widx
].filerem
== 0)
2204 logf("Finished buf:%dB", tracks
[track_widx
].filesize
);
2207 audio_strip_id3v1_tag();
2210 track_widx
&= MAX_TRACK_MASK
;
2212 tracks
[track_widx
].filesize
= 0;
2217 logf("%s buf:%dB", ret_val
?"Quick":"Partially",
2218 tracks
[track_widx
].filesize
- tracks
[track_widx
].filerem
);
2223 static bool audio_loadcodec(bool start_play
)
2230 char codec_path
[MAX_PATH
]; /* Full path to codec */
2232 const char * codec_fn
= get_codec_filename(tracks
[track_widx
].id3
.codectype
);
2233 if (codec_fn
== NULL
)
2236 tracks
[track_widx
].has_codec
= false;
2240 /* Load the codec directly from disk and save some memory. */
2241 track_ridx
= track_widx
;
2242 ci
.filesize
= CUR_TI
->filesize
;
2243 ci
.id3
= &CUR_TI
->id3
;
2244 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2246 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2247 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (void *)codec_fn
);
2252 /* If we already have another track than this one buffered */
2253 if (track_widx
!= track_ridx
)
2255 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
2257 /* If the previous codec is the same as this one, there is no need
2258 * to put another copy of it on the file buffer */
2259 if (get_codec_base_type(tracks
[track_widx
].id3
.codectype
) ==
2260 get_codec_base_type(tracks
[prev_track
].id3
.codectype
)
2261 && audio_codec_loaded
)
2263 logf("Reusing prev. codec");
2269 codec_get_full_path(codec_path
, codec_fn
);
2271 fd
= open(codec_path
, O_RDONLY
);
2274 logf("Codec doesn't exist!");
2278 tracks
[track_widx
].codecsize
= filesize(fd
);
2280 /* Never load a partial codec */
2281 if (RINGBUF_ADD_CROSS(buf_widx
,tracks
[track_widx
].codecsize
,buf_ridx
) >= 0)
2283 logf("Not enough space");
2288 while (size
< tracks
[track_widx
].codecsize
)
2290 copy_n
= MIN(conf_filechunk
, filebuflen
- buf_widx
);
2291 rc
= read(fd
, &filebuf
[buf_widx
], copy_n
);
2295 /* This is an error condition, likely the codec file is corrupt */
2296 logf("Partial codec loaded");
2297 /* Must undo the buffer write of the partial codec */
2298 buf_widx
= RINGBUF_SUB(buf_widx
, size
);
2299 tracks
[track_widx
].codecsize
= 0;
2303 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
2308 tracks
[track_widx
].has_codec
= true;
2311 logf("Done: %dB", size
);
2316 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2317 static void audio_set_elapsed(struct mp3entry
* id3
)
2320 if ( id3
->has_toc
) {
2321 /* calculate elapsed time using TOC */
2323 unsigned int remainder
, plen
, relpos
, nextpos
;
2325 /* find wich percent we're at */
2326 for (i
=0; i
<100; i
++ )
2327 if ( id3
->offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
2334 relpos
= id3
->toc
[i
];
2337 nextpos
= id3
->toc
[i
+1];
2341 remainder
= id3
->offset
- (relpos
* (id3
->filesize
/ 256));
2343 /* set time for this percent (divide before multiply to prevent
2344 overflow on long files. loss of precision is negligible on
2346 id3
->elapsed
= i
* (id3
->length
/ 100);
2348 /* calculate remainder time */
2349 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
2350 id3
->elapsed
+= (((remainder
* 100) / plen
) *
2351 (id3
->length
/ 10000));
2354 /* no TOC exists. set a rough estimate using average bitrate */
2355 int tpk
= id3
->length
/ (id3
->filesize
/ 1024);
2356 id3
->elapsed
= id3
->offset
/ 1024 * tpk
;
2361 /* constant bitrate, use exact calculation */
2362 if (id3
->bitrate
!= 0)
2363 id3
->elapsed
= id3
->offset
/ (id3
->bitrate
/ 8);
2367 static bool audio_load_track(int offset
, bool start_play
, bool rebuffer
)
2373 /* Stop buffer filling if there is no free track entries.
2374 Don't fill up the last track entry (we wan't to store next track
2376 if (!audio_have_free_tracks())
2378 logf("No free tracks");
2382 if (current_fd
>= 0)
2384 logf("Nonzero fd in alt");
2391 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
2392 /* Get track name from current playlist read position. */
2393 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
2395 /* Handle broken playlists. */
2396 current_fd
= open(trackname
, O_RDONLY
);
2399 logf("Open failed");
2400 /* Skip invalid entry from playlist. */
2401 playlist_skip_entry(NULL
, last_peek_offset
);
2409 logf("End-of-playlist");
2410 playlist_end
= true;
2414 /* Initialize track entry. */
2415 size
= filesize(current_fd
);
2416 tracks
[track_widx
].filerem
= size
;
2417 tracks
[track_widx
].filesize
= size
;
2418 tracks
[track_widx
].available
= 0;
2420 /* Set default values */
2423 int last_codec
= current_codec
;
2425 current_codec
= CODEC_IDX_AUDIO
;
2426 conf_watermark
= AUDIO_DEFAULT_WATERMARK
;
2427 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
2428 conf_preseek
= AUDIO_REBUFFER_GUESS_SIZE
;
2429 dsp_configure(DSP_RESET
, 0);
2430 current_codec
= last_codec
;
2433 /* Get track metadata if we don't already have it. */
2434 if (!tracks
[track_widx
].taginfo_ready
)
2436 if (get_metadata(&tracks
[track_widx
],current_fd
,trackname
,v1first
))
2440 track_changed
= true;
2441 playlist_update_resume_info(audio_current_track());
2446 logf("mde:%s!",trackname
);
2448 /* Set filesize to zero to indicate no file was loaded. */
2449 tracks
[track_widx
].filesize
= 0;
2450 tracks
[track_widx
].filerem
= 0;
2454 /* Skip invalid entry from playlist. */
2455 playlist_skip_entry(NULL
, last_peek_offset
);
2456 tracks
[track_widx
].taginfo_ready
= false;
2462 /* Load the codec. */
2463 tracks
[track_widx
].codecbuf
= &filebuf
[buf_widx
];
2464 if (!audio_loadcodec(start_play
))
2466 /* Set filesize to zero to indicate no file was loaded. */
2467 tracks
[track_widx
].filesize
= 0;
2468 tracks
[track_widx
].filerem
= 0;
2472 if (tracks
[track_widx
].codecsize
)
2474 /* No space for codec on buffer, not an error */
2475 tracks
[track_widx
].codecsize
= 0;
2479 /* This is an error condition, either no codec was found, or reading
2480 * the codec file failed part way through, either way, skip the track */
2481 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
2482 /* We should not use gui_syncplash from audio thread! */
2483 gui_syncsplash(HZ
*2, true, msgbuf
);
2484 /* Skip invalid entry from playlist. */
2485 playlist_skip_entry(NULL
, last_peek_offset
);
2486 tracks
[track_widx
].taginfo_ready
= false;
2490 tracks
[track_widx
].start_pos
= 0;
2491 set_filebuf_watermark(buffer_margin
);
2492 tracks
[track_widx
].id3
.elapsed
= 0;
2496 switch (tracks
[track_widx
].id3
.codectype
) {
2500 lseek(current_fd
, offset
, SEEK_SET
);
2501 tracks
[track_widx
].id3
.offset
= offset
;
2502 audio_set_elapsed(&tracks
[track_widx
].id3
);
2503 tracks
[track_widx
].filerem
= size
- offset
;
2505 tracks
[track_widx
].start_pos
= offset
;
2509 lseek(current_fd
, offset
, SEEK_SET
);
2510 tracks
[track_widx
].id3
.offset
= offset
;
2511 tracks
[track_widx
].id3
.elapsed
=
2512 tracks
[track_widx
].id3
.length
/ 2;
2513 tracks
[track_widx
].filerem
= size
- offset
;
2515 tracks
[track_widx
].start_pos
= offset
;
2518 case AFMT_OGG_VORBIS
:
2523 tracks
[track_widx
].id3
.offset
= offset
;
2528 logf("alt:%s", trackname
);
2529 tracks
[track_widx
].buf_idx
= buf_widx
;
2531 return audio_read_file(rebuffer
);
2534 static bool audio_read_next_metadata(void)
2541 next_idx
= track_widx
;
2542 if (tracks
[next_idx
].taginfo_ready
)
2545 next_idx
&= MAX_TRACK_MASK
;
2547 if (tracks
[next_idx
].taginfo_ready
)
2551 trackname
= playlist_peek(last_peek_offset
+ 1);
2555 fd
= open(trackname
, O_RDONLY
);
2559 status
= get_metadata(&tracks
[next_idx
],fd
,trackname
,v1first
);
2560 /* Preload the glyphs in the tags */
2563 if (tracks
[next_idx
].id3
.title
)
2564 lcd_getstringsize(tracks
[next_idx
].id3
.title
, NULL
, NULL
);
2565 if (tracks
[next_idx
].id3
.artist
)
2566 lcd_getstringsize(tracks
[next_idx
].id3
.artist
, NULL
, NULL
);
2567 if (tracks
[next_idx
].id3
.album
)
2568 lcd_getstringsize(tracks
[next_idx
].id3
.album
, NULL
, NULL
);
2575 /* Send callback events to notify about new tracks. */
2576 static void audio_generate_postbuffer_events(void)
2581 logf("Postbuffer:%d/%d",track_ridx
,track_widx
);
2583 if (audio_have_tracks())
2585 cur_idx
= track_ridx
;
2588 if (!tracks
[cur_idx
].event_sent
)
2590 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2592 /* Mark the event 'sent' even if we don't really send one */
2593 tracks
[last_idx
].event_sent
= true;
2594 if (track_buffer_callback
)
2595 track_buffer_callback(&tracks
[last_idx
].id3
, false);
2599 if (cur_idx
== track_widx
)
2602 cur_idx
&= MAX_TRACK_MASK
;
2605 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2607 tracks
[last_idx
].event_sent
= true;
2608 if (track_buffer_callback
)
2609 track_buffer_callback(&tracks
[last_idx
].id3
, true);
2612 /* Force WPS reload. */
2613 track_changed
= true;
2617 static bool audio_initialize_buffer_fill(bool clear_tracks
)
2619 /* Don't initialize if we're already initialized */
2623 logf("Starting buffer fill");
2625 /* Set the filling flag true before calling audio_clear_tracks as that
2626 * function can yield and we start looping. */
2630 audio_clear_track_entries(false);
2632 /* Save the current resume position once. */
2633 playlist_update_resume_info(audio_current_track());
2638 static void audio_fill_file_buffer(
2639 bool start_play
, bool rebuffer
, size_t offset
)
2641 bool had_next_track
= audio_next_track() != NULL
;
2642 bool continue_buffering
;
2644 if (!audio_initialize_buffer_fill(!start_play
))
2647 /* If we have a partially buffered track, continue loading,
2648 * otherwise load a new track */
2649 if (tracks
[track_widx
].filesize
> 0)
2650 continue_buffering
= audio_read_file(rebuffer
);
2652 continue_buffering
= audio_load_track(offset
, start_play
, rebuffer
);
2654 if (!had_next_track
&& audio_next_track())
2655 track_changed
= true;
2657 /* If we're done buffering */
2658 if (!continue_buffering
)
2660 audio_read_next_metadata();
2662 audio_generate_postbuffer_events();
2673 static void audio_rebuffer(void)
2675 logf("Forcing rebuffer");
2677 /* Notify the codec that this will take a while */
2678 /* Currently this can cause some problems (logf in reverse order):
2679 * Codec load error:-1
2681 * Codec: Unsupported
2684 * Clearing tracks:7/7, 1
2686 * Check new track buffer
2688 * Clearing tracks:5/5, 0
2689 * Starting buffer fill
2690 * Clearing tracks:5/5, 1
2691 * Re-buffering song w/seek
2694 // queue_post(&codec_callback_queue, Q_CODEC_REQUEST_PENDING, 0);
2696 /* Stop in progress fill, and clear open file descriptor */
2697 if (current_fd
>= 0)
2704 /* Reset buffer and track pointers */
2705 CUR_TI
->buf_idx
= buf_ridx
= buf_widx
= 0;
2706 track_widx
= track_ridx
;
2707 audio_clear_track_entries(true);
2708 CUR_TI
->available
= 0;
2710 /* Fill the buffer */
2711 last_peek_offset
= -1;
2712 CUR_TI
->filesize
= 0;
2713 CUR_TI
->start_pos
= 0;
2716 if (!CUR_TI
->taginfo_ready
)
2717 memset(&CUR_TI
->id3
, 0, sizeof(struct mp3entry
));
2719 audio_fill_file_buffer(false, true, 0);
2722 static void audio_check_new_track(void)
2724 int track_count
= audio_track_count();
2725 int old_track_ridx
= track_ridx
;
2731 if (playlist_next_dir(ci
.new_track
))
2734 CUR_TI
->taginfo_ready
= false;
2740 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
2741 queue_post(&codec_callback_queue
, Q_CODEC_REQUEST_FAILED
, 0);
2749 /* If the playlist isn't that big */
2750 if (!playlist_check(ci
.new_track
))
2752 if (ci
.new_track
>= 0)
2754 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
2755 queue_post(&codec_callback_queue
, Q_CODEC_REQUEST_FAILED
, 0);
2758 /* Find the beginning backward if the user over-skips it */
2759 while (!playlist_check(++ci
.new_track
))
2760 if (ci
.new_track
>= 0)
2762 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
2763 queue_post(&codec_callback_queue
, Q_CODEC_REQUEST_FAILED
, 0);
2767 /* Update the playlist */
2768 last_peek_offset
-= ci
.new_track
;
2770 if (playlist_next(ci
.new_track
) < 0)
2772 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
2773 queue_post(&codec_callback_queue
, Q_CODEC_REQUEST_FAILED
, 0);
2780 new_playlist
= false;
2783 /* Save the old track */
2786 /* Move to the new track */
2787 track_ridx
+= ci
.new_track
;
2788 track_ridx
&= MAX_TRACK_MASK
;
2791 playlist_end
= false;
2793 track_changed
= !automatic_skip
;
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
)
2799 CUR_TI
->taginfo_ready
= false;
2804 forward
= ci
.new_track
> 0;
2807 /* If the target track is clearly not in memory */
2808 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
2814 /* The track may be in memory, see if it really is */
2817 if (!audio_buffer_wind_forward(track_ridx
, old_track_ridx
))
2822 int cur_idx
= track_ridx
;
2823 bool taginfo_ready
= true;
2824 bool wrap
= track_ridx
> old_track_ridx
;
2829 cur_idx
&= MAX_TRACK_MASK
;
2830 if (!(wrap
|| cur_idx
< old_track_ridx
))
2833 /* If we hit a track in between without valid tag info, bail */
2834 if (!tracks
[cur_idx
].taginfo_ready
)
2836 taginfo_ready
= false;
2840 tracks
[cur_idx
].available
= tracks
[cur_idx
].filesize
;
2841 if (tracks
[cur_idx
].codecsize
)
2842 tracks
[cur_idx
].has_codec
= true;
2846 if (!audio_buffer_wind_backward(track_ridx
, old_track_ridx
))
2851 CUR_TI
->taginfo_ready
= false;
2857 audio_update_trackinfo();
2858 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_COMPLETE");
2859 queue_post(&codec_callback_queue
, Q_CODEC_REQUEST_COMPLETE
, 0);
2862 static void audio_rebuffer_and_seek(size_t newpos
)
2864 size_t real_preseek
;
2868 /* (Re-)open current track's file handle. */
2869 trackname
= playlist_peek(0);
2870 fd
= open(trackname
, O_RDONLY
);
2873 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_FAILED");
2874 queue_post(&codec_callback_queue
, Q_CODEC_REQUEST_FAILED
, 0);
2878 if (current_fd
>= 0)
2882 playlist_end
= false;
2886 /* Clear codec buffer. */
2887 track_widx
= track_ridx
;
2888 tracks
[track_widx
].buf_idx
= buf_widx
= buf_ridx
= 0;
2890 last_peek_offset
= 0;
2892 audio_initialize_buffer_fill(true);
2894 /* This may have been tweaked by the id3v1 code */
2895 CUR_TI
->filesize
=filesize(fd
);
2896 if (newpos
> conf_preseek
)
2898 CUR_TI
->start_pos
= newpos
- conf_preseek
;
2899 lseek(current_fd
, CUR_TI
->start_pos
, SEEK_SET
);
2900 CUR_TI
->filerem
= CUR_TI
->filesize
- CUR_TI
->start_pos
;
2901 real_preseek
= conf_preseek
;
2905 CUR_TI
->start_pos
= 0;
2906 CUR_TI
->filerem
= CUR_TI
->filesize
;
2907 real_preseek
= newpos
;
2910 CUR_TI
->available
= 0;
2912 audio_read_file(real_preseek
);
2914 /* Account for the data we just read that is 'behind' us now */
2915 CUR_TI
->available
-= real_preseek
;
2917 buf_ridx
= RINGBUF_ADD(buf_ridx
, real_preseek
);
2919 LOGFQUEUE("audio > codec Q_CODEC_REQUEST_COMPLETE");
2920 queue_post(&codec_callback_queue
, Q_CODEC_REQUEST_COMPLETE
, 0);
2923 void audio_set_track_buffer_event(void (*handler
)(struct mp3entry
*id3
,
2926 track_buffer_callback
= handler
;
2929 void audio_set_track_unbuffer_event(void (*handler
)(struct mp3entry
*id3
,
2932 track_unbuffer_callback
= handler
;
2935 void audio_set_track_changed_event(void (*handler
)(struct mp3entry
*id3
))
2937 track_changed_callback
= handler
;
2940 unsigned long audio_prev_elapsed(void)
2942 return prev_track_elapsed
;
2945 static void audio_stop_codec_flush(void)
2947 ci
.stop_codec
= true;
2949 while (audio_codec_loaded
)
2951 /* If the audio codec is not loaded any more, and the audio is still
2952 * playing, it is now and _only_ now safe to call this function from the
2954 if (pcm_is_playing())
2956 pcmbuf_pause(paused
);
2959 static void audio_stop_playback(void)
2961 /* If we were playing, save resume information */
2964 /* Save the current playing spot, or NULL if the playlist has ended */
2965 playlist_update_resume_info(
2966 (playlist_end
&& ci
.stop_codec
)?NULL
:audio_current_track());
2971 audio_stop_codec_flush();
2974 if (current_fd
>= 0)
2980 /* Mark all entries null. */
2981 audio_clear_track_entries(false);
2982 memset(tracks
, 0, sizeof(struct track_info
) * MAX_TRACK
);
2985 static void audio_play_start(size_t offset
)
2987 #if defined(HAVE_RECORDING) || defined(CONFIG_TUNER)
2988 rec_set_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
2991 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2992 audio_stop_codec_flush();
2994 track_changed
= true;
2995 playlist_end
= false;
3002 if (current_fd
>= 0)
3008 sound_set_volume(global_settings
.volume
);
3009 track_widx
= track_ridx
= 0;
3010 buf_ridx
= buf_widx
= 0;
3012 /* Mark all entries null. */
3013 memset(tracks
, 0, sizeof(struct track_info
) * MAX_TRACK
);
3015 last_peek_offset
= -1;
3017 audio_fill_file_buffer(true, false, offset
);
3021 /* Invalidates all but currently playing track. */
3022 static void audio_invalidate_tracks(void)
3024 if (audio_have_tracks()) {
3025 last_peek_offset
= 0;
3027 playlist_end
= false;
3028 track_widx
= track_ridx
;
3029 /* Mark all other entries null (also buffered wrong metadata). */
3030 audio_clear_track_entries(true);
3032 /* If the current track is fully buffered, advance the write pointer */
3033 if (tracks
[track_widx
].filerem
== 0)
3034 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
3036 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3038 audio_read_next_metadata();
3042 static void audio_new_playlist(void)
3044 /* Prepare to start a new fill from the beginning of the playlist */
3045 last_peek_offset
= -1;
3046 if (audio_have_tracks()) {
3047 playlist_end
= false;
3048 track_widx
= track_ridx
;
3049 audio_clear_track_entries(true);
3052 track_widx
&= MAX_TRACK_MASK
;
3054 /* Stop reading the current track */
3055 CUR_TI
->filerem
= 0;
3059 /* Mark the current track as invalid to prevent skipping back to it */
3060 CUR_TI
->taginfo_ready
= false;
3062 /* Invalidate the buffer other than the playing track */
3063 buf_widx
= RINGBUF_ADD(buf_ridx
, CUR_TI
->available
);
3066 /* Signal the codec to initiate a track change forward */
3067 new_playlist
= true;
3069 audio_fill_file_buffer(false, true, 0);
3072 static void audio_initiate_track_change(long direction
)
3074 playlist_end
= false;
3075 ci
.new_track
+= direction
;
3076 wps_offset
-= direction
;
3079 static void audio_initiate_dir_change(long direction
)
3081 playlist_end
= false;
3083 ci
.new_track
= direction
;
3086 static void audio_reset_buffer(void)
3090 /* Set up file buffer as all space available */
3091 filebuf
= (char *)&audiobuf
[talk_get_bufsize()+MALLOC_BUFSIZE
];
3092 filebuflen
= audiobufend
- (unsigned char *) filebuf
- GUARD_BUFSIZE
-
3093 (pcmbuf_get_bufsize() + get_pcmbuf_descsize() + PCMBUF_MIX_CHUNK
* 2);
3095 /* Allow for codec(s) at end of file buffer */
3096 if (talk_voice_required())
3098 /* Allow 2 codecs at end of file buffer */
3099 filebuflen
-= 2 * (CODEC_IRAM_SIZE
+ CODEC_SIZE
);
3101 iram_buf
[0] = &filebuf
[filebuflen
];
3102 iram_buf
[1] = &filebuf
[filebuflen
+CODEC_IRAM_SIZE
];
3103 dram_buf
[0] = (unsigned char *)&filebuf
[filebuflen
+CODEC_IRAM_SIZE
*2];
3104 dram_buf
[1] = (unsigned char *)&filebuf
[filebuflen
+CODEC_IRAM_SIZE
*2+CODEC_SIZE
];
3108 /* Allow for 1 codec at end of file buffer */
3109 filebuflen
-= CODEC_IRAM_SIZE
+ CODEC_SIZE
;
3111 iram_buf
[0] = &filebuf
[filebuflen
];
3113 dram_buf
[0] = (unsigned char *)&filebuf
[filebuflen
+CODEC_IRAM_SIZE
];
3117 /* Ensure that file buffer is aligned */
3118 offset
= (-(size_t)filebuf
) & 3;
3120 filebuflen
-= offset
;
3125 #ifdef ROCKBOX_HAS_LOGF
3126 static void audio_test_track_changed_event(struct mp3entry
*id3
)
3130 logf("tce:%s", id3
->path
);
3134 static void audio_playback_init(void)
3136 #ifdef PLAYBACK_VOICE
3137 static bool voicetagtrue
= true;
3138 static struct mp3entry id3_voice
;
3142 logf("playback api init");
3145 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
3146 /* Set the input multiplexer to Line In */
3150 #ifdef ROCKBOX_HAS_LOGF
3151 audio_set_track_changed_event(audio_test_track_changed_event
);
3154 /* Initialize codec api. */
3155 ci
.read_filebuf
= codec_filebuf_callback
;
3156 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
3157 ci
.pcmbuf_insert_split
= codec_pcmbuf_insert_split_callback
;
3158 ci
.get_codec_memory
= codec_get_memory_callback
;
3159 ci
.request_buffer
= codec_request_buffer_callback
;
3160 ci
.advance_buffer
= codec_advance_buffer_callback
;
3161 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
3162 ci
.request_next_track
= codec_request_next_track_callback
;
3163 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
3164 ci
.seek_buffer
= codec_seek_buffer_callback
;
3165 ci
.seek_complete
= codec_seek_complete_callback
;
3166 ci
.set_elapsed
= codec_set_elapsed_callback
;
3167 ci
.set_offset
= codec_set_offset_callback
;
3168 ci
.configure
= codec_configure_callback
;
3169 ci
.discard_codec
= codec_discard_codec_callback
;
3171 /* Initialize voice codec api. */
3172 #ifdef PLAYBACK_VOICE
3173 memcpy(&ci_voice
, &ci
, sizeof(struct codec_api
));
3174 memset(&id3_voice
, 0, sizeof(struct mp3entry
));
3175 ci_voice
.read_filebuf
= voice_filebuf_callback
;
3176 ci_voice
.pcmbuf_insert
= voice_pcmbuf_insert_callback
;
3177 ci_voice
.pcmbuf_insert_split
= voice_pcmbuf_insert_split_callback
;
3178 ci_voice
.get_codec_memory
= voice_get_memory_callback
;
3179 ci_voice
.request_buffer
= voice_request_buffer_callback
;
3180 ci_voice
.advance_buffer
= voice_advance_buffer_callback
;
3181 ci_voice
.advance_buffer_loc
= voice_advance_buffer_loc_callback
;
3182 ci_voice
.request_next_track
= voice_request_next_track_callback
;
3183 ci_voice
.mp3_get_filepos
= voice_mp3_get_filepos_callback
;
3184 ci_voice
.seek_buffer
= voice_seek_buffer_callback
;
3185 ci_voice
.seek_complete
= voice_do_nothing
;
3186 ci_voice
.set_elapsed
= voice_set_elapsed_callback
;
3187 ci_voice
.set_offset
= voice_set_offset_callback
;
3188 ci_voice
.discard_codec
= voice_do_nothing
;
3189 ci_voice
.taginfo_ready
= &voicetagtrue
;
3190 ci_voice
.id3
= &id3_voice
;
3191 id3_voice
.frequency
= 11200;
3192 id3_voice
.length
= 1000000L;
3195 codec_thread_p
= create_thread(codec_thread
, codec_stack
,
3196 sizeof(codec_stack
),
3197 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
));
3201 queue_wait(&audio_queue
, &ev
);
3202 if (ev
.id
== Q_AUDIO_POSTINIT
)
3206 if (ev
.id
== SYS_USB_CONNECTED
)
3208 logf("USB: Audio preinit");
3209 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
3210 usb_wait_for_disconnect(&audio_queue
);
3215 filebuf
= (char *)&audiobuf
[MALLOC_BUFSIZE
]; /* Will be reset by reset_buffer */
3217 audio_set_crossfade(global_settings
.crossfade
);
3219 audio_is_initialized
= true;
3221 sound_settings_apply();
3224 static void audio_thread(void)
3228 /* At first initialize audio system in background. */
3229 audio_playback_init();
3235 queue_wait_w_tmo(&audio_queue
, &ev
, 0);
3236 if (ev
.id
== SYS_TIMEOUT
)
3237 ev
.id
= Q_AUDIO_FILL_BUFFER
;
3240 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
3243 case Q_AUDIO_FILL_BUFFER
:
3244 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3246 if (!playing
|| playlist_end
|| ci
.stop_codec
)
3248 audio_fill_file_buffer(false, false, 0);
3252 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3253 audio_clear_track_entries(false);
3254 audio_play_start((size_t)ev
.data
);
3258 LOGFQUEUE("audio < Q_AUDIO_STOP");
3259 audio_stop_playback();
3263 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3264 pcmbuf_pause((bool)ev
.data
);
3265 paused
= (bool)ev
.data
;
3269 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3270 audio_initiate_track_change((long)ev
.data
);
3273 case Q_AUDIO_PRE_FF_REWIND
:
3274 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3280 case Q_AUDIO_FF_REWIND
:
3281 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3284 ci
.seek_time
= (long)ev
.data
+1;
3287 case Q_AUDIO_REBUFFER_SEEK
:
3288 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
3289 audio_rebuffer_and_seek((size_t)ev
.data
);
3292 case Q_AUDIO_CHECK_NEW_TRACK
:
3293 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3294 audio_check_new_track();
3297 case Q_AUDIO_DIR_SKIP
:
3298 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3299 playlist_end
= false;
3300 audio_initiate_dir_change((long)ev
.data
);
3303 case Q_AUDIO_NEW_PLAYLIST
:
3304 LOGFQUEUE("audio < Q_AUDIO_NEW_PLAYLIST");
3305 audio_new_playlist();
3309 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3310 audio_invalidate_tracks();
3313 case Q_AUDIO_TRACK_CHANGED
:
3314 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3315 if (track_changed_callback
)
3316 track_changed_callback(&CUR_TI
->id3
);
3317 track_changed
= true;
3318 playlist_update_resume_info(audio_current_track());
3322 case SYS_USB_CONNECTED
:
3323 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3324 audio_stop_playback();
3325 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
3326 usb_wait_for_disconnect(&audio_queue
);
3331 LOGFQUEUE("audio < SYS_TIMEOUT");
3335 LOGFQUEUE("audio < default");