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"
45 #include "voice_thread.h"
46 #include "mp3_playback.h"
61 #ifdef HAVE_LCD_BITMAP
63 #include "peakmeter.h"
74 #include "ata_idle_notify.h"
77 #include "recording.h"
81 #define PLAYBACK_VOICE
83 /* default point to start buffer refill */
84 #define AUDIO_DEFAULT_WATERMARK (1024*512)
85 /* amount of guess-space to allow for codecs that must hunt and peck
86 * for their correct seeek target, 32k seems a good size */
87 #define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
89 /* Define LOGF_ENABLE to enable logf output in this file */
90 /*#define LOGF_ENABLE*/
93 /* macros to enable logf for queues
94 logging on SYS_TIMEOUT can be disabled */
96 /* Define this for logf output of all queuing except SYS_TIMEOUT */
97 #define PLAYBACK_LOGQUEUES
98 /* Define this to logf SYS_TIMEOUT messages */
99 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
102 #ifdef PLAYBACK_LOGQUEUES
103 #define LOGFQUEUE logf
105 #define LOGFQUEUE(...)
108 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
109 #define LOGFQUEUE_SYS_TIMEOUT logf
111 #define LOGFQUEUE_SYS_TIMEOUT(...)
115 /* Define one constant that includes recording related functionality */
116 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
117 #define AUDIO_HAVE_RECORDING
126 Q_AUDIO_PRE_FF_REWIND
,
128 Q_AUDIO_CHECK_NEW_TRACK
,
130 Q_AUDIO_TRACK_CHANGED
,
135 Q_CODEC_REQUEST_COMPLETE
,
136 Q_CODEC_REQUEST_FAILED
,
141 #ifdef AUDIO_HAVE_RECORDING
148 STATE_IDLE
, /* audio is stopped: nothing to do */
149 STATE_FILLING
, /* adding tracks to the buffer */
150 STATE_FULL
, /* can't add any more tracks */
151 STATE_FINISHED
, /* all remaining tracks have been added */
154 /* As defined in plugins/lib/xxx2wav.h */
156 #define MALLOC_BUFSIZE (512*1024)
157 #define GUARD_BUFSIZE (32*1024)
159 #define MALLOC_BUFSIZE (100*1024)
160 #define GUARD_BUFSIZE (8*1024)
163 /* As defined in plugin.lds */
165 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
166 #define CODEC_IRAM_SIZE ((size_t)0xc000)
167 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
168 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
169 #define CODEC_IRAM_SIZE ((size_t)0x10000)
171 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
172 #define CODEC_IRAM_SIZE ((size_t)0xc000)
175 bool audio_is_initialized
= false;
176 static bool audio_thread_ready SHAREDBSS_ATTR
= false;
178 /* Variables are commented with the threads that use them: *
179 * A=audio, C=codec, V=voice. A suffix of - indicates that *
180 * the variable is read but not updated on that thread. */
181 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
183 /* Main state control */
184 static volatile bool audio_codec_loaded SHAREDBSS_ATTR
= false; /* Codec loaded? (C/A-) */
185 static volatile bool playing SHAREDBSS_ATTR
= false; /* Is audio playing? (A) */
186 static volatile bool paused SHAREDBSS_ATTR
= false; /* Is audio paused? (A/C-) */
188 /* Ring buffer where compressed audio and codecs are loaded */
189 static unsigned char *filebuf
= NULL
; /* Start of buffer (A/C-) */
190 static unsigned char *malloc_buf
= NULL
; /* Start of malloc buffer (A/C-) */
191 /* FIXME: make filebuflen static */
192 size_t filebuflen
= 0; /* Size of buffer (A/C-) */
193 /* FIXME: make buf_ridx (C/A-) */
195 /* Possible arrangements of the buffer */
196 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
197 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
198 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
199 static int buffer_state
= BUFFER_STATE_TRASHED
; /* Buffer state */
201 /* Used to keep the WPS up-to-date during track transtition */
202 static struct mp3entry prevtrack_id3
;
204 /* Used to provide the codec with a pointer */
205 static struct mp3entry curtrack_id3
;
207 /* Used to make next track info available while playing last track on buffer */
208 static struct mp3entry lasttrack_id3
;
210 /* Track info structure about songs in the file buffer (A/C-) */
212 int audio_hid
; /* The ID for the track's buffer handle */
213 int id3_hid
; /* The ID for the track's metadata handle */
214 int codec_hid
; /* The ID for the track's codec handle */
216 int aa_hid
; /* The ID for the track's album art handle */
219 size_t filesize
; /* File total length */
221 bool taginfo_ready
; /* Is metadata read */
224 static struct track_info tracks
[MAX_TRACK
];
225 static volatile int track_ridx
= 0; /* Track being decoded (A/C-) */
226 static int track_widx
= 0; /* Track being buffered (A) */
228 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
229 static struct track_info
*prev_ti
= NULL
; /* Pointer to the previously played
232 /* Set by the audio thread when the current track information has updated
233 * and the WPS may need to update its cached information */
234 static bool track_changed
= false;
236 /* Information used only for filling the buffer */
237 /* Playlist steps from playing track to next track to be buffered (A) */
238 static int last_peek_offset
= 0;
240 /* Scrobbler support */
241 static unsigned long prev_track_elapsed
= 0; /* Previous track elapsed time (C/A-)*/
243 static enum filling_state filling
;
245 /* Track change controls */
246 static bool automatic_skip
= false; /* Who initiated in-progress skip? (C/A-) */
247 static bool dir_skip
= false; /* Is a directory skip pending? (A) */
248 static bool new_playlist
= false; /* Are we starting a new playlist? (A) */
249 static int wps_offset
= 0; /* Pending track change offset, to keep WPS responsive (A) */
250 static bool skipped_during_pause
= false; /* Do we need to clear the PCM buffer when playback resumes (A) */
252 static bool start_play_g
= false; /* Used by audio_load_track to notify
253 audio_finish_load_track about start_play */
255 /* Set to true if the codec thread should send an audio stop request
256 * (typically because the end of the playlist has been reached).
258 static bool codec_requested_stop
= false;
260 static size_t buffer_margin
= 0; /* Buffer margin aka anti-skip buffer (A/C-) */
262 /* Multiple threads */
263 /* Set the watermark to trigger buffer fill (A/C) FIXME */
264 static void set_filebuf_watermark(int seconds
, size_t max
);
267 static struct event_queue audio_queue SHAREDBSS_ATTR
;
268 static struct queue_sender_list audio_queue_sender_list SHAREDBSS_ATTR
;
269 static long audio_stack
[(DEFAULT_STACK_SIZE
+ 0x1000)/sizeof(long)];
270 static const char audio_thread_name
[] = "audio";
272 static void audio_thread(void);
273 static void audio_initiate_track_change(long direction
);
274 static bool audio_have_tracks(void);
275 static void audio_reset_buffer(void);
278 extern struct codec_api ci
;
279 static struct event_queue codec_queue SHAREDBSS_ATTR
;
280 static struct queue_sender_list codec_queue_sender_list
;
281 static long codec_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
283 static const char codec_thread_name
[] = "codec";
284 struct thread_entry
*codec_thread_p
; /* For modifying thread priority later. */
286 /* PCM buffer messaging */
287 static struct event_queue pcmbuf_queue SHAREDBSS_ATTR
;
289 /* Function to be called by pcm buffer callbacks.
290 * Permissible Context(s): Audio interrupt
292 static void pcmbuf_callback_queue_post(long id
, intptr_t data
)
294 /* No lock since we're already in audio interrupt context */
295 queue_post(&pcmbuf_queue
, id
, data
);
298 /* Scan the pcmbuf queue and return true if a message pulled.
299 * Permissible Context(s): Thread
301 static bool pcmbuf_queue_scan(struct queue_event
*ev
)
303 if (!queue_empty(&pcmbuf_queue
))
305 /* Transfer message to audio queue */
307 /* Pull message - never, ever any blocking call! */
308 queue_wait_w_tmo(&pcmbuf_queue
, ev
, 0);
316 /* Clear the pcmbuf queue of messages
317 * Permissible Context(s): Thread
319 static void pcmbuf_queue_clear(void)
322 queue_clear(&pcmbuf_queue
);
326 /* --- Helper functions --- */
328 static struct mp3entry
*bufgetid3(int handle_id
)
333 struct mp3entry
*id3
;
334 ssize_t ret
= bufgetdata(handle_id
, 0, (void *)&id3
);
336 if (ret
< 0 || ret
!= sizeof(struct mp3entry
))
342 static bool clear_track_info(struct track_info
*track
)
344 /* bufclose returns true if the handle is not found, or if it is closed
345 * successfully, so these checks are safe on non-existant handles */
349 if (track
->codec_hid
>= 0) {
350 if (bufclose(track
->codec_hid
))
351 track
->codec_hid
= -1;
356 if (track
->id3_hid
>= 0) {
357 if (bufclose(track
->id3_hid
))
363 if (track
->audio_hid
>= 0) {
364 if (bufclose(track
->audio_hid
))
365 track
->audio_hid
= -1;
371 if (track
->aa_hid
>= 0) {
372 if (bufclose(track
->aa_hid
))
380 track
->taginfo_ready
= false;
385 /* --- External interfaces --- */
387 /* This sends a stop message and the audio thread will dump all it's
388 subsequenct messages */
389 void audio_hard_stop(void)
392 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
393 queue_send(&audio_queue
, Q_AUDIO_STOP
, 1);
394 #ifdef PLAYBACK_VOICE
399 bool audio_restore_playback(int type
)
403 case AUDIO_WANT_PLAYBACK
:
404 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
405 audio_reset_buffer();
407 case AUDIO_WANT_VOICE
:
408 if (buffer_state
== BUFFER_STATE_TRASHED
)
409 audio_reset_buffer();
416 unsigned char *audio_get_buffer(bool talk_buf
, size_t *buffer_size
)
418 unsigned char *buf
, *end
;
420 if (audio_is_initialized
)
424 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
426 if (buffer_size
== NULL
)
428 /* Special case for talk_init to use since it already knows it's
430 buffer_state
= BUFFER_STATE_TRASHED
;
434 if (talk_buf
|| buffer_state
== BUFFER_STATE_TRASHED
435 || !talk_voice_required())
437 logf("get buffer: talk, audio");
438 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
439 the talk buffer is not needed because voice isn't being used, or
440 could be BUFFER_STATE_TRASHED already. If state is
441 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
442 without the caller knowing what's going on. Changing certain settings
443 may move it to a worse condition but the memory in use by something
444 else will remain undisturbed.
446 if (buffer_state
!= BUFFER_STATE_TRASHED
)
449 buffer_state
= BUFFER_STATE_TRASHED
;
457 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
458 still BUFFER_STATE_INITIALIZED */
459 /* Skip talk buffer and move pcm buffer to end to maximize available
460 contiguous memory - no audio running means voice will not need the
462 logf("get buffer: audio");
463 buf
= audiobuf
+ talk_get_bufsize();
464 end
= audiobufend
- pcmbuf_init(audiobufend
);
465 buffer_state
= BUFFER_STATE_VOICED_ONLY
;
468 *buffer_size
= end
- buf
;
473 #ifdef HAVE_RECORDING
474 unsigned char *audio_get_recording_buffer(size_t *buffer_size
)
476 /* Stop audio, voice and obtain all available buffer space */
480 unsigned char *end
= audiobufend
;
481 buffer_state
= BUFFER_STATE_TRASHED
;
482 *buffer_size
= end
- audiobuf
;
484 return (unsigned char *)audiobuf
;
487 bool audio_load_encoder(int afmt
)
490 const char *enc_fn
= get_codec_filename(afmt
| CODEC_TYPE_ENCODER
);
494 audio_remove_encoder();
495 ci
.enc_codec_loaded
= 0; /* clear any previous error condition */
497 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
498 queue_post(&codec_queue
, Q_ENCODER_LOAD_DISK
, (intptr_t)enc_fn
);
500 while (ci
.enc_codec_loaded
== 0)
503 logf("codec loaded: %d", ci
.enc_codec_loaded
);
505 return ci
.enc_codec_loaded
> 0;
510 } /* audio_load_encoder */
512 void audio_remove_encoder(void)
515 /* force encoder codec unload (if currently loaded) */
516 if (ci
.enc_codec_loaded
<= 0)
519 ci
.stop_encoder
= true;
520 while (ci
.enc_codec_loaded
> 0)
523 } /* audio_remove_encoder */
525 #endif /* HAVE_RECORDING */
528 int audio_current_aa_hid(void)
531 int offset
= ci
.new_track
+ wps_offset
;
533 cur_idx
= track_ridx
+ offset
;
534 cur_idx
&= MAX_TRACK_MASK
;
536 return tracks
[cur_idx
].aa_hid
;
540 struct mp3entry
* audio_current_track(void)
542 const char *filename
;
544 static struct mp3entry temp_id3
;
545 struct playlist_track_info trackinfo
;
547 int offset
= ci
.new_track
+ wps_offset
;
549 cur_idx
= (track_ridx
+ offset
) & MAX_TRACK_MASK
;
551 if (cur_idx
== track_ridx
&& *curtrack_id3
.path
)
554 return &curtrack_id3
;
556 else if (automatic_skip
&& offset
== -1 && *prevtrack_id3
.path
)
558 /* We're in a track transition. The codec has moved on to the nex track,
559 but the audio being played is still the same (now previous) track.
560 prevtrack_id3.elapsed is being updated in an ISR by
561 codec_pcmbuf_position_callback */
562 return &prevtrack_id3
;
564 else if (tracks
[cur_idx
].id3_hid
>= 0)
566 /* Get the ID3 metadata from the main buffer */
567 struct mp3entry
*ret
= bufgetid3(tracks
[cur_idx
].id3_hid
);
571 /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info
572 we have and return that. */
574 memset(&temp_id3
, 0, sizeof(struct mp3entry
));
576 playlist_get_track_info(NULL
, playlist_next(0)+wps_offset
, &trackinfo
);
577 filename
= trackinfo
.filename
;
579 filename
= "No file!";
581 #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
582 if (tagcache_fill_tags(&temp_id3
, filename
))
586 p
= strrchr(filename
, '/');
592 strncpy(temp_id3
.path
, p
, sizeof(temp_id3
.path
)-1);
593 temp_id3
.title
= &temp_id3
.path
[0];
598 struct mp3entry
* audio_next_track(void)
601 int offset
= ci
.new_track
+ wps_offset
;
603 if (!audio_have_tracks())
606 if (wps_offset
== -1 && *prevtrack_id3
.path
)
608 /* We're in a track transition. The next track for the WPS is the one
609 currently being decoded. */
610 return &curtrack_id3
;
613 next_idx
= (track_ridx
+ offset
+ 1) & MAX_TRACK_MASK
;
615 if (tracks
[next_idx
].id3_hid
>= 0)
616 return bufgetid3(tracks
[next_idx
].id3_hid
);
618 if (next_idx
== track_widx
)
620 /* The next track hasn't been buffered yet, so we return the static
621 version of its metadata. */
622 return &lasttrack_id3
;
628 bool audio_has_changed_track(void)
632 track_changed
= false;
639 void audio_play(long offset
)
643 #ifdef PLAYBACK_VOICE
644 /* Truncate any existing voice output so we don't have spelling
645 * etc. over the first part of the played track */
650 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset
);
651 /* Don't return until playback has actually started */
652 queue_send(&audio_queue
, Q_AUDIO_PLAY
, offset
);
655 void audio_stop(void)
658 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
659 /* Don't return until playback has actually stopped */
660 queue_send(&audio_queue
, Q_AUDIO_STOP
, 0);
663 void audio_pause(void)
665 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
666 /* Don't return until playback has actually paused */
667 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, true);
670 void audio_resume(void)
672 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
673 /* Don't return until playback has actually resumed */
674 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, false);
677 static void audio_skip(int direction
)
679 if (playlist_check(ci
.new_track
+ wps_offset
+ direction
))
681 if (global_settings
.beep
)
682 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
684 LOGFQUEUE("audio > audio Q_AUDIO_SKIP %d", direction
);
685 queue_post(&audio_queue
, Q_AUDIO_SKIP
, direction
);
686 /* Update wps while our message travels inside deep playback queues. */
687 wps_offset
+= direction
;
688 track_changed
= true;
692 /* No more tracks. */
693 if (global_settings
.beep
)
694 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
698 void audio_next(void)
703 void audio_prev(void)
708 void audio_next_dir(void)
710 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
711 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, 1);
714 void audio_prev_dir(void)
716 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
717 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, -1);
720 void audio_pre_ff_rewind(void)
722 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
723 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
726 void audio_ff_rewind(long newpos
)
728 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
729 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, newpos
);
732 void audio_flush_and_reload_tracks(void)
734 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
735 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
738 void audio_error_clear(void)
740 #ifdef AUDIO_HAVE_RECORDING
741 pcm_rec_error_clear();
745 int audio_status(void)
750 ret
|= AUDIO_STATUS_PLAY
;
753 ret
|= AUDIO_STATUS_PAUSE
;
755 #ifdef HAVE_RECORDING
756 /* Do this here for constitency with mpeg.c version */
757 ret
|= pcm_rec_status();
763 int audio_get_file_pos(void)
768 #ifndef HAVE_FLASH_STORAGE
769 void audio_set_buffer_margin(int setting
)
771 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
772 buffer_margin
= lookup
[setting
];
773 logf("buffer margin: %ld", (long)buffer_margin
);
774 set_filebuf_watermark(buffer_margin
, 0);
778 /* Take necessary steps to enable or disable the crossfade setting */
779 void audio_set_crossfade(int enable
)
785 /* Tell it the next setting to use */
786 pcmbuf_crossfade_enable(enable
);
788 /* Return if size hasn't changed or this is too early to determine
789 which in the second case there's no way we could be playing
791 if (pcmbuf_is_same_size())
793 /* This function is a copout and just syncs some variables -
794 to be removed at a later date */
795 pcmbuf_crossfade_enable_finished();
800 was_playing
= playing
;
802 /* Playback has to be stopped before changing the buffer size */
805 /* Store the track resume position */
806 offset
= curtrack_id3
.offset
;
807 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK
));
810 /* Blast it - audio buffer will have to be setup again next time
812 audio_get_buffer(true, &size
);
814 /* Restart playback if audio was running previously */
819 /* --- Routines called from multiple threads --- */
821 static void set_filebuf_watermark(int seconds
, size_t max
)
826 return; /* Audio buffers not yet set up */
828 bytes
= seconds
?MAX(curtrack_id3
.bitrate
* seconds
* (1000/8), max
):max
;
829 bytes
= MIN(bytes
, filebuflen
/ 2);
830 buf_set_watermark(bytes
);
833 const char *get_codec_filename(int cod_spec
)
837 #ifdef HAVE_RECORDING
838 /* Can choose decoder or encoder if one available */
839 int type
= cod_spec
& CODEC_TYPE_MASK
;
840 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
842 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
843 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
845 fname
= (type
== CODEC_TYPE_ENCODER
) ?
846 audio_formats
[afmt
].codec_enc_root_fn
:
847 audio_formats
[afmt
].codec_root_fn
;
850 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
851 afmt
, fname
? fname
: "<unknown>");
852 #else /* !HAVE_RECORDING */
854 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
855 cod_spec
= AFMT_UNKNOWN
;
856 fname
= audio_formats
[cod_spec
].codec_root_fn
;
857 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
858 #endif /* HAVE_RECORDING */
861 } /* get_codec_filename */
863 /* --- Codec thread --- */
864 static bool codec_pcmbuf_insert_callback(
865 const void *ch1
, const void *ch2
, int count
)
867 const char *src
[2] = { ch1
, ch2
};
871 int out_count
= dsp_output_count(ci
.dsp
, count
);
875 /* Prevent audio from a previous track from playing */
876 if (ci
.new_track
|| ci
.stop_codec
)
879 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
883 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
887 /* Get the real input_size for output_size bytes, guarding
888 * against resampling buffer overflows. */
889 inp_count
= dsp_input_count(ci
.dsp
, out_count
);
894 /* Input size has grown, no error, just don't write more than length */
895 if (inp_count
> count
)
898 out_count
= dsp_process(ci
.dsp
, dest
, src
, inp_count
);
903 pcmbuf_write_complete(out_count
);
909 } /* codec_pcmbuf_insert_callback */
911 static void* codec_get_memory_callback(size_t *size
)
913 *size
= MALLOC_BUFSIZE
;
917 /* Between the codec and PCM track change, we need to keep updating the
918 "elapsed" value of the previous (to the codec, but current to the
919 user/PCM/WPS) track, so that the progressbar reaches the end.
920 During that transition, the WPS will display prevtrack_id3. */
921 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
922 static void codec_pcmbuf_position_callback(size_t size
)
924 /* This is called from an ISR, so be quick */
925 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
926 prevtrack_id3
.elapsed
;
928 if (time
>= prevtrack_id3
.length
)
930 pcmbuf_set_position_callback(NULL
);
931 prevtrack_id3
.elapsed
= prevtrack_id3
.length
;
934 prevtrack_id3
.elapsed
= time
;
937 static void codec_set_elapsed_callback(unsigned int value
)
939 unsigned int latency
;
943 #ifdef AB_REPEAT_ENABLE
944 ab_position_report(value
);
947 latency
= pcmbuf_get_latency();
949 curtrack_id3
.elapsed
= 0;
950 else if (value
- latency
> curtrack_id3
.elapsed
||
951 value
- latency
< curtrack_id3
.elapsed
- 2)
953 curtrack_id3
.elapsed
= value
- latency
;
957 static void codec_set_offset_callback(size_t value
)
959 unsigned int latency
;
964 latency
= pcmbuf_get_latency() * curtrack_id3
.bitrate
/ 8;
966 curtrack_id3
.offset
= 0;
968 curtrack_id3
.offset
= value
- latency
;
971 static void codec_advance_buffer_counters(size_t amount
)
973 bufadvance(CUR_TI
->audio_hid
, amount
);
977 /* copy up-to size bytes into ptr and return the actual size copied */
978 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
982 if (ci
.stop_codec
|| !playing
)
985 copy_n
= bufread(CUR_TI
->audio_hid
, size
, ptr
);
987 /* Nothing requested OR nothing left */
991 /* Update read and other position pointers */
992 codec_advance_buffer_counters(copy_n
);
994 /* Return the actual amount of data copied to the buffer */
996 } /* codec_filebuf_callback */
998 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1000 size_t copy_n
= reqsize
;
1010 ret
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, &ptr
);
1012 copy_n
= MIN((size_t)ret
, reqsize
);
1023 } /* codec_request_buffer_callback */
1025 static int get_codec_base_type(int type
)
1037 static void codec_advance_buffer_callback(size_t amount
)
1039 codec_advance_buffer_counters(amount
);
1040 codec_set_offset_callback(ci
.curpos
);
1043 static void codec_advance_buffer_loc_callback(void *ptr
)
1045 size_t amount
= buf_get_offset(CUR_TI
->audio_hid
, ptr
);
1046 codec_advance_buffer_callback(amount
);
1049 static void codec_seek_complete_callback(void)
1051 logf("seek_complete");
1052 if (pcm_is_paused())
1054 /* If this is not a seamless seek, clear the buffer */
1056 dsp_configure(ci
.dsp
, DSP_FLUSH
, 0);
1058 /* If playback was not 'deliberately' paused, unpause now */
1060 pcmbuf_pause(false);
1065 static bool codec_seek_buffer_callback(size_t newpos
)
1067 logf("codec_seek_buffer_callback");
1069 int ret
= bufseek(CUR_TI
->audio_hid
, newpos
);
1079 static void codec_configure_callback(int setting
, intptr_t value
)
1082 case CODEC_SET_FILEBUF_WATERMARK
:
1083 set_filebuf_watermark(buffer_margin
, value
);
1087 if (!dsp_configure(ci
.dsp
, setting
, value
))
1088 { logf("Illegal key:%d", setting
); }
1092 static void codec_track_changed(void)
1094 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1095 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1098 static void codec_pcmbuf_track_changed_callback(void)
1100 pcmbuf_set_position_callback(NULL
);
1101 pcmbuf_callback_queue_post(Q_AUDIO_TRACK_CHANGED
, 0);
1104 static void codec_discard_codec_callback(void)
1106 if (CUR_TI
->codec_hid
>= 0)
1108 bufclose(CUR_TI
->codec_hid
);
1109 CUR_TI
->codec_hid
= -1;
1113 static inline void codec_gapless_track_change(void)
1115 /* callback keeps the progress bar moving while the pcmbuf empties */
1116 pcmbuf_set_position_callback(codec_pcmbuf_position_callback
);
1117 /* set the pcmbuf callback for when the track really changes */
1118 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1121 static inline void codec_crossfade_track_change(void)
1123 /* Initiate automatic crossfade mode */
1124 pcmbuf_crossfade_init(false);
1125 /* Notify the wps that the track change starts now */
1126 codec_track_changed();
1129 static void codec_track_skip_done(bool was_manual
)
1131 /* Manual track change (always crossfade or flush audio). */
1134 pcmbuf_crossfade_init(true);
1135 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1136 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1138 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1139 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1140 && global_settings
.crossfade
!= CROSSFADE_ENABLE_TRACKSKIP
)
1142 if (global_settings
.crossfade
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1144 if (global_settings
.playlist_shuffle
)
1145 /* shuffle mode is on, so crossfade: */
1146 codec_crossfade_track_change();
1148 /* shuffle mode is off, so do a gapless track change */
1149 codec_gapless_track_change();
1152 /* normal crossfade: */
1153 codec_crossfade_track_change();
1156 /* normal gapless playback. */
1157 codec_gapless_track_change();
1160 static bool codec_load_next_track(void)
1162 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1164 prev_track_elapsed
= curtrack_id3
.elapsed
;
1166 #ifdef AB_REPEAT_ENABLE
1167 ab_end_of_track_report();
1170 logf("Request new track");
1172 if (ci
.new_track
== 0)
1175 automatic_skip
= true;
1180 trigger_cpu_boost();
1181 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1182 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1187 case Q_CODEC_REQUEST_COMPLETE
:
1188 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1189 codec_track_skip_done(!automatic_skip
);
1192 case Q_CODEC_REQUEST_FAILED
:
1193 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1195 ci
.stop_codec
= true;
1196 codec_requested_stop
= true;
1200 LOGFQUEUE("codec |< default");
1201 ci
.stop_codec
= true;
1202 codec_requested_stop
= true;
1207 static bool codec_request_next_track_callback(void)
1211 if (ci
.stop_codec
|| !playing
)
1214 prev_codectype
= get_codec_base_type(curtrack_id3
.codectype
);
1216 if (!codec_load_next_track())
1219 /* Seek to the beginning of the new track because if the struct
1220 mp3entry was buffered, "elapsed" might not be zero (if the track has
1221 been played already but not unbuffered) */
1222 codec_seek_buffer_callback(curtrack_id3
.first_frame_offset
);
1224 /* Check if the next codec is the same file. */
1225 if (prev_codectype
== get_codec_base_type(curtrack_id3
.codectype
))
1227 logf("New track loaded");
1228 codec_discard_codec_callback();
1233 logf("New codec:%d/%d", curtrack_id3
.codectype
, prev_codectype
);
1238 static void codec_thread(void)
1240 struct queue_event ev
;
1246 if (!pcmbuf_is_crossfade_active()) {
1250 queue_wait(&codec_queue
, &ev
);
1251 codec_requested_stop
= false;
1254 case Q_CODEC_LOAD_DISK
:
1255 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1256 queue_reply(&codec_queue
, 1);
1257 audio_codec_loaded
= true;
1258 ci
.stop_codec
= false;
1259 status
= codec_load_file((const char *)ev
.data
, &ci
);
1263 LOGFQUEUE("codec < Q_CODEC_LOAD");
1264 if (CUR_TI
->codec_hid
< 0) {
1265 logf("Codec slot is empty!");
1266 /* Wait for the pcm buffer to go empty */
1267 while (pcm_is_playing())
1269 /* This must be set to prevent an infinite loop */
1270 ci
.stop_codec
= true;
1271 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1272 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
1276 audio_codec_loaded
= true;
1277 ci
.stop_codec
= false;
1278 status
= codec_load_buf(CUR_TI
->codec_hid
, &ci
);
1281 #ifdef AUDIO_HAVE_RECORDING
1282 case Q_ENCODER_LOAD_DISK
:
1283 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1284 audio_codec_loaded
= false; /* Not audio codec! */
1285 logf("loading encoder");
1286 ci
.stop_encoder
= false;
1287 status
= codec_load_file((const char *)ev
.data
, &ci
);
1288 logf("encoder stopped");
1290 #endif /* AUDIO_HAVE_RECORDING */
1293 LOGFQUEUE("codec < default");
1296 if (audio_codec_loaded
)
1305 audio_codec_loaded
= false;
1309 case Q_CODEC_LOAD_DISK
:
1311 LOGFQUEUE("codec < Q_CODEC_LOAD");
1314 if (ci
.new_track
|| status
!= CODEC_OK
)
1318 logf("Codec failure");
1319 gui_syncsplash(HZ
*2, "Codec failure");
1322 if (!codec_load_next_track())
1324 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1325 /* End of playlist */
1326 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1332 logf("Codec finished");
1335 /* Wait for the audio to stop playing before
1336 * triggering the WPS exit */
1337 while(pcm_is_playing())
1339 curtrack_id3
.elapsed
=
1340 curtrack_id3
.length
- pcmbuf_get_latency();
1344 if (codec_requested_stop
)
1346 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
1347 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
1353 if (CUR_TI
->codec_hid
>= 0)
1355 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
1356 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
1360 const char *codec_fn
=
1361 get_codec_filename(curtrack_id3
.codectype
);
1364 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1365 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
1366 (intptr_t)codec_fn
);
1372 #ifdef AUDIO_HAVE_RECORDING
1373 case Q_ENCODER_LOAD_DISK
:
1374 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1376 if (status
== CODEC_OK
)
1379 logf("Encoder failure");
1380 gui_syncsplash(HZ
*2, "Encoder failure");
1382 if (ci
.enc_codec_loaded
< 0)
1385 logf("Encoder failed to load");
1386 ci
.enc_codec_loaded
= -1;
1388 #endif /* AUDIO_HAVE_RECORDING */
1391 LOGFQUEUE("codec < default");
1398 /* --- Buffering callbacks --- */
1400 static void buffering_low_buffer_callback(void *data
)
1403 logf("low buffer callback");
1405 if (filling
== STATE_FULL
) {
1406 /* force a refill */
1407 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
1408 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1412 static void buffering_handle_rebuffer_callback(void *data
)
1415 LOGFQUEUE("audio >| audio Q_AUDIO_FLUSH");
1416 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
1419 static void buffering_handle_finished_callback(int *data
)
1421 logf("handle %d finished buffering", *data
);
1423 if (*data
== tracks
[track_widx
].id3_hid
)
1425 /* The metadata handle for the last loaded track has been buffered.
1426 We can ask the audio thread to load the rest of the track's data. */
1427 LOGFQUEUE("audio >| audio Q_AUDIO_FINISH_LOAD");
1428 queue_post(&audio_queue
, Q_AUDIO_FINISH_LOAD
, 0);
1432 /* This is most likely an audio handle, so we strip the useless
1433 trailing tags that are left. */
1439 /* --- Audio thread --- */
1441 static bool audio_have_tracks(void)
1443 return (audio_track_count() != 0);
1446 static int audio_free_track_count(void)
1448 /* Used tracks + free tracks adds up to MAX_TRACK - 1 */
1449 return MAX_TRACK
- 1 - audio_track_count();
1452 int audio_track_count(void)
1454 /* Calculate difference from track_ridx to track_widx
1455 * taking into account a possible wrap-around. */
1456 return (MAX_TRACK
+ track_widx
- track_ridx
) & MAX_TRACK_MASK
;
1459 long audio_filebufused(void)
1461 return (long) buf_used();
1464 /* Update track info after successful a codec track change */
1465 static void audio_update_trackinfo(void)
1467 /* Load the curent track's metadata into curtrack_id3 */
1468 if (CUR_TI
->id3_hid
>= 0)
1469 copy_mp3entry(&curtrack_id3
, bufgetid3(CUR_TI
->id3_hid
));
1471 /* Reset current position */
1472 curtrack_id3
.elapsed
= 0;
1473 curtrack_id3
.offset
= 0;
1475 /* Update the codec API */
1476 ci
.filesize
= CUR_TI
->filesize
;
1477 ci
.id3
= &curtrack_id3
;
1479 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
1482 /* Clear tracks between write and read, non inclusive */
1483 static void audio_clear_track_entries(void)
1485 int cur_idx
= track_widx
;
1487 logf("Clearing tracks:%d/%d", track_ridx
, track_widx
);
1489 /* Loop over all tracks from write-to-read */
1492 cur_idx
= (cur_idx
+ 1) & MAX_TRACK_MASK
;
1494 if (cur_idx
== track_ridx
)
1497 clear_track_info(&tracks
[cur_idx
]);
1501 /* Clear all tracks */
1502 static bool audio_release_tracks(void)
1506 logf("releasing all tracks");
1508 for(i
= 0; i
< MAX_TRACK
; i
++)
1510 cur_idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
1511 if (!clear_track_info(&tracks
[cur_idx
]))
1518 static bool audio_loadcodec(bool start_play
)
1521 char codec_path
[MAX_PATH
]; /* Full path to codec */
1522 const struct mp3entry
*id3
, *prev_id3
;
1524 if (tracks
[track_widx
].id3_hid
< 0) {
1528 id3
= bufgetid3(tracks
[track_widx
].id3_hid
);
1532 const char *codec_fn
= get_codec_filename(id3
->codectype
);
1533 if (codec_fn
== NULL
)
1536 tracks
[track_widx
].codec_hid
= -1;
1540 /* Load the codec directly from disk and save some memory. */
1541 track_ridx
= track_widx
;
1542 ci
.filesize
= CUR_TI
->filesize
;
1543 ci
.id3
= &curtrack_id3
;
1544 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
1546 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
1547 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
1552 /* If we already have another track than this one buffered */
1553 if (track_widx
!= track_ridx
)
1555 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
1557 id3
= bufgetid3(tracks
[track_widx
].id3_hid
);
1558 prev_id3
= bufgetid3(tracks
[prev_track
].id3_hid
);
1560 /* If the previous codec is the same as this one, there is no need
1561 * to put another copy of it on the file buffer */
1562 if (id3
&& prev_id3
&&
1563 get_codec_base_type(id3
->codectype
) ==
1564 get_codec_base_type(prev_id3
->codectype
)
1565 && audio_codec_loaded
)
1567 logf("Reusing prev. codec");
1573 codec_get_full_path(codec_path
, codec_fn
);
1575 tracks
[track_widx
].codec_hid
= bufopen(codec_path
, 0, TYPE_CODEC
);
1576 if (tracks
[track_widx
].codec_hid
< 0)
1579 logf("Loaded codec");
1584 /* Load metadata for the next track (with bufopen). The rest of the track
1585 loading will be handled by audio_finish_load_track once the metadata has been
1586 actually loaded by the buffering thread. */
1587 static bool audio_load_track(size_t offset
, bool start_play
)
1589 const char *trackname
;
1592 start_play_g
= start_play
; /* will be read by audio_finish_load_track */
1594 /* Stop buffer filling if there is no free track entries.
1595 Don't fill up the last track entry (we wan't to store next track
1597 if (!audio_free_track_count())
1599 logf("No free tracks");
1604 tracks
[track_widx
].taginfo_ready
= false;
1606 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
1607 /* Get track name from current playlist read position. */
1608 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
1610 /* Handle broken playlists. */
1611 fd
= open(trackname
, O_RDONLY
);
1614 logf("Open failed");
1615 /* Skip invalid entry from playlist. */
1616 playlist_skip_entry(NULL
, last_peek_offset
);
1624 logf("End-of-playlist");
1625 memset(&lasttrack_id3
, 0, sizeof(struct mp3entry
));
1626 filling
= STATE_FINISHED
;
1630 tracks
[track_widx
].filesize
= filesize(fd
);
1632 if (offset
> tracks
[track_widx
].filesize
)
1635 /* Set default values */
1638 buf_set_watermark(AUDIO_DEFAULT_WATERMARK
);
1639 dsp_configure(ci
.dsp
, DSP_RESET
, 0);
1640 track_changed
= true;
1641 playlist_update_resume_info(audio_current_track());
1644 /* Get track metadata if we don't already have it. */
1645 if (tracks
[track_widx
].id3_hid
< 0)
1647 tracks
[track_widx
].id3_hid
= bufopen(trackname
, 0, TYPE_ID3
);
1649 if (tracks
[track_widx
].id3_hid
< 0)
1651 /* Buffer is full. */
1652 get_metadata(&lasttrack_id3
, fd
, trackname
);
1655 logf("buffer is full for now");
1656 filling
= STATE_FULL
;
1660 if (track_widx
== track_ridx
)
1662 buf_request_buffer_handle(tracks
[track_widx
].id3_hid
);
1663 copy_mp3entry(&curtrack_id3
, bufgetid3(tracks
[track_widx
].id3_hid
));
1664 curtrack_id3
.offset
= offset
;
1669 track_changed
= true;
1670 playlist_update_resume_info(audio_current_track());
1678 /* Second part of the track loading: We now have the metadata available, so we
1679 can load the codec, the album art and finally the audio data.
1680 This is called on the audio thread after the buffering thread calls the
1681 buffering_handle_finished_callback callback. */
1682 static void audio_finish_load_track(void)
1685 size_t file_offset
= 0;
1687 bool start_play
= start_play_g
;
1690 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
1692 char cuepath
[MAX_PATH
];
1694 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
1696 if (look_for_cuesheet_file(trackname
, cuepath
) &&
1697 parse_cuesheet(cuepath
, cue
))
1699 strcpy((cue
)->audio_filename
, trackname
);
1701 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
1706 if (tracks
[track_widx
].id3_hid
< 0) {
1707 logf("no metatdata");
1711 struct mp3entry
*track_id3
;
1713 if (track_widx
== track_ridx
)
1714 track_id3
= &curtrack_id3
;
1716 track_id3
= bufgetid3(tracks
[track_widx
].id3_hid
);
1718 if (track_id3
->length
== 0 && track_id3
->filesize
== 0)
1720 logf("audio_finish_load_track: invalid metadata");
1722 /* Invalid metadata */
1723 bufclose(tracks
[track_widx
].id3_hid
);
1724 tracks
[track_widx
].id3_hid
= -1;
1726 /* Skip invalid entry from playlist. */
1727 playlist_skip_entry(NULL
, last_peek_offset
--);
1729 /* load next track */
1730 LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER %d", (int)start_play
);
1731 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, start_play
);
1736 #ifdef HAVE_ALBUMART
1737 if (tracks
[track_widx
].aa_hid
< 0 && gui_sync_wps_uses_albumart())
1739 char aa_path
[MAX_PATH
];
1740 if (find_albumart(track_id3
, aa_path
, sizeof(aa_path
)))
1741 tracks
[track_widx
].aa_hid
= bufopen(aa_path
, 0, TYPE_BITMAP
);
1745 /* Load the codec. */
1746 if (!audio_loadcodec(start_play
))
1748 if (tracks
[track_widx
].codec_hid
== ERR_BUFFER_FULL
)
1750 /* No space for codec on buffer, not an error */
1754 /* This is an error condition, either no codec was found, or reading
1755 * the codec file failed part way through, either way, skip the track */
1756 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", track_id3
->path
);
1757 /* We should not use gui_syncplash from audio thread! */
1758 gui_syncsplash(HZ
*2, msgbuf
);
1759 /* Skip invalid entry from playlist. */
1760 playlist_skip_entry(NULL
, last_peek_offset
);
1764 track_id3
->elapsed
= 0;
1765 offset
= track_id3
->offset
;
1767 enum data_type type
= TYPE_PACKET_AUDIO
;
1769 switch (track_id3
->codectype
) {
1774 file_offset
= offset
;
1775 track_id3
->offset
= offset
;
1781 file_offset
= offset
;
1782 track_id3
->offset
= offset
;
1783 track_id3
->elapsed
= track_id3
->length
/ 2;
1787 case AFMT_OGG_VORBIS
:
1797 track_id3
->offset
= offset
;
1803 logf("Loading atomic %d",track_id3
->codectype
);
1804 type
= TYPE_ATOMIC_AUDIO
;
1808 logf("alt:%s", track_id3
->path
);
1810 if (file_offset
> AUDIO_REBUFFER_GUESS_SIZE
)
1811 file_offset
-= AUDIO_REBUFFER_GUESS_SIZE
;
1812 else if (track_id3
->first_frame_offset
)
1813 file_offset
= track_id3
->first_frame_offset
;
1817 tracks
[track_widx
].audio_hid
= bufopen(track_id3
->path
, file_offset
, type
);
1819 if (tracks
[track_widx
].audio_hid
< 0)
1822 /* All required data is now available for the codec. */
1823 tracks
[track_widx
].taginfo_ready
= true;
1827 ci
.curpos
=file_offset
;
1828 buf_request_buffer_handle(tracks
[track_widx
].audio_hid
);
1831 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
1833 send_event(PLAYBACK_EVENT_TRACK_BUFFER
, track_id3
);
1835 /* load next track */
1836 LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER");
1837 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
1842 static void audio_fill_file_buffer(bool start_play
, size_t offset
)
1844 bool had_next_track
= audio_next_track() != NULL
;
1846 filling
= STATE_FILLING
;
1847 trigger_cpu_boost();
1849 /* No need to rebuffer if there are track skips pending. */
1850 if (ci
.new_track
!= 0)
1853 /* Must reset the buffer before use if trashed or voice only - voice
1854 file size shouldn't have changed so we can go straight from
1855 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
1856 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
1857 audio_reset_buffer();
1859 logf("Starting buffer fill");
1862 audio_clear_track_entries();
1864 /* Save the current resume position once. */
1865 playlist_update_resume_info(audio_current_track());
1867 audio_load_track(offset
, start_play
);
1869 if (!had_next_track
&& audio_next_track())
1870 track_changed
= true;
1873 static void audio_rebuffer(void)
1875 logf("Forcing rebuffer");
1877 clear_track_info(CUR_TI
);
1879 /* Reset track pointers */
1880 track_widx
= track_ridx
;
1881 audio_clear_track_entries();
1883 /* Fill the buffer */
1884 last_peek_offset
= -1;
1887 if (!CUR_TI
->taginfo_ready
)
1888 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
1890 audio_fill_file_buffer(false, 0);
1893 /* Called on request from the codec to get a new track. This is the codec part
1894 of the track transition. */
1895 static int audio_check_new_track(void)
1897 int track_count
= audio_track_count();
1898 int old_track_ridx
= track_ridx
;
1902 /* Now it's good time to send track finish events. */
1903 send_event(PLAYBACK_EVENT_TRACK_FINISH
, &curtrack_id3
);
1907 if (playlist_next_dir(ci
.new_track
))
1915 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1916 return Q_CODEC_REQUEST_FAILED
;
1923 /* If the playlist isn't that big */
1926 while (!playlist_check(ci
.new_track
))
1928 if (ci
.new_track
>= 0)
1930 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1931 return Q_CODEC_REQUEST_FAILED
;
1937 /* Update the playlist */
1938 last_peek_offset
-= ci
.new_track
;
1940 if (playlist_next(ci
.new_track
) < 0)
1942 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
1943 return Q_CODEC_REQUEST_FAILED
;
1949 new_playlist
= false;
1952 /* Save the track metadata to allow the WPS to display it
1953 while PCM finishes playing that track */
1954 copy_mp3entry(&prevtrack_id3
, &curtrack_id3
);
1956 /* Update the main buffer copy of the track metadata with the one
1957 the codec has been using (for the unbuffer callbacks) */
1958 if (CUR_TI
->id3_hid
>= 0)
1959 copy_mp3entry(bufgetid3(CUR_TI
->id3_hid
), &curtrack_id3
);
1961 /* Save a pointer to the old track to allow later clearing */
1964 for (i
= 0; i
< ci
.new_track
; i
++)
1966 idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
1967 struct mp3entry
*id3
= bufgetid3(tracks
[idx
].id3_hid
);
1968 ssize_t offset
= buf_handle_offset(tracks
[idx
].audio_hid
);
1969 if (!id3
|| offset
< 0 || (unsigned)offset
> id3
->first_frame_offset
)
1971 /* We don't have all the audio data for that track, so clear it,
1972 but keep the metadata. */
1973 if (tracks
[idx
].audio_hid
>= 0 && bufclose(tracks
[idx
].audio_hid
))
1975 tracks
[idx
].audio_hid
= -1;
1976 tracks
[idx
].filesize
= 0;
1981 /* Move to the new track */
1982 track_ridx
= (track_ridx
+ ci
.new_track
) & MAX_TRACK_MASK
;
1984 buf_set_base_handle(CUR_TI
->audio_hid
);
1988 wps_offset
= -ci
.new_track
;
1989 track_changed
= true;
1992 /* If it is not safe to even skip this many track entries */
1993 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
2000 forward
= ci
.new_track
> 0;
2003 /* If the target track is clearly not in memory */
2004 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
2010 /* When skipping backwards, it is possible that we've found a track that's
2011 * buffered, but which is around the track-wrap and therefore not the track
2012 * we are looking for */
2015 int cur_idx
= track_ridx
;
2016 bool taginfo_ready
= true;
2017 /* We've wrapped the buffer backwards if new > old */
2018 bool wrap
= track_ridx
> old_track_ridx
;
2022 cur_idx
= (cur_idx
+ 1) & MAX_TRACK_MASK
;
2024 /* if we've advanced past the wrap when cur_idx is zeroed */
2028 /* if we aren't still on the wrap and we've caught the old track */
2029 if (!(wrap
|| cur_idx
< old_track_ridx
))
2032 /* If we hit a track in between without valid tag info, bail */
2033 if (!tracks
[cur_idx
].taginfo_ready
)
2035 taginfo_ready
= false;
2046 audio_update_trackinfo();
2047 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2048 return Q_CODEC_REQUEST_COMPLETE
;
2051 unsigned long audio_prev_elapsed(void)
2053 return prev_track_elapsed
;
2056 static void audio_stop_codec_flush(void)
2058 ci
.stop_codec
= true;
2061 while (audio_codec_loaded
)
2064 /* If the audio codec is not loaded any more, and the audio is still
2065 * playing, it is now and _only_ now safe to call this function from the
2067 if (pcm_is_playing())
2070 pcmbuf_queue_clear();
2072 pcmbuf_pause(paused
);
2075 static void audio_stop_playback(void)
2077 /* If we were playing, save resume information */
2080 struct mp3entry
*id3
= NULL
;
2084 /* Set this early, the outside code yields and may allow the codec
2085 to try to wait for a reply on a buffer wait */
2086 ci
.stop_codec
= true;
2087 id3
= audio_current_track();
2090 /* Save the current playing spot, or NULL if the playlist has ended */
2091 playlist_update_resume_info(id3
);
2093 /* TODO: Create auto bookmark too? */
2095 prev_track_elapsed
= curtrack_id3
.elapsed
;
2097 remove_event(EVENT_BUFFER_LOW
, buffering_low_buffer_callback
);
2101 audio_stop_codec_flush();
2104 filling
= STATE_IDLE
;
2106 /* Mark all entries null. */
2107 audio_clear_track_entries();
2109 /* Close all tracks */
2110 audio_release_tracks();
2112 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
2115 static void audio_play_start(size_t offset
)
2119 #if INPUT_SRC_CAPS != 0
2120 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
2121 audio_set_output_source(AUDIO_SRC_PLAYBACK
);
2124 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2126 audio_stop_codec_flush();
2128 track_changed
= true;
2136 sound_set_volume(global_settings
.volume
);
2137 track_widx
= track_ridx
= 0;
2139 /* Clear all track entries. */
2140 for (i
= 0; i
< MAX_TRACK
; i
++) {
2141 clear_track_info(&tracks
[i
]);
2144 last_peek_offset
= -1;
2146 /* Officially playing */
2147 queue_reply(&audio_queue
, 1);
2149 #ifndef HAVE_FLASH_STORAGE
2150 set_filebuf_watermark(buffer_margin
, 0);
2153 audio_fill_file_buffer(true, offset
);
2155 add_event(EVENT_BUFFER_LOW
, false, buffering_low_buffer_callback
);
2157 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2158 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
2162 /* Invalidates all but currently playing track. */
2163 static void audio_invalidate_tracks(void)
2165 if (audio_have_tracks())
2167 last_peek_offset
= 0;
2168 track_widx
= track_ridx
;
2170 /* Mark all other entries null (also buffered wrong metadata). */
2171 audio_clear_track_entries();
2173 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
2175 audio_fill_file_buffer(false, 0);
2179 static void audio_new_playlist(void)
2181 /* Prepare to start a new fill from the beginning of the playlist */
2182 last_peek_offset
= -1;
2183 if (audio_have_tracks())
2186 skipped_during_pause
= true;
2187 track_widx
= track_ridx
;
2188 audio_clear_track_entries();
2190 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
2192 /* Mark the current track as invalid to prevent skipping back to it */
2193 CUR_TI
->taginfo_ready
= false;
2196 /* Signal the codec to initiate a track change forward */
2197 new_playlist
= true;
2200 /* Officially playing */
2201 queue_reply(&audio_queue
, 1);
2203 audio_fill_file_buffer(false, 0);
2206 /* Called on manual track skip */
2207 static void audio_initiate_track_change(long direction
)
2209 logf("audio_initiate_track_change(%ld)", direction
);
2211 ci
.new_track
+= direction
;
2212 wps_offset
-= direction
;
2214 skipped_during_pause
= true;
2217 /* Called on manual dir skip */
2218 static void audio_initiate_dir_change(long direction
)
2221 ci
.new_track
= direction
;
2223 skipped_during_pause
= true;
2226 /* Called when PCM track change is complete */
2227 static void audio_finalise_track_change(void)
2229 logf("audio_finalise_track_change");
2234 automatic_skip
= false;
2236 /* Invalidate prevtrack_id3 */
2237 prevtrack_id3
.path
[0] = 0;
2239 if (prev_ti
&& prev_ti
->audio_hid
< 0)
2241 /* No audio left so we clear all the track info. */
2242 clear_track_info(prev_ti
);
2245 if (prev_ti
&& prev_ti
->id3_hid
>= 0)
2247 /* Reset the elapsed time to force the progressbar to be empty if
2248 the user skips back to this track */
2249 bufgetid3(prev_ti
->id3_hid
)->elapsed
= 0;
2253 send_event(PLAYBACK_EVENT_TRACK_CHANGE
, &curtrack_id3
);
2255 track_changed
= true;
2256 playlist_update_resume_info(audio_current_track());
2260 * Layout audio buffer as follows - iram buffer depends on target:
2261 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
2263 static void audio_reset_buffer(void)
2265 /* see audio_get_recording_buffer if this is modified */
2266 logf("audio_reset_buffer");
2268 /* If the setup of anything allocated before the file buffer is
2269 changed, do check the adjustments after the buffer_alloc call
2270 as it will likely be affected and need sliding over */
2272 /* Initially set up file buffer as all space available */
2273 malloc_buf
= audiobuf
+ talk_get_bufsize();
2274 /* Align the malloc buf to line size. Especially important to cf
2275 targets that do line reads/writes. */
2276 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
2277 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
2278 filebuflen
= audiobufend
- filebuf
;
2282 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
2283 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
2285 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
2286 will already be line aligned */
2289 buffering_reset(filebuf
, filebuflen
);
2291 /* Clear any references to the file buffer */
2292 buffer_state
= BUFFER_STATE_INITIALIZED
;
2294 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
2295 /* Make sure everything adds up - yes, some info is a bit redundant but
2296 aids viewing and the sumation of certain variables should add up to
2297 the location of others. */
2300 const unsigned char *pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
2301 logf("mabuf: %08X", (unsigned)malloc_buf
);
2302 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
2303 logf("fbuf: %08X", (unsigned)filebuf
);
2304 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
2305 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
2306 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
2307 logf("pcmb: %08X", (unsigned)pcmbuf
);
2308 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
2313 static void audio_thread(void)
2315 struct queue_event ev
;
2319 audio_thread_ready
= true;
2323 if (filling
!= STATE_FILLING
) {
2327 if (!pcmbuf_queue_scan(&ev
))
2328 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
2332 case Q_AUDIO_FILL_BUFFER
:
2333 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER %d", (int)ev
.data
);
2334 audio_fill_file_buffer((bool)ev
.data
, 0);
2337 case Q_AUDIO_FINISH_LOAD
:
2338 LOGFQUEUE("audio < Q_AUDIO_FINISH_LOAD");
2339 audio_finish_load_track();
2343 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2344 if (playing
&& ev
.data
<= 0)
2345 audio_new_playlist();
2348 audio_stop_playback();
2349 audio_play_start((size_t)ev
.data
);
2354 LOGFQUEUE("audio < Q_AUDIO_STOP");
2356 audio_stop_playback();
2358 queue_clear(&audio_queue
);
2362 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
2363 if (!(bool) ev
.data
&& skipped_during_pause
&& !pcmbuf_is_crossfade_active())
2364 pcmbuf_play_stop(); /* Flush old track on resume after skip */
2365 skipped_during_pause
= false;
2368 pcmbuf_pause((bool)ev
.data
);
2369 paused
= (bool)ev
.data
;
2373 LOGFQUEUE("audio < Q_AUDIO_SKIP");
2374 audio_initiate_track_change((long)ev
.data
);
2377 case Q_AUDIO_PRE_FF_REWIND
:
2378 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
2384 case Q_AUDIO_FF_REWIND
:
2385 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
2390 /* An automatic track skip is in progress. Finalize it,
2391 then go back to the previous track */
2392 audio_finalise_track_change();
2395 ci
.seek_time
= (long)ev
.data
+1;
2398 case Q_AUDIO_CHECK_NEW_TRACK
:
2399 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
2400 queue_reply(&audio_queue
, audio_check_new_track());
2403 case Q_AUDIO_DIR_SKIP
:
2404 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2405 audio_initiate_dir_change(ev
.data
);
2409 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
2410 audio_invalidate_tracks();
2413 case Q_AUDIO_TRACK_CHANGED
:
2414 /* PCM track change done */
2415 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2416 audio_finalise_track_change();
2420 case SYS_USB_CONNECTED
:
2421 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2423 audio_stop_playback();
2424 #ifdef PLAYBACK_VOICE
2427 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
2428 usb_wait_for_disconnect(&audio_queue
);
2430 /* Mark all entries null. */
2431 audio_clear_track_entries();
2433 /* release tracks to make sure all handles are closed */
2434 audio_release_tracks();
2439 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
2443 LOGFQUEUE("audio < default");
2449 /* Initialize the audio system - called from init() in main.c.
2450 * Last function because of all the references to internal symbols
2452 void audio_init(void)
2454 struct thread_entry
*audio_thread_p
;
2456 /* Can never do this twice */
2457 if (audio_is_initialized
)
2459 logf("audio: already initialized");
2463 logf("audio: initializing");
2465 /* Initialize queues before giving control elsewhere in case it likes
2466 to send messages. Thread creation will be delayed however so nothing
2467 starts running until ready if something yields such as talk_init. */
2468 queue_init(&audio_queue
, true);
2469 queue_init(&codec_queue
, false);
2470 queue_init(&pcmbuf_queue
, false);
2474 /* Initialize codec api. */
2475 ci
.read_filebuf
= codec_filebuf_callback
;
2476 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
2477 ci
.get_codec_memory
= codec_get_memory_callback
;
2478 ci
.request_buffer
= codec_request_buffer_callback
;
2479 ci
.advance_buffer
= codec_advance_buffer_callback
;
2480 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
2481 ci
.request_next_track
= codec_request_next_track_callback
;
2482 ci
.seek_buffer
= codec_seek_buffer_callback
;
2483 ci
.seek_complete
= codec_seek_complete_callback
;
2484 ci
.set_elapsed
= codec_set_elapsed_callback
;
2485 ci
.set_offset
= codec_set_offset_callback
;
2486 ci
.configure
= codec_configure_callback
;
2487 ci
.discard_codec
= codec_discard_codec_callback
;
2488 ci
.dsp
= (struct dsp_config
*)dsp_configure(NULL
, DSP_MYDSP
,
2491 /* initialize the buffer */
2494 /* audio_reset_buffer must to know the size of voice buffer so init
2498 codec_thread_p
= create_thread(
2499 codec_thread
, codec_stack
, sizeof(codec_stack
),
2500 CREATE_THREAD_FROZEN
,
2501 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
2504 queue_enable_queue_send(&codec_queue
, &codec_queue_sender_list
,
2507 audio_thread_p
= create_thread(audio_thread
, audio_stack
,
2508 sizeof(audio_stack
), CREATE_THREAD_FROZEN
,
2509 audio_thread_name
IF_PRIO(, PRIORITY_USER_INTERFACE
)
2512 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
,
2515 #ifdef PLAYBACK_VOICE
2516 voice_thread_init();
2519 /* Set crossfade setting for next buffer init which should be about... */
2520 pcmbuf_crossfade_enable(global_settings
.crossfade
);
2522 /* initialize the buffering system */
2525 /* ...now! Set up the buffers */
2526 audio_reset_buffer();
2529 for(i
= 0; i
< MAX_TRACK
; i
++)
2531 tracks
[i
].audio_hid
= -1;
2532 tracks
[i
].id3_hid
= -1;
2533 tracks
[i
].codec_hid
= -1;
2534 #ifdef HAVE_ALBUMART
2535 tracks
[i
].aa_hid
= -1;
2539 add_event(EVENT_HANDLE_REBUFFER
, false, buffering_handle_rebuffer_callback
);
2540 add_event(EVENT_HANDLE_FINISHED
, false, buffering_handle_finished_callback
);
2542 /* Probably safe to say */
2543 audio_is_initialized
= true;
2545 sound_settings_apply();
2546 #ifndef HAVE_FLASH_STORAGE
2547 audio_set_buffer_margin(global_settings
.buffer_margin
);
2550 /* it's safe to let the threads run now */
2551 #ifdef PLAYBACK_VOICE
2552 voice_thread_resume();
2554 thread_thaw(codec_thread_p
);
2555 thread_thaw(audio_thread_p
);
2559 void audio_wait_for_init(void)
2561 /* audio thread will only set this once after it finished the final
2562 * audio hardware init so this little construct is safe - even
2564 while (!audio_thread_ready
)