From 5ce8e2cb0d2361606f3646e9fa59a39393500ba8 Mon Sep 17 00:00:00 2001 From: Jeffrey Goode Date: Wed, 4 Nov 2009 03:58:33 +0000 Subject: Clarify track transition code in pcmbuf and playback. No functional changes yet. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23506 a1c6a512-1295-4272-9138-f99709370657 --- apps/codec_thread.c | 44 ++-------------------------- apps/pcmbuf.c | 82 ++++++++++++++++++++++++++++++++++------------------- apps/pcmbuf.h | 3 +- apps/playback.c | 40 +++++++++++++++++--------- apps/playback.h | 1 + 5 files changed, 85 insertions(+), 85 deletions(-) diff --git a/apps/codec_thread.c b/apps/codec_thread.c index d4217c3789..affb560183 100644 --- a/apps/codec_thread.c +++ b/apps/codec_thread.c @@ -416,46 +416,8 @@ void codec_init_codec_api(void) } -/** pcmbuf track change callbacks */ - -/* Between the codec and PCM track change, we need to keep updating the - "elapsed" value of the previous (to the codec, but current to the - user/PCM/WPS) track, so that the progressbar reaches the end. - During that transition, the WPS will display prevtrack_id3. */ -static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR; -static void codec_pcmbuf_position_callback(size_t size) -{ - /* This is called from an ISR, so be quick */ - unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY + - othertrack_id3->elapsed; - - if (time >= othertrack_id3->length) - { - pcmbuf_set_position_callback(NULL); - othertrack_id3->elapsed = othertrack_id3->length; - } - else - othertrack_id3->elapsed = time; -} - -static void codec_pcmbuf_track_changed_callback(void) -{ - LOGFQUEUE("codec > pcmbuf/audio Q_AUDIO_TRACK_CHANGED"); - pcmbuf_set_position_callback(NULL); - audio_post_track_change(); -} - - /** track change functions */ -static inline void codec_gapless_track_change(void) -{ - /* callback keeps the progress bar moving while the pcmbuf empties */ - pcmbuf_set_position_callback(codec_pcmbuf_position_callback); - /* set the pcmbuf callback for when the track really changes */ - pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback); -} - static inline void codec_crossfade_track_change(void) { /* Initiate automatic crossfade mode */ @@ -484,8 +446,8 @@ static void codec_track_skip_done(bool was_manual) /* shuffle mode is on, so crossfade: */ codec_crossfade_track_change(); else - /* shuffle mode is off, so do a gapless track change */ - codec_gapless_track_change(); + /* shuffle mode is off, so normal gapless playback */ + pcmbuf_start_track_change(); } else /* normal crossfade: */ @@ -493,7 +455,7 @@ static void codec_track_skip_done(bool was_manual) } else /* normal gapless playback. */ - codec_gapless_track_change(); + pcmbuf_start_track_change(); } static bool codec_load_next_track(void) diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index 3ec0c114da..3b461ecdc1 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c @@ -25,6 +25,7 @@ #include #include "pcmbuf.h" #include "pcm.h" +#include "playback.h" /* Define LOGF_ENABLE to enable logf output in this file */ /*#define LOGF_ENABLE*/ @@ -62,8 +63,8 @@ struct pcmbufdesc void *addr; size_t size; struct pcmbufdesc* link; - /* Call this when the buffer has been played */ - void (*callback)(void); + /* true if last chunk in the track */ + bool end_of_track; }; #define PCMBUF_DESCS(bufsize) \ @@ -82,8 +83,8 @@ static size_t audiobuffer_fillpos IDATA_ATTR; static char *fadebuf IDATA_ATTR; static char *voicebuf IDATA_ATTR; -static void (*pcmbuf_event_handler)(void) IDATA_ATTR; -static void (*position_callback)(size_t size) IDATA_ATTR; +static bool end_of_track IDATA_ATTR; +bool track_transition IDATA_ATTR; /* Crossfade related state */ static bool crossfade_enabled; @@ -134,25 +135,57 @@ static bool prepare_insert(size_t length); static void pcmbuf_under_watermark(bool under); static bool pcmbuf_flush_fillpos(void); -#define CALL_IF_EXISTS(function, args...) if (function) function(args) -/* This function has 3 major logical parts (separated by brackets both for + +/* Track change functions */ + +/* The codec is moving on to the next track, but the current track is + * still playing. Set flags to make sure the elapsed time of the current + * track is updated properly, and mark the currently written chunk as the + * last one in the track. */ +void pcmbuf_start_track_change(void) +{ + /* we're starting a track transition */ + track_transition = true; + + /* mark the last chunk in the track */ + end_of_track = true; +} + +/* Called when the last chunk in the track has been played */ +static void pcmbuf_finish_track_change(void) +{ + /* not in a track transition anymore */ + if(track_transition){logf("pcmbuf: (finish change) track transition false");} + track_transition = false; + + /* notify playback that the track has just finished */ + audio_post_track_change(); +} + + +/** PCM driver callback + * This function has 3 major logical parts (separated by brackets both for * readability and variable scoping). The first part performs the * operations related to finishing off the last buffer we fed to the DMA. * The second part detects the end of playlist condition when the pcm * buffer is empty except for uncommitted samples. Then they are committed. * The third part performs the operations involved in sending a new buffer * to the DMA. */ -static void pcmbuf_callback(unsigned char** start, size_t* size) ICODE_ATTR; -static void pcmbuf_callback(unsigned char** start, size_t* size) +static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) ICODE_ATTR; +static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) { { struct pcmbufdesc *pcmbuf_current = pcmbuf_read; /* Take the finished buffer out of circulation */ pcmbuf_read = pcmbuf_current->link; - /* The buffer is finished, call the callback functions */ - CALL_IF_EXISTS(position_callback, last_chunksize); - CALL_IF_EXISTS(pcmbuf_current->callback); + /* if during a track transition, update the elapsed time */ + if (track_transition) + audio_pcmbuf_position_callback(last_chunksize); + + /* if last buffer in the track, let the audio thread know */ + if (pcmbuf_current->end_of_track) + pcmbuf_finish_track_change(); /* Put the finished buffer back into circulation */ pcmbuf_write_end->link = pcmbuf_current; @@ -170,7 +203,7 @@ static void pcmbuf_callback(unsigned char** start, size_t* size) /* Commit last samples at end of playlist */ if (audiobuffer_fillpos && !pcmbuf_read) { - logf("pcmbuf callback: commit last samples"); + logf("pcmbuf_pcm_callback: commit last samples"); pcmbuf_flush_fillpos(); } } @@ -195,16 +228,12 @@ static void pcmbuf_callback(unsigned char** start, size_t* size) last_chunksize = 0; *realsize = 0; *realstart = NULL; - CALL_IF_EXISTS(pcmbuf_event_handler); + if (end_of_track) + pcmbuf_finish_track_change(); } } } -void pcmbuf_set_position_callback(void (*callback)(size_t size)) -{ - position_callback = callback; -} - static void pcmbuf_set_watermark_bytes(void) { pcmbuf_watermark = (crossfade_enabled && pcmbuf_size) ? @@ -225,10 +254,9 @@ static inline void pcmbuf_add_chunk(void) /* Fill in the values in the new buffer chunk */ pcmbuf_current->addr = &audiobuffer[audiobuffer_pos]; pcmbuf_current->size = size; - pcmbuf_current->callback = pcmbuf_event_handler; + pcmbuf_current->end_of_track = end_of_track; pcmbuf_current->link = NULL; - /* This is single use only */ - pcmbuf_event_handler = NULL; + end_of_track = false; /* This is single use only */ if (pcmbuf_read != NULL) { if (pcmbuf_flush) { @@ -320,11 +348,6 @@ static void pcmbuf_under_watermark(bool under) } } -void pcmbuf_set_event_handler(void (*event_handler)(void)) -{ - pcmbuf_event_handler = event_handler; -} - unsigned int pcmbuf_get_latency(void) { /* Be careful how this calculation is rearranged, it's easy to overflow */ @@ -493,8 +516,9 @@ size_t pcmbuf_init(unsigned char *bufend) pcmbuf_init_pcmbuffers(); - position_callback = NULL; - pcmbuf_event_handler = NULL; + if(track_transition){logf("pcmbuf: (init) track transition false");} + end_of_track = false; + track_transition = false; pcmbuf_crossfade_enable_finished(); @@ -531,7 +555,7 @@ void pcmbuf_play_start(void) { last_chunksize = pcmbuf_read->size; pcmbuf_unplayed_bytes -= last_chunksize; - pcm_play_data(pcmbuf_callback, + pcm_play_data(pcmbuf_pcm_callback, (unsigned char *)pcmbuf_read->addr, last_chunksize); } } diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h index b4e551f74d..b6f0c767f2 100644 --- a/apps/pcmbuf.h +++ b/apps/pcmbuf.h @@ -57,8 +57,7 @@ void pcmbuf_set_boost_mode(bool state); bool pcmbuf_is_lowdata(void); void pcmbuf_play_start(void); bool pcmbuf_crossfade_init(bool manual_skip); -void pcmbuf_set_event_handler(void (*callback)(void)); -void pcmbuf_set_position_callback(void (*callback)(size_t size)); +void pcmbuf_start_track_change(void); size_t pcmbuf_free(void); unsigned int pcmbuf_get_latency(void); void pcmbuf_set_low_latency(bool state); diff --git a/apps/playback.c b/apps/playback.c index bebbfb1e43..d3c4b46a99 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -179,6 +179,7 @@ static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A /* Track change controls */ bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */ +extern bool track_transition; /* Are we in a track transition? */ static bool dir_skip = false; /* Is a directory skip pending? (A) */ static bool new_playlist = false; /* Are we starting a new playlist? (A) */ static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */ @@ -223,10 +224,31 @@ static void audio_stop_playback(void); /**************************************/ -/* Post message from pcmbuf callback in the codec thread that - * the end of the previous track has just been played. */ +/* Between the codec and PCM track change, we need to keep updating the + "elapsed" value of the previous (to the codec, but current to the + user/PCM/WPS) track, so that the progressbar reaches the end. + During that transition, the WPS will display othertrack_id3. */ +void audio_pcmbuf_position_callback(size_t size) +{ + /* This is called from an ISR, so be quick */ + unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY + + othertrack_id3->elapsed; + + if (time >= othertrack_id3->length) + { + if(track_transition){logf("playback: (callback) track transition false");} + track_transition = false; + othertrack_id3->elapsed = othertrack_id3->length; + } + else + othertrack_id3->elapsed = time; +} + +/* Post message from pcmbuf that the end of the previous track + * has just been played. */ void audio_post_track_change(void) { + LOGFQUEUE("pcmbuf > pcmbuf Q_AUDIO_TRACK_CHANGED"); queue_post(&pcmbuf_queue, Q_AUDIO_TRACK_CHANGED, 0); } @@ -248,16 +270,6 @@ static bool pcmbuf_queue_scan(struct queue_event *ev) return false; } -/* Clear the pcmbuf queue of messages - * Permissible Context(s): Thread - */ -static void pcmbuf_queue_clear(void) -{ - pcm_play_lock(); - queue_clear(&pcmbuf_queue); - pcm_play_unlock(); -} - /* --- Helper functions --- */ static struct mp3entry *bufgetid3(int handle_id) @@ -1617,7 +1629,9 @@ static void audio_stop_codec_flush(void) if (pcm_is_playing()) { pcmbuf_play_stop(); - pcmbuf_queue_clear(); + pcm_play_lock(); + queue_clear(&pcmbuf_queue); + pcm_play_unlock(); } pcmbuf_pause(paused); } diff --git a/apps/playback.h b/apps/playback.h index 95b0bef0df..b168770361 100644 --- a/apps/playback.h +++ b/apps/playback.h @@ -69,6 +69,7 @@ enum }; bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */ size_t audio_get_filebuflen(void); +void audio_pcmbuf_position_callback(size_t size) ICODE_ATTR; void audio_post_track_change(void); int get_audio_hid(void); int *get_codec_hid(void); -- cgit v1.2.3