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 */
215 static struct track_info tracks
[MAX_TRACK
];
216 static volatile int track_ridx
= 0; /* Track being decoded (A/C-) */
217 static int track_widx
= 0; /* Track being buffered (A) */
219 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
220 static struct track_info
*prev_ti
= NULL
; /* Pointer to the previously played
223 /* Set by the audio thread when the current track information has updated
224 * and the WPS may need to update its cached information */
225 static bool track_changed
= false;
227 /* Information used only for filling the buffer */
228 /* Playlist steps from playing track to next track to be buffered (A) */
229 static int last_peek_offset
= 0;
231 /* Scrobbler support */
232 static unsigned long prev_track_elapsed
= 0; /* Previous track elapsed time (C/A-)*/
234 /* Track change controls */
235 static bool automatic_skip
= false; /* Who initiated in-progress skip? (C/A-) */
236 static bool playlist_end
= false; /* Has the current playlist ended? (A) */
237 static bool auto_dir_skip
= false; /* Have we changed dirs automatically? */
238 static bool dir_skip
= false; /* Is a directory skip pending? (A) */
239 static bool new_playlist
= false; /* Are we starting a new playlist? (A) */
240 static int wps_offset
= 0; /* Pending track change offset, to keep WPS responsive (A) */
241 static bool skipped_during_pause
= false; /* Do we need to clear the PCM buffer when playback resumes (A) */
243 /* Set to true if the codec thread should send an audio stop request
244 * (typically because the end of the playlist has been reached).
246 static bool codec_requested_stop
= false;
248 static size_t buffer_margin
= 0; /* Buffer margin aka anti-skip buffer (A/C-) */
250 /* Multiple threads */
251 /* Set the watermark to trigger buffer fill (A/C) FIXME */
252 static void set_filebuf_watermark(int seconds
, size_t max
);
255 static struct event_queue audio_queue NOCACHEBSS_ATTR
;
256 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR
;
257 static long audio_stack
[(DEFAULT_STACK_SIZE
+ 0x1000)/sizeof(long)];
258 static const char audio_thread_name
[] = "audio";
260 static void audio_thread(void);
261 static void audio_initiate_track_change(long direction
);
262 static bool audio_have_tracks(void);
263 static void audio_reset_buffer(void);
266 extern struct codec_api ci
;
267 static struct event_queue codec_queue NOCACHEBSS_ATTR
;
268 static struct queue_sender_list codec_queue_sender_list
;
269 static long codec_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
271 static const char codec_thread_name
[] = "codec";
272 struct thread_entry
*codec_thread_p
; /* For modifying thread priority later. */
274 /* PCM buffer messaging */
275 static struct event_queue pcmbuf_queue NOCACHEBSS_ATTR
;
277 /* Function to be called by pcm buffer callbacks.
278 * Permissible Context(s): Audio interrupt
280 static void pcmbuf_callback_queue_post(long id
, intptr_t data
)
282 /* No lock since we're already in audio interrupt context */
283 queue_post(&pcmbuf_queue
, id
, data
);
286 /* Scan the pcmbuf queue and return true if a message pulled.
287 * Permissible Context(s): Thread
289 static bool pcmbuf_queue_scan(struct queue_event
*ev
)
291 if (!queue_empty(&pcmbuf_queue
))
293 /* Transfer message to audio queue */
295 /* Pull message - never, ever any blocking call! */
296 queue_wait_w_tmo(&pcmbuf_queue
, ev
, 0);
304 /* Clear the pcmbuf queue of messages
305 * Permissible Context(s): Thread
307 static void pcmbuf_queue_clear(void)
310 queue_clear(&pcmbuf_queue
);
314 /* --- Helper functions --- */
316 static struct mp3entry
*bufgetid3(int handle_id
)
321 struct mp3entry
*id3
;
322 ssize_t ret
= bufgetdata(handle_id
, 0, (void *)&id3
);
324 if (ret
< 0 || ret
!= sizeof(struct mp3entry
))
330 static bool clear_track_info(struct track_info
*track
)
332 /* bufclose returns true if the handle is not found, or if it is closed
333 * successfully, so these checks are safe on non-existant handles */
337 if (track
->codec_hid
>= 0) {
338 if (bufclose(track
->codec_hid
))
339 track
->codec_hid
= -1;
344 if (track
->id3_hid
>= 0) {
345 if (bufclose(track
->id3_hid
))
351 if (track
->audio_hid
>= 0) {
352 if (bufclose(track
->audio_hid
))
353 track
->audio_hid
= -1;
359 if (track
->aa_hid
>= 0) {
360 if (bufclose(track
->aa_hid
))
368 track
->taginfo_ready
= false;
373 /* --- External interfaces --- */
375 /* This sends a stop message and the audio thread will dump all it's
376 subsequenct messages */
377 void audio_hard_stop(void)
380 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
381 queue_send(&audio_queue
, Q_AUDIO_STOP
, 1);
382 #ifdef PLAYBACK_VOICE
387 bool audio_restore_playback(int type
)
391 case AUDIO_WANT_PLAYBACK
:
392 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
393 audio_reset_buffer();
395 case AUDIO_WANT_VOICE
:
396 if (buffer_state
== BUFFER_STATE_TRASHED
)
397 audio_reset_buffer();
404 unsigned char *audio_get_buffer(bool talk_buf
, size_t *buffer_size
)
406 unsigned char *buf
, *end
;
408 if (audio_is_initialized
)
412 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
414 if (buffer_size
== NULL
)
416 /* Special case for talk_init to use since it already knows it's
418 buffer_state
= BUFFER_STATE_TRASHED
;
422 if (talk_buf
|| buffer_state
== BUFFER_STATE_TRASHED
423 || !talk_voice_required())
425 logf("get buffer: talk, audio");
426 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
427 the talk buffer is not needed because voice isn't being used, or
428 could be BUFFER_STATE_TRASHED already. If state is
429 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
430 without the caller knowing what's going on. Changing certain settings
431 may move it to a worse condition but the memory in use by something
432 else will remain undisturbed.
434 if (buffer_state
!= BUFFER_STATE_TRASHED
)
437 buffer_state
= BUFFER_STATE_TRASHED
;
445 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
446 still BUFFER_STATE_INITIALIZED */
447 /* Skip talk buffer and move pcm buffer to end to maximize available
448 contiguous memory - no audio running means voice will not need the
450 logf("get buffer: audio");
451 buf
= audiobuf
+ talk_get_bufsize();
452 end
= audiobufend
- pcmbuf_init(audiobufend
);
453 buffer_state
= BUFFER_STATE_VOICED_ONLY
;
456 *buffer_size
= end
- buf
;
461 #ifdef HAVE_RECORDING
462 unsigned char *audio_get_recording_buffer(size_t *buffer_size
)
464 /* Stop audio, voice and obtain all available buffer space */
468 unsigned char *end
= audiobufend
;
469 buffer_state
= BUFFER_STATE_TRASHED
;
470 *buffer_size
= end
- audiobuf
;
472 return (unsigned char *)audiobuf
;
475 bool audio_load_encoder(int afmt
)
478 const char *enc_fn
= get_codec_filename(afmt
| CODEC_TYPE_ENCODER
);
482 audio_remove_encoder();
483 ci
.enc_codec_loaded
= 0; /* clear any previous error condition */
485 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
486 queue_post(&codec_queue
, Q_ENCODER_LOAD_DISK
, (intptr_t)enc_fn
);
488 while (ci
.enc_codec_loaded
== 0)
491 logf("codec loaded: %d", ci
.enc_codec_loaded
);
493 return ci
.enc_codec_loaded
> 0;
498 } /* audio_load_encoder */
500 void audio_remove_encoder(void)
503 /* force encoder codec unload (if currently loaded) */
504 if (ci
.enc_codec_loaded
<= 0)
507 ci
.stop_encoder
= true;
508 while (ci
.enc_codec_loaded
> 0)
511 } /* audio_remove_encoder */
513 #endif /* HAVE_RECORDING */
516 int audio_current_aa_hid(void)
519 int offset
= ci
.new_track
+ wps_offset
;
521 cur_idx
= track_ridx
+ offset
;
522 cur_idx
&= MAX_TRACK_MASK
;
524 return tracks
[cur_idx
].aa_hid
;
528 struct mp3entry
* audio_current_track(void)
530 const char *filename
;
532 static struct mp3entry temp_id3
;
534 int offset
= ci
.new_track
+ wps_offset
;
536 cur_idx
= (track_ridx
+ offset
) & MAX_TRACK_MASK
;
538 if (cur_idx
== track_ridx
&& *curtrack_id3
.path
)
541 return &curtrack_id3
;
543 else if (offset
== -1 && *prevtrack_id3
.path
)
545 /* We're in a track transition. The codec has moved on to the nex track,
546 but the audio being played is still the same (now previous) track.
547 prevtrack_id3.elapsed is being updated in an ISR by
548 codec_pcmbuf_position_callback */
549 return &prevtrack_id3
;
551 else if (tracks
[cur_idx
].id3_hid
>= 0)
553 /* Get the ID3 metadata from the main buffer */
554 return bufgetid3(tracks
[cur_idx
].id3_hid
);
557 /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info
558 we have and return that. */
560 memset(&temp_id3
, 0, sizeof(struct mp3entry
));
562 filename
= playlist_peek(0);
564 filename
= "No file!";
566 #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
567 if (tagcache_fill_tags(&temp_id3
, filename
))
571 p
= strrchr(filename
, '/');
577 strncpy(temp_id3
.path
, p
, sizeof(temp_id3
.path
)-1);
578 temp_id3
.title
= &temp_id3
.path
[0];
583 struct mp3entry
* audio_next_track(void)
586 int offset
= ci
.new_track
+ wps_offset
;
588 if (!audio_have_tracks())
591 if (wps_offset
== -1 && *prevtrack_id3
.path
)
593 /* We're in a track transition. The next track for the WPS is the one
594 currently being decoded. */
595 return &curtrack_id3
;
598 next_idx
= (track_ridx
+ offset
+ 1) & MAX_TRACK_MASK
;
600 if (next_idx
== track_widx
)
602 /* The next track hasn't been buffered yet, so we return the static
603 version of its metadata. */
604 return &lasttrack_id3
;
607 if (tracks
[next_idx
].id3_hid
< 0)
610 return bufgetid3(tracks
[next_idx
].id3_hid
);
613 bool audio_has_changed_track(void)
617 track_changed
= false;
624 void audio_play(long offset
)
628 #ifdef PLAYBACK_VOICE
629 /* Truncate any existing voice output so we don't have spelling
630 * etc. over the first part of the played track */
635 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset
);
636 /* Don't return until playback has actually started */
637 queue_send(&audio_queue
, Q_AUDIO_PLAY
, offset
);
640 void audio_stop(void)
643 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
644 /* Don't return until playback has actually stopped */
645 queue_send(&audio_queue
, Q_AUDIO_STOP
, 0);
648 void audio_pause(void)
650 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
651 /* Don't return until playback has actually paused */
652 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, true);
655 void audio_resume(void)
657 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
658 /* Don't return until playback has actually resumed */
659 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, false);
662 static void audio_skip(int direction
)
664 if (playlist_check(ci
.new_track
+ wps_offset
+ direction
))
666 if (global_settings
.beep
)
667 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
669 LOGFQUEUE("audio > audio Q_AUDIO_SKIP %d", direction
);
670 queue_post(&audio_queue
, Q_AUDIO_SKIP
, direction
);
671 /* Update wps while our message travels inside deep playback queues. */
672 wps_offset
+= direction
;
673 /* Immediately update the playlist index */
674 playlist_next(direction
);
675 track_changed
= true;
679 /* No more tracks. */
680 if (global_settings
.beep
)
681 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
685 void audio_next(void)
690 void audio_prev(void)
695 void audio_next_dir(void)
697 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
698 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, 1);
701 void audio_prev_dir(void)
703 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
704 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, -1);
707 void audio_pre_ff_rewind(void)
709 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
710 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
713 void audio_ff_rewind(long newpos
)
715 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
716 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, newpos
);
719 void audio_flush_and_reload_tracks(void)
721 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
722 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
725 void audio_error_clear(void)
727 #ifdef AUDIO_HAVE_RECORDING
728 pcm_rec_error_clear();
732 int audio_status(void)
737 ret
|= AUDIO_STATUS_PLAY
;
740 ret
|= AUDIO_STATUS_PAUSE
;
742 #ifdef HAVE_RECORDING
743 /* Do this here for constitency with mpeg.c version */
744 ret
|= pcm_rec_status();
750 int audio_get_file_pos(void)
755 #ifndef HAVE_FLASH_STORAGE
756 void audio_set_buffer_margin(int setting
)
758 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
759 buffer_margin
= lookup
[setting
];
760 logf("buffer margin: %ld", (long)buffer_margin
);
761 set_filebuf_watermark(buffer_margin
, 0);
765 /* Take nescessary steps to enable or disable the crossfade setting */
766 void audio_set_crossfade(int enable
)
772 /* Tell it the next setting to use */
773 pcmbuf_crossfade_enable(enable
);
775 /* Return if size hasn't changed or this is too early to determine
776 which in the second case there's no way we could be playing
778 if (pcmbuf_is_same_size())
780 /* This function is a copout and just syncs some variables -
781 to be removed at a later date */
782 pcmbuf_crossfade_enable_finished();
787 was_playing
= playing
;
789 /* Playback has to be stopped before changing the buffer size */
792 /* Store the track resume position */
793 offset
= curtrack_id3
.offset
;
794 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK
));
797 /* Blast it - audio buffer will have to be setup again next time
799 audio_get_buffer(true, &size
);
801 /* Restart playback if audio was running previously */
806 /* --- Routines called from multiple threads --- */
808 static void set_filebuf_watermark(int seconds
, size_t max
)
813 return; /* Audio buffers not yet set up */
815 bytes
= seconds
?MAX(curtrack_id3
.bitrate
* seconds
* (1000/8), max
):max
;
816 bytes
= MIN(bytes
, filebuflen
/ 2);
817 buf_set_watermark(bytes
);
820 const char * get_codec_filename(int cod_spec
)
824 #ifdef HAVE_RECORDING
825 /* Can choose decoder or encoder if one available */
826 int type
= cod_spec
& CODEC_TYPE_MASK
;
827 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
829 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
830 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
832 fname
= (type
== CODEC_TYPE_ENCODER
) ?
833 audio_formats
[afmt
].codec_enc_root_fn
:
834 audio_formats
[afmt
].codec_root_fn
;
837 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
838 afmt
, fname
? fname
: "<unknown>");
839 #else /* !HAVE_RECORDING */
841 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
842 cod_spec
= AFMT_UNKNOWN
;
843 fname
= audio_formats
[cod_spec
].codec_root_fn
;
844 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
845 #endif /* HAVE_RECORDING */
848 } /* get_codec_filename */
850 /* --- Codec thread --- */
851 static bool codec_pcmbuf_insert_callback(
852 const void *ch1
, const void *ch2
, int count
)
854 const char *src
[2] = { ch1
, ch2
};
858 int out_count
= dsp_output_count(ci
.dsp
, count
);
862 /* Prevent audio from a previous track from playing */
863 if (ci
.new_track
|| ci
.stop_codec
)
866 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
870 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
874 /* Get the real input_size for output_size bytes, guarding
875 * against resampling buffer overflows. */
876 inp_count
= dsp_input_count(ci
.dsp
, out_count
);
881 /* Input size has grown, no error, just don't write more than length */
882 if (inp_count
> count
)
885 out_count
= dsp_process(ci
.dsp
, dest
, src
, inp_count
);
890 pcmbuf_write_complete(out_count
);
896 } /* codec_pcmbuf_insert_callback */
898 static void* codec_get_memory_callback(size_t *size
)
900 *size
= MALLOC_BUFSIZE
;
904 /* Between the codec and PCM track change, we need to keep updating the
905 "elapsed" value of the previous (to the codec, but current to the
906 user/PCM/WPS) track, so that the progressbar reaches the end.
907 During that transition, the WPS will display prevtrack_id3. */
908 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
909 static void codec_pcmbuf_position_callback(size_t size
)
911 /* This is called from an ISR, so be quick */
912 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
913 prevtrack_id3
.elapsed
;
915 if (time
>= prevtrack_id3
.length
)
917 pcmbuf_set_position_callback(NULL
);
918 prevtrack_id3
.elapsed
= prevtrack_id3
.length
;
921 prevtrack_id3
.elapsed
= time
;
924 static void codec_set_elapsed_callback(unsigned int value
)
926 unsigned int latency
;
930 #ifdef AB_REPEAT_ENABLE
931 ab_position_report(value
);
934 latency
= pcmbuf_get_latency();
936 curtrack_id3
.elapsed
= 0;
937 else if (value
- latency
> curtrack_id3
.elapsed
||
938 value
- latency
< curtrack_id3
.elapsed
- 2)
940 curtrack_id3
.elapsed
= value
- latency
;
944 static void codec_set_offset_callback(size_t value
)
946 unsigned int latency
;
951 latency
= pcmbuf_get_latency() * curtrack_id3
.bitrate
/ 8;
953 curtrack_id3
.offset
= 0;
955 curtrack_id3
.offset
= value
- latency
;
958 static void codec_advance_buffer_counters(size_t amount
)
960 bufadvance(CUR_TI
->audio_hid
, amount
);
964 /* copy up-to size bytes into ptr and return the actual size copied */
965 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
969 if (ci
.stop_codec
|| !playing
)
972 copy_n
= bufread(CUR_TI
->audio_hid
, size
, ptr
);
974 /* Nothing requested OR nothing left */
978 /* Update read and other position pointers */
979 codec_advance_buffer_counters(copy_n
);
981 /* Return the actual amount of data copied to the buffer */
983 } /* codec_filebuf_callback */
985 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
987 size_t copy_n
= reqsize
;
997 ret
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, &ptr
);
999 copy_n
= MIN((size_t)ret
, reqsize
);
1010 } /* codec_request_buffer_callback */
1012 static int get_codec_base_type(int type
)
1024 static void codec_advance_buffer_callback(size_t amount
)
1026 codec_advance_buffer_counters(amount
);
1027 codec_set_offset_callback(ci
.curpos
);
1030 static void codec_advance_buffer_loc_callback(void *ptr
)
1032 size_t amount
= buf_get_offset(CUR_TI
->audio_hid
, ptr
);
1033 codec_advance_buffer_callback(amount
);
1036 /* Copied from mpeg.c. Should be moved somewhere else. */
1037 static int codec_get_file_pos(void)
1040 struct mp3entry
*id3
= audio_current_track();
1046 /* Use the TOC to find the new position */
1047 unsigned int percent
, remainder
;
1048 int curtoc
, nexttoc
, plen
;
1050 percent
= (id3
->elapsed
*100)/id3
->length
;
1054 curtoc
= id3
->toc
[percent
];
1057 nexttoc
= id3
->toc
[percent
+1];
1061 pos
= (id3
->filesize
/256)*curtoc
;
1063 /* Use the remainder to get a more accurate position */
1064 remainder
= (id3
->elapsed
*100)%id3
->length
;
1065 remainder
= (remainder
*100)/id3
->length
;
1066 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1067 pos
+= (plen
/100)*remainder
;
1071 /* No TOC exists, estimate the new position */
1072 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1073 (id3
->elapsed
/ 1000);
1076 else if (id3
->bitrate
)
1077 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1081 pos
+= id3
->first_frame_offset
;
1083 /* Don't seek right to the end of the file so that we can
1084 transition properly to the next song */
1085 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1086 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1091 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1095 curtrack_id3
.elapsed
= newtime
;
1096 newpos
= codec_get_file_pos();
1101 static void codec_seek_complete_callback(void)
1103 logf("seek_complete");
1104 if (pcm_is_paused())
1106 /* If this is not a seamless seek, clear the buffer */
1108 dsp_configure(ci
.dsp
, DSP_FLUSH
, 0);
1110 /* If playback was not 'deliberately' paused, unpause now */
1112 pcmbuf_pause(false);
1117 static bool codec_seek_buffer_callback(size_t newpos
)
1119 logf("codec_seek_buffer_callback");
1121 int ret
= bufseek(CUR_TI
->audio_hid
, newpos
);
1131 static void codec_configure_callback(int setting
, intptr_t value
)
1134 case CODEC_SET_FILEBUF_WATERMARK
:
1135 set_filebuf_watermark(buffer_margin
, value
);
1139 if (!dsp_configure(ci
.dsp
, setting
, value
))
1140 { logf("Illegal key:%d", setting
); }
1144 static void codec_track_changed(void)
1146 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1147 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1150 static void codec_pcmbuf_track_changed_callback(void)
1152 pcmbuf_set_position_callback(NULL
);
1153 pcmbuf_callback_queue_post(Q_AUDIO_TRACK_CHANGED
, 0);
1156 static void codec_discard_codec_callback(void)
1158 if (CUR_TI
->codec_hid
>= 0)
1160 bufclose(CUR_TI
->codec_hid
);
1161 CUR_TI
->codec_hid
= -1;
1165 static inline void codec_gapless_track_change(void)
1167 /* callback keeps the progress bar moving while the pcmbuf empties */
1168 pcmbuf_set_position_callback(codec_pcmbuf_position_callback
);
1169 /* set the pcmbuf callback for when the track really changes */
1170 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1173 static inline void codec_crossfade_track_change(void)
1175 /* Initiate automatic crossfade mode */
1176 pcmbuf_crossfade_init(false);
1177 /* Notify the wps that the track change starts now */
1178 codec_track_changed();
1181 static void codec_track_skip_done(bool was_manual
)
1183 /* Manual track change (always crossfade or flush audio). */
1186 pcmbuf_crossfade_init(true);
1187 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1188 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1190 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1191 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1192 && global_settings
.crossfade
!= CROSSFADE_ENABLE_TRACKSKIP
)
1194 if (global_settings
.crossfade
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1196 if (global_settings
.playlist_shuffle
)
1197 /* shuffle mode is on, so crossfade: */
1198 codec_crossfade_track_change();
1200 /* shuffle mode is off, so do a gapless track change */
1201 codec_gapless_track_change();
1204 /* normal crossfade: */
1205 codec_crossfade_track_change();
1208 /* normal gapless playback. */
1209 codec_gapless_track_change();
1212 static bool codec_load_next_track(void)
1214 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1216 prev_track_elapsed
= curtrack_id3
.elapsed
;
1218 #ifdef AB_REPEAT_ENABLE
1219 ab_end_of_track_report();
1222 logf("Request new track");
1224 if (ci
.new_track
== 0)
1227 automatic_skip
= true;
1232 trigger_cpu_boost();
1233 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1234 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1239 case Q_CODEC_REQUEST_COMPLETE
:
1240 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1241 codec_track_skip_done(!automatic_skip
);
1244 case Q_CODEC_REQUEST_FAILED
:
1245 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1247 ci
.stop_codec
= true;
1248 codec_requested_stop
= true;
1252 LOGFQUEUE("codec |< default");
1253 ci
.stop_codec
= true;
1254 codec_requested_stop
= true;
1259 static bool codec_request_next_track_callback(void)
1263 if (ci
.stop_codec
|| !playing
)
1266 prev_codectype
= get_codec_base_type(curtrack_id3
.codectype
);
1268 if (!codec_load_next_track())
1271 /* Check if the next codec is the same file. */
1272 if (prev_codectype
== get_codec_base_type(curtrack_id3
.codectype
))
1274 logf("New track loaded");
1275 codec_discard_codec_callback();
1280 logf("New codec:%d/%d", curtrack_id3
.codectype
, prev_codectype
);
1285 static void codec_thread(void)
1287 struct queue_event ev
;
1293 queue_wait(&codec_queue
, &ev
);
1294 codec_requested_stop
= false;
1297 case Q_CODEC_LOAD_DISK
:
1298 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1299 queue_reply(&codec_queue
, 1);
1300 audio_codec_loaded
= true;
1301 ci
.stop_codec
= false;
1302 status
= codec_load_file((const char *)ev
.data
, &ci
);
1306 LOGFQUEUE("codec < Q_CODEC_LOAD");
1307 if (CUR_TI
->codec_hid
< 0) {
1308 logf("Codec slot is empty!");
1309 /* Wait for the pcm buffer to go empty */
1310 while (pcm_is_playing())
1312 /* This must be set to prevent an infinite loop */
1313 ci
.stop_codec
= true;
1314 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1315 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
1319 audio_codec_loaded
= true;
1320 ci
.stop_codec
= false;
1321 status
= codec_load_buf(CUR_TI
->codec_hid
, &ci
);
1324 #ifdef AUDIO_HAVE_RECORDING
1325 case Q_ENCODER_LOAD_DISK
:
1326 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1327 audio_codec_loaded
= false; /* Not audio codec! */
1328 logf("loading encoder");
1329 ci
.stop_encoder
= false;
1330 status
= codec_load_file((const char *)ev
.data
, &ci
);
1331 logf("encoder stopped");
1333 #endif /* AUDIO_HAVE_RECORDING */
1336 LOGFQUEUE("codec < default");
1339 if (audio_codec_loaded
)
1348 audio_codec_loaded
= false;
1352 case Q_CODEC_LOAD_DISK
:
1354 LOGFQUEUE("codec < Q_CODEC_LOAD");
1357 if (ci
.new_track
|| status
!= CODEC_OK
)
1361 logf("Codec failure");
1362 gui_syncsplash(HZ
*2, "Codec failure");
1365 if (!codec_load_next_track())
1367 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1368 /* End of playlist */
1369 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1375 logf("Codec finished");
1378 /* Wait for the audio to stop playing before
1379 * triggering the WPS exit */
1380 while(pcm_is_playing())
1382 curtrack_id3
.elapsed
=
1383 curtrack_id3
.length
- pcmbuf_get_latency();
1387 if (codec_requested_stop
)
1389 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1390 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1396 if (CUR_TI
->codec_hid
>= 0)
1398 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1399 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
1403 const char *codec_fn
=
1404 get_codec_filename(curtrack_id3
.codectype
);
1407 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1408 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
1409 (intptr_t)codec_fn
);
1415 #ifdef AUDIO_HAVE_RECORDING
1416 case Q_ENCODER_LOAD_DISK
:
1417 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1419 if (status
== CODEC_OK
)
1422 logf("Encoder failure");
1423 gui_syncsplash(HZ
*2, "Encoder failure");
1425 if (ci
.enc_codec_loaded
< 0)
1428 logf("Encoder failed to load");
1429 ci
.enc_codec_loaded
= -1;
1431 #endif /* AUDIO_HAVE_RECORDING */
1434 LOGFQUEUE("codec < default");
1441 /* --- Audio thread --- */
1443 static bool audio_have_tracks(void)
1445 return (audio_track_count() != 0);
1448 static int audio_free_track_count(void)
1450 /* Used tracks + free tracks adds up to MAX_TRACK - 1 */
1451 return MAX_TRACK
- 1 - audio_track_count();
1454 int audio_track_count(void)
1456 /* Calculate difference from track_ridx to track_widx
1457 * taking into account a possible wrap-around. */
1458 return (MAX_TRACK
+ track_widx
- track_ridx
) & MAX_TRACK_MASK
;
1461 long audio_filebufused(void)
1463 return (long) buf_used();
1466 /* Update track info after successful a codec track change */
1467 static void audio_update_trackinfo(void)
1469 /* Load the curent track's metadata into curtrack_id3 */
1470 CUR_TI
->taginfo_ready
= (CUR_TI
->id3_hid
>= 0);
1471 if (CUR_TI
->id3_hid
>= 0)
1472 copy_mp3entry(&curtrack_id3
, bufgetid3(CUR_TI
->id3_hid
));
1474 int next_idx
= (track_ridx
+ 1) & MAX_TRACK_MASK
;
1475 tracks
[next_idx
].taginfo_ready
= (tracks
[next_idx
].id3_hid
>= 0);
1477 /* Reset current position */
1478 curtrack_id3
.elapsed
= 0;
1479 curtrack_id3
.offset
= 0;
1481 /* Update the codec API */
1482 ci
.filesize
= CUR_TI
->filesize
;
1483 ci
.id3
= &curtrack_id3
;
1485 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
1488 static void buffering_audio_callback(enum callback_event ev
, int value
)
1491 logf("buffering_audio_callback");
1495 case EVENT_BUFFER_LOW
:
1496 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1497 queue_remove_from_head(&audio_queue
, Q_AUDIO_FILL_BUFFER
);
1498 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1501 case EVENT_HANDLE_REBUFFER
:
1502 LOGFQUEUE("audio >| audio Q_AUDIO_FLUSH");
1503 queue_send(&audio_queue
, Q_AUDIO_FLUSH
, 0);
1506 case EVENT_HANDLE_FINISHED
:
1507 logf("handle %d finished buffering", value
);
1516 /* Clear tracks between write and read, non inclusive */
1517 static void audio_clear_track_entries(void)
1519 int cur_idx
= track_widx
;
1521 logf("Clearing tracks:%d/%d", track_ridx
, track_widx
);
1523 /* Loop over all tracks from write-to-read */
1526 cur_idx
= (cur_idx
+ 1) & MAX_TRACK_MASK
;
1528 if (cur_idx
== track_ridx
)
1531 clear_track_info(&tracks
[cur_idx
]);
1535 /* Clear all tracks */
1536 static bool audio_release_tracks(void)
1540 logf("releasing all tracks");
1542 for(i
= 0; i
< MAX_TRACK
; i
++)
1544 cur_idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
1545 if (!clear_track_info(&tracks
[cur_idx
]))
1552 static bool audio_loadcodec(bool start_play
)
1555 char codec_path
[MAX_PATH
]; /* Full path to codec */
1557 if (tracks
[track_widx
].id3_hid
< 0) {
1561 const char * codec_fn
=
1562 get_codec_filename(bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
);
1563 if (codec_fn
== NULL
)
1566 tracks
[track_widx
].codec_hid
= -1;
1570 /* Load the codec directly from disk and save some memory. */
1571 track_ridx
= track_widx
;
1572 ci
.filesize
= CUR_TI
->filesize
;
1573 ci
.id3
= &curtrack_id3
;
1574 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
1576 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1577 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
1582 /* If we already have another track than this one buffered */
1583 if (track_widx
!= track_ridx
)
1585 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
1587 /* If the previous codec is the same as this one, there is no need
1588 * to put another copy of it on the file buffer */
1589 if (get_codec_base_type(
1590 bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
) ==
1591 get_codec_base_type(
1592 bufgetid3(tracks
[prev_track
].id3_hid
)->codectype
)
1593 && audio_codec_loaded
)
1595 logf("Reusing prev. codec");
1601 codec_get_full_path(codec_path
, codec_fn
);
1603 tracks
[track_widx
].codec_hid
= bufopen(codec_path
, 0, TYPE_CODEC
);
1604 if (tracks
[track_widx
].codec_hid
< 0)
1607 logf("Loaded codec");
1612 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
1613 static void audio_set_elapsed(struct mp3entry
* id3
)
1615 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
1616 id3
->offset
- id3
->first_frame_offset
: 0;
1619 if ( id3
->has_toc
) {
1620 /* calculate elapsed time using TOC */
1622 unsigned int remainder
, plen
, relpos
, nextpos
;
1624 /* find wich percent we're at */
1625 for (i
=0; i
<100; i
++ )
1626 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
1633 relpos
= id3
->toc
[i
];
1636 nextpos
= id3
->toc
[i
+1];
1640 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
1642 /* set time for this percent (divide before multiply to prevent
1643 overflow on long files. loss of precision is negligible on
1645 id3
->elapsed
= i
* (id3
->length
/ 100);
1647 /* calculate remainder time */
1648 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
1649 id3
->elapsed
+= (((remainder
* 100) / plen
) *
1650 (id3
->length
/ 10000));
1653 /* no TOC exists. set a rough estimate using average bitrate */
1654 int tpk
= id3
->length
/
1655 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
1657 id3
->elapsed
= offset
/ 1024 * tpk
;
1662 /* constant bitrate, use exact calculation */
1663 if (id3
->bitrate
!= 0)
1664 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
1668 /* Load one track by making the appropriate bufopen calls. Return true if
1669 everything required was loaded correctly, false if not. */
1670 static bool audio_load_track(int offset
, bool start_play
)
1675 int file_offset
= 0;
1676 struct mp3entry id3
;
1678 /* Stop buffer filling if there is no free track entries.
1679 Don't fill up the last track entry (we wan't to store next track
1681 if (!audio_free_track_count())
1683 logf("No free tracks");
1688 tracks
[track_widx
].taginfo_ready
= false;
1691 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
1692 /* Get track name from current playlist read position. */
1693 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
1695 /* Handle broken playlists. */
1696 fd
= open(trackname
, O_RDONLY
);
1699 logf("Open failed");
1700 /* Skip invalid entry from playlist. */
1701 playlist_skip_entry(NULL
, last_peek_offset
);
1709 logf("End-of-playlist");
1710 playlist_end
= true;
1711 memset(&lasttrack_id3
, 0, sizeof(struct mp3entry
));
1715 tracks
[track_widx
].filesize
= filesize(fd
);
1717 if ((unsigned)offset
> tracks
[track_widx
].filesize
)
1720 /* Set default values */
1723 buf_set_watermark(AUDIO_DEFAULT_WATERMARK
);
1724 dsp_configure(ci
.dsp
, DSP_RESET
, 0);
1725 track_changed
= true;
1726 playlist_update_resume_info(audio_current_track());
1729 /* Get track metadata if we don't already have it. */
1730 if (tracks
[track_widx
].id3_hid
< 0)
1732 if (get_metadata(&id3
, fd
, trackname
))
1734 send_event(PLAYBACK_EVENT_TRACK_BUFFER
, &id3
);
1736 tracks
[track_widx
].id3_hid
=
1737 bufalloc(&id3
, sizeof(struct mp3entry
), TYPE_ID3
);
1739 if (tracks
[track_widx
].id3_hid
< 0)
1743 copy_mp3entry(&lasttrack_id3
, &id3
);
1747 if (track_widx
== track_ridx
)
1748 copy_mp3entry(&curtrack_id3
, &id3
);
1752 track_changed
= true;
1753 playlist_update_resume_info(audio_current_track());
1758 logf("mde:%s!",trackname
);
1760 /* Skip invalid entry from playlist. */
1761 playlist_skip_entry(NULL
, last_peek_offset
);
1771 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
1773 char cuepath
[MAX_PATH
];
1775 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
1777 if (look_for_cuesheet_file(trackname
, cuepath
) &&
1778 parse_cuesheet(cuepath
, cue
))
1780 strcpy((cue
)->audio_filename
, trackname
);
1782 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
1787 struct mp3entry
*track_id3
;
1789 if (track_widx
== track_ridx
)
1790 track_id3
= &curtrack_id3
;
1792 track_id3
= bufgetid3(tracks
[track_widx
].id3_hid
);
1794 #ifdef HAVE_ALBUMART
1795 if (tracks
[track_widx
].aa_hid
< 0 && gui_sync_wps_uses_albumart())
1797 char aa_path
[MAX_PATH
];
1798 if (find_albumart(track_id3
, aa_path
, sizeof(aa_path
)))
1799 tracks
[track_widx
].aa_hid
= bufopen(aa_path
, 0, TYPE_BITMAP
);
1803 /* Load the codec. */
1804 if (!audio_loadcodec(start_play
))
1806 if (tracks
[track_widx
].codec_hid
== ERR_BUFFER_FULL
)
1808 /* No space for codec on buffer, not an error */
1812 /* This is an error condition, either no codec was found, or reading
1813 * the codec file failed part way through, either way, skip the track */
1814 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
1815 /* We should not use gui_syncplash from audio thread! */
1816 gui_syncsplash(HZ
*2, msgbuf
);
1817 /* Skip invalid entry from playlist. */
1818 playlist_skip_entry(NULL
, last_peek_offset
);
1822 track_id3
->elapsed
= 0;
1824 enum data_type type
= TYPE_PACKET_AUDIO
;
1826 switch (track_id3
->codectype
) {
1831 file_offset
= offset
;
1832 track_id3
->offset
= offset
;
1833 audio_set_elapsed(track_id3
);
1839 file_offset
= offset
;
1840 track_id3
->offset
= offset
;
1841 track_id3
->elapsed
= track_id3
->length
/ 2;
1845 case AFMT_OGG_VORBIS
:
1854 track_id3
->offset
= offset
;
1860 logf("Loading atomic %d",track_id3
->codectype
);
1861 type
= TYPE_ATOMIC_AUDIO
;
1865 logf("alt:%s", trackname
);
1867 if (file_offset
> AUDIO_REBUFFER_GUESS_SIZE
)
1868 file_offset
-= AUDIO_REBUFFER_GUESS_SIZE
;
1869 else if (track_id3
->first_frame_offset
)
1870 file_offset
= track_id3
->first_frame_offset
;
1874 tracks
[track_widx
].audio_hid
= bufopen(trackname
, file_offset
, type
);
1876 if (tracks
[track_widx
].audio_hid
< 0)
1879 /* All required data is now available for the codec. */
1880 tracks
[track_widx
].taginfo_ready
= true;
1884 ci
.curpos
=file_offset
;
1885 buf_request_buffer_handle(tracks
[track_widx
].audio_hid
);
1888 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
1893 static void audio_fill_file_buffer(bool start_play
, size_t offset
)
1895 struct queue_event ev
;
1896 bool had_next_track
= audio_next_track() != NULL
;
1897 bool continue_buffering
;
1899 /* No need to rebuffer if there are track skips pending. */
1900 if (ci
.new_track
!= 0)
1903 /* Must reset the buffer before use if trashed or voice only - voice
1904 file size shouldn't have changed so we can go straight from
1905 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
1906 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
1907 audio_reset_buffer();
1909 logf("Starting buffer fill");
1912 audio_clear_track_entries();
1914 /* Save the current resume position once. */
1915 playlist_update_resume_info(audio_current_track());
1918 continue_buffering
= audio_load_track(offset
, start_play
);
1922 if (queue_peek(&audio_queue
, &ev
)) {
1923 if (ev
.id
!= Q_AUDIO_FILL_BUFFER
)
1925 /* There's a message in the queue. break the loop to treat it,
1926 and go back to filling after that. */
1927 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1928 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1932 } while (continue_buffering
);
1934 if (!had_next_track
&& audio_next_track())
1935 track_changed
= true;
1939 static void audio_rebuffer(void)
1941 logf("Forcing rebuffer");
1943 clear_track_info(CUR_TI
);
1945 /* Reset track pointers */
1946 track_widx
= track_ridx
;
1947 audio_clear_track_entries();
1949 /* Fill the buffer */
1950 last_peek_offset
= -1;
1953 if (!CUR_TI
->taginfo_ready
)
1954 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
1956 audio_fill_file_buffer(false, 0);
1959 /* Called on request from the codec to get a new track. This is the codec part
1960 of the track transition. */
1961 static int audio_check_new_track(void)
1963 int track_count
= audio_track_count();
1964 int old_track_ridx
= track_ridx
;
1966 int next_playlist_index
;
1968 bool end_of_playlist
; /* Temporary flag, not the same as playlist_end */
1970 /* Now it's good time to send track unbuffer events. */
1971 send_event(PLAYBACK_EVENT_TRACK_FINISH
, &curtrack_id3
);
1976 if (playlist_next_dir(ci
.new_track
))
1984 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1985 return Q_CODEC_REQUEST_FAILED
;
1992 end_of_playlist
= playlist_peek(automatic_skip
? ci
.new_track
: 0) == NULL
;
1993 auto_dir_skip
= end_of_playlist
&& global_settings
.next_folder
;
1995 /* If the playlist isn't that big */
1996 if (automatic_skip
&& !playlist_check(ci
.new_track
))
1998 if (ci
.new_track
>= 0)
2000 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2001 return Q_CODEC_REQUEST_FAILED
;
2003 /* Find the beginning backward if the user over-skips it */
2004 while (!playlist_check(++ci
.new_track
))
2005 if (ci
.new_track
>= 0)
2007 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2008 return Q_CODEC_REQUEST_FAILED
;
2012 /* Update the playlist */
2013 last_peek_offset
-= ci
.new_track
;
2017 /* If the track change was the result of an auto dir skip,
2018 we need to update the playlist now */
2019 next_playlist_index
= playlist_next(ci
.new_track
);
2021 if (next_playlist_index
< 0)
2023 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2024 return Q_CODEC_REQUEST_FAILED
;
2031 new_playlist
= false;
2034 /* Save the track metadata to allow the WPS to display it
2035 while PCM finishes playing that track */
2036 copy_mp3entry(&prevtrack_id3
, &curtrack_id3
);
2038 /* Update the main buffer copy of the track metadata with the one
2039 the codec has been using (for the unbuffer callbacks) */
2040 if (CUR_TI
->id3_hid
>= 0)
2041 copy_mp3entry(bufgetid3(CUR_TI
->id3_hid
), &curtrack_id3
);
2043 /* Save a pointer to the old track to allow later clearing */
2046 for (i
= 0; i
< ci
.new_track
; i
++)
2048 idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
2049 struct mp3entry
*id3
= bufgetid3(tracks
[idx
].id3_hid
);
2050 ssize_t offset
= buf_handle_offset(tracks
[idx
].audio_hid
);
2051 if (!id3
|| offset
< 0 || (unsigned)offset
> id3
->first_frame_offset
)
2053 /* We don't have all the audio data for that track, so clear it,
2054 but keep the metadata. */
2055 if (tracks
[idx
].audio_hid
>= 0 && bufclose(tracks
[idx
].audio_hid
))
2057 tracks
[idx
].audio_hid
= -1;
2058 tracks
[idx
].filesize
= 0;
2063 /* Move to the new track */
2064 track_ridx
= (track_ridx
+ ci
.new_track
) & MAX_TRACK_MASK
;
2066 buf_set_base_handle(CUR_TI
->audio_hid
);
2070 playlist_end
= false;
2071 wps_offset
= -ci
.new_track
;
2072 track_changed
= true;
2075 /* If it is not safe to even skip this many track entries */
2076 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
2083 forward
= ci
.new_track
> 0;
2086 /* If the target track is clearly not in memory */
2087 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
2093 /* When skipping backwards, it is possible that we've found a track that's
2094 * buffered, but which is around the track-wrap and therefor not the track
2095 * we are looking for */
2098 int cur_idx
= track_ridx
;
2099 bool taginfo_ready
= true;
2100 /* We've wrapped the buffer backwards if new > old */
2101 bool wrap
= track_ridx
> old_track_ridx
;
2105 cur_idx
= (cur_idx
+ 1) & MAX_TRACK_MASK
;
2107 /* if we've advanced past the wrap when cur_idx is zeroed */
2111 /* if we aren't still on the wrap and we've caught the old track */
2112 if (!(wrap
|| cur_idx
< old_track_ridx
))
2115 /* If we hit a track in between without valid tag info, bail */
2116 if (!tracks
[cur_idx
].taginfo_ready
)
2118 taginfo_ready
= false;
2129 audio_update_trackinfo();
2130 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2131 return Q_CODEC_REQUEST_COMPLETE
;
2134 unsigned long audio_prev_elapsed(void)
2136 return prev_track_elapsed
;
2139 static void audio_stop_codec_flush(void)
2141 ci
.stop_codec
= true;
2144 while (audio_codec_loaded
)
2147 /* If the audio codec is not loaded any more, and the audio is still
2148 * playing, it is now and _only_ now safe to call this function from the
2150 if (pcm_is_playing())
2153 pcmbuf_queue_clear();
2155 pcmbuf_pause(paused
);
2158 static void audio_stop_playback(void)
2160 /* If we were playing, save resume information */
2163 struct mp3entry
*id3
= NULL
;
2165 if (!playlist_end
|| !ci
.stop_codec
)
2167 /* Set this early, the outside code yields and may allow the codec
2168 to try to wait for a reply on a buffer wait */
2169 ci
.stop_codec
= true;
2170 id3
= audio_current_track();
2173 /* Save the current playing spot, or NULL if the playlist has ended */
2174 playlist_update_resume_info(id3
);
2176 /* TODO: Create auto bookmark too? */
2178 prev_track_elapsed
= curtrack_id3
.elapsed
;
2182 audio_stop_codec_flush();
2185 /* Mark all entries null. */
2186 audio_clear_track_entries();
2188 /* Close all tracks */
2189 audio_release_tracks();
2191 unregister_buffering_callback(buffering_audio_callback
);
2193 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
2196 static void audio_play_start(size_t offset
)
2200 #if INPUT_SRC_CAPS != 0
2201 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
2202 audio_set_output_source(AUDIO_SRC_PLAYBACK
);
2205 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2207 audio_stop_codec_flush();
2209 track_changed
= true;
2210 playlist_end
= false;
2218 sound_set_volume(global_settings
.volume
);
2219 track_widx
= track_ridx
= 0;
2221 /* Clear all track entries. */
2222 for (i
= 0; i
< MAX_TRACK
; i
++) {
2223 clear_track_info(&tracks
[i
]);
2226 last_peek_offset
= -1;
2228 /* Officially playing */
2229 queue_reply(&audio_queue
, 1);
2231 #ifndef HAVE_FLASH_STORAGE
2232 set_filebuf_watermark(buffer_margin
, 0);
2234 audio_fill_file_buffer(true, offset
);
2235 register_buffering_callback(buffering_audio_callback
);
2237 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2238 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
2242 /* Invalidates all but currently playing track. */
2243 static void audio_invalidate_tracks(void)
2245 if (audio_have_tracks())
2247 last_peek_offset
= 0;
2248 playlist_end
= false;
2249 track_widx
= track_ridx
;
2251 /* Mark all other entries null (also buffered wrong metadata). */
2252 audio_clear_track_entries();
2254 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
2256 audio_fill_file_buffer(false, 0);
2260 static void audio_new_playlist(void)
2262 /* Prepare to start a new fill from the beginning of the playlist */
2263 last_peek_offset
= -1;
2264 if (audio_have_tracks())
2267 skipped_during_pause
= true;
2268 playlist_end
= false;
2269 track_widx
= track_ridx
;
2270 audio_clear_track_entries();
2272 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
2274 /* Mark the current track as invalid to prevent skipping back to it */
2275 CUR_TI
->taginfo_ready
= false;
2278 /* Signal the codec to initiate a track change forward */
2279 new_playlist
= true;
2282 /* Officially playing */
2283 queue_reply(&audio_queue
, 1);
2285 audio_fill_file_buffer(false, 0);
2288 /* Called on manual track skip */
2289 static void audio_initiate_track_change(long direction
)
2291 logf("audio_initiate_track_change(%ld)", direction
);
2293 playlist_end
= false;
2294 ci
.new_track
+= direction
;
2295 wps_offset
-= direction
;
2297 skipped_during_pause
= true;
2300 /* Called on manual dir skip */
2301 static void audio_initiate_dir_change(long direction
)
2303 playlist_end
= false;
2305 ci
.new_track
= direction
;
2307 skipped_during_pause
= true;
2310 /* Called when PCM track change is complete */
2311 static void audio_finalise_track_change(void)
2313 logf("audio_finalise_track_change");
2318 playlist_next(-wps_offset
);
2321 automatic_skip
= false;
2324 auto_dir_skip
= false;
2326 /* Invalidate prevtrack_id3 */
2327 prevtrack_id3
.path
[0] = 0;
2329 if (prev_ti
&& prev_ti
->audio_hid
< 0)
2331 /* No audio left so we clear all the track info. */
2332 clear_track_info(prev_ti
);
2335 if (prev_ti
&& prev_ti
->id3_hid
>= 0)
2337 /* Reset the elapsed time to force the progressbar to be empty if
2338 the user skips back to this track */
2339 bufgetid3(prev_ti
->id3_hid
)->elapsed
= 0;
2342 send_event(PLAYBACK_EVENT_TRACK_CHANGE
, &curtrack_id3
);
2344 track_changed
= true;
2345 playlist_update_resume_info(audio_current_track());
2349 * Layout audio buffer as follows - iram buffer depends on target:
2350 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
2352 static void audio_reset_buffer(void)
2354 /* see audio_get_recording_buffer if this is modified */
2355 logf("audio_reset_buffer");
2357 /* If the setup of anything allocated before the file buffer is
2358 changed, do check the adjustments after the buffer_alloc call
2359 as it will likely be affected and need sliding over */
2361 /* Initially set up file buffer as all space available */
2362 malloc_buf
= audiobuf
+ talk_get_bufsize();
2363 /* Align the malloc buf to line size. Especially important to cf
2364 targets that do line reads/writes. */
2365 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
2366 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
2367 filebuflen
= audiobufend
- filebuf
;
2371 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
2372 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
2374 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
2375 will already be line aligned */
2378 buffering_reset(filebuf
, filebuflen
);
2380 /* Clear any references to the file buffer */
2381 buffer_state
= BUFFER_STATE_INITIALIZED
;
2383 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
2384 /* Make sure everything adds up - yes, some info is a bit redundant but
2385 aids viewing and the sumation of certain variables should add up to
2386 the location of others. */
2389 unsigned char * pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
2390 logf("mabuf: %08X", (unsigned)malloc_buf
);
2391 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
2392 logf("fbuf: %08X", (unsigned)filebuf
);
2393 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
2394 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
2395 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
2396 logf("pcmb: %08X", (unsigned)pcmbuf
);
2397 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
2402 static void audio_thread(void)
2404 struct queue_event ev
;
2408 audio_thread_ready
= true;
2413 if (!pcmbuf_queue_scan(&ev
))
2414 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
2417 case Q_AUDIO_FILL_BUFFER
:
2418 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
2419 if (!playing
|| playlist_end
|| ci
.stop_codec
)
2421 audio_fill_file_buffer(false, 0);
2425 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2426 if (playing
&& ev
.data
<= 0)
2427 audio_new_playlist();
2430 audio_stop_playback();
2431 audio_play_start((size_t)ev
.data
);
2436 LOGFQUEUE("audio < Q_AUDIO_STOP");
2438 audio_stop_playback();
2440 queue_clear(&audio_queue
);
2444 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
2445 if (!(bool) ev
.data
&& skipped_during_pause
&& !pcmbuf_is_crossfade_active())
2446 pcmbuf_play_stop(); /* Flush old track on resume after skip */
2447 skipped_during_pause
= false;
2450 pcmbuf_pause((bool)ev
.data
);
2451 paused
= (bool)ev
.data
;
2455 LOGFQUEUE("audio < Q_AUDIO_SKIP");
2456 audio_initiate_track_change((long)ev
.data
);
2459 case Q_AUDIO_PRE_FF_REWIND
:
2460 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
2466 case Q_AUDIO_FF_REWIND
:
2467 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
2472 /* An automatic track skip is in progress. Finalize it,
2473 then go back to the previous track */
2474 audio_finalise_track_change();
2477 ci
.seek_time
= (long)ev
.data
+1;
2480 case Q_AUDIO_CHECK_NEW_TRACK
:
2481 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
2482 queue_reply(&audio_queue
, audio_check_new_track());
2485 case Q_AUDIO_DIR_SKIP
:
2486 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2487 playlist_end
= false;
2488 audio_initiate_dir_change(ev
.data
);
2492 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
2493 audio_invalidate_tracks();
2496 case Q_AUDIO_TRACK_CHANGED
:
2497 /* PCM track change done */
2498 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2499 audio_finalise_track_change();
2503 case SYS_USB_CONNECTED
:
2504 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2506 audio_stop_playback();
2507 #ifdef PLAYBACK_VOICE
2510 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
2511 usb_wait_for_disconnect(&audio_queue
);
2513 /* Mark all entries null. */
2514 audio_clear_track_entries();
2516 /* release tracks to make sure all handles are closed */
2517 audio_release_tracks();
2522 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
2526 LOGFQUEUE("audio < default");
2532 /* Initialize the audio system - called from init() in main.c.
2533 * Last function because of all the references to internal symbols
2535 void audio_init(void)
2537 struct thread_entry
*audio_thread_p
;
2539 /* Can never do this twice */
2540 if (audio_is_initialized
)
2542 logf("audio: already initialized");
2546 logf("audio: initializing");
2548 /* Initialize queues before giving control elsewhere in case it likes
2549 to send messages. Thread creation will be delayed however so nothing
2550 starts running until ready if something yields such as talk_init. */
2551 queue_init(&audio_queue
, true);
2552 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
2553 queue_init(&codec_queue
, false);
2554 queue_enable_queue_send(&codec_queue
, &codec_queue_sender_list
);
2555 queue_init(&pcmbuf_queue
, false);
2559 /* Initialize codec api. */
2560 ci
.read_filebuf
= codec_filebuf_callback
;
2561 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
2562 ci
.get_codec_memory
= codec_get_memory_callback
;
2563 ci
.request_buffer
= codec_request_buffer_callback
;
2564 ci
.advance_buffer
= codec_advance_buffer_callback
;
2565 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
2566 ci
.request_next_track
= codec_request_next_track_callback
;
2567 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
2568 ci
.seek_buffer
= codec_seek_buffer_callback
;
2569 ci
.seek_complete
= codec_seek_complete_callback
;
2570 ci
.set_elapsed
= codec_set_elapsed_callback
;
2571 ci
.set_offset
= codec_set_offset_callback
;
2572 ci
.configure
= codec_configure_callback
;
2573 ci
.discard_codec
= codec_discard_codec_callback
;
2574 ci
.dsp
= (struct dsp_config
*)dsp_configure(NULL
, DSP_MYDSP
,
2577 /* initialize the buffer */
2580 /* audio_reset_buffer must to know the size of voice buffer so init
2584 codec_thread_p
= create_thread(
2585 codec_thread
, codec_stack
, sizeof(codec_stack
),
2586 CREATE_THREAD_FROZEN
,
2587 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
2590 audio_thread_p
= create_thread(audio_thread
, audio_stack
,
2591 sizeof(audio_stack
), CREATE_THREAD_FROZEN
,
2592 audio_thread_name
IF_PRIO(, PRIORITY_SYSTEM
)
2595 #ifdef PLAYBACK_VOICE
2596 voice_thread_init();
2599 /* Set crossfade setting for next buffer init which should be about... */
2600 pcmbuf_crossfade_enable(global_settings
.crossfade
);
2602 /* initialize the buffering system */
2605 /* ...now! Set up the buffers */
2606 audio_reset_buffer();
2609 for(i
= 0; i
< MAX_TRACK
; i
++)
2611 tracks
[i
].audio_hid
= -1;
2612 tracks
[i
].id3_hid
= -1;
2613 tracks
[i
].codec_hid
= -1;
2614 #ifdef HAVE_ALBUMART
2615 tracks
[i
].aa_hid
= -1;
2619 /* Probably safe to say */
2620 audio_is_initialized
= true;
2622 sound_settings_apply();
2623 #ifndef HAVE_FLASH_STORAGE
2624 audio_set_buffer_margin(global_settings
.buffer_margin
);
2627 /* it's safe to let the threads run now */
2628 #ifdef PLAYBACK_VOICE
2629 voice_thread_resume();
2631 thread_thaw(codec_thread_p
);
2632 thread_thaw(audio_thread_p
);
2636 void audio_wait_for_init(void)
2638 /* audio thread will only set this once after it finished the final
2639 * audio hardware init so this little construct is safe - even
2641 while (!audio_thread_ready
)