forked from len0rd/rockbox
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
This commit is contained in:
parent
606a333a5f
commit
5ce8e2cb0d
5 changed files with 85 additions and 85 deletions
|
@ -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 */
|
/** 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)
|
static inline void codec_crossfade_track_change(void)
|
||||||
{
|
{
|
||||||
/* Initiate automatic crossfade mode */
|
/* Initiate automatic crossfade mode */
|
||||||
|
@ -484,8 +446,8 @@ static void codec_track_skip_done(bool was_manual)
|
||||||
/* shuffle mode is on, so crossfade: */
|
/* shuffle mode is on, so crossfade: */
|
||||||
codec_crossfade_track_change();
|
codec_crossfade_track_change();
|
||||||
else
|
else
|
||||||
/* shuffle mode is off, so do a gapless track change */
|
/* shuffle mode is off, so normal gapless playback */
|
||||||
codec_gapless_track_change();
|
pcmbuf_start_track_change();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* normal crossfade: */
|
/* normal crossfade: */
|
||||||
|
@ -493,7 +455,7 @@ static void codec_track_skip_done(bool was_manual)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* normal gapless playback. */
|
/* normal gapless playback. */
|
||||||
codec_gapless_track_change();
|
pcmbuf_start_track_change();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool codec_load_next_track(void)
|
static bool codec_load_next_track(void)
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include "pcmbuf.h"
|
#include "pcmbuf.h"
|
||||||
#include "pcm.h"
|
#include "pcm.h"
|
||||||
|
#include "playback.h"
|
||||||
|
|
||||||
/* Define LOGF_ENABLE to enable logf output in this file */
|
/* Define LOGF_ENABLE to enable logf output in this file */
|
||||||
/*#define LOGF_ENABLE*/
|
/*#define LOGF_ENABLE*/
|
||||||
|
@ -62,8 +63,8 @@ struct pcmbufdesc
|
||||||
void *addr;
|
void *addr;
|
||||||
size_t size;
|
size_t size;
|
||||||
struct pcmbufdesc* link;
|
struct pcmbufdesc* link;
|
||||||
/* Call this when the buffer has been played */
|
/* true if last chunk in the track */
|
||||||
void (*callback)(void);
|
bool end_of_track;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PCMBUF_DESCS(bufsize) \
|
#define PCMBUF_DESCS(bufsize) \
|
||||||
|
@ -82,8 +83,8 @@ static size_t audiobuffer_fillpos IDATA_ATTR;
|
||||||
static char *fadebuf IDATA_ATTR;
|
static char *fadebuf IDATA_ATTR;
|
||||||
static char *voicebuf IDATA_ATTR;
|
static char *voicebuf IDATA_ATTR;
|
||||||
|
|
||||||
static void (*pcmbuf_event_handler)(void) IDATA_ATTR;
|
static bool end_of_track IDATA_ATTR;
|
||||||
static void (*position_callback)(size_t size) IDATA_ATTR;
|
bool track_transition IDATA_ATTR;
|
||||||
|
|
||||||
/* Crossfade related state */
|
/* Crossfade related state */
|
||||||
static bool crossfade_enabled;
|
static bool crossfade_enabled;
|
||||||
|
@ -134,25 +135,57 @@ static bool prepare_insert(size_t length);
|
||||||
static void pcmbuf_under_watermark(bool under);
|
static void pcmbuf_under_watermark(bool under);
|
||||||
static bool pcmbuf_flush_fillpos(void);
|
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
|
* readability and variable scoping). The first part performs the
|
||||||
* operations related to finishing off the last buffer we fed to the DMA.
|
* 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
|
* The second part detects the end of playlist condition when the pcm
|
||||||
* buffer is empty except for uncommitted samples. Then they are committed.
|
* buffer is empty except for uncommitted samples. Then they are committed.
|
||||||
* The third part performs the operations involved in sending a new buffer
|
* The third part performs the operations involved in sending a new buffer
|
||||||
* to the DMA. */
|
* to the DMA. */
|
||||||
static void pcmbuf_callback(unsigned char** start, size_t* size) ICODE_ATTR;
|
static void pcmbuf_pcm_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)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
struct pcmbufdesc *pcmbuf_current = pcmbuf_read;
|
struct pcmbufdesc *pcmbuf_current = pcmbuf_read;
|
||||||
/* Take the finished buffer out of circulation */
|
/* Take the finished buffer out of circulation */
|
||||||
pcmbuf_read = pcmbuf_current->link;
|
pcmbuf_read = pcmbuf_current->link;
|
||||||
|
|
||||||
/* The buffer is finished, call the callback functions */
|
/* if during a track transition, update the elapsed time */
|
||||||
CALL_IF_EXISTS(position_callback, last_chunksize);
|
if (track_transition)
|
||||||
CALL_IF_EXISTS(pcmbuf_current->callback);
|
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 */
|
/* Put the finished buffer back into circulation */
|
||||||
pcmbuf_write_end->link = pcmbuf_current;
|
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 */
|
/* Commit last samples at end of playlist */
|
||||||
if (audiobuffer_fillpos && !pcmbuf_read)
|
if (audiobuffer_fillpos && !pcmbuf_read)
|
||||||
{
|
{
|
||||||
logf("pcmbuf callback: commit last samples");
|
logf("pcmbuf_pcm_callback: commit last samples");
|
||||||
pcmbuf_flush_fillpos();
|
pcmbuf_flush_fillpos();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,16 +228,12 @@ static void pcmbuf_callback(unsigned char** start, size_t* size)
|
||||||
last_chunksize = 0;
|
last_chunksize = 0;
|
||||||
*realsize = 0;
|
*realsize = 0;
|
||||||
*realstart = NULL;
|
*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)
|
static void pcmbuf_set_watermark_bytes(void)
|
||||||
{
|
{
|
||||||
pcmbuf_watermark = (crossfade_enabled && pcmbuf_size) ?
|
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 */
|
/* Fill in the values in the new buffer chunk */
|
||||||
pcmbuf_current->addr = &audiobuffer[audiobuffer_pos];
|
pcmbuf_current->addr = &audiobuffer[audiobuffer_pos];
|
||||||
pcmbuf_current->size = size;
|
pcmbuf_current->size = size;
|
||||||
pcmbuf_current->callback = pcmbuf_event_handler;
|
pcmbuf_current->end_of_track = end_of_track;
|
||||||
pcmbuf_current->link = NULL;
|
pcmbuf_current->link = NULL;
|
||||||
/* This is single use only */
|
end_of_track = false; /* This is single use only */
|
||||||
pcmbuf_event_handler = NULL;
|
|
||||||
if (pcmbuf_read != NULL) {
|
if (pcmbuf_read != NULL) {
|
||||||
if (pcmbuf_flush)
|
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)
|
unsigned int pcmbuf_get_latency(void)
|
||||||
{
|
{
|
||||||
/* Be careful how this calculation is rearranged, it's easy to overflow */
|
/* 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();
|
pcmbuf_init_pcmbuffers();
|
||||||
|
|
||||||
position_callback = NULL;
|
if(track_transition){logf("pcmbuf: (init) track transition false");}
|
||||||
pcmbuf_event_handler = NULL;
|
end_of_track = false;
|
||||||
|
track_transition = false;
|
||||||
|
|
||||||
pcmbuf_crossfade_enable_finished();
|
pcmbuf_crossfade_enable_finished();
|
||||||
|
|
||||||
|
@ -531,7 +555,7 @@ void pcmbuf_play_start(void)
|
||||||
{
|
{
|
||||||
last_chunksize = pcmbuf_read->size;
|
last_chunksize = pcmbuf_read->size;
|
||||||
pcmbuf_unplayed_bytes -= last_chunksize;
|
pcmbuf_unplayed_bytes -= last_chunksize;
|
||||||
pcm_play_data(pcmbuf_callback,
|
pcm_play_data(pcmbuf_pcm_callback,
|
||||||
(unsigned char *)pcmbuf_read->addr, last_chunksize);
|
(unsigned char *)pcmbuf_read->addr, last_chunksize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,8 +57,7 @@ void pcmbuf_set_boost_mode(bool state);
|
||||||
bool pcmbuf_is_lowdata(void);
|
bool pcmbuf_is_lowdata(void);
|
||||||
void pcmbuf_play_start(void);
|
void pcmbuf_play_start(void);
|
||||||
bool pcmbuf_crossfade_init(bool manual_skip);
|
bool pcmbuf_crossfade_init(bool manual_skip);
|
||||||
void pcmbuf_set_event_handler(void (*callback)(void));
|
void pcmbuf_start_track_change(void);
|
||||||
void pcmbuf_set_position_callback(void (*callback)(size_t size));
|
|
||||||
size_t pcmbuf_free(void);
|
size_t pcmbuf_free(void);
|
||||||
unsigned int pcmbuf_get_latency(void);
|
unsigned int pcmbuf_get_latency(void);
|
||||||
void pcmbuf_set_low_latency(bool state);
|
void pcmbuf_set_low_latency(bool state);
|
||||||
|
|
|
@ -179,6 +179,7 @@ static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A
|
||||||
|
|
||||||
/* Track change controls */
|
/* Track change controls */
|
||||||
bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */
|
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 dir_skip = false; /* Is a directory skip pending? (A) */
|
||||||
static bool new_playlist = false; /* Are we starting a new playlist? (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) */
|
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
|
/* Between the codec and PCM track change, we need to keep updating the
|
||||||
* the end of the previous track has just been played. */
|
"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)
|
void audio_post_track_change(void)
|
||||||
{
|
{
|
||||||
|
LOGFQUEUE("pcmbuf > pcmbuf Q_AUDIO_TRACK_CHANGED");
|
||||||
queue_post(&pcmbuf_queue, Q_AUDIO_TRACK_CHANGED, 0);
|
queue_post(&pcmbuf_queue, Q_AUDIO_TRACK_CHANGED, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,16 +270,6 @@ static bool pcmbuf_queue_scan(struct queue_event *ev)
|
||||||
return false;
|
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 --- */
|
/* --- Helper functions --- */
|
||||||
|
|
||||||
static struct mp3entry *bufgetid3(int handle_id)
|
static struct mp3entry *bufgetid3(int handle_id)
|
||||||
|
@ -1617,7 +1629,9 @@ static void audio_stop_codec_flush(void)
|
||||||
if (pcm_is_playing())
|
if (pcm_is_playing())
|
||||||
{
|
{
|
||||||
pcmbuf_play_stop();
|
pcmbuf_play_stop();
|
||||||
pcmbuf_queue_clear();
|
pcm_play_lock();
|
||||||
|
queue_clear(&pcmbuf_queue);
|
||||||
|
pcm_play_unlock();
|
||||||
}
|
}
|
||||||
pcmbuf_pause(paused);
|
pcmbuf_pause(paused);
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ enum
|
||||||
};
|
};
|
||||||
bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */
|
bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */
|
||||||
size_t audio_get_filebuflen(void);
|
size_t audio_get_filebuflen(void);
|
||||||
|
void audio_pcmbuf_position_callback(size_t size) ICODE_ATTR;
|
||||||
void audio_post_track_change(void);
|
void audio_post_track_change(void);
|
||||||
int get_audio_hid(void);
|
int get_audio_hid(void);
|
||||||
int *get_codec_hid(void);
|
int *get_codec_hid(void);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue