mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-13 18:17:39 -04:00
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:
parent
463b3ed8b2
commit
7ad2cad173
32 changed files with 969 additions and 830 deletions
|
@ -77,9 +77,10 @@ struct codec_load_info
|
||||||
static int codec_type = AFMT_UNKNOWN; /* Codec type (C,A-) */
|
static int codec_type = AFMT_UNKNOWN; /* Codec type (C,A-) */
|
||||||
|
|
||||||
/* Private interfaces to main playback control */
|
/* Private interfaces to main playback control */
|
||||||
extern void audio_codec_update_elapsed(unsigned long value);
|
extern void audio_codec_update_elapsed(unsigned long elapsed);
|
||||||
extern void audio_codec_update_offset(size_t value);
|
extern void audio_codec_update_offset(size_t offset);
|
||||||
extern void audio_queue_post(long id, intptr_t data);
|
extern void audio_codec_complete(int status);
|
||||||
|
extern void audio_codec_seek_complete(void);
|
||||||
extern struct codec_api ci; /* from codecs.c */
|
extern struct codec_api ci; /* from codecs.c */
|
||||||
|
|
||||||
/* Codec thread */
|
/* Codec thread */
|
||||||
|
@ -251,7 +252,7 @@ static void codec_pcmbuf_insert_callback(
|
||||||
if (out_count <= 0)
|
if (out_count <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pcmbuf_write_complete(out_count);
|
pcmbuf_write_complete(out_count, ci.id3->elapsed, ci.id3->offset);
|
||||||
|
|
||||||
count -= inp_count;
|
count -= inp_count;
|
||||||
}
|
}
|
||||||
|
@ -334,9 +335,11 @@ static void codec_seek_complete_callback(void)
|
||||||
/* Clear DSP */
|
/* Clear DSP */
|
||||||
dsp_configure(ci.dsp, DSP_FLUSH, 0);
|
dsp_configure(ci.dsp, DSP_FLUSH, 0);
|
||||||
|
|
||||||
|
/* Sync position */
|
||||||
|
audio_codec_update_offset(ci.curpos);
|
||||||
|
|
||||||
/* Post notification to audio thread */
|
/* Post notification to audio thread */
|
||||||
LOGFQUEUE("audio > Q_AUDIO_CODEC_SEEK_COMPLETE");
|
audio_codec_seek_complete();
|
||||||
audio_queue_post(Q_AUDIO_CODEC_SEEK_COMPLETE, 0);
|
|
||||||
|
|
||||||
/* Wait for urgent or go message */
|
/* Wait for urgent or go message */
|
||||||
do
|
do
|
||||||
|
@ -521,8 +524,7 @@ static void run_codec(void)
|
||||||
|
|
||||||
/* Notify audio that we're done for better or worse - advise of the
|
/* Notify audio that we're done for better or worse - advise of the
|
||||||
status */
|
status */
|
||||||
LOGFQUEUE("codec > audio Q_AUDIO_CODEC_COMPLETE: %d", status);
|
audio_codec_complete(status);
|
||||||
audio_queue_post(Q_AUDIO_CODEC_COMPLETE, status);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,7 @@ enum codec_status codec_run(void)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ci->seek_buffer(ci->id3->first_frame_offset);
|
ci->seek_buffer(ci->id3->first_frame_offset);
|
||||||
samplesdone = 0;
|
ci->set_elapsed(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
|
@ -178,6 +178,7 @@ enum codec_status codec_run(void)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Seek to the first packet */
|
/* Seek to the first packet */
|
||||||
|
ci->set_elapsed(0);
|
||||||
ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE );
|
ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,8 +134,6 @@ enum codec_status codec_run(void)
|
||||||
if (m4a_seek_raw(&demux_res, &input_stream, file_offset,
|
if (m4a_seek_raw(&demux_res, &input_stream, file_offset,
|
||||||
&sound_samples_done, (int*) &i)) {
|
&sound_samples_done, (int*) &i)) {
|
||||||
sound_samples_done *= sbr_fac;
|
sound_samples_done *= sbr_fac;
|
||||||
elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
|
|
||||||
ci->set_elapsed(elapsed_time);
|
|
||||||
} else {
|
} else {
|
||||||
sound_samples_done = 0;
|
sound_samples_done = 0;
|
||||||
}
|
}
|
||||||
|
@ -143,6 +141,9 @@ enum codec_status codec_run(void)
|
||||||
} else {
|
} else {
|
||||||
sound_samples_done = 0;
|
sound_samples_done = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
|
||||||
|
ci->set_elapsed(elapsed_time);
|
||||||
|
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -209,7 +209,7 @@ enum codec_status codec_run(void)
|
||||||
|
|
||||||
/* get in position */
|
/* get in position */
|
||||||
ci->seek_buffer(bufoff);
|
ci->seek_buffer(bufoff);
|
||||||
|
ci->set_elapsed(0);
|
||||||
|
|
||||||
/* setup pcm buffer format */
|
/* setup pcm buffer format */
|
||||||
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
|
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
|
||||||
|
@ -276,6 +276,11 @@ enum codec_status codec_run(void)
|
||||||
loop_count++;
|
loop_count++;
|
||||||
}
|
}
|
||||||
ci->seek_buffer(bufoff);
|
ci->seek_buffer(bufoff);
|
||||||
|
|
||||||
|
ci->set_elapsed(
|
||||||
|
((end_adr-start_adr)*loop_count + bufoff-chanstart)*
|
||||||
|
1000LL/avgbytespersec);
|
||||||
|
|
||||||
ci->seek_complete();
|
ci->seek_complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -288,6 +288,8 @@ enum codec_status codec_run(void)
|
||||||
bytesdone = 0;
|
bytesdone = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
|
||||||
|
|
||||||
/* The main decoder loop */
|
/* The main decoder loop */
|
||||||
endofstream = 0;
|
endofstream = 0;
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,8 @@ enum codec_status codec_run(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ci->set_elapsed(elapsedtime);
|
||||||
|
|
||||||
/* The main decoding loop */
|
/* The main decoding loop */
|
||||||
while (i < demux_res.num_sample_byte_sizes) {
|
while (i < demux_res.num_sample_byte_sizes) {
|
||||||
enum codec_command_action action = ci->get_command(¶m);
|
enum codec_command_action action = ci->get_command(¶m);
|
||||||
|
|
|
@ -220,6 +220,9 @@ enum codec_status codec_run(void)
|
||||||
firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */
|
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 */
|
/* Initialise the buffer */
|
||||||
inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
|
inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
|
||||||
|
|
||||||
|
|
|
@ -253,6 +253,8 @@ enum codec_status codec_run(void)
|
||||||
bytesdone = 0;
|
bytesdone = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
|
||||||
|
|
||||||
/* The main decoder loop */
|
/* The main decoder loop */
|
||||||
endofstream = 0;
|
endofstream = 0;
|
||||||
|
|
||||||
|
|
|
@ -105,8 +105,10 @@ enum codec_status codec_run(void)
|
||||||
param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate);
|
param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate);
|
||||||
action = CODEC_ACTION_SEEK_TIME;
|
action = CODEC_ACTION_SEEK_TIME;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
ci->set_elapsed(0);
|
||||||
|
}
|
||||||
|
|
||||||
ci->set_elapsed(0);
|
|
||||||
ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
|
ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
|
||||||
|
|
||||||
/* The main decoder loop */
|
/* The main decoder loop */
|
||||||
|
|
|
@ -460,7 +460,9 @@ enum codec_status codec_run(void)
|
||||||
codec_set_replaygain(ci->id3);
|
codec_set_replaygain(ci->id3);
|
||||||
|
|
||||||
flac_seek_offset(&fc, samplesdone);
|
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 */
|
/* The main decoding loop */
|
||||||
frame=0;
|
frame=0;
|
||||||
|
|
|
@ -1333,12 +1333,11 @@ enum codec_status codec_run(void)
|
||||||
/* New time is ready in param */
|
/* New time is ready in param */
|
||||||
modplayer.patterntableposition = param/1000;
|
modplayer.patterntableposition = param/1000;
|
||||||
modplayer.currentline = 0;
|
modplayer.currentline = 0;
|
||||||
ci->set_elapsed(modplayer.patterntableposition*1000+500);
|
|
||||||
ci->seek_complete();
|
ci->seek_complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(old_patterntableposition != modplayer.patterntableposition) {
|
if(old_patterntableposition != modplayer.patterntableposition) {
|
||||||
ci->set_elapsed(modplayer.patterntableposition*1000+500);
|
ci->set_elapsed(modplayer.patterntableposition*1000);
|
||||||
old_patterntableposition=modplayer.patterntableposition;
|
old_patterntableposition=modplayer.patterntableposition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,7 @@ static void set_elapsed(struct mp3entry* id3)
|
||||||
{
|
{
|
||||||
unsigned long offset = id3->offset > id3->first_frame_offset ?
|
unsigned long offset = id3->offset > id3->first_frame_offset ?
|
||||||
id3->offset - id3->first_frame_offset : 0;
|
id3->offset - id3->first_frame_offset : 0;
|
||||||
|
unsigned long elapsed = id3->elapsed;
|
||||||
|
|
||||||
if ( id3->vbr ) {
|
if ( id3->vbr ) {
|
||||||
if ( id3->has_toc ) {
|
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
|
/* set time for this percent (divide before multiply to prevent
|
||||||
overflow on long files. loss of precision is negligible on
|
overflow on long files. loss of precision is negligible on
|
||||||
short files) */
|
short files) */
|
||||||
id3->elapsed = i * (id3->length / 100);
|
elapsed = i * (id3->length / 100);
|
||||||
|
|
||||||
/* calculate remainder time */
|
/* calculate remainder time */
|
||||||
plen = (nextpos - relpos) * (id3->filesize / 256);
|
plen = (nextpos - relpos) * (id3->filesize / 256);
|
||||||
id3->elapsed += (((remainder * 100) / plen) *
|
elapsed += (((remainder * 100) / plen) * (id3->length / 10000));
|
||||||
(id3->length / 10000));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* no TOC exists. set a rough estimate using average bitrate */
|
/* no TOC exists. set a rough estimate using average bitrate */
|
||||||
int tpk = id3->length /
|
int tpk = id3->length /
|
||||||
((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
|
((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
|
||||||
1024);
|
1024);
|
||||||
id3->elapsed = offset / 1024 * tpk;
|
elapsed = offset / 1024 * tpk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* constant bitrate, use exact calculation */
|
/* constant bitrate, use exact calculation */
|
||||||
if (id3->bitrate != 0)
|
if (id3->bitrate != 0)
|
||||||
id3->elapsed = offset / (id3->bitrate / 8);
|
elapsed = offset / (id3->bitrate / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ci->set_elapsed(elapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MPA_SYNTH_ON_COP
|
#ifdef MPA_SYNTH_ON_COP
|
||||||
|
|
|
@ -123,6 +123,8 @@ enum codec_status codec_run(void)
|
||||||
codec_set_replaygain(ci->id3);
|
codec_set_replaygain(ci->id3);
|
||||||
|
|
||||||
/* Resume to saved sample offset. */
|
/* Resume to saved sample offset. */
|
||||||
|
elapsed_time = 0;
|
||||||
|
|
||||||
if (samplesdone > 0)
|
if (samplesdone > 0)
|
||||||
{
|
{
|
||||||
if (mpc_demux_seek_sample(demux, samplesdone) == MPC_STATUS_OK)
|
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. */
|
/* This is the decoding loop. */
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
|
|
@ -99,6 +99,8 @@ enum codec_status codec_run(void)
|
||||||
sc.bitindex = sc.gb.index - 8*consumed;
|
sc.bitindex = sc.gb.index - 8*consumed;
|
||||||
|
|
||||||
seek_start:
|
seek_start:
|
||||||
|
ci->set_elapsed(0);
|
||||||
|
|
||||||
/* The main decoding loop */
|
/* The main decoding loop */
|
||||||
ci->memset(&decoded0, 0, sizeof(int32_t)*MAX_DECODE_SIZE);
|
ci->memset(&decoded0, 0, sizeof(int32_t)*MAX_DECODE_SIZE);
|
||||||
ci->memset(&decoded1, 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 &&
|
if (param == 0 &&
|
||||||
ci->seek_buffer(sc.header_bits/8 + ci->id3->first_frame_offset)) {
|
ci->seek_buffer(sc.header_bits/8 + ci->id3->first_frame_offset)) {
|
||||||
sc.bitindex = sc.header_bits - 8*(sc.header_bits/8);
|
sc.bitindex = sc.header_bits - 8*(sc.header_bits/8);
|
||||||
ci->set_elapsed(0);
|
|
||||||
ci->seek_complete();
|
ci->seek_complete();
|
||||||
goto seek_start;
|
goto seek_start;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1299,8 +1299,8 @@ enum codec_status codec_run(void)
|
||||||
nSamplesToRender = 0; /* Start the rendering from scratch */
|
nSamplesToRender = 0; /* Start the rendering from scratch */
|
||||||
|
|
||||||
/* Set the elapsed time to the current subsong (in seconds) */
|
/* Set the elapsed time to the current subsong (in seconds) */
|
||||||
ci->seek_complete();
|
|
||||||
ci->set_elapsed(subSong*1000);
|
ci->set_elapsed(subSong*1000);
|
||||||
|
ci->seek_complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
nSamplesRendered = 0;
|
nSamplesRendered = 0;
|
||||||
|
|
|
@ -429,6 +429,8 @@ enum codec_status codec_run(void)
|
||||||
bytesdone = 0;
|
bytesdone = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
|
||||||
|
|
||||||
/* The main decoder loop */
|
/* The main decoder loop */
|
||||||
endofstream = 0;
|
endofstream = 0;
|
||||||
|
|
||||||
|
|
|
@ -560,6 +560,8 @@ enum codec_status codec_run(void)
|
||||||
return CODEC_ERROR;
|
return CODEC_ERROR;
|
||||||
|
|
||||||
DEBUGF("SPC: read size = 0x%lx\n",(unsigned long)buffersize);
|
DEBUGF("SPC: read size = 0x%lx\n",(unsigned long)buffersize);
|
||||||
|
ci->set_elapsed(0);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (load_spc_buffer(buffer, buffersize)) {
|
if (load_spc_buffer(buffer, buffersize)) {
|
||||||
|
|
|
@ -417,6 +417,7 @@ enum codec_status codec_run(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
ci->seek_buffer(0);
|
ci->seek_buffer(0);
|
||||||
|
ci->set_elapsed(0);
|
||||||
|
|
||||||
stereo = speex_stereo_state_init();
|
stereo = speex_stereo_state_init();
|
||||||
spx_ogg_sync_init(&oy);
|
spx_ogg_sync_init(&oy);
|
||||||
|
|
|
@ -90,6 +90,8 @@ enum codec_status codec_run(void)
|
||||||
decodedsamples = new_pos;
|
decodedsamples = new_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ci->set_elapsed((uint64_t)info.LENGTH * 1000 * decodedsamples / info.DATALENGTH);
|
||||||
|
|
||||||
while (!endofstream)
|
while (!endofstream)
|
||||||
{
|
{
|
||||||
enum codec_command_action action = ci->get_command(¶m);
|
enum codec_command_action action = ci->get_command(¶m);
|
||||||
|
|
|
@ -196,6 +196,9 @@ enum codec_status codec_run(void)
|
||||||
ci->set_elapsed(ov_time_tell(&vf));
|
ci->set_elapsed(ov_time_tell(&vf));
|
||||||
ci->set_offset(ov_raw_tell(&vf));
|
ci->set_offset(ov_raw_tell(&vf));
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
ci->set_elapsed(0);
|
||||||
|
}
|
||||||
|
|
||||||
previous_section = -1;
|
previous_section = -1;
|
||||||
eof = 0;
|
eof = 0;
|
||||||
|
|
|
@ -141,6 +141,8 @@ enum codec_status codec_run(void)
|
||||||
bytesdone = 0;
|
bytesdone = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
|
||||||
|
|
||||||
/* The main decoder loop */
|
/* The main decoder loop */
|
||||||
endofstream = 0;
|
endofstream = 0;
|
||||||
|
|
||||||
|
|
|
@ -378,6 +378,8 @@ enum codec_status codec_run(void)
|
||||||
bytesdone = 0;
|
bytesdone = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
|
||||||
|
|
||||||
/* The main decoder loop */
|
/* The main decoder loop */
|
||||||
endofstream = 0;
|
endofstream = 0;
|
||||||
|
|
||||||
|
|
|
@ -381,6 +381,8 @@ enum codec_status codec_run(void)
|
||||||
bytesdone = 0;
|
bytesdone = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
|
||||||
|
|
||||||
/* The main decoder loop */
|
/* The main decoder loop */
|
||||||
endofstream = 0;
|
endofstream = 0;
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ enum codec_status codec_run(void)
|
||||||
ci->configure(DSP_SET_STEREO_MODE, nchans == 2 ? STEREO_INTERLEAVED : STEREO_MONO);
|
ci->configure(DSP_SET_STEREO_MODE, nchans == 2 ? STEREO_INTERLEAVED : STEREO_MONO);
|
||||||
sr_100 = ci->id3->frequency / 100;
|
sr_100 = ci->id3->frequency / 100;
|
||||||
|
|
||||||
ci->set_elapsed (0);
|
ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10);
|
||||||
|
|
||||||
/* The main decoder loop */
|
/* The main decoder loop */
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,6 @@ restart_track:
|
||||||
% wfx.packet_size;
|
% wfx.packet_size;
|
||||||
ci->seek_buffer(resume_offset - packet_offset);
|
ci->seek_buffer(resume_offset - packet_offset);
|
||||||
elapsedtime = asf_get_timestamp(&i);
|
elapsedtime = asf_get_timestamp(&i);
|
||||||
ci->set_elapsed(elapsedtime);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -93,6 +92,8 @@ restart_track:
|
||||||
elapsedtime = 0;
|
elapsedtime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ci->set_elapsed(elapsedtime);
|
||||||
|
|
||||||
resume_offset = 0;
|
resume_offset = 0;
|
||||||
ci->configure(DSP_SWITCH_FREQUENCY, wfx.rate);
|
ci->configure(DSP_SWITCH_FREQUENCY, wfx.rate);
|
||||||
ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ?
|
ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ?
|
||||||
|
|
|
@ -79,6 +79,7 @@ restart_track:
|
||||||
ci->seek_buffer(ci->id3->first_frame_offset);
|
ci->seek_buffer(ci->id3->first_frame_offset);
|
||||||
|
|
||||||
elapsedtime = 0;
|
elapsedtime = 0;
|
||||||
|
ci->set_elapsed(0);
|
||||||
|
|
||||||
/* The main decoding loop */
|
/* The main decoding loop */
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,8 @@ restart_track:
|
||||||
ci->seek_buffer(ci->id3->first_frame_offset);
|
ci->seek_buffer(ci->id3->first_frame_offset);
|
||||||
|
|
||||||
elapsedtime = 0;
|
elapsedtime = 0;
|
||||||
|
ci->set_elapsed(0);
|
||||||
|
|
||||||
resume_offset = 0;
|
resume_offset = 0;
|
||||||
|
|
||||||
/* The main decoding loop */
|
/* The main decoding loop */
|
||||||
|
|
1457
apps/pcmbuf.c
1457
apps/pcmbuf.c
File diff suppressed because it is too large
Load diff
|
@ -21,9 +21,11 @@
|
||||||
#ifndef PCMBUF_H
|
#ifndef PCMBUF_H
|
||||||
#define PCMBUF_H
|
#define PCMBUF_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
/* Commit PCM data */
|
/* Commit PCM data */
|
||||||
void *pcmbuf_request_buffer(int *count);
|
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 */
|
/* Init */
|
||||||
size_t pcmbuf_init(unsigned char *bufend);
|
size_t pcmbuf_init(unsigned char *bufend);
|
||||||
|
@ -33,20 +35,30 @@ void pcmbuf_play_start(void);
|
||||||
void pcmbuf_play_stop(void);
|
void pcmbuf_play_stop(void);
|
||||||
void pcmbuf_pause(bool pause);
|
void pcmbuf_pause(bool pause);
|
||||||
void pcmbuf_monitor_track_change(bool monitor);
|
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 */
|
/* Crossfade */
|
||||||
#ifdef HAVE_CROSSFADE
|
#ifdef HAVE_CROSSFADE
|
||||||
bool pcmbuf_is_crossfade_active(void);
|
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);
|
bool pcmbuf_is_same_size(void);
|
||||||
#else
|
#else
|
||||||
/* Dummy functions with sensible returns */
|
/* Dummy functions with sensible returns */
|
||||||
static inline bool pcmbuf_is_crossfade_active(void)
|
static FORCE_INLINE bool pcmbuf_is_crossfade_active(void)
|
||||||
{ return false; }
|
{ 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; }
|
{ return; (void)on_off; }
|
||||||
static inline bool pcmbuf_is_same_size(void)
|
static FORCE_INLINE bool pcmbuf_is_same_size(void)
|
||||||
{ return true; }
|
{ return true; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -59,9 +71,7 @@ size_t pcmbuf_free(void);
|
||||||
size_t pcmbuf_get_bufsize(void);
|
size_t pcmbuf_get_bufsize(void);
|
||||||
int pcmbuf_descs(void);
|
int pcmbuf_descs(void);
|
||||||
int pcmbuf_used_descs(void);
|
int pcmbuf_used_descs(void);
|
||||||
#ifdef ROCKBOX_HAS_LOGF
|
unsigned int pcmbuf_get_position_key(void);
|
||||||
unsigned char *pcmbuf_get_meminfo(size_t *length);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Misc */
|
/* Misc */
|
||||||
void pcmbuf_fade(bool fade, bool in);
|
void pcmbuf_fade(bool fade, bool in);
|
||||||
|
@ -69,6 +79,5 @@ bool pcmbuf_fading(void);
|
||||||
void pcmbuf_soft_mode(bool shhh);
|
void pcmbuf_soft_mode(bool shhh);
|
||||||
bool pcmbuf_is_lowdata(void);
|
bool pcmbuf_is_lowdata(void);
|
||||||
void pcmbuf_set_low_latency(bool state);
|
void pcmbuf_set_low_latency(bool state);
|
||||||
unsigned long pcmbuf_get_latency(void);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
211
apps/playback.c
211
apps/playback.c
|
@ -330,7 +330,7 @@ static struct
|
||||||
static bool codec_skip_pending = false;
|
static bool codec_skip_pending = false;
|
||||||
static int codec_skip_status;
|
static int codec_skip_status;
|
||||||
static bool codec_seeking = false; /* Codec seeking ack expected? */
|
static bool codec_seeking = false; /* Codec seeking ack expected? */
|
||||||
|
static unsigned int position_key = 0;
|
||||||
|
|
||||||
/* Event queues */
|
/* Event queues */
|
||||||
static struct event_queue audio_queue SHAREDBSS_ATTR;
|
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_buffer_low_callback(void *data);
|
||||||
static void buffer_event_rebuffer_callback(void *data);
|
static void buffer_event_rebuffer_callback(void *data);
|
||||||
static void buffer_event_finished_callback(void *data);
|
static void buffer_event_finished_callback(void *data);
|
||||||
|
void audio_pcmbuf_sync_position(void);
|
||||||
|
|
||||||
|
|
||||||
/**************************************/
|
/**************************************/
|
||||||
|
|
||||||
/** --- audio_queue helpers --- **/
|
/** --- audio_queue helpers --- **/
|
||||||
|
static void audio_queue_post(long id, intptr_t data)
|
||||||
/* codec thread needs access */
|
|
||||||
void audio_queue_post(long id, intptr_t data)
|
|
||||||
{
|
{
|
||||||
queue_post(&audio_queue, id, 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
|
aids viewing and the summation of certain variables should add up to
|
||||||
the location of others. */
|
the location of others. */
|
||||||
{
|
{
|
||||||
size_t pcmbufsize;
|
|
||||||
const unsigned char *pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
|
|
||||||
logf("fbuf: %08X", (unsigned)filebuf);
|
logf("fbuf: %08X", (unsigned)filebuf);
|
||||||
logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
|
logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
|
||||||
logf("sbuf: %08X", (unsigned)audio_scratch_memory);
|
logf("sbuf: %08X", (unsigned)audio_scratch_memory);
|
||||||
logf("sbufe: %08X", (unsigned)(audio_scratch_memory + allocsize));
|
logf("sbufe: %08X", (unsigned)(audio_scratch_memory + allocsize));
|
||||||
logf("pcmb: %08X", (unsigned)pcmbuf);
|
|
||||||
logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -978,7 +973,8 @@ static void audio_handle_track_load_status(int trackstat)
|
||||||
/* Announce the end of playing the current track */
|
/* Announce the end of playing the current track */
|
||||||
static void audio_playlist_track_finish(void)
|
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);
|
playlist_update_resume_info(filling == STATE_ENDED ? NULL : id3);
|
||||||
|
|
||||||
|
@ -1001,6 +997,8 @@ static void audio_playlist_track_change(void)
|
||||||
if (id3)
|
if (id3)
|
||||||
send_event(PLAYBACK_EVENT_TRACK_CHANGE, id3);
|
send_event(PLAYBACK_EVENT_TRACK_CHANGE, id3);
|
||||||
|
|
||||||
|
position_key = pcmbuf_get_position_key();
|
||||||
|
|
||||||
playlist_update_resume_info(id3);
|
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
|
/* Bring the user current mp3entry up to date and set a new offset for the
|
||||||
buffered metadata */
|
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();
|
id3_mutex_lock();
|
||||||
|
|
||||||
struct mp3entry *id3 = bufgetid3(user_info->id3_hid);
|
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);
|
playing_id3->elapsed = e;
|
||||||
size_t play_offset = ply_id3->offset;
|
playing_id3->offset = o;
|
||||||
long play_elapsed = ply_id3->elapsed;
|
|
||||||
id3_write(PLAYING_ID3, id3);
|
|
||||||
ply_id3->offset = play_offset;
|
|
||||||
ply_id3->elapsed = play_elapsed;
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
pcm_play_unlock();
|
||||||
id3_write(PLAYING_ID3, id3);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id3)
|
if (id3)
|
||||||
id3->offset = offset;
|
id3->offset = offset;
|
||||||
|
@ -1093,13 +1093,6 @@ static bool halt_decoding_track(bool stop)
|
||||||
return retval;
|
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 */
|
/* Wait for any in-progress fade to complete */
|
||||||
static void audio_wait_fade_complete(void)
|
static void audio_wait_fade_complete(void)
|
||||||
{
|
{
|
||||||
|
@ -1121,6 +1114,7 @@ static void audio_ff_rewind_end(void)
|
||||||
{
|
{
|
||||||
/* Clear the buffer */
|
/* Clear the buffer */
|
||||||
pcmbuf_play_stop();
|
pcmbuf_play_stop();
|
||||||
|
audio_pcmbuf_sync_position();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (play_status != PLAY_PAUSED)
|
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
|
/* Called to make an outstanding track skip the current track and to send the
|
||||||
transition events */
|
transition events */
|
||||||
static void audio_finalise_track_change(bool delayed)
|
static void audio_finalise_track_change(void)
|
||||||
{
|
{
|
||||||
switch (skip_pending)
|
switch (skip_pending)
|
||||||
{
|
{
|
||||||
|
@ -2117,15 +2111,6 @@ static void audio_finalise_track_change(bool delayed)
|
||||||
|
|
||||||
id3_write(PLAYING_ID3, track_id3);
|
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 */
|
/* The skip is technically over */
|
||||||
skip_pending = TRACK_SKIP_NONE;
|
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
|
/* 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
|
it now or ask pcmbuf for notification depending on the type */
|
||||||
has to say */
|
static void audio_begin_track_change(enum pcm_track_change_type type,
|
||||||
static void audio_begin_track_change(bool auto_skip, int trackstat)
|
int trackstat)
|
||||||
{
|
{
|
||||||
/* Even if the new track is bad, the old track must be finished off */
|
/* 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 */
|
/* Manual track change happens now */
|
||||||
audio_finalise_track_change(false);
|
audio_finalise_track_change();
|
||||||
|
pcmbuf_sync_position_update();
|
||||||
|
|
||||||
if (play_status == PLAY_STOPPED)
|
if (play_status == PLAY_STOPPED)
|
||||||
return; /* Stopped us */
|
return; /* Stopped us */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!auto_skip)
|
|
||||||
audio_clear_paused_pcm();
|
|
||||||
|
|
||||||
if (trackstat >= LOAD_TRACK_OK)
|
if (trackstat >= LOAD_TRACK_OK)
|
||||||
{
|
{
|
||||||
struct track_info *info = track_list_current(0);
|
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 */
|
/* Everything needed for the codec is ready - start it */
|
||||||
if (audio_start_codec(auto_skip))
|
if (audio_start_codec(auto_skip))
|
||||||
{
|
{
|
||||||
if (finalised)
|
if (!auto_skip)
|
||||||
playing_id3_sync(info, -1);
|
playing_id3_sync(info, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2186,7 +2171,7 @@ static void audio_monitor_end_of_playlist(void)
|
||||||
{
|
{
|
||||||
skip_pending = TRACK_SKIP_AUTO_END_PLAYLIST;
|
skip_pending = TRACK_SKIP_AUTO_END_PLAYLIST;
|
||||||
filling = STATE_ENDING;
|
filling = STATE_ENDING;
|
||||||
pcmbuf_monitor_track_change(true);
|
pcmbuf_start_track_change(TRACK_CHANGE_END_OF_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Codec has completed decoding the track
|
/* Codec has completed decoding the track
|
||||||
|
@ -2221,14 +2206,6 @@ static void audio_on_codec_complete(int status)
|
||||||
|
|
||||||
codec_skip_pending = false;
|
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;
|
int trackstat = LOAD_TRACK_OK;
|
||||||
|
|
||||||
automatic_skip = true;
|
automatic_skip = true;
|
||||||
|
@ -2263,7 +2240,7 @@ static void audio_on_codec_complete(int status)
|
||||||
{
|
{
|
||||||
/* Continue filling after this track */
|
/* Continue filling after this track */
|
||||||
audio_reset_and_rebuffer(TRACK_LIST_KEEP_CURRENT, 1);
|
audio_reset_and_rebuffer(TRACK_LIST_KEEP_CURRENT, 1);
|
||||||
audio_begin_track_change(true, trackstat);
|
audio_begin_track_change(TRACK_CHANGE_AUTO, trackstat);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* else rebuffer at this track; status applies to the track we
|
/* 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
|
/* 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)
|
static void audio_on_track_changed(void)
|
||||||
{
|
{
|
||||||
/* Finish whatever is pending so that the WPS is in sync */
|
/* Finish whatever is pending so that the WPS is in sync */
|
||||||
audio_finalise_track_change(true);
|
audio_finalise_track_change();
|
||||||
|
|
||||||
if (codec_skip_pending)
|
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);
|
track_list_clear(TRACK_LIST_CLEAR_ALL);
|
||||||
|
|
||||||
/* Indicate manual track change */
|
/* Indicate manual track change */
|
||||||
pcmbuf_start_track_change(false);
|
pcmbuf_start_track_change(TRACK_CHANGE_MANUAL);
|
||||||
audio_clear_paused_pcm();
|
|
||||||
wipe_track_metadata(true);
|
wipe_track_metadata(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2398,6 +2374,10 @@ static void audio_start_playback(size_t offset, unsigned int flags)
|
||||||
play_status = PLAY_PLAYING;
|
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 */
|
/* Start fill from beginning of playlist */
|
||||||
playlist_peek_offset = -1;
|
playlist_peek_offset = -1;
|
||||||
buf_set_base_handle(-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);
|
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
|
/* Skip to the next/previous directory
|
||||||
|
@ -2638,7 +2618,7 @@ static void audio_on_dir_skip(int direction)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_begin_track_change(false, trackstat);
|
audio_begin_track_change(TRACK_CHANGE_MANUAL, trackstat);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enter seek mode in order to start a seek
|
/* Enter seek mode in order to start a seek
|
||||||
|
@ -2689,11 +2669,6 @@ static void audio_on_ff_rewind(long time)
|
||||||
if (time == 0)
|
if (time == 0)
|
||||||
send_event(PLAYBACK_EVENT_TRACK_FINISH, id3);
|
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;
|
id3->elapsed = time;
|
||||||
queue_reply(&audio_queue, 1);
|
queue_reply(&audio_queue, 1);
|
||||||
|
|
||||||
|
@ -2703,6 +2678,9 @@ static void audio_on_ff_rewind(long time)
|
||||||
halt that will reset it */
|
halt that will reset it */
|
||||||
codec_seeking = true;
|
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 (pending == TRACK_SKIP_AUTO)
|
||||||
{
|
{
|
||||||
if (!track_list_advance_current(-1))
|
if (!track_list_advance_current(-1))
|
||||||
|
@ -3124,75 +3102,66 @@ static void buffer_event_finished_callback(void *data)
|
||||||
|
|
||||||
/** -- Codec callbacks -- **/
|
/** -- Codec callbacks -- **/
|
||||||
|
|
||||||
/* Update elapsed times with latency-adjusted values */
|
/* Update elapsed time for next PCM insert */
|
||||||
void audio_codec_update_elapsed(unsigned long value)
|
void audio_codec_update_elapsed(unsigned long elapsed)
|
||||||
{
|
{
|
||||||
#ifdef AB_REPEAT_ENABLE
|
#ifdef AB_REPEAT_ENABLE
|
||||||
ab_position_report(value);
|
ab_position_report(elapsed);
|
||||||
#endif
|
#endif
|
||||||
|
/* Save in codec's id3 where it is used at next pcm insert */
|
||||||
unsigned long latency = pcmbuf_get_latency();
|
id3_get(CODEC_ID3)->elapsed = elapsed;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update offsets with latency-adjusted values */
|
/* Update offset for next PCM insert */
|
||||||
void audio_codec_update_offset(size_t value)
|
void audio_codec_update_offset(size_t offset)
|
||||||
{
|
{
|
||||||
struct mp3entry *ci_id3 = id3_get(CODEC_ID3);
|
/* Save in codec's id3 where it is used at next pcm insert */
|
||||||
unsigned long latency = pcmbuf_get_latency() * ci_id3->bitrate / 8;
|
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;
|
/* Normal automatic skip */
|
||||||
}
|
ab_end_of_track_report();
|
||||||
else
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Track codec: used later when updating the playing id3 at the user
|
LOGFQUEUE("codec > audio Q_AUDIO_CODEC_COMPLETE: %d", status);
|
||||||
transition */
|
audio_queue_post(Q_AUDIO_CODEC_COMPLETE, status);
|
||||||
ci_id3->offset = value;
|
}
|
||||||
|
|
||||||
/* If a skip is pending, the PCM buffer is updating the time on the
|
/* Codec has finished seeking */
|
||||||
previous song */
|
void audio_codec_seek_complete(void)
|
||||||
if (LIKELY(skip_pending == TRACK_SKIP_NONE))
|
{
|
||||||
id3_get(PLAYING_ID3)->offset = value;
|
LOGFQUEUE("codec > audio Q_AUDIO_CODEC_SEEK_COMPLETE");
|
||||||
|
audio_queue_post(Q_AUDIO_CODEC_SEEK_COMPLETE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** --- Pcmbuf callbacks --- **/
|
/** --- Pcmbuf callbacks --- **/
|
||||||
|
|
||||||
/* Between the codec and PCM track change, we need to keep updating the
|
/* Update the elapsed and offset from the information cached during the
|
||||||
* "elapsed" value of the previous (to the codec, but current to the
|
PCM buffer insert */
|
||||||
* user/PCM/WPS) track, so that the progressbar reaches the end. */
|
void audio_pcmbuf_position_callback(unsigned long elapsed, off_t offset,
|
||||||
void audio_pcmbuf_position_callback(unsigned int time)
|
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;
|
/* Synchronize position info to the codec's */
|
||||||
|
void audio_pcmbuf_sync_position(void)
|
||||||
id3->elapsed = MIN(time, id3->length);
|
{
|
||||||
|
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
|
/* Post message from pcmbuf that the end of the previous track has just
|
||||||
|
|
|
@ -378,12 +378,16 @@ static inline void cpucache_flush(void)
|
||||||
#if defined(CPU_ARM)
|
#if defined(CPU_ARM)
|
||||||
/* Use ARMs cache alignment. */
|
/* Use ARMs cache alignment. */
|
||||||
#define MEM_ALIGN_ATTR CACHEALIGN_ATTR
|
#define MEM_ALIGN_ATTR CACHEALIGN_ATTR
|
||||||
|
#define MEM_ALIGN_SIZE CACHEALIGN_SIZE
|
||||||
#elif defined(CPU_COLDFIRE)
|
#elif defined(CPU_COLDFIRE)
|
||||||
/* Use fixed alignment of 16 bytes. Speed up only for 'movem' in DRAM. */
|
/* Use fixed alignment of 16 bytes. Speed up only for 'movem' in DRAM. */
|
||||||
#define MEM_ALIGN_ATTR __attribute__((aligned(16)))
|
#define MEM_ALIGN_ATTR __attribute__((aligned(16)))
|
||||||
|
#define MEM_ALIGN_SIZE 16
|
||||||
#else
|
#else
|
||||||
/* Do nothing. */
|
/* Do nothing. */
|
||||||
#define MEM_ALIGN_ATTR
|
#define MEM_ALIGN_ATTR
|
||||||
|
/* Align pointer size */
|
||||||
|
#define MEM_ALIGN_SIZE sizeof(intptr_t)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef STORAGE_WANTS_ALIGN
|
#ifdef STORAGE_WANTS_ALIGN
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue