Commit work started in FS#12153 to put timing/position information in PCM

buffer chunks.

* Samples and position indication is closely associated with audio data
  instead of compensating by a latency constant. Alleviates problems with
  using the elapsed as a track indicator where it could be off by several
  steps.

* Timing is accurate throughout track even if resampling for pitch shift,
  whereas before it updated during transition latency at the normal 1:1 rate.

* Simpler PCM buffer with a constant chunk size, no linked lists.

In converting crossfade, a minor change was made to not change the WPS until
the fade-in of the incoming track, whereas before it would change upon the
start of the fade-out of the outgoing track possibly having the WPS change
with far too much lead time.

Codec changes are to set elapsed times *before* writing next PCM frame because
 time and position data last set are saved in the next committed PCM chunk. 


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30366 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sevakis 2011-08-28 07:45:35 +00:00
parent 463b3ed8b2
commit 7ad2cad173
32 changed files with 969 additions and 830 deletions

View file

@ -77,9 +77,10 @@ struct codec_load_info
static int codec_type = AFMT_UNKNOWN; /* Codec type (C,A-) */
/* Private interfaces to main playback control */
extern void audio_codec_update_elapsed(unsigned long value);
extern void audio_codec_update_offset(size_t value);
extern void audio_queue_post(long id, intptr_t data);
extern void audio_codec_update_elapsed(unsigned long elapsed);
extern void audio_codec_update_offset(size_t offset);
extern void audio_codec_complete(int status);
extern void audio_codec_seek_complete(void);
extern struct codec_api ci; /* from codecs.c */
/* Codec thread */
@ -251,7 +252,7 @@ static void codec_pcmbuf_insert_callback(
if (out_count <= 0)
return;
pcmbuf_write_complete(out_count);
pcmbuf_write_complete(out_count, ci.id3->elapsed, ci.id3->offset);
count -= inp_count;
}
@ -334,9 +335,11 @@ static void codec_seek_complete_callback(void)
/* Clear DSP */
dsp_configure(ci.dsp, DSP_FLUSH, 0);
/* Sync position */
audio_codec_update_offset(ci.curpos);
/* Post notification to audio thread */
LOGFQUEUE("audio > Q_AUDIO_CODEC_SEEK_COMPLETE");
audio_queue_post(Q_AUDIO_CODEC_SEEK_COMPLETE, 0);
audio_codec_seek_complete();
/* Wait for urgent or go message */
do
@ -521,8 +524,7 @@ static void run_codec(void)
/* Notify audio that we're done for better or worse - advise of the
status */
LOGFQUEUE("codec > audio Q_AUDIO_CODEC_COMPLETE: %d", status);
audio_queue_post(Q_AUDIO_CODEC_COMPLETE, status);
audio_codec_complete(status);
}
}

View file

@ -158,7 +158,7 @@ enum codec_status codec_run(void)
}
else {
ci->seek_buffer(ci->id3->first_frame_offset);
samplesdone = 0;
ci->set_elapsed(0);
}
while (1) {

View file

@ -178,6 +178,7 @@ enum codec_status codec_run(void)
}
else {
/* Seek to the first packet */
ci->set_elapsed(0);
ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE );
}

View file

@ -134,8 +134,6 @@ enum codec_status codec_run(void)
if (m4a_seek_raw(&demux_res, &input_stream, file_offset,
&sound_samples_done, (int*) &i)) {
sound_samples_done *= sbr_fac;
elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
ci->set_elapsed(elapsed_time);
} else {
sound_samples_done = 0;
}
@ -143,6 +141,9 @@ enum codec_status codec_run(void)
} else {
sound_samples_done = 0;
}
elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
ci->set_elapsed(elapsed_time);
if (i == 0)
{

View file

@ -209,7 +209,7 @@ enum codec_status codec_run(void)
/* get in position */
ci->seek_buffer(bufoff);
ci->set_elapsed(0);
/* setup pcm buffer format */
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@ -276,6 +276,11 @@ enum codec_status codec_run(void)
loop_count++;
}
ci->seek_buffer(bufoff);
ci->set_elapsed(
((end_adr-start_adr)*loop_count + bufoff-chanstart)*
1000LL/avgbytespersec);
ci->seek_complete();
}

View file

@ -288,6 +288,8 @@ enum codec_status codec_run(void)
bytesdone = 0;
}
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
/* The main decoder loop */
endofstream = 0;

View file

@ -97,6 +97,8 @@ enum codec_status codec_run(void)
}
}
ci->set_elapsed(elapsedtime);
/* The main decoding loop */
while (i < demux_res.num_sample_byte_sizes) {
enum codec_command_action action = ci->get_command(&param);

View file

@ -220,6 +220,9 @@ enum codec_status codec_run(void)
firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */
}
elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
ci->set_elapsed(elapsedtime);
/* Initialise the buffer */
inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);

View file

@ -253,6 +253,8 @@ enum codec_status codec_run(void)
bytesdone = 0;
}
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
/* The main decoder loop */
endofstream = 0;

View file

@ -105,8 +105,10 @@ enum codec_status codec_run(void)
param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate);
action = CODEC_ACTION_SEEK_TIME;
}
else {
ci->set_elapsed(0);
}
ci->set_elapsed(0);
ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
/* The main decoder loop */

View file

@ -460,7 +460,9 @@ enum codec_status codec_run(void)
codec_set_replaygain(ci->id3);
flac_seek_offset(&fc, samplesdone);
samplesdone=0;
samplesdone=fc.samplenumber+fc.blocksize;
elapsedtime=(samplesdone*10)/(ci->id3->frequency/100);
ci->set_elapsed(elapsedtime);
/* The main decoding loop */
frame=0;

View file

@ -1333,12 +1333,11 @@ enum codec_status codec_run(void)
/* New time is ready in param */
modplayer.patterntableposition = param/1000;
modplayer.currentline = 0;
ci->set_elapsed(modplayer.patterntableposition*1000+500);
ci->seek_complete();
}
if(old_patterntableposition != modplayer.patterntableposition) {
ci->set_elapsed(modplayer.patterntableposition*1000+500);
ci->set_elapsed(modplayer.patterntableposition*1000);
old_patterntableposition=modplayer.patterntableposition;
}

View file

@ -144,6 +144,7 @@ static void set_elapsed(struct mp3entry* id3)
{
unsigned long offset = id3->offset > id3->first_frame_offset ?
id3->offset - id3->first_frame_offset : 0;
unsigned long elapsed = id3->elapsed;
if ( id3->vbr ) {
if ( id3->has_toc ) {
@ -172,27 +173,28 @@ static void set_elapsed(struct mp3entry* id3)
/* set time for this percent (divide before multiply to prevent
overflow on long files. loss of precision is negligible on
short files) */
id3->elapsed = i * (id3->length / 100);
elapsed = i * (id3->length / 100);
/* calculate remainder time */
plen = (nextpos - relpos) * (id3->filesize / 256);
id3->elapsed += (((remainder * 100) / plen) *
(id3->length / 10000));
elapsed += (((remainder * 100) / plen) * (id3->length / 10000));
}
else {
/* no TOC exists. set a rough estimate using average bitrate */
int tpk = id3->length /
((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
1024);
id3->elapsed = offset / 1024 * tpk;
elapsed = offset / 1024 * tpk;
}
}
else
{
/* constant bitrate, use exact calculation */
if (id3->bitrate != 0)
id3->elapsed = offset / (id3->bitrate / 8);
elapsed = offset / (id3->bitrate / 8);
}
ci->set_elapsed(elapsed);
}
#ifdef MPA_SYNTH_ON_COP

View file

@ -123,6 +123,8 @@ enum codec_status codec_run(void)
codec_set_replaygain(ci->id3);
/* Resume to saved sample offset. */
elapsed_time = 0;
if (samplesdone > 0)
{
if (mpc_demux_seek_sample(demux, samplesdone) == MPC_STATUS_OK)
@ -136,6 +138,8 @@ enum codec_status codec_run(void)
}
}
ci->set_elapsed(elapsed_time);
/* This is the decoding loop. */
do
{

View file

@ -99,6 +99,8 @@ enum codec_status codec_run(void)
sc.bitindex = sc.gb.index - 8*consumed;
seek_start:
ci->set_elapsed(0);
/* The main decoding loop */
ci->memset(&decoded0, 0, sizeof(int32_t)*MAX_DECODE_SIZE);
ci->memset(&decoded1, 0, sizeof(int32_t)*MAX_DECODE_SIZE);
@ -118,7 +120,6 @@ seek_start:
if (param == 0 &&
ci->seek_buffer(sc.header_bits/8 + ci->id3->first_frame_offset)) {
sc.bitindex = sc.header_bits - 8*(sc.header_bits/8);
ci->set_elapsed(0);
ci->seek_complete();
goto seek_start;
}

View file

@ -1299,8 +1299,8 @@ enum codec_status codec_run(void)
nSamplesToRender = 0; /* Start the rendering from scratch */
/* Set the elapsed time to the current subsong (in seconds) */
ci->seek_complete();
ci->set_elapsed(subSong*1000);
ci->seek_complete();
}
nSamplesRendered = 0;

View file

@ -429,6 +429,8 @@ enum codec_status codec_run(void)
bytesdone = 0;
}
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
/* The main decoder loop */
endofstream = 0;

View file

@ -560,6 +560,8 @@ enum codec_status codec_run(void)
return CODEC_ERROR;
DEBUGF("SPC: read size = 0x%lx\n",(unsigned long)buffersize);
ci->set_elapsed(0);
do
{
if (load_spc_buffer(buffer, buffersize)) {

View file

@ -417,6 +417,7 @@ enum codec_status codec_run(void)
}
ci->seek_buffer(0);
ci->set_elapsed(0);
stereo = speex_stereo_state_init();
spx_ogg_sync_init(&oy);

View file

@ -90,6 +90,8 @@ enum codec_status codec_run(void)
decodedsamples = new_pos;
}
ci->set_elapsed((uint64_t)info.LENGTH * 1000 * decodedsamples / info.DATALENGTH);
while (!endofstream)
{
enum codec_command_action action = ci->get_command(&param);

View file

@ -196,6 +196,9 @@ enum codec_status codec_run(void)
ci->set_elapsed(ov_time_tell(&vf));
ci->set_offset(ov_raw_tell(&vf));
}
else {
ci->set_elapsed(0);
}
previous_section = -1;
eof = 0;

View file

@ -141,6 +141,8 @@ enum codec_status codec_run(void)
bytesdone = 0;
}
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
/* The main decoder loop */
endofstream = 0;

View file

@ -378,6 +378,8 @@ enum codec_status codec_run(void)
bytesdone = 0;
}
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
/* The main decoder loop */
endofstream = 0;

View file

@ -381,6 +381,8 @@ enum codec_status codec_run(void)
bytesdone = 0;
}
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
/* The main decoder loop */
endofstream = 0;

View file

@ -75,7 +75,7 @@ enum codec_status codec_run(void)
ci->configure(DSP_SET_STEREO_MODE, nchans == 2 ? STEREO_INTERLEAVED : STEREO_MONO);
sr_100 = ci->id3->frequency / 100;
ci->set_elapsed (0);
ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10);
/* The main decoder loop */

View file

@ -84,7 +84,6 @@ restart_track:
% wfx.packet_size;
ci->seek_buffer(resume_offset - packet_offset);
elapsedtime = asf_get_timestamp(&i);
ci->set_elapsed(elapsedtime);
}
else
{
@ -93,6 +92,8 @@ restart_track:
elapsedtime = 0;
}
ci->set_elapsed(elapsedtime);
resume_offset = 0;
ci->configure(DSP_SWITCH_FREQUENCY, wfx.rate);
ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ?

View file

@ -79,6 +79,7 @@ restart_track:
ci->seek_buffer(ci->id3->first_frame_offset);
elapsedtime = 0;
ci->set_elapsed(0);
/* The main decoding loop */

View file

@ -109,6 +109,8 @@ restart_track:
ci->seek_buffer(ci->id3->first_frame_offset);
elapsedtime = 0;
ci->set_elapsed(0);
resume_offset = 0;
/* The main decoding loop */

File diff suppressed because it is too large Load diff

View file

@ -21,9 +21,11 @@
#ifndef PCMBUF_H
#define PCMBUF_H
#include <sys/types.h>
/* Commit PCM data */
void *pcmbuf_request_buffer(int *count);
void pcmbuf_write_complete(int count);
void pcmbuf_write_complete(int count, unsigned long elapsed, off_t offset);
/* Init */
size_t pcmbuf_init(unsigned char *bufend);
@ -33,20 +35,30 @@ void pcmbuf_play_start(void);
void pcmbuf_play_stop(void);
void pcmbuf_pause(bool pause);
void pcmbuf_monitor_track_change(bool monitor);
bool pcmbuf_start_track_change(bool manual_skip);
void pcmbuf_sync_position_update(void);
/* Track change origin type */
enum pcm_track_change_type
{
TRACK_CHANGE_NONE = 0, /* No track change pending */
TRACK_CHANGE_MANUAL, /* Manual change (from user) */
TRACK_CHANGE_AUTO, /* Automatic change (from codec) */
TRACK_CHANGE_END_OF_DATA, /* Expect no more data (from codec) */
};
void pcmbuf_start_track_change(enum pcm_track_change_type type);
/* Crossfade */
#ifdef HAVE_CROSSFADE
bool pcmbuf_is_crossfade_active(void);
void pcmbuf_request_crossfade_enable(bool on_off);
void pcmbuf_request_crossfade_enable(int setting);
bool pcmbuf_is_same_size(void);
#else
/* Dummy functions with sensible returns */
static inline bool pcmbuf_is_crossfade_active(void)
static FORCE_INLINE bool pcmbuf_is_crossfade_active(void)
{ return false; }
static inline void pcmbuf_request_crossfade_enable(bool on_off)
static FORCE_INLINE void pcmbuf_request_crossfade_enable(bool on_off)
{ return; (void)on_off; }
static inline bool pcmbuf_is_same_size(void)
static FORCE_INLINE bool pcmbuf_is_same_size(void)
{ return true; }
#endif
@ -59,9 +71,7 @@ size_t pcmbuf_free(void);
size_t pcmbuf_get_bufsize(void);
int pcmbuf_descs(void);
int pcmbuf_used_descs(void);
#ifdef ROCKBOX_HAS_LOGF
unsigned char *pcmbuf_get_meminfo(size_t *length);
#endif
unsigned int pcmbuf_get_position_key(void);
/* Misc */
void pcmbuf_fade(bool fade, bool in);
@ -69,6 +79,5 @@ bool pcmbuf_fading(void);
void pcmbuf_soft_mode(bool shhh);
bool pcmbuf_is_lowdata(void);
void pcmbuf_set_low_latency(bool state);
unsigned long pcmbuf_get_latency(void);
#endif

View file

@ -330,7 +330,7 @@ static struct
static bool codec_skip_pending = false;
static int codec_skip_status;
static bool codec_seeking = false; /* Codec seeking ack expected? */
static unsigned int position_key = 0;
/* Event queues */
static struct event_queue audio_queue SHAREDBSS_ATTR;
@ -353,14 +353,13 @@ static void audio_stop_playback(void);
static void buffer_event_buffer_low_callback(void *data);
static void buffer_event_rebuffer_callback(void *data);
static void buffer_event_finished_callback(void *data);
void audio_pcmbuf_sync_position(void);
/**************************************/
/** --- audio_queue helpers --- **/
/* codec thread needs access */
void audio_queue_post(long id, intptr_t data)
static void audio_queue_post(long id, intptr_t data)
{
queue_post(&audio_queue, id, data);
}
@ -805,14 +804,10 @@ static void audio_reset_buffer(void)
aids viewing and the summation of certain variables should add up to
the location of others. */
{
size_t pcmbufsize;
const unsigned char *pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
logf("fbuf: %08X", (unsigned)filebuf);
logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
logf("sbuf: %08X", (unsigned)audio_scratch_memory);
logf("sbufe: %08X", (unsigned)(audio_scratch_memory + allocsize));
logf("pcmb: %08X", (unsigned)pcmbuf);
logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
}
#endif
@ -978,7 +973,8 @@ static void audio_handle_track_load_status(int trackstat)
/* Announce the end of playing the current track */
static void audio_playlist_track_finish(void)
{
struct mp3entry *id3 = valid_mp3entry(id3_get(PLAYING_ID3));
struct mp3entry *ply_id3 = id3_get(PLAYING_ID3);
struct mp3entry *id3 = valid_mp3entry(ply_id3);
playlist_update_resume_info(filling == STATE_ENDED ? NULL : id3);
@ -1001,6 +997,8 @@ static void audio_playlist_track_change(void)
if (id3)
send_event(PLAYBACK_EVENT_TRACK_CHANGE, id3);
position_key = pcmbuf_get_position_key();
playlist_update_resume_info(id3);
}
@ -1014,26 +1012,28 @@ static void audio_update_and_announce_next_track(const struct mp3entry *id3_next
/* Bring the user current mp3entry up to date and set a new offset for the
buffered metadata */
static void playing_id3_sync(struct track_info *user_info, size_t offset)
static void playing_id3_sync(struct track_info *user_info, off_t offset)
{
id3_mutex_lock();
struct mp3entry *id3 = bufgetid3(user_info->id3_hid);
struct mp3entry *playing_id3 = id3_get(PLAYING_ID3);
if (offset == (size_t)-1)
pcm_play_lock();
unsigned long e = playing_id3->elapsed;
unsigned long o = playing_id3->offset;
id3_write(PLAYING_ID3, id3);
if (offset < 0)
{
struct mp3entry *ply_id3 = id3_get(PLAYING_ID3);
size_t play_offset = ply_id3->offset;
long play_elapsed = ply_id3->elapsed;
id3_write(PLAYING_ID3, id3);
ply_id3->offset = play_offset;
ply_id3->elapsed = play_elapsed;
playing_id3->elapsed = e;
playing_id3->offset = o;
offset = 0;
}
else
{
id3_write(PLAYING_ID3, id3);
}
pcm_play_unlock();
if (id3)
id3->offset = offset;
@ -1093,13 +1093,6 @@ static bool halt_decoding_track(bool stop)
return retval;
}
/* Clear the PCM on a manual skip */
static void audio_clear_paused_pcm(void)
{
if (play_status == PLAY_PAUSED && !pcmbuf_is_crossfade_active())
pcmbuf_play_stop();
}
/* Wait for any in-progress fade to complete */
static void audio_wait_fade_complete(void)
{
@ -1121,6 +1114,7 @@ static void audio_ff_rewind_end(void)
{
/* Clear the buffer */
pcmbuf_play_stop();
audio_pcmbuf_sync_position();
}
if (play_status != PLAY_PAUSED)
@ -2063,7 +2057,7 @@ static void audio_on_handle_finished(int hid)
/* Called to make an outstanding track skip the current track and to send the
transition events */
static void audio_finalise_track_change(bool delayed)
static void audio_finalise_track_change(void)
{
switch (skip_pending)
{
@ -2117,15 +2111,6 @@ static void audio_finalise_track_change(bool delayed)
id3_write(PLAYING_ID3, track_id3);
if (delayed)
{
/* Delayed skip where codec is ahead of user's current track */
struct mp3entry *ci_id3 = id3_get(CODEC_ID3);
struct mp3entry *ply_id3 = id3_get(PLAYING_ID3);
ply_id3->elapsed = ci_id3->elapsed;
ply_id3->offset = ci_id3->offset;
}
/* The skip is technically over */
skip_pending = TRACK_SKIP_NONE;
@ -2141,25 +2126,25 @@ static void audio_finalise_track_change(bool delayed)
}
/* Actually begin a transition and take care of the codec change - may complete
it now or ask pcmbuf for notification depending on the type and what pcmbuf
has to say */
static void audio_begin_track_change(bool auto_skip, int trackstat)
it now or ask pcmbuf for notification depending on the type */
static void audio_begin_track_change(enum pcm_track_change_type type,
int trackstat)
{
/* Even if the new track is bad, the old track must be finished off */
bool finalised = pcmbuf_start_track_change(auto_skip);
pcmbuf_start_track_change(type);
if (finalised)
bool auto_skip = type != TRACK_CHANGE_MANUAL;
if (!auto_skip)
{
/* pcmbuf says that the transition happens now - complete it */
audio_finalise_track_change(false);
/* Manual track change happens now */
audio_finalise_track_change();
pcmbuf_sync_position_update();
if (play_status == PLAY_STOPPED)
return; /* Stopped us */
}
if (!auto_skip)
audio_clear_paused_pcm();
if (trackstat >= LOAD_TRACK_OK)
{
struct track_info *info = track_list_current(0);
@ -2170,7 +2155,7 @@ static void audio_begin_track_change(bool auto_skip, int trackstat)
/* Everything needed for the codec is ready - start it */
if (audio_start_codec(auto_skip))
{
if (finalised)
if (!auto_skip)
playing_id3_sync(info, -1);
return;
}
@ -2186,7 +2171,7 @@ static void audio_monitor_end_of_playlist(void)
{
skip_pending = TRACK_SKIP_AUTO_END_PLAYLIST;
filling = STATE_ENDING;
pcmbuf_monitor_track_change(true);
pcmbuf_start_track_change(TRACK_CHANGE_END_OF_DATA);
}
/* Codec has completed decoding the track
@ -2221,14 +2206,6 @@ static void audio_on_codec_complete(int status)
codec_skip_pending = false;
#ifdef AB_REPEAT_ENABLE
if (status >= 0)
{
/* Normal automatic skip */
ab_end_of_track_report();
}
#endif
int trackstat = LOAD_TRACK_OK;
automatic_skip = true;
@ -2263,7 +2240,7 @@ static void audio_on_codec_complete(int status)
{
/* Continue filling after this track */
audio_reset_and_rebuffer(TRACK_LIST_KEEP_CURRENT, 1);
audio_begin_track_change(true, trackstat);
audio_begin_track_change(TRACK_CHANGE_AUTO, trackstat);
return;
}
/* else rebuffer at this track; status applies to the track we
@ -2299,7 +2276,7 @@ static void audio_on_codec_complete(int status)
}
}
audio_begin_track_change(true, trackstat);
audio_begin_track_change(TRACK_CHANGE_AUTO, trackstat);
}
/* Called when codec completes seek operation
@ -2316,7 +2293,7 @@ static void audio_on_codec_seek_complete(void)
static void audio_on_track_changed(void)
{
/* Finish whatever is pending so that the WPS is in sync */
audio_finalise_track_change(true);
audio_finalise_track_change();
if (codec_skip_pending)
{
@ -2367,8 +2344,7 @@ static void audio_start_playback(size_t offset, unsigned int flags)
track_list_clear(TRACK_LIST_CLEAR_ALL);
/* Indicate manual track change */
pcmbuf_start_track_change(false);
audio_clear_paused_pcm();
pcmbuf_start_track_change(TRACK_CHANGE_MANUAL);
wipe_track_metadata(true);
}
@ -2398,6 +2374,10 @@ static void audio_start_playback(size_t offset, unsigned int flags)
play_status = PLAY_PLAYING;
}
/* Codec's position should be available as soon as it knows it */
position_key = pcmbuf_get_position_key();
pcmbuf_sync_position_update();
/* Start fill from beginning of playlist */
playlist_peek_offset = -1;
buf_set_base_handle(-1);
@ -2592,7 +2572,7 @@ static void audio_on_skip(void)
trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1);
}
audio_begin_track_change(false, trackstat);
audio_begin_track_change(TRACK_CHANGE_MANUAL, trackstat);
}
/* Skip to the next/previous directory
@ -2638,7 +2618,7 @@ static void audio_on_dir_skip(int direction)
return;
}
audio_begin_track_change(false, trackstat);
audio_begin_track_change(TRACK_CHANGE_MANUAL, trackstat);
}
/* Enter seek mode in order to start a seek
@ -2689,11 +2669,6 @@ static void audio_on_ff_rewind(long time)
if (time == 0)
send_event(PLAYBACK_EVENT_TRACK_FINISH, id3);
/* Prevent user codec time update - coerce to something that is
innocuous concerning lookaheads */
if (pending == TRACK_SKIP_NONE)
skip_pending = TRACK_SKIP_AUTO_END_PLAYLIST;
id3->elapsed = time;
queue_reply(&audio_queue, 1);
@ -2703,6 +2678,9 @@ static void audio_on_ff_rewind(long time)
halt that will reset it */
codec_seeking = true;
/* If in transition, key will have changed - sync to it */
position_key = pcmbuf_get_position_key();
if (pending == TRACK_SKIP_AUTO)
{
if (!track_list_advance_current(-1))
@ -3124,75 +3102,66 @@ static void buffer_event_finished_callback(void *data)
/** -- Codec callbacks -- **/
/* Update elapsed times with latency-adjusted values */
void audio_codec_update_elapsed(unsigned long value)
/* Update elapsed time for next PCM insert */
void audio_codec_update_elapsed(unsigned long elapsed)
{
#ifdef AB_REPEAT_ENABLE
ab_position_report(value);
ab_position_report(elapsed);
#endif
unsigned long latency = pcmbuf_get_latency();
if (LIKELY(value >= latency))
{
unsigned long elapsed = value - latency;
if (elapsed > value || elapsed < value - 2)
value = elapsed;
}
else
{
value = 0;
}
/* Track codec: used later when updating the playing at the user
transition */
id3_get(CODEC_ID3)->elapsed = value;
/* If a skip is pending, the PCM buffer is updating the time on the
previous song */
if (LIKELY(skip_pending == TRACK_SKIP_NONE))
id3_get(PLAYING_ID3)->elapsed = value;
/* Save in codec's id3 where it is used at next pcm insert */
id3_get(CODEC_ID3)->elapsed = elapsed;
}
/* Update offsets with latency-adjusted values */
void audio_codec_update_offset(size_t value)
/* Update offset for next PCM insert */
void audio_codec_update_offset(size_t offset)
{
struct mp3entry *ci_id3 = id3_get(CODEC_ID3);
unsigned long latency = pcmbuf_get_latency() * ci_id3->bitrate / 8;
/* Save in codec's id3 where it is used at next pcm insert */
id3_get(CODEC_ID3)->offset = offset;
}
if (LIKELY(value >= latency))
/* Codec has finished running */
void audio_codec_complete(int status)
{
#ifdef AB_REPEAT_ENABLE
if (status >= CODEC_OK)
{
value -= latency;
}
else
{
value = 0;
/* Normal automatic skip */
ab_end_of_track_report();
}
#endif
/* Track codec: used later when updating the playing id3 at the user
transition */
ci_id3->offset = value;
LOGFQUEUE("codec > audio Q_AUDIO_CODEC_COMPLETE: %d", status);
audio_queue_post(Q_AUDIO_CODEC_COMPLETE, status);
}
/* If a skip is pending, the PCM buffer is updating the time on the
previous song */
if (LIKELY(skip_pending == TRACK_SKIP_NONE))
id3_get(PLAYING_ID3)->offset = value;
/* Codec has finished seeking */
void audio_codec_seek_complete(void)
{
LOGFQUEUE("codec > audio Q_AUDIO_CODEC_SEEK_COMPLETE");
audio_queue_post(Q_AUDIO_CODEC_SEEK_COMPLETE, 0);
}
/** --- Pcmbuf 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. */
void audio_pcmbuf_position_callback(unsigned int time)
/* Update the elapsed and offset from the information cached during the
PCM buffer insert */
void audio_pcmbuf_position_callback(unsigned long elapsed, off_t offset,
unsigned int key)
{
struct mp3entry *id3 = id3_get(PLAYING_ID3);
if (key == position_key)
{
struct mp3entry *id3 = id3_get(PLAYING_ID3);
id3->elapsed = elapsed;
id3->offset = offset;
}
}
time += id3->elapsed;
id3->elapsed = MIN(time, id3->length);
/* Synchronize position info to the codec's */
void audio_pcmbuf_sync_position(void)
{
audio_pcmbuf_position_callback(ci.id3->elapsed, ci.id3->offset,
pcmbuf_get_position_key());
}
/* Post message from pcmbuf that the end of the previous track has just

View file

@ -378,12 +378,16 @@ static inline void cpucache_flush(void)
#if defined(CPU_ARM)
/* Use ARMs cache alignment. */
#define MEM_ALIGN_ATTR CACHEALIGN_ATTR
#define MEM_ALIGN_SIZE CACHEALIGN_SIZE
#elif defined(CPU_COLDFIRE)
/* Use fixed alignment of 16 bytes. Speed up only for 'movem' in DRAM. */
#define MEM_ALIGN_ATTR __attribute__((aligned(16)))
#define MEM_ALIGN_SIZE 16
#else
/* Do nothing. */
#define MEM_ALIGN_ATTR
/* Align pointer size */
#define MEM_ALIGN_SIZE sizeof(intptr_t)
#endif
#ifdef STORAGE_WANTS_ALIGN