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 "voice_thread.h"
51 #include "mp3_playback.h"
66 #ifdef HAVE_LCD_BITMAP
68 #include "peakmeter.h"
79 #include "ata_idle_notify.h"
82 #include "recording.h"
87 #include "menus/eq_menu.h"
90 #define PLAYBACK_VOICE
92 /* default point to start buffer refill */
93 #define AUDIO_DEFAULT_WATERMARK (1024*512)
94 /* amount of guess-space to allow for codecs that must hunt and peck
95 * for their correct seeek target, 32k seems a good size */
96 #define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
98 /* Define LOGF_ENABLE to enable logf output in this file */
99 /*#define LOGF_ENABLE*/
102 /* macros to enable logf for queues
103 logging on SYS_TIMEOUT can be disabled */
105 /* Define this for logf output of all queuing except SYS_TIMEOUT */
106 #define PLAYBACK_LOGQUEUES
107 /* Define this to logf SYS_TIMEOUT messages */
108 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
111 #ifdef PLAYBACK_LOGQUEUES
112 #define LOGFQUEUE logf
114 #define LOGFQUEUE(...)
117 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
118 #define LOGFQUEUE_SYS_TIMEOUT logf
120 #define LOGFQUEUE_SYS_TIMEOUT(...)
124 /* Define one constant that includes recording related functionality */
125 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
126 #define AUDIO_HAVE_RECORDING
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
,
149 #ifdef AUDIO_HAVE_RECORDING
155 /* As defined in plugins/lib/xxx2wav.h */
157 #define MALLOC_BUFSIZE (512*1024)
158 #define GUARD_BUFSIZE (32*1024)
160 #define MALLOC_BUFSIZE (100*1024)
161 #define GUARD_BUFSIZE (8*1024)
164 /* As defined in plugin.lds */
166 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
167 #define CODEC_IRAM_SIZE ((size_t)0xc000)
168 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
169 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
170 #define CODEC_IRAM_SIZE ((size_t)0x10000)
172 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
173 #define CODEC_IRAM_SIZE ((size_t)0xc000)
176 bool audio_is_initialized
= false;
177 static bool audio_thread_ready NOCACHEBSS_ATTR
= false;
179 /* Variables are commented with the threads that use them: *
180 * A=audio, C=codec, V=voice. A suffix of - indicates that *
181 * the variable is read but not updated on that thread. */
182 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
184 /* Main state control */
185 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR
= false; /* Codec loaded? (C/A-) */
186 static volatile bool playing NOCACHEBSS_ATTR
= false; /* Is audio playing? (A) */
187 static volatile bool paused NOCACHEBSS_ATTR
= false; /* Is audio paused? (A/C-) */
189 /* Ring buffer where compressed audio and codecs are loaded */
190 static unsigned char *filebuf
= NULL
; /* Start of buffer (A/C-) */
191 static unsigned char *malloc_buf
= NULL
; /* Start of malloc buffer (A/C-) */
192 /* FIXME: make filebuflen static */
193 size_t filebuflen
= 0; /* Size of buffer (A/C-) */
194 /* FIXME: make buf_ridx (C/A-) */
196 /* Possible arrangements of the buffer */
197 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
198 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
199 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
200 static int buffer_state
= BUFFER_STATE_TRASHED
; /* Buffer state */
202 /* Used to keep the WPS up-to-date during track transtition */
203 static struct mp3entry prevtrack_id3
;
205 /* Used to provide the codec with a pointer */
206 static struct mp3entry curtrack_id3
;
208 /* Used to make next track info available while playing last track on buffer */
209 static struct mp3entry lasttrack_id3
;
211 /* Track info structure about songs in the file buffer (A/C-) */
213 int audio_hid
; /* The ID for the track's buffer handle */
214 int id3_hid
; /* The ID for the track's metadata handle */
215 int codec_hid
; /* The ID for the track's codec handle */
217 int aa_hid
; /* The ID for the track's album art handle */
220 size_t filesize
; /* File total length */
222 bool taginfo_ready
; /* Is metadata read */
224 bool event_sent
; /* Was this track's buffered event sent */
227 static struct track_info tracks
[MAX_TRACK
];
228 static volatile int track_ridx
= 0; /* Track being decoded (A/C-) */
229 static int track_widx
= 0; /* Track being buffered (A) */
231 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
232 static struct track_info
*prev_ti
= NULL
; /* Pointer to the previously played
235 /* Set by the audio thread when the current track information has updated
236 * and the WPS may need to update its cached information */
237 static bool track_changed
= false;
239 /* Information used only for filling the buffer */
240 /* Playlist steps from playing track to next track to be buffered (A) */
241 static int last_peek_offset
= 0;
243 /* Scrobbler support */
244 static unsigned long prev_track_elapsed
= 0; /* Previous track elapsed time (C/A-)*/
246 /* Track change controls */
247 static bool automatic_skip
= false; /* Who initiated in-progress skip? (C/A-) */
248 static bool playlist_end
= false; /* Has the current playlist ended? (A) */
249 static bool dir_skip
= false; /* Is a directory skip pending? (A) */
250 static bool new_playlist
= false; /* Are we starting a new playlist? (A) */
251 static int wps_offset
= 0; /* Pending track change offset, to keep WPS responsive (A) */
252 static bool skipped_during_pause
= false; /* Do we need to clear the PCM buffer when playback resumes (A) */
254 /* Callbacks which applications or plugins may set */
255 /* When the playing track has changed from the user's perspective */
256 void (*track_changed_callback
)(struct mp3entry
*id3
) = NULL
;
257 /* When a track has been buffered */
258 void (*track_buffer_callback
)(struct mp3entry
*id3
) = NULL
;
259 /* When a track's buffer has been overwritten or cleared */
260 void (*track_unbuffer_callback
)(struct mp3entry
*id3
) = NULL
;
262 static size_t buffer_margin
= 0; /* Buffer margin aka anti-skip buffer (A/C-) */
264 /* Multiple threads */
265 /* Set the watermark to trigger buffer fill (A/C) FIXME */
266 static void set_filebuf_watermark(int seconds
, size_t max
);
269 static struct event_queue audio_queue NOCACHEBSS_ATTR
;
270 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR
;
271 static long audio_stack
[(DEFAULT_STACK_SIZE
+ 0x1000)/sizeof(long)];
272 static const char audio_thread_name
[] = "audio";
274 static void audio_thread(void);
275 static void audio_initiate_track_change(long direction
);
276 static bool audio_have_tracks(void);
277 static void audio_reset_buffer(void);
280 extern struct codec_api ci
;
281 static struct event_queue codec_queue NOCACHEBSS_ATTR
;
282 static struct queue_sender_list codec_queue_sender_list
;
283 static long codec_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
285 static const char codec_thread_name
[] = "codec";
286 struct thread_entry
*codec_thread_p
; /* For modifying thread priority later. */
288 /* --- Helper functions --- */
290 static struct mp3entry
*bufgetid3(int handle_id
)
295 struct mp3entry
*id3
;
296 ssize_t ret
= bufgetdata(handle_id
, 0, (void *)&id3
);
298 if (ret
< 0 || ret
!= sizeof(struct mp3entry
))
304 static bool clear_track_info(struct track_info
*track
)
306 /* bufclose returns true if the handle is not found, or if it is closed
307 * successfully, so these checks are safe on non-existant handles */
311 if (track
->codec_hid
>= 0) {
312 if (bufclose(track
->codec_hid
))
313 track
->codec_hid
= -1;
318 if (track
->id3_hid
>= 0) {
319 if (bufclose(track
->id3_hid
))
325 if (track
->audio_hid
>= 0) {
326 if (bufclose(track
->audio_hid
))
327 track
->audio_hid
= -1;
333 if (track
->aa_hid
>= 0) {
334 if (bufclose(track
->aa_hid
))
342 track
->taginfo_ready
= false;
343 track
->event_sent
= false;
348 /* --- External interfaces --- */
350 /* This sends a stop message and the audio thread will dump all it's
351 subsequenct messages */
352 void audio_hard_stop(void)
355 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
356 queue_send(&audio_queue
, Q_AUDIO_STOP
, 1);
357 #ifdef PLAYBACK_VOICE
362 bool audio_restore_playback(int type
)
366 case AUDIO_WANT_PLAYBACK
:
367 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
368 audio_reset_buffer();
370 case AUDIO_WANT_VOICE
:
371 if (buffer_state
== BUFFER_STATE_TRASHED
)
372 audio_reset_buffer();
379 unsigned char *audio_get_buffer(bool talk_buf
, size_t *buffer_size
)
381 unsigned char *buf
, *end
;
383 if (audio_is_initialized
)
387 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
389 if (buffer_size
== NULL
)
391 /* Special case for talk_init to use since it already knows it's
393 buffer_state
= BUFFER_STATE_TRASHED
;
397 if (talk_buf
|| buffer_state
== BUFFER_STATE_TRASHED
398 || !talk_voice_required())
400 logf("get buffer: talk, audio");
401 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
402 the talk buffer is not needed because voice isn't being used, or
403 could be BUFFER_STATE_TRASHED already. If state is
404 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
405 without the caller knowing what's going on. Changing certain settings
406 may move it to a worse condition but the memory in use by something
407 else will remain undisturbed.
409 if (buffer_state
!= BUFFER_STATE_TRASHED
)
412 buffer_state
= BUFFER_STATE_TRASHED
;
420 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
421 still BUFFER_STATE_INITIALIZED */
422 /* Skip talk buffer and move pcm buffer to end to maximize available
423 contiguous memory - no audio running means voice will not need the
425 logf("get buffer: audio");
426 buf
= audiobuf
+ talk_get_bufsize();
427 end
= audiobufend
- pcmbuf_init(audiobufend
);
428 buffer_state
= BUFFER_STATE_VOICED_ONLY
;
431 *buffer_size
= end
- buf
;
436 #ifdef HAVE_RECORDING
437 unsigned char *audio_get_recording_buffer(size_t *buffer_size
)
439 /* Stop audio, voice and obtain all available buffer space */
443 unsigned char *end
= audiobufend
;
444 buffer_state
= BUFFER_STATE_TRASHED
;
445 *buffer_size
= end
- audiobuf
;
447 return (unsigned char *)audiobuf
;
450 bool audio_load_encoder(int afmt
)
453 const char *enc_fn
= get_codec_filename(afmt
| CODEC_TYPE_ENCODER
);
457 audio_remove_encoder();
458 ci
.enc_codec_loaded
= 0; /* clear any previous error condition */
460 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
461 queue_post(&codec_queue
, Q_ENCODER_LOAD_DISK
, (intptr_t)enc_fn
);
463 while (ci
.enc_codec_loaded
== 0)
466 logf("codec loaded: %d", ci
.enc_codec_loaded
);
468 return ci
.enc_codec_loaded
> 0;
473 } /* audio_load_encoder */
475 void audio_remove_encoder(void)
478 /* force encoder codec unload (if currently loaded) */
479 if (ci
.enc_codec_loaded
<= 0)
482 ci
.stop_encoder
= true;
483 while (ci
.enc_codec_loaded
> 0)
486 } /* audio_remove_encoder */
488 #endif /* HAVE_RECORDING */
491 int audio_current_aa_hid(void)
494 int offset
= ci
.new_track
+ wps_offset
;
496 cur_idx
= track_ridx
+ offset
;
497 cur_idx
&= MAX_TRACK_MASK
;
499 return tracks
[cur_idx
].aa_hid
;
503 struct mp3entry
* audio_current_track(void)
505 const char *filename
;
507 static struct mp3entry temp_id3
;
509 int offset
= ci
.new_track
+ wps_offset
;
511 cur_idx
= track_ridx
+ offset
;
512 cur_idx
&= MAX_TRACK_MASK
;
514 if (cur_idx
== track_ridx
&& *curtrack_id3
.path
)
517 return &curtrack_id3
;
519 else if (offset
== -1 && *prevtrack_id3
.path
)
521 /* We're in a track transition. The codec has moved on to the nex track,
522 but the audio being played is still the same (now previous) track.
523 prevtrack_id3.elapsed is being updated in an ISR by
524 codec_pcmbuf_position_callback */
525 return &prevtrack_id3
;
527 else if (tracks
[cur_idx
].id3_hid
>= 0)
529 /* Get the ID3 metadata from the main buffer */
530 return bufgetid3(tracks
[cur_idx
].id3_hid
);
533 /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info
534 we have and return that. */
536 memset(&temp_id3
, 0, sizeof(struct mp3entry
));
538 filename
= playlist_peek(0);
540 filename
= "No file!";
542 #ifdef HAVE_TC_RAMCACHE
543 if (tagcache_fill_tags(&temp_id3
, filename
))
547 p
= strrchr(filename
, '/');
553 strncpy(temp_id3
.path
, p
, sizeof(temp_id3
.path
)-1);
554 temp_id3
.title
= &temp_id3
.path
[0];
559 struct mp3entry
* audio_next_track(void)
561 int next_idx
= track_ridx
;
563 if (!audio_have_tracks())
566 if (wps_offset
== -1 && *prevtrack_id3
.path
)
568 /* We're in a track transition. The next track for the WPS is the one
569 currently being decoded. */
570 return &curtrack_id3
;
574 next_idx
&= MAX_TRACK_MASK
;
576 if (next_idx
== track_widx
)
578 /* The next track hasn't been buffered yet, so we return the static
579 version of its metadata. */
580 return &lasttrack_id3
;
583 if (tracks
[next_idx
].id3_hid
< 0)
586 return bufgetid3(tracks
[next_idx
].id3_hid
);
589 bool audio_has_changed_track(void)
593 track_changed
= false;
600 void audio_play(long offset
)
604 #ifdef PLAYBACK_VOICE
605 /* Truncate any existing voice output so we don't have spelling
606 * etc. over the first part of the played track */
611 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset
);
612 /* Don't return until playback has actually started */
613 queue_send(&audio_queue
, Q_AUDIO_PLAY
, offset
);
616 void audio_stop(void)
619 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
620 /* Don't return until playback has actually stopped */
621 queue_send(&audio_queue
, Q_AUDIO_STOP
, 0);
624 void audio_pause(void)
626 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
627 /* Don't return until playback has actually paused */
628 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, true);
631 void audio_resume(void)
633 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
634 /* Don't return until playback has actually resumed */
635 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, false);
638 void audio_next(void)
640 if (playlist_check(ci
.new_track
+ wps_offset
+ 1))
642 if (global_settings
.beep
)
643 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
645 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
646 queue_post(&audio_queue
, Q_AUDIO_SKIP
, 1);
647 /* Update wps while our message travels inside deep playback queues. */
649 track_changed
= true;
653 /* No more tracks. */
654 if (global_settings
.beep
)
655 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
659 void audio_prev(void)
661 if (playlist_check(ci
.new_track
+ wps_offset
- 1))
663 if (global_settings
.beep
)
664 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
666 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
667 queue_post(&audio_queue
, Q_AUDIO_SKIP
, -1);
668 /* Update wps while our message travels inside deep playback queues. */
670 track_changed
= true;
674 /* No more tracks. */
675 if (global_settings
.beep
)
676 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
680 void audio_next_dir(void)
682 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
683 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, 1);
686 void audio_prev_dir(void)
688 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
689 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, -1);
692 void audio_pre_ff_rewind(void)
694 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
695 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
698 void audio_ff_rewind(long newpos
)
700 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
701 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, newpos
);
704 void audio_flush_and_reload_tracks(void)
706 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
707 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
710 void audio_error_clear(void)
712 #ifdef AUDIO_HAVE_RECORDING
713 pcm_rec_error_clear();
717 int audio_status(void)
722 ret
|= AUDIO_STATUS_PLAY
;
725 ret
|= AUDIO_STATUS_PAUSE
;
727 #ifdef HAVE_RECORDING
728 /* Do this here for constitency with mpeg.c version */
729 ret
|= pcm_rec_status();
735 int audio_get_file_pos(void)
740 #ifndef HAVE_FLASH_STORAGE
741 void audio_set_buffer_margin(int setting
)
743 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
744 buffer_margin
= lookup
[setting
];
745 logf("buffer margin: %ld", (long)buffer_margin
);
746 set_filebuf_watermark(buffer_margin
, 0);
750 /* Take nescessary steps to enable or disable the crossfade setting */
751 void audio_set_crossfade(int enable
)
757 /* Tell it the next setting to use */
758 pcmbuf_crossfade_enable(enable
);
760 /* Return if size hasn't changed or this is too early to determine
761 which in the second case there's no way we could be playing
763 if (pcmbuf_is_same_size())
765 /* This function is a copout and just syncs some variables -
766 to be removed at a later date */
767 pcmbuf_crossfade_enable_finished();
772 was_playing
= playing
;
774 /* Playback has to be stopped before changing the buffer size */
777 /* Store the track resume position */
778 offset
= curtrack_id3
.offset
;
779 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK
));
782 /* Blast it - audio buffer will have to be setup again next time
784 audio_get_buffer(true, &size
);
786 /* Restart playback if audio was running previously */
791 /* --- Routines called from multiple threads --- */
793 static void set_filebuf_watermark(int seconds
, size_t max
)
798 return; /* Audio buffers not yet set up */
800 bytes
= seconds
?MAX(curtrack_id3
.bitrate
* seconds
* (1000/8), max
):max
;
801 bytes
= MIN(bytes
, filebuflen
/ 2);
802 buf_set_watermark(bytes
);
805 const char * get_codec_filename(int cod_spec
)
809 #ifdef HAVE_RECORDING
810 /* Can choose decoder or encoder if one available */
811 int type
= cod_spec
& CODEC_TYPE_MASK
;
812 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
814 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
815 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
817 fname
= (type
== CODEC_TYPE_ENCODER
) ?
818 audio_formats
[afmt
].codec_enc_root_fn
:
819 audio_formats
[afmt
].codec_root_fn
;
822 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
823 afmt
, fname
? fname
: "<unknown>");
824 #else /* !HAVE_RECORDING */
826 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
827 cod_spec
= AFMT_UNKNOWN
;
828 fname
= audio_formats
[cod_spec
].codec_root_fn
;
829 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
830 #endif /* HAVE_RECORDING */
833 } /* get_codec_filename */
835 /* --- Codec thread --- */
836 static bool codec_pcmbuf_insert_callback(
837 const void *ch1
, const void *ch2
, int count
)
839 const char *src
[2] = { ch1
, ch2
};
843 int out_count
= dsp_output_count(ci
.dsp
, count
);
847 /* Prevent audio from a previous track from playing */
848 if (ci
.new_track
|| ci
.stop_codec
)
851 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
854 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
858 /* Get the real input_size for output_size bytes, guarding
859 * against resampling buffer overflows. */
860 inp_count
= dsp_input_count(ci
.dsp
, out_count
);
865 /* Input size has grown, no error, just don't write more than length */
866 if (inp_count
> count
)
869 out_count
= dsp_process(ci
.dsp
, dest
, src
, inp_count
);
874 pcmbuf_write_complete(out_count
);
880 } /* codec_pcmbuf_insert_callback */
882 static void* codec_get_memory_callback(size_t *size
)
884 *size
= MALLOC_BUFSIZE
;
888 /* Between the codec and PCM track change, we need to keep updating the
889 "elapsed" value of the previous (to the codec, but current to the
890 user/PCM/WPS) track, so that the progressbar reaches the end.
891 During that transition, the WPS will display prevtrack_id3. */
892 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
893 static void codec_pcmbuf_position_callback(size_t size
)
895 /* This is called from an ISR, so be quick */
896 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
897 prevtrack_id3
.elapsed
;
899 if (time
>= prevtrack_id3
.length
)
901 pcmbuf_set_position_callback(NULL
);
902 prevtrack_id3
.elapsed
= prevtrack_id3
.length
;
905 prevtrack_id3
.elapsed
= time
;
908 static void codec_set_elapsed_callback(unsigned int value
)
910 unsigned int latency
;
914 #ifdef AB_REPEAT_ENABLE
915 ab_position_report(value
);
918 latency
= pcmbuf_get_latency();
920 curtrack_id3
.elapsed
= 0;
921 else if (value
- latency
> curtrack_id3
.elapsed
||
922 value
- latency
< curtrack_id3
.elapsed
- 2)
924 curtrack_id3
.elapsed
= value
- latency
;
928 static void codec_set_offset_callback(size_t value
)
930 unsigned int latency
;
935 latency
= pcmbuf_get_latency() * curtrack_id3
.bitrate
/ 8;
937 curtrack_id3
.offset
= 0;
939 curtrack_id3
.offset
= value
- latency
;
942 static void codec_advance_buffer_counters(size_t amount
)
944 bufadvance(CUR_TI
->audio_hid
, amount
);
948 /* copy up-to size bytes into ptr and return the actual size copied */
949 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
953 if (ci
.stop_codec
|| !playing
)
956 copy_n
= bufread(CUR_TI
->audio_hid
, size
, ptr
);
958 /* Nothing requested OR nothing left */
962 /* Update read and other position pointers */
963 codec_advance_buffer_counters(copy_n
);
965 /* Return the actual amount of data copied to the buffer */
967 } /* codec_filebuf_callback */
969 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
971 size_t copy_n
= reqsize
;
981 ret
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, &ptr
);
983 copy_n
= MIN((size_t)ret
, reqsize
);
994 } /* codec_request_buffer_callback */
996 static int get_codec_base_type(int type
)
1008 static void codec_advance_buffer_callback(size_t amount
)
1010 codec_advance_buffer_counters(amount
);
1011 codec_set_offset_callback(ci
.curpos
);
1014 static void codec_advance_buffer_loc_callback(void *ptr
)
1016 size_t amount
= buf_get_offset(CUR_TI
->audio_hid
, ptr
);
1017 codec_advance_buffer_callback(amount
);
1020 /* Copied from mpeg.c. Should be moved somewhere else. */
1021 static int codec_get_file_pos(void)
1024 struct mp3entry
*id3
= audio_current_track();
1030 /* Use the TOC to find the new position */
1031 unsigned int percent
, remainder
;
1032 int curtoc
, nexttoc
, plen
;
1034 percent
= (id3
->elapsed
*100)/id3
->length
;
1038 curtoc
= id3
->toc
[percent
];
1041 nexttoc
= id3
->toc
[percent
+1];
1045 pos
= (id3
->filesize
/256)*curtoc
;
1047 /* Use the remainder to get a more accurate position */
1048 remainder
= (id3
->elapsed
*100)%id3
->length
;
1049 remainder
= (remainder
*100)/id3
->length
;
1050 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1051 pos
+= (plen
/100)*remainder
;
1055 /* No TOC exists, estimate the new position */
1056 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1057 (id3
->elapsed
/ 1000);
1060 else if (id3
->bitrate
)
1061 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1065 pos
+= id3
->first_frame_offset
;
1067 /* Don't seek right to the end of the file so that we can
1068 transition properly to the next song */
1069 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1070 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1075 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1079 curtrack_id3
.elapsed
= newtime
;
1080 newpos
= codec_get_file_pos();
1085 static void codec_seek_complete_callback(void)
1087 logf("seek_complete");
1088 if (pcm_is_paused())
1090 /* If this is not a seamless seek, clear the buffer */
1092 dsp_configure(ci
.dsp
, DSP_FLUSH
, 0);
1094 /* If playback was not 'deliberately' paused, unpause now */
1096 pcmbuf_pause(false);
1101 static bool codec_seek_buffer_callback(size_t newpos
)
1103 logf("codec_seek_buffer_callback");
1105 int ret
= bufseek(CUR_TI
->audio_hid
, newpos
);
1115 static void codec_configure_callback(int setting
, intptr_t value
)
1118 case CODEC_SET_FILEBUF_WATERMARK
:
1119 set_filebuf_watermark(buffer_margin
, value
);
1123 if (!dsp_configure(ci
.dsp
, setting
, value
))
1124 { logf("Illegal key:%d", setting
); }
1128 static void codec_track_changed(void)
1130 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1131 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1134 static void codec_pcmbuf_track_changed_callback(void)
1136 pcmbuf_set_position_callback(NULL
);
1137 codec_track_changed();
1140 static void codec_discard_codec_callback(void)
1142 if (CUR_TI
->codec_hid
>= 0)
1144 bufclose(CUR_TI
->codec_hid
);
1145 CUR_TI
->codec_hid
= -1;
1149 static inline void codec_gapless_track_change(void)
1151 /* callback keeps the progress bar moving while the pcmbuf empties */
1152 pcmbuf_set_position_callback(codec_pcmbuf_position_callback
);
1153 /* set the pcmbuf callback for when the track really changes */
1154 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1157 static inline void codec_crossfade_track_change(void)
1159 /* Initiate automatic crossfade mode */
1160 pcmbuf_crossfade_init(false);
1161 /* Notify the wps that the track change starts now */
1162 codec_track_changed();
1165 static void codec_track_skip_done(bool was_manual
)
1167 /* Manual track change (always crossfade or flush audio). */
1170 pcmbuf_crossfade_init(true);
1171 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1172 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1174 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1175 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1176 && global_settings
.crossfade
!= CROSSFADE_ENABLE_TRACKSKIP
)
1178 if (global_settings
.crossfade
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1180 if (global_settings
.playlist_shuffle
)
1181 /* shuffle mode is on, so crossfade: */
1182 codec_crossfade_track_change();
1184 /* shuffle mode is off, so do a gapless track change */
1185 codec_gapless_track_change();
1188 /* normal crossfade: */
1189 codec_crossfade_track_change();
1192 /* normal gapless playback. */
1193 codec_gapless_track_change();
1196 static bool codec_load_next_track(void)
1198 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1200 prev_track_elapsed
= curtrack_id3
.elapsed
;
1203 codec_seek_complete_callback();
1205 #ifdef AB_REPEAT_ENABLE
1206 ab_end_of_track_report();
1209 logf("Request new track");
1211 if (ci
.new_track
== 0)
1214 automatic_skip
= true;
1219 trigger_cpu_boost();
1220 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1221 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1226 case Q_CODEC_REQUEST_COMPLETE
:
1227 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1228 codec_track_skip_done(!automatic_skip
);
1231 case Q_CODEC_REQUEST_FAILED
:
1232 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1234 ci
.stop_codec
= true;
1238 LOGFQUEUE("codec |< default");
1239 ci
.stop_codec
= true;
1244 static bool codec_request_next_track_callback(void)
1248 if (ci
.stop_codec
|| !playing
)
1251 prev_codectype
= get_codec_base_type(curtrack_id3
.codectype
);
1253 if (!codec_load_next_track())
1256 /* Seek to the beginning of the new track because if the struct mp3entry was
1257 buffered, "elapsed" might not be zero (if the track has been played
1258 already but not unbuffered) */
1259 codec_seek_buffer_callback(curtrack_id3
.first_frame_offset
);
1261 /* Check if the next codec is the same file. */
1262 if (prev_codectype
== get_codec_base_type(curtrack_id3
.codectype
))
1264 logf("New track loaded");
1265 codec_discard_codec_callback();
1270 logf("New codec:%d/%d", curtrack_id3
.codectype
, prev_codectype
);
1275 static void codec_thread(void)
1277 struct queue_event ev
;
1282 queue_wait(&codec_queue
, &ev
);
1285 case Q_CODEC_LOAD_DISK
:
1286 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1287 queue_reply(&codec_queue
, 1);
1288 audio_codec_loaded
= true;
1289 ci
.stop_codec
= false;
1290 status
= codec_load_file((const char *)ev
.data
, &ci
);
1294 LOGFQUEUE("codec < Q_CODEC_LOAD");
1295 if (CUR_TI
->codec_hid
< 0) {
1296 logf("Codec slot is empty!");
1297 /* Wait for the pcm buffer to go empty */
1298 while (pcm_is_playing())
1300 /* This must be set to prevent an infinite loop */
1301 ci
.stop_codec
= true;
1302 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1303 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
1307 audio_codec_loaded
= true;
1308 ci
.stop_codec
= false;
1309 status
= codec_load_buf(CUR_TI
->codec_hid
, &ci
);
1312 #ifdef AUDIO_HAVE_RECORDING
1313 case Q_ENCODER_LOAD_DISK
:
1314 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1315 audio_codec_loaded
= false; /* Not audio codec! */
1316 logf("loading encoder");
1317 ci
.stop_encoder
= false;
1318 status
= codec_load_file((const char *)ev
.data
, &ci
);
1319 logf("encoder stopped");
1321 #endif /* AUDIO_HAVE_RECORDING */
1324 LOGFQUEUE("codec < default");
1327 if (audio_codec_loaded
)
1336 audio_codec_loaded
= false;
1340 case Q_CODEC_LOAD_DISK
:
1342 LOGFQUEUE("codec < Q_CODEC_LOAD");
1345 if (ci
.new_track
|| status
!= CODEC_OK
)
1349 logf("Codec failure");
1350 gui_syncsplash(HZ
*2, "Codec failure");
1353 if (!codec_load_next_track())
1355 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1356 /* End of playlist */
1357 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1363 logf("Codec finished");
1366 /* Wait for the audio to stop playing before
1367 * triggering the WPS exit */
1368 while(pcm_is_playing())
1370 curtrack_id3
.elapsed
=
1371 curtrack_id3
.length
- pcmbuf_get_latency();
1374 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1375 /* End of playlist */
1376 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1381 if (CUR_TI
->codec_hid
>= 0)
1383 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1384 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
1388 const char *codec_fn
=
1389 get_codec_filename(curtrack_id3
.codectype
);
1390 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1391 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
1392 (intptr_t)codec_fn
);
1397 #ifdef AUDIO_HAVE_RECORDING
1398 case Q_ENCODER_LOAD_DISK
:
1399 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1401 if (status
== CODEC_OK
)
1404 logf("Encoder failure");
1405 gui_syncsplash(HZ
*2, "Encoder failure");
1407 if (ci
.enc_codec_loaded
< 0)
1410 logf("Encoder failed to load");
1411 ci
.enc_codec_loaded
= -1;
1413 #endif /* AUDIO_HAVE_RECORDING */
1416 LOGFQUEUE("codec < default");
1423 /* --- Audio thread --- */
1425 static bool audio_have_tracks(void)
1427 return track_ridx
!= track_widx
|| CUR_TI
->filesize
;
1430 static bool audio_have_free_tracks(void)
1432 if (track_widx
< track_ridx
)
1433 return track_widx
+ 1 < track_ridx
;
1434 else if (track_ridx
== 0)
1435 return track_widx
< MAX_TRACK
- 1;
1440 int audio_track_count(void)
1442 if (audio_have_tracks())
1444 int relative_track_widx
= track_widx
;
1446 if (track_ridx
> track_widx
)
1447 relative_track_widx
+= MAX_TRACK
;
1449 return relative_track_widx
- track_ridx
+ 1;
1455 long audio_filebufused(void)
1457 return (long) buf_used();
1460 static void audio_update_trackinfo(void)
1462 if (CUR_TI
->id3_hid
>= 0)
1463 copy_mp3entry(&curtrack_id3
, bufgetid3(CUR_TI
->id3_hid
));
1465 CUR_TI
->taginfo_ready
= (CUR_TI
->id3_hid
>= 0);
1467 int next_idx
= track_ridx
+ 1;
1468 next_idx
&= MAX_TRACK_MASK
;
1470 tracks
[next_idx
].taginfo_ready
= (tracks
[next_idx
].id3_hid
>= 0);
1472 ci
.filesize
= CUR_TI
->filesize
;
1473 curtrack_id3
.elapsed
= 0;
1474 curtrack_id3
.offset
= 0;
1475 ci
.id3
= &curtrack_id3
;
1477 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
1480 static void low_buffer_callback(void)
1482 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1483 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1486 static void audio_clear_track_entries(bool clear_unbuffered
)
1488 int cur_idx
= track_widx
;
1490 logf("Clearing tracks:%d/%d, %d", track_ridx
, track_widx
, clear_unbuffered
);
1492 /* This function is always called in association with a stop or a rebuffer,
1493 * we will reregister the callback at the end of a rebuffer if needed */
1494 unregister_buffer_low_callback(low_buffer_callback
);
1496 /* Loop over all tracks from write-to-read */
1500 cur_idx
&= MAX_TRACK_MASK
;
1502 if (cur_idx
== track_ridx
)
1505 /* If the track is buffered, conditionally clear/notify,
1506 * otherwise clear the track if that option is selected */
1507 if (tracks
[cur_idx
].event_sent
)
1509 /* If there is an unbuffer callback, call it, otherwise,
1510 * just clear the track */
1511 if (track_unbuffer_callback
&& tracks
[cur_idx
].id3_hid
>= 0)
1512 track_unbuffer_callback(bufgetid3(tracks
[cur_idx
].id3_hid
));
1514 clear_track_info(&tracks
[cur_idx
]);
1516 else if (clear_unbuffered
)
1517 clear_track_info(&tracks
[cur_idx
]);
1521 static bool audio_release_tracks(void)
1525 logf("releasing all tracks");
1527 for(i
= 0; i
< MAX_TRACK
; i
++)
1529 cur_idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
1530 if (!clear_track_info(&tracks
[cur_idx
]))
1537 static bool audio_loadcodec(bool start_play
)
1540 char codec_path
[MAX_PATH
]; /* Full path to codec */
1542 if (tracks
[track_widx
].id3_hid
< 0) {
1546 const char * codec_fn
=
1547 get_codec_filename(bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
);
1548 if (codec_fn
== NULL
)
1551 tracks
[track_widx
].codec_hid
= -1;
1555 /* Load the codec directly from disk and save some memory. */
1556 track_ridx
= track_widx
;
1557 ci
.filesize
= CUR_TI
->filesize
;
1558 ci
.id3
= &curtrack_id3
;
1559 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
1561 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1562 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
1567 /* If we already have another track than this one buffered */
1568 if (track_widx
!= track_ridx
)
1570 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
1572 /* If the previous codec is the same as this one, there is no need
1573 * to put another copy of it on the file buffer */
1574 if (get_codec_base_type(
1575 bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
) ==
1576 get_codec_base_type(
1577 bufgetid3(tracks
[prev_track
].id3_hid
)->codectype
)
1578 && audio_codec_loaded
)
1580 logf("Reusing prev. codec");
1586 codec_get_full_path(codec_path
, codec_fn
);
1588 tracks
[track_widx
].codec_hid
= bufopen(codec_path
, 0, TYPE_CODEC
);
1589 if (tracks
[track_widx
].codec_hid
< 0)
1592 logf("Loaded codec");
1597 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
1598 static void audio_set_elapsed(struct mp3entry
* id3
)
1600 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
1601 id3
->offset
- id3
->first_frame_offset
: 0;
1604 if ( id3
->has_toc
) {
1605 /* calculate elapsed time using TOC */
1607 unsigned int remainder
, plen
, relpos
, nextpos
;
1609 /* find wich percent we're at */
1610 for (i
=0; i
<100; i
++ )
1611 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
1618 relpos
= id3
->toc
[i
];
1621 nextpos
= id3
->toc
[i
+1];
1625 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
1627 /* set time for this percent (divide before multiply to prevent
1628 overflow on long files. loss of precision is negligible on
1630 id3
->elapsed
= i
* (id3
->length
/ 100);
1632 /* calculate remainder time */
1633 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
1634 id3
->elapsed
+= (((remainder
* 100) / plen
) *
1635 (id3
->length
/ 10000));
1638 /* no TOC exists. set a rough estimate using average bitrate */
1639 int tpk
= id3
->length
/
1640 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
1642 id3
->elapsed
= offset
/ 1024 * tpk
;
1647 /* constant bitrate, use exact calculation */
1648 if (id3
->bitrate
!= 0)
1649 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
1653 /* Load one track by making the appropriate bufopen calls. Return true if
1654 everything required was loaded correctly, false if not. */
1655 static bool audio_load_track(int offset
, bool start_play
)
1660 int file_offset
= 0;
1661 struct mp3entry id3
;
1663 /* Stop buffer filling if there is no free track entries.
1664 Don't fill up the last track entry (we wan't to store next track
1666 if (!audio_have_free_tracks())
1668 logf("No free tracks");
1674 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
1675 /* Get track name from current playlist read position. */
1676 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
1678 /* Handle broken playlists. */
1679 fd
= open(trackname
, O_RDONLY
);
1682 logf("Open failed");
1683 /* Skip invalid entry from playlist. */
1684 playlist_skip_entry(NULL
, last_peek_offset
);
1692 logf("End-of-playlist");
1693 playlist_end
= true;
1694 memset(&lasttrack_id3
, 0, sizeof(struct mp3entry
));
1698 tracks
[track_widx
].filesize
= filesize(fd
);
1700 /* Set default values */
1703 buf_set_watermark(AUDIO_DEFAULT_WATERMARK
);
1704 dsp_configure(ci
.dsp
, DSP_RESET
, 0);
1705 track_changed
= true;
1706 playlist_update_resume_info(audio_current_track());
1709 /* Get track metadata if we don't already have it. */
1710 if (tracks
[track_widx
].id3_hid
< 0)
1712 if (get_metadata(&id3
, fd
, trackname
))
1714 tracks
[track_widx
].id3_hid
=
1715 bufalloc(&id3
, sizeof(struct mp3entry
), TYPE_ID3
);
1716 tracks
[track_widx
].taginfo_ready
= (tracks
[track_widx
].id3_hid
>= 0);
1718 if (tracks
[track_widx
].id3_hid
< 0)
1722 copy_mp3entry(&lasttrack_id3
, &id3
);
1726 if (track_widx
== track_ridx
)
1727 copy_mp3entry(&curtrack_id3
, &id3
);
1731 track_changed
= true;
1732 playlist_update_resume_info(audio_current_track());
1737 logf("mde:%s!",trackname
);
1739 /* Skip invalid entry from playlist. */
1740 playlist_skip_entry(NULL
, last_peek_offset
);
1741 tracks
[track_widx
].taginfo_ready
= false;
1751 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
1753 char cuepath
[MAX_PATH
];
1755 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
1757 if (look_for_cuesheet_file(trackname
, cuepath
) &&
1758 parse_cuesheet(cuepath
, cue
))
1760 strcpy((cue
)->audio_filename
, trackname
);
1762 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
1767 struct mp3entry
*track_id3
;
1769 if (track_widx
== track_ridx
)
1770 track_id3
= &curtrack_id3
;
1772 track_id3
= bufgetid3(tracks
[track_widx
].id3_hid
);
1774 #ifdef HAVE_ALBUMART
1775 if (tracks
[track_widx
].aa_hid
< 0 && gui_sync_wps_uses_albumart())
1777 char aa_path
[MAX_PATH
];
1778 if (find_albumart(track_id3
, aa_path
, sizeof(aa_path
)))
1779 tracks
[track_widx
].aa_hid
= bufopen(aa_path
, 0, TYPE_BITMAP
);
1783 /* Load the codec. */
1784 if (!audio_loadcodec(start_play
))
1786 if (tracks
[track_widx
].codec_hid
== ERR_BUFFER_FULL
)
1788 /* No space for codec on buffer, not an error */
1792 /* This is an error condition, either no codec was found, or reading
1793 * the codec file failed part way through, either way, skip the track */
1794 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
1795 /* We should not use gui_syncplash from audio thread! */
1796 gui_syncsplash(HZ
*2, msgbuf
);
1797 /* Skip invalid entry from playlist. */
1798 playlist_skip_entry(NULL
, last_peek_offset
);
1799 tracks
[track_widx
].taginfo_ready
= false;
1803 track_id3
->elapsed
= 0;
1805 enum data_type type
= TYPE_PACKET_AUDIO
;
1807 switch (track_id3
->codectype
) {
1812 file_offset
= offset
;
1813 track_id3
->offset
= offset
;
1814 audio_set_elapsed(track_id3
);
1820 file_offset
= offset
;
1821 track_id3
->offset
= offset
;
1822 track_id3
->elapsed
= track_id3
->length
/ 2;
1826 case AFMT_OGG_VORBIS
:
1835 track_id3
->offset
= offset
;
1841 logf("Loading atomic %d",track_id3
->codectype
);
1842 type
= TYPE_ATOMIC_AUDIO
;
1846 logf("alt:%s", trackname
);
1848 if (file_offset
> AUDIO_REBUFFER_GUESS_SIZE
)
1849 file_offset
-= AUDIO_REBUFFER_GUESS_SIZE
;
1850 else if (track_id3
->first_frame_offset
)
1851 file_offset
= track_id3
->first_frame_offset
;
1855 tracks
[track_widx
].audio_hid
= bufopen(trackname
, file_offset
, type
);
1857 if (tracks
[track_widx
].audio_hid
< 0)
1862 ci
.curpos
=file_offset
;
1863 buf_request_buffer_handle(tracks
[track_widx
].audio_hid
);
1867 track_widx
&= MAX_TRACK_MASK
;
1872 /* Send callback events to notify about new tracks. */
1873 static void audio_generate_postbuffer_events(void)
1877 logf("Postbuffer:%d/%d",track_ridx
,track_widx
);
1879 if (audio_have_tracks())
1881 cur_idx
= track_ridx
;
1884 if (!tracks
[cur_idx
].event_sent
)
1886 /* Mark the event 'sent' even if we don't really send one */
1887 tracks
[cur_idx
].event_sent
= true;
1888 if (track_buffer_callback
&& tracks
[cur_idx
].id3_hid
>= 0)
1889 track_buffer_callback(bufgetid3(tracks
[cur_idx
].id3_hid
));
1891 if (cur_idx
== track_widx
)
1894 cur_idx
&= MAX_TRACK_MASK
;
1899 static void audio_fill_file_buffer(bool start_play
, size_t offset
)
1901 struct queue_event ev
;
1902 bool had_next_track
= audio_next_track() != NULL
;
1903 bool continue_buffering
;
1905 /* Must reset the buffer before use if trashed or voice only - voice
1906 file size shouldn't have changed so we can go straight from
1907 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
1908 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
1909 audio_reset_buffer();
1911 logf("Starting buffer fill");
1914 audio_clear_track_entries(false);
1916 /* Save the current resume position once. */
1917 playlist_update_resume_info(audio_current_track());
1920 continue_buffering
= audio_load_track(offset
, start_play
);
1924 if (queue_peek(&audio_queue
, &ev
)) {
1925 if (ev
.id
!= Q_AUDIO_FILL_BUFFER
)
1927 /* There's a message in the queue. break the loop to treat it,
1928 and go back to filling after that. */
1929 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1930 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1934 } while (continue_buffering
);
1936 if (!had_next_track
&& audio_next_track())
1937 track_changed
= true;
1939 audio_generate_postbuffer_events();
1941 if (!continue_buffering
)
1942 register_buffer_low_callback(low_buffer_callback
);
1945 static void audio_rebuffer(void)
1947 logf("Forcing rebuffer");
1949 clear_track_info(CUR_TI
);
1951 /* Reset track pointers */
1952 track_widx
= track_ridx
;
1953 audio_clear_track_entries(true);
1955 /* Fill the buffer */
1956 last_peek_offset
= -1;
1959 if (!CUR_TI
->taginfo_ready
)
1960 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
1962 audio_fill_file_buffer(false, 0);
1965 /* Called on request from the codec to get a new track. This is the codec part
1966 of the track transition. */
1967 static int audio_check_new_track(void)
1969 int track_count
= audio_track_count();
1970 int old_track_ridx
= track_ridx
;
1977 if (playlist_next_dir(ci
.new_track
))
1985 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1986 return Q_CODEC_REQUEST_FAILED
;
1993 /* If the playlist isn't that big */
1994 if (!playlist_check(ci
.new_track
))
1996 if (ci
.new_track
>= 0)
1998 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1999 return Q_CODEC_REQUEST_FAILED
;
2001 /* Find the beginning backward if the user over-skips it */
2002 while (!playlist_check(++ci
.new_track
))
2003 if (ci
.new_track
>= 0)
2005 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2006 return Q_CODEC_REQUEST_FAILED
;
2009 /* Update the playlist */
2010 last_peek_offset
-= ci
.new_track
;
2012 if (playlist_next(ci
.new_track
) < 0)
2014 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2015 return Q_CODEC_REQUEST_FAILED
;
2021 new_playlist
= false;
2024 /* Save the old track's metadata to allow the WPS to display it */
2025 copy_mp3entry(&prevtrack_id3
, &curtrack_id3
);
2027 /* Save a pointer to the old track to allow later clearing */
2030 for (i
= 0; i
< ci
.new_track
; i
++)
2032 idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
2033 struct mp3entry
*id3
= bufgetid3(tracks
[idx
].id3_hid
);
2034 ssize_t offset
= buf_handle_offset(tracks
[idx
].audio_hid
);
2035 if (!id3
|| offset
< 0 || (unsigned)offset
> id3
->first_frame_offset
)
2037 /* We don't have all the audio data for that track, so clear it,
2038 but keep the metadata. */
2039 if (tracks
[idx
].audio_hid
>= 0 && bufclose(tracks
[idx
].audio_hid
))
2041 tracks
[idx
].audio_hid
= -1;
2042 tracks
[idx
].filesize
= 0;
2047 /* Move to the new track */
2048 track_ridx
+= ci
.new_track
;
2049 track_ridx
&= MAX_TRACK_MASK
;
2051 buf_set_base_handle(CUR_TI
->audio_hid
);
2055 playlist_end
= false;
2056 wps_offset
= -ci
.new_track
;
2059 track_changed
= true;
2061 /* If it is not safe to even skip this many track entries */
2062 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
2069 forward
= ci
.new_track
> 0;
2072 /* If the target track is clearly not in memory */
2073 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
2079 /* When skipping backwards, it is possible that we've found a track that's
2080 * buffered, but which is around the track-wrap and therefor not the track
2081 * we are looking for */
2084 int cur_idx
= track_ridx
;
2085 bool taginfo_ready
= true;
2086 /* We've wrapped the buffer backwards if new > old */
2087 bool wrap
= track_ridx
> old_track_ridx
;
2092 cur_idx
&= MAX_TRACK_MASK
;
2094 /* if we've advanced past the wrap when cur_idx is zeroed */
2098 /* if we aren't still on the wrap and we've caught the old track */
2099 if (!(wrap
|| cur_idx
< old_track_ridx
))
2102 /* If we hit a track in between without valid tag info, bail */
2103 if (!tracks
[cur_idx
].taginfo_ready
)
2105 taginfo_ready
= false;
2116 audio_update_trackinfo();
2117 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2118 return Q_CODEC_REQUEST_COMPLETE
;
2121 void audio_set_track_buffer_event(void (*handler
)(struct mp3entry
*id3
))
2123 track_buffer_callback
= handler
;
2126 void audio_set_track_unbuffer_event(void (*handler
)(struct mp3entry
*id3
))
2128 track_unbuffer_callback
= handler
;
2131 void audio_set_track_changed_event(void (*handler
)(struct mp3entry
*id3
))
2133 track_changed_callback
= handler
;
2136 unsigned long audio_prev_elapsed(void)
2138 return prev_track_elapsed
;
2141 static void audio_stop_codec_flush(void)
2143 ci
.stop_codec
= true;
2146 while (audio_codec_loaded
)
2149 /* If the audio codec is not loaded any more, and the audio is still
2150 * playing, it is now and _only_ now safe to call this function from the
2152 if (pcm_is_playing())
2154 pcmbuf_pause(paused
);
2157 static void audio_stop_playback(void)
2159 /* If we were playing, save resume information */
2162 struct mp3entry
*id3
= NULL
;
2164 if (!playlist_end
|| !ci
.stop_codec
)
2166 /* Set this early, the outside code yields and may allow the codec
2167 to try to wait for a reply on a buffer wait */
2168 ci
.stop_codec
= true;
2169 id3
= audio_current_track();
2172 /* Save the current playing spot, or NULL if the playlist has ended */
2173 playlist_update_resume_info(id3
);
2175 prev_track_elapsed
= curtrack_id3
.elapsed
;
2177 /* Increment index so runtime info is saved in audio_clear_track_entries().
2178 * Done here, as audio_stop_playback() may be called more than once.
2179 * Don't update runtime unless playback is stopped because of end of playlist.
2180 * Updating runtime when manually stopping a tracks, can destroy autoscores
2186 track_ridx
&= MAX_TRACK_MASK
;
2191 audio_stop_codec_flush();
2194 /* Mark all entries null. */
2195 audio_clear_track_entries(false);
2197 /* Close all tracks */
2198 audio_release_tracks();
2200 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
2203 static void audio_play_start(size_t offset
)
2207 #if INPUT_SRC_CAPS != 0
2208 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
2209 audio_set_output_source(AUDIO_SRC_PLAYBACK
);
2212 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2214 audio_stop_codec_flush();
2216 track_changed
= true;
2217 playlist_end
= false;
2225 sound_set_volume(global_settings
.volume
);
2226 track_widx
= track_ridx
= 0;
2228 /* Clear all track entries. */
2229 for (i
= 0; i
< MAX_TRACK
; i
++) {
2230 clear_track_info(&tracks
[i
]);
2233 last_peek_offset
= -1;
2235 /* Officially playing */
2236 queue_reply(&audio_queue
, 1);
2238 #ifndef HAVE_FLASH_STORAGE
2239 set_filebuf_watermark(buffer_margin
, 0);
2241 audio_fill_file_buffer(true, offset
);
2243 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2244 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
2248 /* Invalidates all but currently playing track. */
2249 static void audio_invalidate_tracks(void)
2251 if (audio_have_tracks())
2253 last_peek_offset
= 0;
2254 playlist_end
= false;
2255 track_widx
= track_ridx
;
2257 /* Mark all other entries null (also buffered wrong metadata). */
2258 audio_clear_track_entries(true);
2260 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
2262 audio_fill_file_buffer(false, 0);
2266 static void audio_new_playlist(void)
2268 /* Prepare to start a new fill from the beginning of the playlist */
2269 last_peek_offset
= -1;
2270 if (audio_have_tracks())
2273 skipped_during_pause
= true;
2274 playlist_end
= false;
2275 track_widx
= track_ridx
;
2276 audio_clear_track_entries(true);
2279 track_widx
&= MAX_TRACK_MASK
;
2281 /* Mark the current track as invalid to prevent skipping back to it */
2282 CUR_TI
->taginfo_ready
= false;
2285 /* Signal the codec to initiate a track change forward */
2286 new_playlist
= true;
2289 /* Officially playing */
2290 queue_reply(&audio_queue
, 1);
2292 audio_fill_file_buffer(false, 0);
2295 static void audio_initiate_track_change(long direction
)
2297 playlist_end
= false;
2298 ci
.new_track
+= direction
;
2299 wps_offset
-= direction
;
2301 skipped_during_pause
= true;
2304 static void audio_initiate_dir_change(long direction
)
2306 playlist_end
= false;
2308 ci
.new_track
= direction
;
2310 skipped_during_pause
= true;
2313 /* Called when PCM track change is complete */
2314 static void audio_finalise_track_change(void)
2316 logf("audio_finalise_track_change");
2321 automatic_skip
= false;
2323 prevtrack_id3
.path
[0] = 0;
2325 if (prev_ti
&& prev_ti
->audio_hid
< 0)
2327 /* No audio left so we clear all the track info. */
2328 clear_track_info(prev_ti
);
2331 if (track_changed_callback
)
2332 track_changed_callback(&curtrack_id3
);
2333 track_changed
= true;
2334 playlist_update_resume_info(audio_current_track());
2338 * Layout audio buffer as follows - iram buffer depends on target:
2339 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
2341 static void audio_reset_buffer(void)
2343 /* see audio_get_recording_buffer if this is modified */
2344 logf("audio_reset_buffer");
2346 /* If the setup of anything allocated before the file buffer is
2347 changed, do check the adjustments after the buffer_alloc call
2348 as it will likely be affected and need sliding over */
2350 /* Initially set up file buffer as all space available */
2351 malloc_buf
= audiobuf
+ talk_get_bufsize();
2352 /* Align the malloc buf to line size. Especially important to cf
2353 targets that do line reads/writes. */
2354 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
2355 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
2356 filebuflen
= audiobufend
- filebuf
;
2360 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
2361 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
2363 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
2364 will already be line aligned */
2367 buffering_reset(filebuf
, filebuflen
);
2369 /* Clear any references to the file buffer */
2370 buffer_state
= BUFFER_STATE_INITIALIZED
;
2372 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
2373 /* Make sure everything adds up - yes, some info is a bit redundant but
2374 aids viewing and the sumation of certain variables should add up to
2375 the location of others. */
2378 unsigned char * pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
2379 logf("mabuf: %08X", (unsigned)malloc_buf
);
2380 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
2381 logf("fbuf: %08X", (unsigned)filebuf
);
2382 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
2383 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
2384 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
2385 logf("pcmb: %08X", (unsigned)pcmbuf
);
2386 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
2391 static void audio_thread(void)
2393 struct queue_event ev
;
2397 audio_thread_ready
= true;
2401 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
2404 case Q_AUDIO_FILL_BUFFER
:
2405 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
2406 if (!playing
|| playlist_end
|| ci
.stop_codec
)
2408 audio_fill_file_buffer(false, 0);
2412 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2413 if (playing
&& ev
.data
<= 0)
2414 audio_new_playlist();
2417 audio_stop_playback();
2418 audio_play_start((size_t)ev
.data
);
2423 LOGFQUEUE("audio < Q_AUDIO_STOP");
2425 audio_stop_playback();
2427 queue_clear(&audio_queue
);
2431 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
2432 if (!(bool) ev
.data
&& skipped_during_pause
&& !pcmbuf_is_crossfade_active())
2433 pcmbuf_play_stop(); /* Flush old track on resume after skip */
2434 skipped_during_pause
= false;
2437 pcmbuf_pause((bool)ev
.data
);
2438 paused
= (bool)ev
.data
;
2442 LOGFQUEUE("audio < Q_AUDIO_SKIP");
2443 audio_initiate_track_change((long)ev
.data
);
2446 case Q_AUDIO_PRE_FF_REWIND
:
2447 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
2453 case Q_AUDIO_FF_REWIND
:
2454 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
2457 ci
.seek_time
= (long)ev
.data
+1;
2460 case Q_AUDIO_CHECK_NEW_TRACK
:
2461 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
2462 queue_reply(&audio_queue
, audio_check_new_track());
2465 case Q_AUDIO_DIR_SKIP
:
2466 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2467 playlist_end
= false;
2468 audio_initiate_dir_change(ev
.data
);
2472 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
2473 audio_invalidate_tracks();
2476 case Q_AUDIO_TRACK_CHANGED
:
2477 /* PCM track change done */
2478 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2479 audio_finalise_track_change();
2483 case SYS_USB_CONNECTED
:
2484 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2486 audio_stop_playback();
2487 #ifdef PLAYBACK_VOICE
2490 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
2491 usb_wait_for_disconnect(&audio_queue
);
2493 /* Mark all entries null. */
2494 audio_clear_track_entries(false);
2496 /* release tracks to make sure all handles are closed */
2497 audio_release_tracks();
2502 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
2506 LOGFQUEUE("audio < default");
2512 #ifdef ROCKBOX_HAS_LOGF
2513 static void audio_test_track_changed_event(struct mp3entry
*id3
)
2517 logf("tce:%s", id3
->path
);
2521 /* Initialize the audio system - called from init() in main.c.
2522 * Last function because of all the references to internal symbols
2524 void audio_init(void)
2526 struct thread_entry
*audio_thread_p
;
2528 /* Can never do this twice */
2529 if (audio_is_initialized
)
2531 logf("audio: already initialized");
2535 logf("audio: initializing");
2537 /* Initialize queues before giving control elsewhere in case it likes
2538 to send messages. Thread creation will be delayed however so nothing
2539 starts running until ready if something yields such as talk_init. */
2540 queue_init(&audio_queue
, true);
2541 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
2542 queue_init(&codec_queue
, false);
2543 queue_enable_queue_send(&codec_queue
, &codec_queue_sender_list
);
2547 #ifdef ROCKBOX_HAS_LOGF
2548 audio_set_track_changed_event(audio_test_track_changed_event
);
2551 /* Initialize codec api. */
2552 ci
.read_filebuf
= codec_filebuf_callback
;
2553 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
2554 ci
.get_codec_memory
= codec_get_memory_callback
;
2555 ci
.request_buffer
= codec_request_buffer_callback
;
2556 ci
.advance_buffer
= codec_advance_buffer_callback
;
2557 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
2558 ci
.request_next_track
= codec_request_next_track_callback
;
2559 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
2560 ci
.seek_buffer
= codec_seek_buffer_callback
;
2561 ci
.seek_complete
= codec_seek_complete_callback
;
2562 ci
.set_elapsed
= codec_set_elapsed_callback
;
2563 ci
.set_offset
= codec_set_offset_callback
;
2564 ci
.configure
= codec_configure_callback
;
2565 ci
.discard_codec
= codec_discard_codec_callback
;
2566 ci
.dsp
= (struct dsp_config
*)dsp_configure(NULL
, DSP_MYDSP
,
2569 /* initialize the buffer */
2572 /* audio_reset_buffer must to know the size of voice buffer so init
2576 codec_thread_p
= create_thread(
2577 codec_thread
, codec_stack
, sizeof(codec_stack
),
2578 CREATE_THREAD_FROZEN
,
2579 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
2582 audio_thread_p
= create_thread(audio_thread
, audio_stack
,
2583 sizeof(audio_stack
), CREATE_THREAD_FROZEN
,
2584 audio_thread_name
IF_PRIO(, PRIORITY_BACKGROUND
)
2587 #ifdef PLAYBACK_VOICE
2588 voice_thread_init();
2591 /* Set crossfade setting for next buffer init which should be about... */
2592 pcmbuf_crossfade_enable(global_settings
.crossfade
);
2594 /* initialize the buffering system */
2597 /* ...now! Set up the buffers */
2598 audio_reset_buffer();
2601 for(i
= 0; i
< MAX_TRACK
; i
++)
2603 tracks
[i
].audio_hid
= -1;
2604 tracks
[i
].id3_hid
= -1;
2605 tracks
[i
].codec_hid
= -1;
2606 #ifdef HAVE_ALBUMART
2607 tracks
[i
].aa_hid
= -1;
2611 /* Probably safe to say */
2612 audio_is_initialized
= true;
2614 sound_settings_apply();
2616 eq_hw_enable(global_settings
.eq_hw_enabled
);
2618 #ifndef HAVE_FLASH_STORAGE
2619 audio_set_buffer_margin(global_settings
.buffer_margin
);
2622 /* it's safe to let the threads run now */
2623 #ifdef PLAYBACK_VOICE
2624 voice_thread_resume();
2626 thread_thaw(codec_thread_p
);
2627 thread_thaw(audio_thread_p
);
2631 void audio_wait_for_init(void)
2633 /* audio thread will only set this once after it finished the final
2634 * audio hardware init so this little construct is safe - even
2636 while (!audio_thread_ready
)