mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-20 02:22:43 -05:00
PCM buffering fixes. Made a temporary workaround for playback glitch
bug (see the patch). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7049 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
8d3855eb53
commit
3eb962d13b
4 changed files with 87 additions and 72 deletions
|
|
@ -277,6 +277,9 @@ int codec_load_file(const char *plugin)
|
||||||
int fd;
|
int fd;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
/* zero out codec buffer to ensure a properly zeroed bss area */
|
||||||
|
memset(codecbuf, 0, CODEC_SIZE);
|
||||||
|
|
||||||
fd = open(plugin, O_RDONLY);
|
fd = open(plugin, O_RDONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
snprintf(msgbuf, sizeof(msgbuf)-1, "Couldn't load codec: %s", plugin);
|
snprintf(msgbuf, sizeof(msgbuf)-1, "Couldn't load codec: %s", plugin);
|
||||||
|
|
|
||||||
|
|
@ -39,12 +39,6 @@ void abort(void) {
|
||||||
|
|
||||||
|
|
||||||
#define INPUT_CHUNK_SIZE 8192
|
#define INPUT_CHUNK_SIZE 8192
|
||||||
#define OUTPUT_BUFFER_SIZE 65536 /* Must be an integer multiple of 4. */
|
|
||||||
|
|
||||||
unsigned char OutputBuffer[OUTPUT_BUFFER_SIZE];
|
|
||||||
unsigned char *OutputPtr;
|
|
||||||
unsigned char *GuardPtr = NULL;
|
|
||||||
const unsigned char *OutputBufferEnd = OutputBuffer + OUTPUT_BUFFER_SIZE;
|
|
||||||
|
|
||||||
mad_fixed_t mad_frame_overlap[2][32][18] IDATA_ATTR;
|
mad_fixed_t mad_frame_overlap[2][32][18] IDATA_ATTR;
|
||||||
unsigned char mad_main_data[MAD_BUFFER_MDLEN] IDATA_ATTR;
|
unsigned char mad_main_data[MAD_BUFFER_MDLEN] IDATA_ATTR;
|
||||||
|
|
@ -115,7 +109,6 @@ enum codec_status codec_start(struct codec_api* api)
|
||||||
|
|
||||||
first_frame = false;
|
first_frame = false;
|
||||||
file_end = 0;
|
file_end = 0;
|
||||||
OutputPtr = OutputBuffer;
|
|
||||||
|
|
||||||
while (!*ci->taginfo_ready)
|
while (!*ci->taginfo_ready)
|
||||||
ci->yield();
|
ci->yield();
|
||||||
|
|
@ -195,7 +188,7 @@ enum codec_status codec_start(struct codec_api* api)
|
||||||
}
|
}
|
||||||
else if(MAD_RECOVERABLE(Stream.error))
|
else if(MAD_RECOVERABLE(Stream.error))
|
||||||
{
|
{
|
||||||
if(Stream.error!=MAD_ERROR_LOSTSYNC || Stream.this_frame!=GuardPtr)
|
if(Stream.error!=MAD_ERROR_LOSTSYNC)
|
||||||
{
|
{
|
||||||
// rb->splash(HZ*1, true, "Recoverable...!");
|
// rb->splash(HZ*1, true, "Recoverable...!");
|
||||||
}
|
}
|
||||||
|
|
@ -209,9 +202,9 @@ enum codec_status codec_start(struct codec_api* api)
|
||||||
Status=1;
|
Status=1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
break ;
|
||||||
}
|
}
|
||||||
if (Stream.next_frame)
|
|
||||||
ci->advance_buffer_loc((void *)Stream.next_frame);
|
|
||||||
file_end = false;
|
file_end = false;
|
||||||
/* ?? Do we need the timer module? */
|
/* ?? Do we need the timer module? */
|
||||||
// mad_timer_add(&Timer,Frame.header.duration);
|
// mad_timer_add(&Timer,Frame.header.duration);
|
||||||
|
|
@ -241,6 +234,11 @@ enum codec_status codec_start(struct codec_api* api)
|
||||||
}
|
}
|
||||||
start_skip = 0; /* not very elegant, and might want to keep this value */
|
start_skip = 0; /* not very elegant, and might want to keep this value */
|
||||||
|
|
||||||
|
if (Stream.next_frame)
|
||||||
|
ci->advance_buffer_loc((void *)Stream.next_frame);
|
||||||
|
else
|
||||||
|
ci->advance_buffer(size);
|
||||||
|
|
||||||
samplesdone += Synth.pcm.length;
|
samplesdone += Synth.pcm.length;
|
||||||
samplecount -= Synth.pcm.length;
|
samplecount -= Synth.pcm.length;
|
||||||
ci->set_elapsed(samplesdone / (frequency_divider / 10));
|
ci->set_elapsed(samplesdone / (frequency_divider / 10));
|
||||||
|
|
|
||||||
|
|
@ -659,12 +659,12 @@ void audio_fill_file_buffer(void)
|
||||||
buf_widx -= codecbuflen;
|
buf_widx -= codecbuflen;
|
||||||
i += rc;
|
i += rc;
|
||||||
tracks[track_widx].available += rc;
|
tracks[track_widx].available += rc;
|
||||||
|
tracks[track_widx].filerem -= rc;
|
||||||
|
tracks[track_widx].filepos += rc;
|
||||||
codecbufused += rc;
|
codecbufused += rc;
|
||||||
fill_bytesleft -= rc;
|
fill_bytesleft -= rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracks[track_widx].filerem -= i;
|
|
||||||
tracks[track_widx].filepos += i;
|
|
||||||
/*logf("Filled:%d/%d", tracks[track_widx].available,
|
/*logf("Filled:%d/%d", tracks[track_widx].available,
|
||||||
tracks[track_widx].filerem);*/
|
tracks[track_widx].filerem);*/
|
||||||
}
|
}
|
||||||
|
|
@ -890,8 +890,9 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
|
||||||
|
|
||||||
/* Starting playback from an offset is only support in MPA at the moment */
|
/* Starting playback from an offset is only support in MPA at the moment */
|
||||||
if (offset > 0) {
|
if (offset > 0) {
|
||||||
if ((tracks[track_widx].id3.codectype==AFMT_MPA_L2) ||
|
switch (tracks[track_widx].id3.codectype) {
|
||||||
(tracks[track_widx].id3.codectype==AFMT_MPA_L3)) {
|
case AFMT_MPA_L2:
|
||||||
|
case AFMT_MPA_L3:
|
||||||
lseek(fd, offset, SEEK_SET);
|
lseek(fd, offset, SEEK_SET);
|
||||||
tracks[track_widx].id3.offset = offset;
|
tracks[track_widx].id3.offset = offset;
|
||||||
mp3_set_elapsed(&tracks[track_widx].id3);
|
mp3_set_elapsed(&tracks[track_widx].id3);
|
||||||
|
|
@ -899,8 +900,9 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
|
||||||
tracks[track_widx].filerem = tracks[track_widx].filesize - offset;
|
tracks[track_widx].filerem = tracks[track_widx].filesize - offset;
|
||||||
ci.curpos = offset;
|
ci.curpos = offset;
|
||||||
tracks[track_widx].start_pos = offset;
|
tracks[track_widx].start_pos = offset;
|
||||||
}
|
break;
|
||||||
else if (tracks[track_widx].id3.codectype==AFMT_WAVPACK) {
|
|
||||||
|
case AFMT_WAVPACK:
|
||||||
lseek(fd, offset, SEEK_SET);
|
lseek(fd, offset, SEEK_SET);
|
||||||
tracks[track_widx].id3.offset = offset;
|
tracks[track_widx].id3.offset = offset;
|
||||||
tracks[track_widx].id3.elapsed = tracks[track_widx].id3.length / 2;
|
tracks[track_widx].id3.elapsed = tracks[track_widx].id3.length / 2;
|
||||||
|
|
@ -908,6 +910,7 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
|
||||||
tracks[track_widx].filerem = tracks[track_widx].filesize - offset;
|
tracks[track_widx].filerem = tracks[track_widx].filesize - offset;
|
||||||
ci.curpos = offset;
|
ci.curpos = offset;
|
||||||
tracks[track_widx].start_pos = offset;
|
tracks[track_widx].start_pos = offset;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1795,6 +1798,8 @@ void audio_init(void)
|
||||||
track_buffer_callback = NULL;
|
track_buffer_callback = NULL;
|
||||||
track_unbuffer_callback = NULL;
|
track_unbuffer_callback = NULL;
|
||||||
track_changed_callback = NULL;
|
track_changed_callback = NULL;
|
||||||
|
/* Just to prevent cur_ti never be anything random. */
|
||||||
|
cur_ti = &tracks[0];
|
||||||
|
|
||||||
logf("abuf:%0x", PCMBUF_SIZE);
|
logf("abuf:%0x", PCMBUF_SIZE);
|
||||||
logf("fbuf:%0x", codecbuflen);
|
logf("fbuf:%0x", codecbuflen);
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,8 @@ static void pcm_play_callback(unsigned char** start, long* size)
|
||||||
if(pcm_play_num_used_buffers())
|
if(pcm_play_num_used_buffers())
|
||||||
{
|
{
|
||||||
/* Play max 64K at a time */
|
/* Play max 64K at a time */
|
||||||
sz = MIN(desc->size, 32768);
|
//sz = MIN(desc->size, 32768);
|
||||||
|
sz = desc->size;
|
||||||
*start = desc->addr;
|
*start = desc->addr;
|
||||||
*size = sz;
|
*size = sz;
|
||||||
|
|
||||||
|
|
@ -245,11 +246,21 @@ void pcm_play_data(const unsigned char* start, int size,
|
||||||
void (*get_more)(unsigned char** start, long* size))
|
void (*get_more)(unsigned char** start, long* size))
|
||||||
{
|
{
|
||||||
callback_for_more = get_more;
|
callback_for_more = get_more;
|
||||||
|
/** FIXME: This is a temporary fix to prevent playback glitches when
|
||||||
|
* playing the first file. We will just drop the first frame to prevent
|
||||||
|
* that problem from occurring.
|
||||||
|
* Some debug data:
|
||||||
|
* - This problem will occur only when the first file.
|
||||||
|
* - First frame will be totally corrupt and the song will begin
|
||||||
|
* from the next frame. But at the next time (when the bug has
|
||||||
|
* already happened), the song will start from first frame.
|
||||||
|
* - Dropping some frames directly from (mpa) codec will also
|
||||||
|
* prevent the problem from happening. So it's unlikely you can
|
||||||
|
* find the explanation for this bug from this file.
|
||||||
|
*/
|
||||||
|
get_more((unsigned char **)&start, (long *)&size); // REMOVE THIS TO TEST
|
||||||
get_more(&next_start, &next_size);
|
get_more(&next_start, &next_size);
|
||||||
dma_start(start, size);
|
dma_start(start, size);
|
||||||
|
|
||||||
/* Sleep a while, then unmute audio output */
|
|
||||||
sleep(HZ/8);
|
|
||||||
uda1380_mute(false);
|
uda1380_mute(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -310,7 +321,7 @@ void DMA0(void)
|
||||||
if(res & 0x70)
|
if(res & 0x70)
|
||||||
{
|
{
|
||||||
dma_stop();
|
dma_stop();
|
||||||
logf("DMA Error");
|
logf("DMA Error:0x%04x", res);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -326,7 +337,7 @@ void DMA0(void)
|
||||||
{
|
{
|
||||||
/* Finished playing */
|
/* Finished playing */
|
||||||
dma_stop();
|
dma_stop();
|
||||||
logf("DMA No Data");
|
logf("DMA No Data:0x%04x", res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -431,7 +442,7 @@ bool pcm_is_lowdata(void)
|
||||||
bool pcm_crossfade_init(void)
|
bool pcm_crossfade_init(void)
|
||||||
{
|
{
|
||||||
if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 8 || !crossfade_enabled
|
if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 8 || !crossfade_enabled
|
||||||
|| crossfade_active) {
|
|| crossfade_active || crossfade_init) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
logf("pcm_crossfade_init");
|
logf("pcm_crossfade_init");
|
||||||
|
|
@ -457,21 +468,27 @@ void pcm_flush_audio(void)
|
||||||
|
|
||||||
void pcm_flush_fillpos(void)
|
void pcm_flush_fillpos(void)
|
||||||
{
|
{
|
||||||
if (audiobuffer_fillpos) {
|
int copy_n;
|
||||||
|
|
||||||
|
copy_n = MIN(audiobuffer_fillpos, CHUNK_SIZE);
|
||||||
|
|
||||||
|
if (copy_n) {
|
||||||
while (!pcm_play_add_chunk(&audiobuffer[audiobuffer_pos],
|
while (!pcm_play_add_chunk(&audiobuffer[audiobuffer_pos],
|
||||||
audiobuffer_fillpos, pcm_event_handler)) {
|
copy_n, pcm_event_handler)) {
|
||||||
pcm_boost(false);
|
pcm_boost(false);
|
||||||
yield();
|
yield();
|
||||||
/* This is a fatal error situation that should never happen. */
|
/* This is a fatal error situation that should never happen. */
|
||||||
if (!pcm_playing)
|
if (!pcm_playing) {
|
||||||
|
logf("pcm_flush_fillpos error");
|
||||||
break ;
|
break ;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pcm_event_handler = NULL;
|
pcm_event_handler = NULL;
|
||||||
audiobuffer_pos += audiobuffer_fillpos;
|
audiobuffer_pos += copy_n;
|
||||||
if (audiobuffer_pos >= PCMBUF_SIZE)
|
if (audiobuffer_pos >= PCMBUF_SIZE)
|
||||||
audiobuffer_pos -= PCMBUF_SIZE;
|
audiobuffer_pos -= PCMBUF_SIZE;
|
||||||
audiobuffer_free -= audiobuffer_fillpos;
|
audiobuffer_free -= copy_n;
|
||||||
audiobuffer_fillpos = 0;
|
audiobuffer_fillpos -= copy_n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -541,7 +558,7 @@ int crossfade(short *buf, const short *buf2, int length)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static bool prepare_insert(long length)
|
static bool prepare_insert(long length)
|
||||||
{
|
{
|
||||||
if (crossfade_init)
|
if (crossfade_init)
|
||||||
crossfade_start();
|
crossfade_start();
|
||||||
|
|
@ -566,9 +583,10 @@ void* pcm_request_buffer(long length, long *realsize)
|
||||||
{
|
{
|
||||||
void *ptr = NULL;
|
void *ptr = NULL;
|
||||||
|
|
||||||
if (!prepare_insert(length)) {
|
while (audiobuffer_free < length + audiobuffer_fillpos
|
||||||
*realsize = 0;
|
+ CHUNK_SIZE && !crossfade_active) {
|
||||||
return NULL;
|
pcm_boost(false);
|
||||||
|
yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crossfade_active) {
|
if (crossfade_active) {
|
||||||
|
|
@ -596,6 +614,8 @@ void pcm_flush_buffer(long length)
|
||||||
int copy_n;
|
int copy_n;
|
||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
|
prepare_insert(length);
|
||||||
|
|
||||||
if (crossfade_active) {
|
if (crossfade_active) {
|
||||||
buf = &guardbuf[0];
|
buf = &guardbuf[0];
|
||||||
length = MIN(length, PCMBUF_GUARD);
|
length = MIN(length, PCMBUF_GUARD);
|
||||||
|
|
@ -699,15 +719,9 @@ void pcm_play_init(void)
|
||||||
audiobuffer = &audiobuf[(audiobufend - audiobuf) -
|
audiobuffer = &audiobuf[(audiobufend - audiobuf) -
|
||||||
PCMBUF_SIZE - PCMBUF_GUARD];
|
PCMBUF_SIZE - PCMBUF_GUARD];
|
||||||
guardbuf = &audiobuffer[PCMBUF_SIZE];
|
guardbuf = &audiobuffer[PCMBUF_SIZE];
|
||||||
audiobuffer_free = PCMBUF_SIZE;
|
|
||||||
audiobuffer_pos = 0;
|
/* Call dma_stop to initialize everything. */
|
||||||
audiobuffer_fillpos = 0;
|
dma_stop();
|
||||||
boost_mode = 0;
|
|
||||||
pcmbuf_read_index = 0;
|
|
||||||
pcmbuf_write_index = 0;
|
|
||||||
pcmbuf_unplayed_bytes = 0;
|
|
||||||
crossfade_active = false;
|
|
||||||
crossfade_init = false;
|
|
||||||
pcm_event_handler = NULL;
|
pcm_event_handler = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -723,9 +737,8 @@ bool pcm_is_crossfade_enabled(void)
|
||||||
|
|
||||||
void pcm_play_start(void)
|
void pcm_play_start(void)
|
||||||
{
|
{
|
||||||
struct pcmbufdesc *desc = &pcmbuffers[pcmbuf_read_index];
|
unsigned long size;
|
||||||
int size;
|
unsigned char *start;
|
||||||
char *start;
|
|
||||||
|
|
||||||
if (crossfade_enabled) {
|
if (crossfade_enabled) {
|
||||||
pcm_play_set_watermark(PCM_CF_WATERMARK, pcm_watermark_callback);
|
pcm_play_set_watermark(PCM_CF_WATERMARK, pcm_watermark_callback);
|
||||||
|
|
@ -736,11 +749,7 @@ void pcm_play_start(void)
|
||||||
|
|
||||||
if(!pcm_is_playing())
|
if(!pcm_is_playing())
|
||||||
{
|
{
|
||||||
size = MIN(desc->size, 32768);
|
pcm_play_callback(&start, &size);
|
||||||
start = desc->addr;
|
|
||||||
last_chunksize = size;
|
|
||||||
desc->size -= size;
|
|
||||||
desc->addr += size;
|
|
||||||
pcm_play_data(start, size, pcm_play_callback);
|
pcm_play_data(start, size, pcm_play_callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue