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: Pause should be handled in here, rather than PCMBUF so that voice can
21 * play whilst audio is paused */
43 #include "buffering.h"
44 #include "voice_thread.h"
45 #include "mp3_playback.h"
60 #ifdef HAVE_LCD_BITMAP
62 #include "peakmeter.h"
73 #include "ata_idle_notify.h"
76 #include "recording.h"
80 #define PLAYBACK_VOICE
82 /* default point to start buffer refill */
83 #define AUDIO_DEFAULT_WATERMARK (1024*512)
84 /* amount of guess-space to allow for codecs that must hunt and peck
85 * for their correct seeek target, 32k seems a good size */
86 #define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
88 /* Define LOGF_ENABLE to enable logf output in this file */
89 /*#define LOGF_ENABLE*/
92 /* macros to enable logf for queues
93 logging on SYS_TIMEOUT can be disabled */
95 /* Define this for logf output of all queuing except SYS_TIMEOUT */
96 #define PLAYBACK_LOGQUEUES
97 /* Define this to logf SYS_TIMEOUT messages */
98 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
101 #ifdef PLAYBACK_LOGQUEUES
102 #define LOGFQUEUE logf
104 #define LOGFQUEUE(...)
107 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
108 #define LOGFQUEUE_SYS_TIMEOUT logf
110 #define LOGFQUEUE_SYS_TIMEOUT(...)
114 /* Define one constant that includes recording related functionality */
115 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
116 #define AUDIO_HAVE_RECORDING
125 Q_AUDIO_PRE_FF_REWIND
,
127 Q_AUDIO_CHECK_NEW_TRACK
,
129 Q_AUDIO_TRACK_CHANGED
,
133 Q_CODEC_REQUEST_COMPLETE
,
134 Q_CODEC_REQUEST_FAILED
,
139 #ifdef AUDIO_HAVE_RECORDING
145 /* As defined in plugins/lib/xxx2wav.h */
147 #define MALLOC_BUFSIZE (512*1024)
148 #define GUARD_BUFSIZE (32*1024)
150 #define MALLOC_BUFSIZE (100*1024)
151 #define GUARD_BUFSIZE (8*1024)
154 /* As defined in plugin.lds */
156 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
157 #define CODEC_IRAM_SIZE ((size_t)0xc000)
158 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
159 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
160 #define CODEC_IRAM_SIZE ((size_t)0x10000)
162 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
163 #define CODEC_IRAM_SIZE ((size_t)0xc000)
166 bool audio_is_initialized
= false;
167 static bool audio_thread_ready NOCACHEBSS_ATTR
= false;
169 /* Variables are commented with the threads that use them: *
170 * A=audio, C=codec, V=voice. A suffix of - indicates that *
171 * the variable is read but not updated on that thread. */
172 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
174 /* Main state control */
175 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR
= false; /* Codec loaded? (C/A-) */
176 static volatile bool playing NOCACHEBSS_ATTR
= false; /* Is audio playing? (A) */
177 static volatile bool paused NOCACHEBSS_ATTR
= false; /* Is audio paused? (A/C-) */
179 /* Ring buffer where compressed audio and codecs are loaded */
180 static unsigned char *filebuf
= NULL
; /* Start of buffer (A/C-) */
181 static unsigned char *malloc_buf
= NULL
; /* Start of malloc buffer (A/C-) */
182 /* FIXME: make filebuflen static */
183 size_t filebuflen
= 0; /* Size of buffer (A/C-) */
184 /* FIXME: make buf_ridx (C/A-) */
186 /* Possible arrangements of the buffer */
187 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
188 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
189 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
190 static int buffer_state
= BUFFER_STATE_TRASHED
; /* Buffer state */
192 /* Used to keep the WPS up-to-date during track transtition */
193 static struct mp3entry prevtrack_id3
;
195 /* Used to provide the codec with a pointer */
196 static struct mp3entry curtrack_id3
;
198 /* Used to make next track info available while playing last track on buffer */
199 static struct mp3entry lasttrack_id3
;
201 /* Track info structure about songs in the file buffer (A/C-) */
203 int audio_hid
; /* The ID for the track's buffer handle */
204 int id3_hid
; /* The ID for the track's metadata handle */
205 int codec_hid
; /* The ID for the track's codec handle */
207 int aa_hid
; /* The ID for the track's album art handle */
210 size_t filesize
; /* File total length */
212 bool taginfo_ready
; /* Is metadata read */
214 bool event_sent
; /* Was this track's buffered event sent */
217 static struct track_info tracks
[MAX_TRACK
];
218 static volatile int track_ridx
= 0; /* Track being decoded (A/C-) */
219 static int track_widx
= 0; /* Track being buffered (A) */
221 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
222 static struct track_info
*prev_ti
= NULL
; /* Pointer to the previously played
225 /* Set by the audio thread when the current track information has updated
226 * and the WPS may need to update its cached information */
227 static bool track_changed
= false;
229 /* Information used only for filling the buffer */
230 /* Playlist steps from playing track to next track to be buffered (A) */
231 static int last_peek_offset
= 0;
233 /* Scrobbler support */
234 static unsigned long prev_track_elapsed
= 0; /* Previous track elapsed time (C/A-)*/
236 /* Track change controls */
237 static bool automatic_skip
= false; /* Who initiated in-progress skip? (C/A-) */
238 static bool playlist_end
= false; /* Has the current playlist ended? (A) */
239 static bool auto_dir_skip
= false; /* Have we changed dirs automatically? */
240 static bool dir_skip
= false; /* Is a directory skip pending? (A) */
241 static bool new_playlist
= false; /* Are we starting a new playlist? (A) */
242 static int wps_offset
= 0; /* Pending track change offset, to keep WPS responsive (A) */
243 static bool skipped_during_pause
= false; /* Do we need to clear the PCM buffer when playback resumes (A) */
245 /* Callbacks which applications or plugins may set */
246 /* When the playing track has changed from the user's perspective */
247 void (*track_changed_callback
)(struct mp3entry
*id3
) = NULL
;
248 /* When a track has been buffered */
249 void (*track_buffer_callback
)(struct mp3entry
*id3
) = NULL
;
250 /* When a track's buffer has been overwritten or cleared */
251 void (*track_unbuffer_callback
)(struct mp3entry
*id3
) = NULL
;
253 static size_t buffer_margin
= 0; /* Buffer margin aka anti-skip buffer (A/C-) */
255 /* Multiple threads */
256 /* Set the watermark to trigger buffer fill (A/C) FIXME */
257 static void set_filebuf_watermark(int seconds
, size_t max
);
260 static struct event_queue audio_queue NOCACHEBSS_ATTR
;
261 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR
;
262 static long audio_stack
[(DEFAULT_STACK_SIZE
+ 0x1000)/sizeof(long)];
263 static const char audio_thread_name
[] = "audio";
265 static void audio_thread(void);
266 static void audio_initiate_track_change(long direction
);
267 static bool audio_have_tracks(void);
268 static void audio_reset_buffer(void);
271 extern struct codec_api ci
;
272 static struct event_queue codec_queue NOCACHEBSS_ATTR
;
273 static struct queue_sender_list codec_queue_sender_list
;
274 static long codec_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
276 static const char codec_thread_name
[] = "codec";
277 struct thread_entry
*codec_thread_p
; /* For modifying thread priority later. */
279 /* --- Helper functions --- */
281 static struct mp3entry
*bufgetid3(int handle_id
)
286 struct mp3entry
*id3
;
287 ssize_t ret
= bufgetdata(handle_id
, 0, (void *)&id3
);
289 if (ret
< 0 || ret
!= sizeof(struct mp3entry
))
295 static bool clear_track_info(struct track_info
*track
)
297 /* bufclose returns true if the handle is not found, or if it is closed
298 * successfully, so these checks are safe on non-existant handles */
302 if (track
->codec_hid
>= 0) {
303 if (bufclose(track
->codec_hid
))
304 track
->codec_hid
= -1;
309 if (track
->id3_hid
>= 0) {
310 if (track
->event_sent
&& track_unbuffer_callback
) {
311 /* If there is an unbuffer callback, call it */
312 track_unbuffer_callback(bufgetid3(track
->id3_hid
));
315 if (bufclose(track
->id3_hid
))
321 if (track
->audio_hid
>= 0) {
322 if (bufclose(track
->audio_hid
))
323 track
->audio_hid
= -1;
329 if (track
->aa_hid
>= 0) {
330 if (bufclose(track
->aa_hid
))
338 track
->taginfo_ready
= false;
339 track
->event_sent
= false;
344 /* --- External interfaces --- */
346 /* This sends a stop message and the audio thread will dump all it's
347 subsequenct messages */
348 void audio_hard_stop(void)
351 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
352 queue_send(&audio_queue
, Q_AUDIO_STOP
, 1);
353 #ifdef PLAYBACK_VOICE
358 bool audio_restore_playback(int type
)
362 case AUDIO_WANT_PLAYBACK
:
363 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
364 audio_reset_buffer();
366 case AUDIO_WANT_VOICE
:
367 if (buffer_state
== BUFFER_STATE_TRASHED
)
368 audio_reset_buffer();
375 unsigned char *audio_get_buffer(bool talk_buf
, size_t *buffer_size
)
377 unsigned char *buf
, *end
;
379 if (audio_is_initialized
)
383 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
385 if (buffer_size
== NULL
)
387 /* Special case for talk_init to use since it already knows it's
389 buffer_state
= BUFFER_STATE_TRASHED
;
393 if (talk_buf
|| buffer_state
== BUFFER_STATE_TRASHED
394 || !talk_voice_required())
396 logf("get buffer: talk, audio");
397 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
398 the talk buffer is not needed because voice isn't being used, or
399 could be BUFFER_STATE_TRASHED already. If state is
400 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
401 without the caller knowing what's going on. Changing certain settings
402 may move it to a worse condition but the memory in use by something
403 else will remain undisturbed.
405 if (buffer_state
!= BUFFER_STATE_TRASHED
)
408 buffer_state
= BUFFER_STATE_TRASHED
;
416 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
417 still BUFFER_STATE_INITIALIZED */
418 /* Skip talk buffer and move pcm buffer to end to maximize available
419 contiguous memory - no audio running means voice will not need the
421 logf("get buffer: audio");
422 buf
= audiobuf
+ talk_get_bufsize();
423 end
= audiobufend
- pcmbuf_init(audiobufend
);
424 buffer_state
= BUFFER_STATE_VOICED_ONLY
;
427 *buffer_size
= end
- buf
;
432 #ifdef HAVE_RECORDING
433 unsigned char *audio_get_recording_buffer(size_t *buffer_size
)
435 /* Stop audio, voice and obtain all available buffer space */
439 unsigned char *end
= audiobufend
;
440 buffer_state
= BUFFER_STATE_TRASHED
;
441 *buffer_size
= end
- audiobuf
;
443 return (unsigned char *)audiobuf
;
446 bool audio_load_encoder(int afmt
)
449 const char *enc_fn
= get_codec_filename(afmt
| CODEC_TYPE_ENCODER
);
453 audio_remove_encoder();
454 ci
.enc_codec_loaded
= 0; /* clear any previous error condition */
456 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
457 queue_post(&codec_queue
, Q_ENCODER_LOAD_DISK
, (intptr_t)enc_fn
);
459 while (ci
.enc_codec_loaded
== 0)
462 logf("codec loaded: %d", ci
.enc_codec_loaded
);
464 return ci
.enc_codec_loaded
> 0;
469 } /* audio_load_encoder */
471 void audio_remove_encoder(void)
474 /* force encoder codec unload (if currently loaded) */
475 if (ci
.enc_codec_loaded
<= 0)
478 ci
.stop_encoder
= true;
479 while (ci
.enc_codec_loaded
> 0)
482 } /* audio_remove_encoder */
484 #endif /* HAVE_RECORDING */
487 int audio_current_aa_hid(void)
490 int offset
= ci
.new_track
+ wps_offset
;
492 cur_idx
= track_ridx
+ offset
;
493 cur_idx
&= MAX_TRACK_MASK
;
495 return tracks
[cur_idx
].aa_hid
;
499 struct mp3entry
* audio_current_track(void)
501 const char *filename
;
503 static struct mp3entry temp_id3
;
505 int offset
= ci
.new_track
+ wps_offset
;
507 cur_idx
= (track_ridx
+ offset
) & MAX_TRACK_MASK
;
509 if (cur_idx
== track_ridx
&& *curtrack_id3
.path
)
512 return &curtrack_id3
;
514 else if (offset
== -1 && *prevtrack_id3
.path
)
516 /* We're in a track transition. The codec has moved on to the nex track,
517 but the audio being played is still the same (now previous) track.
518 prevtrack_id3.elapsed is being updated in an ISR by
519 codec_pcmbuf_position_callback */
520 return &prevtrack_id3
;
522 else if (tracks
[cur_idx
].id3_hid
>= 0)
524 /* Get the ID3 metadata from the main buffer */
525 return bufgetid3(tracks
[cur_idx
].id3_hid
);
528 /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info
529 we have and return that. */
531 memset(&temp_id3
, 0, sizeof(struct mp3entry
));
533 filename
= playlist_peek(0);
535 filename
= "No file!";
537 #ifdef HAVE_TC_RAMCACHE
538 if (tagcache_fill_tags(&temp_id3
, filename
))
542 p
= strrchr(filename
, '/');
548 strncpy(temp_id3
.path
, p
, sizeof(temp_id3
.path
)-1);
549 temp_id3
.title
= &temp_id3
.path
[0];
554 struct mp3entry
* audio_next_track(void)
556 int next_idx
= track_ridx
;
558 if (!audio_have_tracks())
561 if (wps_offset
== -1 && *prevtrack_id3
.path
)
563 /* We're in a track transition. The next track for the WPS is the one
564 currently being decoded. */
565 return &curtrack_id3
;
568 next_idx
= (next_idx
+ 1) & MAX_TRACK_MASK
;
570 if (next_idx
== track_widx
)
572 /* The next track hasn't been buffered yet, so we return the static
573 version of its metadata. */
574 return &lasttrack_id3
;
577 if (tracks
[next_idx
].id3_hid
< 0)
580 return bufgetid3(tracks
[next_idx
].id3_hid
);
583 bool audio_has_changed_track(void)
587 track_changed
= false;
594 void audio_play(long offset
)
598 #ifdef PLAYBACK_VOICE
599 /* Truncate any existing voice output so we don't have spelling
600 * etc. over the first part of the played track */
605 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset
);
606 /* Don't return until playback has actually started */
607 queue_send(&audio_queue
, Q_AUDIO_PLAY
, offset
);
610 void audio_stop(void)
613 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
614 /* Don't return until playback has actually stopped */
615 queue_send(&audio_queue
, Q_AUDIO_STOP
, 0);
618 void audio_pause(void)
620 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
621 /* Don't return until playback has actually paused */
622 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, true);
625 void audio_resume(void)
627 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
628 /* Don't return until playback has actually resumed */
629 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, false);
632 void audio_next(void)
634 if (playlist_check(ci
.new_track
+ wps_offset
+ 1))
636 if (global_settings
.beep
)
637 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
639 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
640 queue_post(&audio_queue
, Q_AUDIO_SKIP
, 1);
641 /* Update wps while our message travels inside deep playback queues. */
643 track_changed
= true;
647 /* No more tracks. */
648 if (global_settings
.beep
)
649 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
653 void audio_prev(void)
655 if (playlist_check(ci
.new_track
+ wps_offset
- 1))
657 if (global_settings
.beep
)
658 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
660 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
661 queue_post(&audio_queue
, Q_AUDIO_SKIP
, -1);
662 /* Update wps while our message travels inside deep playback queues. */
664 track_changed
= true;
668 /* No more tracks. */
669 if (global_settings
.beep
)
670 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
674 void audio_next_dir(void)
676 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
677 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, 1);
680 void audio_prev_dir(void)
682 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
683 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, -1);
686 void audio_pre_ff_rewind(void)
688 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
689 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
692 void audio_ff_rewind(long newpos
)
694 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
695 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, newpos
);
698 void audio_flush_and_reload_tracks(void)
700 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
701 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
704 void audio_error_clear(void)
706 #ifdef AUDIO_HAVE_RECORDING
707 pcm_rec_error_clear();
711 int audio_status(void)
716 ret
|= AUDIO_STATUS_PLAY
;
719 ret
|= AUDIO_STATUS_PAUSE
;
721 #ifdef HAVE_RECORDING
722 /* Do this here for constitency with mpeg.c version */
723 ret
|= pcm_rec_status();
729 int audio_get_file_pos(void)
734 #ifndef HAVE_FLASH_STORAGE
735 void audio_set_buffer_margin(int setting
)
737 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
738 buffer_margin
= lookup
[setting
];
739 logf("buffer margin: %ld", (long)buffer_margin
);
740 set_filebuf_watermark(buffer_margin
, 0);
744 /* Take nescessary steps to enable or disable the crossfade setting */
745 void audio_set_crossfade(int enable
)
751 /* Tell it the next setting to use */
752 pcmbuf_crossfade_enable(enable
);
754 /* Return if size hasn't changed or this is too early to determine
755 which in the second case there's no way we could be playing
757 if (pcmbuf_is_same_size())
759 /* This function is a copout and just syncs some variables -
760 to be removed at a later date */
761 pcmbuf_crossfade_enable_finished();
766 was_playing
= playing
;
768 /* Playback has to be stopped before changing the buffer size */
771 /* Store the track resume position */
772 offset
= curtrack_id3
.offset
;
773 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK
));
776 /* Blast it - audio buffer will have to be setup again next time
778 audio_get_buffer(true, &size
);
780 /* Restart playback if audio was running previously */
785 /* --- Routines called from multiple threads --- */
787 static void set_filebuf_watermark(int seconds
, size_t max
)
792 return; /* Audio buffers not yet set up */
794 bytes
= seconds
?MAX(curtrack_id3
.bitrate
* seconds
* (1000/8), max
):max
;
795 bytes
= MIN(bytes
, filebuflen
/ 2);
796 buf_set_watermark(bytes
);
799 const char * get_codec_filename(int cod_spec
)
803 #ifdef HAVE_RECORDING
804 /* Can choose decoder or encoder if one available */
805 int type
= cod_spec
& CODEC_TYPE_MASK
;
806 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
808 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
809 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
811 fname
= (type
== CODEC_TYPE_ENCODER
) ?
812 audio_formats
[afmt
].codec_enc_root_fn
:
813 audio_formats
[afmt
].codec_root_fn
;
816 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
817 afmt
, fname
? fname
: "<unknown>");
818 #else /* !HAVE_RECORDING */
820 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
821 cod_spec
= AFMT_UNKNOWN
;
822 fname
= audio_formats
[cod_spec
].codec_root_fn
;
823 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
824 #endif /* HAVE_RECORDING */
827 } /* get_codec_filename */
829 /* --- Codec thread --- */
830 static bool codec_pcmbuf_insert_callback(
831 const void *ch1
, const void *ch2
, int count
)
833 const char *src
[2] = { ch1
, ch2
};
837 int out_count
= dsp_output_count(ci
.dsp
, count
);
841 /* Prevent audio from a previous track from playing */
842 if (ci
.new_track
|| ci
.stop_codec
)
845 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
849 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
853 /* Get the real input_size for output_size bytes, guarding
854 * against resampling buffer overflows. */
855 inp_count
= dsp_input_count(ci
.dsp
, out_count
);
860 /* Input size has grown, no error, just don't write more than length */
861 if (inp_count
> count
)
864 out_count
= dsp_process(ci
.dsp
, dest
, src
, inp_count
);
869 pcmbuf_write_complete(out_count
);
875 } /* codec_pcmbuf_insert_callback */
877 static void* codec_get_memory_callback(size_t *size
)
879 *size
= MALLOC_BUFSIZE
;
883 /* Between the codec and PCM track change, we need to keep updating the
884 "elapsed" value of the previous (to the codec, but current to the
885 user/PCM/WPS) track, so that the progressbar reaches the end.
886 During that transition, the WPS will display prevtrack_id3. */
887 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
888 static void codec_pcmbuf_position_callback(size_t size
)
890 /* This is called from an ISR, so be quick */
891 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
892 prevtrack_id3
.elapsed
;
894 if (time
>= prevtrack_id3
.length
)
896 pcmbuf_set_position_callback(NULL
);
897 prevtrack_id3
.elapsed
= prevtrack_id3
.length
;
900 prevtrack_id3
.elapsed
= time
;
903 static void codec_set_elapsed_callback(unsigned int value
)
905 unsigned int latency
;
909 #ifdef AB_REPEAT_ENABLE
910 ab_position_report(value
);
913 latency
= pcmbuf_get_latency();
915 curtrack_id3
.elapsed
= 0;
916 else if (value
- latency
> curtrack_id3
.elapsed
||
917 value
- latency
< curtrack_id3
.elapsed
- 2)
919 curtrack_id3
.elapsed
= value
- latency
;
923 static void codec_set_offset_callback(size_t value
)
925 unsigned int latency
;
930 latency
= pcmbuf_get_latency() * curtrack_id3
.bitrate
/ 8;
932 curtrack_id3
.offset
= 0;
934 curtrack_id3
.offset
= value
- latency
;
937 static void codec_advance_buffer_counters(size_t amount
)
939 bufadvance(CUR_TI
->audio_hid
, amount
);
943 /* copy up-to size bytes into ptr and return the actual size copied */
944 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
948 if (ci
.stop_codec
|| !playing
)
951 copy_n
= bufread(CUR_TI
->audio_hid
, size
, ptr
);
953 /* Nothing requested OR nothing left */
957 /* Update read and other position pointers */
958 codec_advance_buffer_counters(copy_n
);
960 /* Return the actual amount of data copied to the buffer */
962 } /* codec_filebuf_callback */
964 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
966 size_t copy_n
= reqsize
;
976 ret
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, &ptr
);
978 copy_n
= MIN((size_t)ret
, reqsize
);
989 } /* codec_request_buffer_callback */
991 static int get_codec_base_type(int type
)
1003 static void codec_advance_buffer_callback(size_t amount
)
1005 codec_advance_buffer_counters(amount
);
1006 codec_set_offset_callback(ci
.curpos
);
1009 static void codec_advance_buffer_loc_callback(void *ptr
)
1011 size_t amount
= buf_get_offset(CUR_TI
->audio_hid
, ptr
);
1012 codec_advance_buffer_callback(amount
);
1015 /* Copied from mpeg.c. Should be moved somewhere else. */
1016 static int codec_get_file_pos(void)
1019 struct mp3entry
*id3
= audio_current_track();
1025 /* Use the TOC to find the new position */
1026 unsigned int percent
, remainder
;
1027 int curtoc
, nexttoc
, plen
;
1029 percent
= (id3
->elapsed
*100)/id3
->length
;
1033 curtoc
= id3
->toc
[percent
];
1036 nexttoc
= id3
->toc
[percent
+1];
1040 pos
= (id3
->filesize
/256)*curtoc
;
1042 /* Use the remainder to get a more accurate position */
1043 remainder
= (id3
->elapsed
*100)%id3
->length
;
1044 remainder
= (remainder
*100)/id3
->length
;
1045 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1046 pos
+= (plen
/100)*remainder
;
1050 /* No TOC exists, estimate the new position */
1051 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1052 (id3
->elapsed
/ 1000);
1055 else if (id3
->bitrate
)
1056 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1060 pos
+= id3
->first_frame_offset
;
1062 /* Don't seek right to the end of the file so that we can
1063 transition properly to the next song */
1064 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1065 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1070 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1074 curtrack_id3
.elapsed
= newtime
;
1075 newpos
= codec_get_file_pos();
1080 static void codec_seek_complete_callback(void)
1082 logf("seek_complete");
1083 if (pcm_is_paused())
1085 /* If this is not a seamless seek, clear the buffer */
1087 dsp_configure(ci
.dsp
, DSP_FLUSH
, 0);
1089 /* If playback was not 'deliberately' paused, unpause now */
1091 pcmbuf_pause(false);
1096 static bool codec_seek_buffer_callback(size_t newpos
)
1098 logf("codec_seek_buffer_callback");
1100 int ret
= bufseek(CUR_TI
->audio_hid
, newpos
);
1110 static void codec_configure_callback(int setting
, intptr_t value
)
1113 case CODEC_SET_FILEBUF_WATERMARK
:
1114 set_filebuf_watermark(buffer_margin
, value
);
1118 if (!dsp_configure(ci
.dsp
, setting
, value
))
1119 { logf("Illegal key:%d", setting
); }
1123 static void codec_track_changed(void)
1125 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1126 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1129 static void codec_pcmbuf_track_changed_callback(void)
1131 pcmbuf_set_position_callback(NULL
);
1132 codec_track_changed();
1135 static void codec_discard_codec_callback(void)
1137 if (CUR_TI
->codec_hid
>= 0)
1139 bufclose(CUR_TI
->codec_hid
);
1140 CUR_TI
->codec_hid
= -1;
1144 static inline void codec_gapless_track_change(void)
1146 /* callback keeps the progress bar moving while the pcmbuf empties */
1147 pcmbuf_set_position_callback(codec_pcmbuf_position_callback
);
1148 /* set the pcmbuf callback for when the track really changes */
1149 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1152 static inline void codec_crossfade_track_change(void)
1154 /* Initiate automatic crossfade mode */
1155 pcmbuf_crossfade_init(false);
1156 /* Notify the wps that the track change starts now */
1157 codec_track_changed();
1160 static void codec_track_skip_done(bool was_manual
)
1162 /* Manual track change (always crossfade or flush audio). */
1165 pcmbuf_crossfade_init(true);
1166 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1167 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1169 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1170 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1171 && global_settings
.crossfade
!= CROSSFADE_ENABLE_TRACKSKIP
)
1173 if (global_settings
.crossfade
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1175 if (global_settings
.playlist_shuffle
)
1176 /* shuffle mode is on, so crossfade: */
1177 codec_crossfade_track_change();
1179 /* shuffle mode is off, so do a gapless track change */
1180 codec_gapless_track_change();
1183 /* normal crossfade: */
1184 codec_crossfade_track_change();
1187 /* normal gapless playback. */
1188 codec_gapless_track_change();
1191 static bool codec_load_next_track(void)
1193 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1195 prev_track_elapsed
= curtrack_id3
.elapsed
;
1197 #ifdef AB_REPEAT_ENABLE
1198 ab_end_of_track_report();
1201 logf("Request new track");
1203 if (ci
.new_track
== 0)
1206 automatic_skip
= true;
1211 trigger_cpu_boost();
1212 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1213 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1218 case Q_CODEC_REQUEST_COMPLETE
:
1219 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1220 codec_track_skip_done(!automatic_skip
);
1223 case Q_CODEC_REQUEST_FAILED
:
1224 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1226 ci
.stop_codec
= true;
1230 LOGFQUEUE("codec |< default");
1231 ci
.stop_codec
= true;
1236 static bool codec_request_next_track_callback(void)
1240 if (ci
.stop_codec
|| !playing
)
1243 prev_codectype
= get_codec_base_type(curtrack_id3
.codectype
);
1245 if (!codec_load_next_track())
1248 /* Check if the next codec is the same file. */
1249 if (prev_codectype
== get_codec_base_type(curtrack_id3
.codectype
))
1251 logf("New track loaded");
1252 codec_discard_codec_callback();
1257 logf("New codec:%d/%d", curtrack_id3
.codectype
, prev_codectype
);
1262 static void codec_thread(void)
1264 struct queue_event ev
;
1270 queue_wait(&codec_queue
, &ev
);
1273 case Q_CODEC_LOAD_DISK
:
1274 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1275 queue_reply(&codec_queue
, 1);
1276 audio_codec_loaded
= true;
1277 ci
.stop_codec
= false;
1278 status
= codec_load_file((const char *)ev
.data
, &ci
);
1282 LOGFQUEUE("codec < Q_CODEC_LOAD");
1283 if (CUR_TI
->codec_hid
< 0) {
1284 logf("Codec slot is empty!");
1285 /* Wait for the pcm buffer to go empty */
1286 while (pcm_is_playing())
1288 /* This must be set to prevent an infinite loop */
1289 ci
.stop_codec
= true;
1290 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1291 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
1295 audio_codec_loaded
= true;
1296 ci
.stop_codec
= false;
1297 status
= codec_load_buf(CUR_TI
->codec_hid
, &ci
);
1300 #ifdef AUDIO_HAVE_RECORDING
1301 case Q_ENCODER_LOAD_DISK
:
1302 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1303 audio_codec_loaded
= false; /* Not audio codec! */
1304 logf("loading encoder");
1305 ci
.stop_encoder
= false;
1306 status
= codec_load_file((const char *)ev
.data
, &ci
);
1307 logf("encoder stopped");
1309 #endif /* AUDIO_HAVE_RECORDING */
1312 LOGFQUEUE("codec < default");
1315 if (audio_codec_loaded
)
1324 audio_codec_loaded
= false;
1328 case Q_CODEC_LOAD_DISK
:
1330 LOGFQUEUE("codec < Q_CODEC_LOAD");
1333 if (ci
.new_track
|| status
!= CODEC_OK
)
1337 logf("Codec failure");
1338 gui_syncsplash(HZ
*2, "Codec failure");
1341 if (!codec_load_next_track())
1343 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1344 /* End of playlist */
1345 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1351 logf("Codec finished");
1354 /* Wait for the audio to stop playing before
1355 * triggering the WPS exit */
1356 while(pcm_is_playing())
1358 curtrack_id3
.elapsed
=
1359 curtrack_id3
.length
- pcmbuf_get_latency();
1362 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1363 /* End of playlist */
1364 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1369 if (CUR_TI
->codec_hid
>= 0)
1371 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1372 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
1376 const char *codec_fn
=
1377 get_codec_filename(curtrack_id3
.codectype
);
1380 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1381 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
1382 (intptr_t)codec_fn
);
1388 #ifdef AUDIO_HAVE_RECORDING
1389 case Q_ENCODER_LOAD_DISK
:
1390 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1392 if (status
== CODEC_OK
)
1395 logf("Encoder failure");
1396 gui_syncsplash(HZ
*2, "Encoder failure");
1398 if (ci
.enc_codec_loaded
< 0)
1401 logf("Encoder failed to load");
1402 ci
.enc_codec_loaded
= -1;
1404 #endif /* AUDIO_HAVE_RECORDING */
1407 LOGFQUEUE("codec < default");
1414 /* --- Audio thread --- */
1416 static bool audio_have_tracks(void)
1418 return (audio_track_count() != 0);
1421 static int audio_free_track_count(void)
1423 /* Used tracks + free tracks adds up to MAX_TRACK - 1 */
1424 return MAX_TRACK
- 1 - audio_track_count();
1427 int audio_track_count(void)
1429 /* Calculate difference from track_ridx to track_widx
1430 * taking into account a possible wrap-around. */
1431 return (MAX_TRACK
+ track_widx
- track_ridx
) & MAX_TRACK_MASK
;
1434 long audio_filebufused(void)
1436 return (long) buf_used();
1439 /* Update track info after successful a codec track change */
1440 static void audio_update_trackinfo(void)
1442 /* Load the curent track's metadata into curtrack_id3 */
1443 CUR_TI
->taginfo_ready
= (CUR_TI
->id3_hid
>= 0);
1444 if (CUR_TI
->id3_hid
>= 0)
1445 copy_mp3entry(&curtrack_id3
, bufgetid3(CUR_TI
->id3_hid
));
1447 int next_idx
= (track_ridx
+ 1) & MAX_TRACK_MASK
;
1448 tracks
[next_idx
].taginfo_ready
= (tracks
[next_idx
].id3_hid
>= 0);
1450 /* Reset current position */
1451 curtrack_id3
.elapsed
= 0;
1452 curtrack_id3
.offset
= 0;
1454 /* Update the codec API */
1455 ci
.filesize
= CUR_TI
->filesize
;
1456 ci
.id3
= &curtrack_id3
;
1458 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
1461 static void buffering_audio_callback(enum callback_event ev
, int value
)
1464 logf("buffering_audio_callback");
1468 case EVENT_BUFFER_LOW
:
1469 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1470 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1473 case EVENT_HANDLE_REBUFFER
:
1474 LOGFQUEUE("audio >| audio Q_AUDIO_FLUSH");
1475 queue_send(&audio_queue
, Q_AUDIO_FLUSH
, 0);
1478 case EVENT_HANDLE_FINISHED
:
1487 /* Clear tracks between write and read, non inclusive */
1488 static void audio_clear_track_entries(bool clear_unbuffered
)
1490 int cur_idx
= track_widx
;
1492 logf("Clearing tracks:%d/%d, %d", track_ridx
, track_widx
, clear_unbuffered
);
1494 /* Loop over all tracks from write-to-read */
1497 cur_idx
= (cur_idx
+ 1) & MAX_TRACK_MASK
;
1499 if (cur_idx
== track_ridx
)
1502 /* If the track is buffered, conditionally clear/notify,
1503 * otherwise clear the track if that option is selected */
1504 if (tracks
[cur_idx
].event_sent
|| clear_unbuffered
)
1505 clear_track_info(&tracks
[cur_idx
]);
1509 /* Clear all tracks */
1510 static bool audio_release_tracks(void)
1514 logf("releasing all tracks");
1516 for(i
= 0; i
< MAX_TRACK
; i
++)
1518 cur_idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
1519 if (!clear_track_info(&tracks
[cur_idx
]))
1526 static bool audio_loadcodec(bool start_play
)
1529 char codec_path
[MAX_PATH
]; /* Full path to codec */
1531 if (tracks
[track_widx
].id3_hid
< 0) {
1535 const char * codec_fn
=
1536 get_codec_filename(bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
);
1537 if (codec_fn
== NULL
)
1540 tracks
[track_widx
].codec_hid
= -1;
1544 /* Load the codec directly from disk and save some memory. */
1545 track_ridx
= track_widx
;
1546 ci
.filesize
= CUR_TI
->filesize
;
1547 ci
.id3
= &curtrack_id3
;
1548 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
1550 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1551 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
1556 /* If we already have another track than this one buffered */
1557 if (track_widx
!= track_ridx
)
1559 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
1561 /* If the previous codec is the same as this one, there is no need
1562 * to put another copy of it on the file buffer */
1563 if (get_codec_base_type(
1564 bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
) ==
1565 get_codec_base_type(
1566 bufgetid3(tracks
[prev_track
].id3_hid
)->codectype
)
1567 && audio_codec_loaded
)
1569 logf("Reusing prev. codec");
1575 codec_get_full_path(codec_path
, codec_fn
);
1577 tracks
[track_widx
].codec_hid
= bufopen(codec_path
, 0, TYPE_CODEC
);
1578 if (tracks
[track_widx
].codec_hid
< 0)
1581 logf("Loaded codec");
1586 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
1587 static void audio_set_elapsed(struct mp3entry
* id3
)
1589 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
1590 id3
->offset
- id3
->first_frame_offset
: 0;
1593 if ( id3
->has_toc
) {
1594 /* calculate elapsed time using TOC */
1596 unsigned int remainder
, plen
, relpos
, nextpos
;
1598 /* find wich percent we're at */
1599 for (i
=0; i
<100; i
++ )
1600 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
1607 relpos
= id3
->toc
[i
];
1610 nextpos
= id3
->toc
[i
+1];
1614 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
1616 /* set time for this percent (divide before multiply to prevent
1617 overflow on long files. loss of precision is negligible on
1619 id3
->elapsed
= i
* (id3
->length
/ 100);
1621 /* calculate remainder time */
1622 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
1623 id3
->elapsed
+= (((remainder
* 100) / plen
) *
1624 (id3
->length
/ 10000));
1627 /* no TOC exists. set a rough estimate using average bitrate */
1628 int tpk
= id3
->length
/
1629 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
1631 id3
->elapsed
= offset
/ 1024 * tpk
;
1636 /* constant bitrate, use exact calculation */
1637 if (id3
->bitrate
!= 0)
1638 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
1642 /* Load one track by making the appropriate bufopen calls. Return true if
1643 everything required was loaded correctly, false if not. */
1644 static bool audio_load_track(int offset
, bool start_play
)
1649 int file_offset
= 0;
1650 struct mp3entry id3
;
1652 /* Stop buffer filling if there is no free track entries.
1653 Don't fill up the last track entry (we wan't to store next track
1655 if (!audio_free_track_count())
1657 logf("No free tracks");
1663 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
1664 /* Get track name from current playlist read position. */
1665 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
1667 /* Handle broken playlists. */
1668 fd
= open(trackname
, O_RDONLY
);
1671 logf("Open failed");
1672 /* Skip invalid entry from playlist. */
1673 playlist_skip_entry(NULL
, last_peek_offset
);
1681 logf("End-of-playlist");
1682 playlist_end
= true;
1683 memset(&lasttrack_id3
, 0, sizeof(struct mp3entry
));
1687 tracks
[track_widx
].filesize
= filesize(fd
);
1689 if ((unsigned)offset
> tracks
[track_widx
].filesize
)
1692 /* Set default values */
1695 buf_set_watermark(AUDIO_DEFAULT_WATERMARK
);
1696 dsp_configure(ci
.dsp
, DSP_RESET
, 0);
1697 track_changed
= true;
1698 playlist_update_resume_info(audio_current_track());
1701 /* Get track metadata if we don't already have it. */
1702 if (tracks
[track_widx
].id3_hid
< 0)
1704 if (get_metadata(&id3
, fd
, trackname
))
1706 if (track_buffer_callback
)
1707 track_buffer_callback(&id3
);
1709 tracks
[track_widx
].id3_hid
=
1710 bufalloc(&id3
, sizeof(struct mp3entry
), TYPE_ID3
);
1711 tracks
[track_widx
].taginfo_ready
= (tracks
[track_widx
].id3_hid
>= 0);
1713 if (tracks
[track_widx
].id3_hid
< 0)
1717 copy_mp3entry(&lasttrack_id3
, &id3
);
1721 if (track_widx
== track_ridx
)
1722 copy_mp3entry(&curtrack_id3
, &id3
);
1726 track_changed
= true;
1727 playlist_update_resume_info(audio_current_track());
1732 logf("mde:%s!",trackname
);
1734 /* Skip invalid entry from playlist. */
1735 playlist_skip_entry(NULL
, last_peek_offset
);
1736 tracks
[track_widx
].taginfo_ready
= false;
1746 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
1748 char cuepath
[MAX_PATH
];
1750 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
1752 if (look_for_cuesheet_file(trackname
, cuepath
) &&
1753 parse_cuesheet(cuepath
, cue
))
1755 strcpy((cue
)->audio_filename
, trackname
);
1757 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
1762 struct mp3entry
*track_id3
;
1764 if (track_widx
== track_ridx
)
1765 track_id3
= &curtrack_id3
;
1767 track_id3
= bufgetid3(tracks
[track_widx
].id3_hid
);
1769 #ifdef HAVE_ALBUMART
1770 if (tracks
[track_widx
].aa_hid
< 0 && gui_sync_wps_uses_albumart())
1772 char aa_path
[MAX_PATH
];
1773 if (find_albumart(track_id3
, aa_path
, sizeof(aa_path
)))
1774 tracks
[track_widx
].aa_hid
= bufopen(aa_path
, 0, TYPE_BITMAP
);
1778 /* Load the codec. */
1779 if (!audio_loadcodec(start_play
))
1781 if (tracks
[track_widx
].codec_hid
== ERR_BUFFER_FULL
)
1783 /* No space for codec on buffer, not an error */
1787 /* This is an error condition, either no codec was found, or reading
1788 * the codec file failed part way through, either way, skip the track */
1789 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
1790 /* We should not use gui_syncplash from audio thread! */
1791 gui_syncsplash(HZ
*2, msgbuf
);
1792 /* Skip invalid entry from playlist. */
1793 playlist_skip_entry(NULL
, last_peek_offset
);
1794 tracks
[track_widx
].taginfo_ready
= false;
1798 track_id3
->elapsed
= 0;
1800 enum data_type type
= TYPE_PACKET_AUDIO
;
1802 switch (track_id3
->codectype
) {
1807 file_offset
= offset
;
1808 track_id3
->offset
= offset
;
1809 audio_set_elapsed(track_id3
);
1815 file_offset
= offset
;
1816 track_id3
->offset
= offset
;
1817 track_id3
->elapsed
= track_id3
->length
/ 2;
1821 case AFMT_OGG_VORBIS
:
1830 track_id3
->offset
= offset
;
1836 logf("Loading atomic %d",track_id3
->codectype
);
1837 type
= TYPE_ATOMIC_AUDIO
;
1841 logf("alt:%s", trackname
);
1843 if (file_offset
> AUDIO_REBUFFER_GUESS_SIZE
)
1844 file_offset
-= AUDIO_REBUFFER_GUESS_SIZE
;
1845 else if (track_id3
->first_frame_offset
)
1846 file_offset
= track_id3
->first_frame_offset
;
1850 tracks
[track_widx
].audio_hid
= bufopen(trackname
, file_offset
, type
);
1852 if (tracks
[track_widx
].audio_hid
< 0)
1857 ci
.curpos
=file_offset
;
1858 buf_request_buffer_handle(tracks
[track_widx
].audio_hid
);
1861 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
1866 /* Send callback events to notify about new tracks. */
1867 static void audio_generate_postbuffer_events(void)
1871 logf("Postbuffer:%d/%d",track_ridx
,track_widx
);
1873 if (audio_have_tracks())
1875 cur_idx
= track_ridx
;
1878 if (!tracks
[cur_idx
].event_sent
)
1880 /* Mark the event 'sent' even if we don't really send one */
1881 tracks
[cur_idx
].event_sent
= true;
1883 if (cur_idx
== track_widx
)
1885 cur_idx
= (cur_idx
+ 1) & MAX_TRACK_MASK
;
1890 static void audio_fill_file_buffer(bool start_play
, size_t offset
)
1892 struct queue_event ev
;
1893 bool had_next_track
= audio_next_track() != NULL
;
1894 bool continue_buffering
;
1896 /* Must reset the buffer before use if trashed or voice only - voice
1897 file size shouldn't have changed so we can go straight from
1898 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
1899 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
1900 audio_reset_buffer();
1902 logf("Starting buffer fill");
1905 audio_clear_track_entries(false);
1907 /* Save the current resume position once. */
1908 playlist_update_resume_info(audio_current_track());
1911 continue_buffering
= audio_load_track(offset
, start_play
);
1915 if (queue_peek(&audio_queue
, &ev
)) {
1916 if (ev
.id
!= Q_AUDIO_FILL_BUFFER
)
1918 /* There's a message in the queue. break the loop to treat it,
1919 and go back to filling after that. */
1920 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1921 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1925 } while (continue_buffering
);
1927 if (!had_next_track
&& audio_next_track())
1928 track_changed
= true;
1930 audio_generate_postbuffer_events();
1933 static void audio_rebuffer(void)
1935 logf("Forcing rebuffer");
1937 clear_track_info(CUR_TI
);
1939 /* Reset track pointers */
1940 track_widx
= track_ridx
;
1941 audio_clear_track_entries(true);
1943 /* Fill the buffer */
1944 last_peek_offset
= -1;
1947 if (!CUR_TI
->taginfo_ready
)
1948 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
1950 audio_fill_file_buffer(false, 0);
1953 /* Called on request from the codec to get a new track. This is the codec part
1954 of the track transition. */
1955 static int audio_check_new_track(void)
1957 int track_count
= audio_track_count();
1958 int old_track_ridx
= track_ridx
;
1960 int next_playlist_index
;
1962 bool end_of_playlist
; /* Temporary flag, not the same as playlist_end */
1967 if (playlist_next_dir(ci
.new_track
))
1975 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1976 return Q_CODEC_REQUEST_FAILED
;
1983 end_of_playlist
= playlist_peek(ci
.new_track
) == NULL
;
1984 auto_dir_skip
= end_of_playlist
&& global_settings
.next_folder
;
1986 /* If the playlist isn't that big */
1987 if (!playlist_check(ci
.new_track
))
1989 if (ci
.new_track
>= 0)
1991 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1992 return Q_CODEC_REQUEST_FAILED
;
1994 /* Find the beginning backward if the user over-skips it */
1995 while (!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
;
2002 /* Update the playlist */
2003 last_peek_offset
-= ci
.new_track
;
2005 if (auto_dir_skip
|| !automatic_skip
)
2007 /* If the track change was manual or the result of an auto dir skip,
2008 we need to update the playlist now */
2009 next_playlist_index
= playlist_next(ci
.new_track
);
2011 if (next_playlist_index
< 0)
2013 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2014 return Q_CODEC_REQUEST_FAILED
;
2021 new_playlist
= false;
2024 /* Save the track metadata to allow the WPS to display it
2025 while PCM finishes playing that track */
2026 copy_mp3entry(&prevtrack_id3
, &curtrack_id3
);
2028 /* Update the main buffer copy of the track metadata with the one
2029 the codec has been using (for the unbuffer callbacks) */
2030 if (CUR_TI
->id3_hid
>= 0)
2031 copy_mp3entry(bufgetid3(CUR_TI
->id3_hid
), &curtrack_id3
);
2033 /* Save a pointer to the old track to allow later clearing */
2036 for (i
= 0; i
< ci
.new_track
; i
++)
2038 idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
2039 struct mp3entry
*id3
= bufgetid3(tracks
[idx
].id3_hid
);
2040 ssize_t offset
= buf_handle_offset(tracks
[idx
].audio_hid
);
2041 if (!id3
|| offset
< 0 || (unsigned)offset
> id3
->first_frame_offset
)
2043 /* We don't have all the audio data for that track, so clear it,
2044 but keep the metadata. */
2045 if (tracks
[idx
].audio_hid
>= 0 && bufclose(tracks
[idx
].audio_hid
))
2047 tracks
[idx
].audio_hid
= -1;
2048 tracks
[idx
].filesize
= 0;
2053 /* Move to the new track */
2054 track_ridx
= (track_ridx
+ ci
.new_track
) & MAX_TRACK_MASK
;
2056 buf_set_base_handle(CUR_TI
->audio_hid
);
2060 playlist_end
= false;
2061 wps_offset
= -ci
.new_track
;
2064 track_changed
= true;
2066 /* If it is not safe to even skip this many track entries */
2067 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
2074 forward
= ci
.new_track
> 0;
2077 /* If the target track is clearly not in memory */
2078 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
2084 /* When skipping backwards, it is possible that we've found a track that's
2085 * buffered, but which is around the track-wrap and therefor not the track
2086 * we are looking for */
2089 int cur_idx
= track_ridx
;
2090 bool taginfo_ready
= true;
2091 /* We've wrapped the buffer backwards if new > old */
2092 bool wrap
= track_ridx
> old_track_ridx
;
2096 cur_idx
= (cur_idx
+ 1) & MAX_TRACK_MASK
;
2098 /* if we've advanced past the wrap when cur_idx is zeroed */
2102 /* if we aren't still on the wrap and we've caught the old track */
2103 if (!(wrap
|| cur_idx
< old_track_ridx
))
2106 /* If we hit a track in between without valid tag info, bail */
2107 if (!tracks
[cur_idx
].taginfo_ready
)
2109 taginfo_ready
= false;
2120 audio_update_trackinfo();
2121 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2122 return Q_CODEC_REQUEST_COMPLETE
;
2125 void audio_set_track_buffer_event(void (*handler
)(struct mp3entry
*id3
))
2127 track_buffer_callback
= handler
;
2130 void audio_set_track_unbuffer_event(void (*handler
)(struct mp3entry
*id3
))
2132 track_unbuffer_callback
= handler
;
2135 void audio_set_track_changed_event(void (*handler
)(struct mp3entry
*id3
))
2137 track_changed_callback
= handler
;
2140 unsigned long audio_prev_elapsed(void)
2142 return prev_track_elapsed
;
2145 static void audio_stop_codec_flush(void)
2147 ci
.stop_codec
= true;
2150 while (audio_codec_loaded
)
2153 /* If the audio codec is not loaded any more, and the audio is still
2154 * playing, it is now and _only_ now safe to call this function from the
2156 if (pcm_is_playing())
2158 pcmbuf_pause(paused
);
2161 static void audio_stop_playback(void)
2163 /* If we were playing, save resume information */
2166 struct mp3entry
*id3
= NULL
;
2168 if (!playlist_end
|| !ci
.stop_codec
)
2170 /* Set this early, the outside code yields and may allow the codec
2171 to try to wait for a reply on a buffer wait */
2172 ci
.stop_codec
= true;
2173 id3
= audio_current_track();
2176 /* Save the current playing spot, or NULL if the playlist has ended */
2177 playlist_update_resume_info(id3
);
2179 prev_track_elapsed
= curtrack_id3
.elapsed
;
2181 /* At end of playlist save current id3 (id3.elapsed!) to buffer and
2182 * Increment index so runtime info is saved in audio_clear_track_entries().
2184 if ((playlist_end
) && (tracks
[track_ridx
].id3_hid
>= 0)) {
2185 copy_mp3entry(bufgetid3(tracks
[track_ridx
].id3_hid
), &curtrack_id3
);
2186 track_ridx
= (track_ridx
+ 1) & 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 unregister_buffering_callback(buffering_audio_callback
);
2202 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
2205 static void audio_play_start(size_t offset
)
2209 #if INPUT_SRC_CAPS != 0
2210 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
2211 audio_set_output_source(AUDIO_SRC_PLAYBACK
);
2214 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2216 audio_stop_codec_flush();
2218 track_changed
= true;
2219 playlist_end
= false;
2227 sound_set_volume(global_settings
.volume
);
2228 track_widx
= track_ridx
= 0;
2230 /* Clear all track entries. */
2231 for (i
= 0; i
< MAX_TRACK
; i
++) {
2232 clear_track_info(&tracks
[i
]);
2235 last_peek_offset
= -1;
2237 /* Officially playing */
2238 queue_reply(&audio_queue
, 1);
2240 #ifndef HAVE_FLASH_STORAGE
2241 set_filebuf_watermark(buffer_margin
, 0);
2243 audio_fill_file_buffer(true, offset
);
2244 register_buffering_callback(buffering_audio_callback
);
2246 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2247 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
2251 /* Invalidates all but currently playing track. */
2252 static void audio_invalidate_tracks(void)
2254 if (audio_have_tracks())
2256 last_peek_offset
= 0;
2257 playlist_end
= false;
2258 track_widx
= track_ridx
;
2260 /* Mark all other entries null (also buffered wrong metadata). */
2261 audio_clear_track_entries(true);
2263 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
2265 audio_fill_file_buffer(false, 0);
2269 static void audio_new_playlist(void)
2271 /* Prepare to start a new fill from the beginning of the playlist */
2272 last_peek_offset
= -1;
2273 if (audio_have_tracks())
2276 skipped_during_pause
= true;
2277 playlist_end
= false;
2278 track_widx
= track_ridx
;
2279 audio_clear_track_entries(true);
2281 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
2283 /* Mark the current track as invalid to prevent skipping back to it */
2284 CUR_TI
->taginfo_ready
= false;
2287 /* Signal the codec to initiate a track change forward */
2288 new_playlist
= true;
2291 /* Officially playing */
2292 queue_reply(&audio_queue
, 1);
2294 audio_fill_file_buffer(false, 0);
2297 static void audio_initiate_track_change(long direction
)
2299 playlist_end
= false;
2300 ci
.new_track
+= direction
;
2301 wps_offset
-= direction
;
2303 skipped_during_pause
= true;
2306 static void audio_initiate_dir_change(long direction
)
2308 playlist_end
= false;
2310 ci
.new_track
= direction
;
2312 skipped_during_pause
= true;
2315 /* Called when PCM track change is complete */
2316 static void audio_finalise_track_change(void)
2318 logf("audio_finalise_track_change");
2323 playlist_next(-wps_offset
);
2326 automatic_skip
= false;
2329 auto_dir_skip
= false;
2331 /* Invalidate prevtrack_id3 */
2332 prevtrack_id3
.path
[0] = 0;
2334 if (prev_ti
&& prev_ti
->audio_hid
< 0)
2336 /* No audio left so we clear all the track info. */
2337 clear_track_info(prev_ti
);
2340 if (prev_ti
&& prev_ti
->id3_hid
>= 0)
2342 /* Reset the elapsed time to force the progressbar to be empty if
2343 the user skips back to this track */
2344 bufgetid3(prev_ti
->id3_hid
)->elapsed
= 0;
2347 if (track_changed_callback
)
2348 track_changed_callback(&curtrack_id3
);
2350 track_changed
= true;
2351 playlist_update_resume_info(audio_current_track());
2355 * Layout audio buffer as follows - iram buffer depends on target:
2356 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
2358 static void audio_reset_buffer(void)
2360 /* see audio_get_recording_buffer if this is modified */
2361 logf("audio_reset_buffer");
2363 /* If the setup of anything allocated before the file buffer is
2364 changed, do check the adjustments after the buffer_alloc call
2365 as it will likely be affected and need sliding over */
2367 /* Initially set up file buffer as all space available */
2368 malloc_buf
= audiobuf
+ talk_get_bufsize();
2369 /* Align the malloc buf to line size. Especially important to cf
2370 targets that do line reads/writes. */
2371 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
2372 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
2373 filebuflen
= audiobufend
- filebuf
;
2377 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
2378 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
2380 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
2381 will already be line aligned */
2384 buffering_reset(filebuf
, filebuflen
);
2386 /* Clear any references to the file buffer */
2387 buffer_state
= BUFFER_STATE_INITIALIZED
;
2389 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
2390 /* Make sure everything adds up - yes, some info is a bit redundant but
2391 aids viewing and the sumation of certain variables should add up to
2392 the location of others. */
2395 unsigned char * pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
2396 logf("mabuf: %08X", (unsigned)malloc_buf
);
2397 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
2398 logf("fbuf: %08X", (unsigned)filebuf
);
2399 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
2400 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
2401 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
2402 logf("pcmb: %08X", (unsigned)pcmbuf
);
2403 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
2408 static void audio_thread(void)
2410 struct queue_event ev
;
2414 audio_thread_ready
= true;
2419 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
2422 case Q_AUDIO_FILL_BUFFER
:
2423 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
2424 if (!playing
|| playlist_end
|| ci
.stop_codec
)
2426 audio_fill_file_buffer(false, 0);
2430 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2431 if (playing
&& ev
.data
<= 0)
2432 audio_new_playlist();
2435 audio_stop_playback();
2436 audio_play_start((size_t)ev
.data
);
2441 LOGFQUEUE("audio < Q_AUDIO_STOP");
2443 audio_stop_playback();
2445 queue_clear(&audio_queue
);
2449 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
2450 if (!(bool) ev
.data
&& skipped_during_pause
&& !pcmbuf_is_crossfade_active())
2451 pcmbuf_play_stop(); /* Flush old track on resume after skip */
2452 skipped_during_pause
= false;
2455 pcmbuf_pause((bool)ev
.data
);
2456 paused
= (bool)ev
.data
;
2460 LOGFQUEUE("audio < Q_AUDIO_SKIP");
2461 audio_initiate_track_change((long)ev
.data
);
2464 case Q_AUDIO_PRE_FF_REWIND
:
2465 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
2471 case Q_AUDIO_FF_REWIND
:
2472 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
2477 /* An automatic track skip is in progress. Finalize it,
2478 then go back to the previous track */
2479 audio_finalise_track_change();
2482 ci
.seek_time
= (long)ev
.data
+1;
2485 case Q_AUDIO_CHECK_NEW_TRACK
:
2486 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
2487 queue_reply(&audio_queue
, audio_check_new_track());
2490 case Q_AUDIO_DIR_SKIP
:
2491 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2492 playlist_end
= false;
2493 audio_initiate_dir_change(ev
.data
);
2497 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
2498 audio_invalidate_tracks();
2501 case Q_AUDIO_TRACK_CHANGED
:
2502 /* PCM track change done */
2503 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2504 audio_finalise_track_change();
2508 case SYS_USB_CONNECTED
:
2509 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2511 audio_stop_playback();
2512 #ifdef PLAYBACK_VOICE
2515 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
2516 usb_wait_for_disconnect(&audio_queue
);
2518 /* Mark all entries null. */
2519 audio_clear_track_entries(false);
2521 /* release tracks to make sure all handles are closed */
2522 audio_release_tracks();
2527 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
2531 LOGFQUEUE("audio < default");
2537 #ifdef ROCKBOX_HAS_LOGF
2538 static void audio_test_track_changed_event(struct mp3entry
*id3
)
2542 logf("tce:%s", id3
->path
);
2546 /* Initialize the audio system - called from init() in main.c.
2547 * Last function because of all the references to internal symbols
2549 void audio_init(void)
2551 struct thread_entry
*audio_thread_p
;
2553 /* Can never do this twice */
2554 if (audio_is_initialized
)
2556 logf("audio: already initialized");
2560 logf("audio: initializing");
2562 /* Initialize queues before giving control elsewhere in case it likes
2563 to send messages. Thread creation will be delayed however so nothing
2564 starts running until ready if something yields such as talk_init. */
2565 queue_init(&audio_queue
, true);
2566 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
2567 queue_init(&codec_queue
, false);
2568 queue_enable_queue_send(&codec_queue
, &codec_queue_sender_list
);
2572 #ifdef ROCKBOX_HAS_LOGF
2573 audio_set_track_changed_event(audio_test_track_changed_event
);
2576 /* Initialize codec api. */
2577 ci
.read_filebuf
= codec_filebuf_callback
;
2578 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
2579 ci
.get_codec_memory
= codec_get_memory_callback
;
2580 ci
.request_buffer
= codec_request_buffer_callback
;
2581 ci
.advance_buffer
= codec_advance_buffer_callback
;
2582 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
2583 ci
.request_next_track
= codec_request_next_track_callback
;
2584 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
2585 ci
.seek_buffer
= codec_seek_buffer_callback
;
2586 ci
.seek_complete
= codec_seek_complete_callback
;
2587 ci
.set_elapsed
= codec_set_elapsed_callback
;
2588 ci
.set_offset
= codec_set_offset_callback
;
2589 ci
.configure
= codec_configure_callback
;
2590 ci
.discard_codec
= codec_discard_codec_callback
;
2591 ci
.dsp
= (struct dsp_config
*)dsp_configure(NULL
, DSP_MYDSP
,
2594 /* initialize the buffer */
2597 /* audio_reset_buffer must to know the size of voice buffer so init
2601 codec_thread_p
= create_thread(
2602 codec_thread
, codec_stack
, sizeof(codec_stack
),
2603 CREATE_THREAD_FROZEN
,
2604 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
2607 audio_thread_p
= create_thread(audio_thread
, audio_stack
,
2608 sizeof(audio_stack
), CREATE_THREAD_FROZEN
,
2609 audio_thread_name
IF_PRIO(, PRIORITY_SYSTEM
)
2612 #ifdef PLAYBACK_VOICE
2613 voice_thread_init();
2616 /* Set crossfade setting for next buffer init which should be about... */
2617 pcmbuf_crossfade_enable(global_settings
.crossfade
);
2619 /* initialize the buffering system */
2622 /* ...now! Set up the buffers */
2623 audio_reset_buffer();
2626 for(i
= 0; i
< MAX_TRACK
; i
++)
2628 tracks
[i
].audio_hid
= -1;
2629 tracks
[i
].id3_hid
= -1;
2630 tracks
[i
].codec_hid
= -1;
2631 #ifdef HAVE_ALBUMART
2632 tracks
[i
].aa_hid
= -1;
2636 /* Probably safe to say */
2637 audio_is_initialized
= true;
2639 sound_settings_apply();
2640 #ifndef HAVE_FLASH_STORAGE
2641 audio_set_buffer_margin(global_settings
.buffer_margin
);
2644 /* it's safe to let the threads run now */
2645 #ifdef PLAYBACK_VOICE
2646 voice_thread_resume();
2648 thread_thaw(codec_thread_p
);
2649 thread_thaw(audio_thread_p
);
2653 void audio_wait_for_init(void)
2655 /* audio thread will only set this once after it finished the final
2656 * audio hardware init so this little construct is safe - even
2658 while (!audio_thread_ready
)