mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-11 14:12:26 -05:00
Fixed: Ogg Vorbis crashing, MP3 file seeking, USB mode and a little
faster file buffering. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6591 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
0f10e898f0
commit
82c2927d1e
4 changed files with 110 additions and 22 deletions
109
apps/playback.c
109
apps/playback.c
|
|
@ -114,11 +114,11 @@ char *codecbuf;
|
||||||
int codecbuflen;
|
int codecbuflen;
|
||||||
|
|
||||||
/* Bytes available in the buffer. */
|
/* Bytes available in the buffer. */
|
||||||
volatile int codecbufused;
|
static volatile int codecbufused;
|
||||||
|
|
||||||
/* Ring buffer read and write indexes. */
|
/* Ring buffer read and write indexes. */
|
||||||
static int buf_ridx;
|
static volatile int buf_ridx;
|
||||||
static int buf_widx;
|
static volatile int buf_widx;
|
||||||
|
|
||||||
#define MAX_TRACK 10
|
#define MAX_TRACK 10
|
||||||
struct track_info {
|
struct track_info {
|
||||||
|
|
@ -140,8 +140,8 @@ struct track_info {
|
||||||
/* Track information (count in file buffer, read/write indexes for
|
/* Track information (count in file buffer, read/write indexes for
|
||||||
track ring structure. */
|
track ring structure. */
|
||||||
static int track_count;
|
static int track_count;
|
||||||
static int track_ridx;
|
static volatile int track_ridx;
|
||||||
static int track_widx;
|
static volatile int track_widx;
|
||||||
static bool track_changed;
|
static bool track_changed;
|
||||||
|
|
||||||
/* Playlist position to tell the next track. */
|
/* Playlist position to tell the next track. */
|
||||||
|
|
@ -224,7 +224,6 @@ size_t codec_filebuf_callback(void *ptr, size_t size)
|
||||||
part_n = MIN(copy_n, codecbuflen - buf_ridx);
|
part_n = MIN(copy_n, codecbuflen - buf_ridx);
|
||||||
memcpy(buf, &codecbuf[buf_ridx], part_n);
|
memcpy(buf, &codecbuf[buf_ridx], part_n);
|
||||||
if (part_n < copy_n) {
|
if (part_n < copy_n) {
|
||||||
part_n = copy_n - part_n;
|
|
||||||
memcpy(&buf[part_n], &codecbuf[0], copy_n - part_n);
|
memcpy(&buf[part_n], &codecbuf[0], copy_n - part_n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -293,6 +292,8 @@ void codec_advance_buffer_loc_callback(void *ptr)
|
||||||
codec_advance_buffer_callback(amount);
|
codec_advance_buffer_callback(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mp3_get_file_pos(void);
|
||||||
|
|
||||||
off_t codec_mp3_get_filepos_callback(int newtime)
|
off_t codec_mp3_get_filepos_callback(int newtime)
|
||||||
{
|
{
|
||||||
int oldtime;
|
int oldtime;
|
||||||
|
|
@ -300,7 +301,7 @@ off_t codec_mp3_get_filepos_callback(int newtime)
|
||||||
|
|
||||||
oldtime = cur_ti->id3.elapsed;
|
oldtime = cur_ti->id3.elapsed;
|
||||||
cur_ti->id3.elapsed = newtime;
|
cur_ti->id3.elapsed = newtime;
|
||||||
newpos = audio_get_file_pos();
|
newpos = mp3_get_file_pos();
|
||||||
cur_ti->id3.elapsed = oldtime;
|
cur_ti->id3.elapsed = oldtime;
|
||||||
|
|
||||||
return newpos;
|
return newpos;
|
||||||
|
|
@ -394,6 +395,18 @@ int probe_file_format(const char *filename)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void yield_codecs(void)
|
||||||
|
{
|
||||||
|
#ifndef SIMULATOR
|
||||||
|
if (!pcm_is_playing())
|
||||||
|
sleep(5);
|
||||||
|
while (pcm_is_lowdata())
|
||||||
|
yield();
|
||||||
|
#else
|
||||||
|
yield();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void audio_fill_file_buffer(void)
|
void audio_fill_file_buffer(void)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
@ -402,7 +415,9 @@ void audio_fill_file_buffer(void)
|
||||||
logf("Filling buffer...");
|
logf("Filling buffer...");
|
||||||
i = 0;
|
i = 0;
|
||||||
while ((off_t)i < tracks[track_widx].filerem) {
|
while ((off_t)i < tracks[track_widx].filerem) {
|
||||||
sleep(5); /* Give codecs some processing time. */
|
/* Give codecs some processing time. */
|
||||||
|
yield_codecs();
|
||||||
|
|
||||||
if (!playing) {
|
if (!playing) {
|
||||||
logf("Filling interrupted");
|
logf("Filling interrupted");
|
||||||
close(current_fd);
|
close(current_fd);
|
||||||
|
|
@ -413,13 +428,13 @@ void audio_fill_file_buffer(void)
|
||||||
if (fill_bytesleft < MIN(AUDIO_FILE_CHUNK,
|
if (fill_bytesleft < MIN(AUDIO_FILE_CHUNK,
|
||||||
tracks[track_widx].filerem - i))
|
tracks[track_widx].filerem - i))
|
||||||
break ;
|
break ;
|
||||||
|
|
||||||
rc = MIN(AUDIO_FILE_CHUNK, codecbuflen - buf_widx);
|
rc = MIN(AUDIO_FILE_CHUNK, codecbuflen - buf_widx);
|
||||||
rc = read(current_fd, &codecbuf[buf_widx], rc);
|
rc = read(current_fd, &codecbuf[buf_widx], rc);
|
||||||
if (rc <= 0) {
|
if (rc <= 0) {
|
||||||
tracks[track_widx].filerem = 0;
|
tracks[track_widx].filerem = 0;
|
||||||
break ;
|
break ;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf_widx += rc;
|
buf_widx += rc;
|
||||||
if (buf_widx == codecbuflen)
|
if (buf_widx == codecbuflen)
|
||||||
buf_widx = 0;
|
buf_widx = 0;
|
||||||
|
|
@ -521,7 +536,7 @@ bool loadcodec(const char *trackname, bool start_play)
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while (i < size) {
|
while (i < size) {
|
||||||
yield();
|
yield_codecs();
|
||||||
if (!playing) {
|
if (!playing) {
|
||||||
logf("Buffering interrupted");
|
logf("Buffering interrupted");
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
@ -616,7 +631,7 @@ bool audio_load_track(int offset, bool start_play)
|
||||||
i = 0;
|
i = 0;
|
||||||
while (i < size) {
|
while (i < size) {
|
||||||
/* Give codecs some processing time to prevent glitches. */
|
/* Give codecs some processing time to prevent glitches. */
|
||||||
sleep(5);
|
yield_codecs();
|
||||||
if (!playing) {
|
if (!playing) {
|
||||||
logf("Buffering interrupted");
|
logf("Buffering interrupted");
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
@ -635,7 +650,7 @@ bool audio_load_track(int offset, bool start_play)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
buf_widx += rc;
|
buf_widx += rc;
|
||||||
if (buf_widx == codecbuflen)
|
if (buf_widx >= codecbuflen)
|
||||||
buf_widx = 0;
|
buf_widx = 0;
|
||||||
i += rc;
|
i += rc;
|
||||||
tracks[track_widx].available += rc;
|
tracks[track_widx].available += rc;
|
||||||
|
|
@ -731,6 +746,7 @@ void audio_check_buffer(void)
|
||||||
for (i = 0; i < MAX_TRACK - track_count; i++) {
|
for (i = 0; i < MAX_TRACK - track_count; i++) {
|
||||||
if (++cur_idx >= MAX_TRACK)
|
if (++cur_idx >= MAX_TRACK)
|
||||||
cur_idx = 0;
|
cur_idx = 0;
|
||||||
|
tracks[cur_idx].filesize = 0;
|
||||||
tracks[cur_idx].available = 0;
|
tracks[cur_idx].available = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -806,7 +822,7 @@ bool codec_request_next_track_callback(void)
|
||||||
if (ci.reload_codec && new_track > 0) {
|
if (ci.reload_codec && new_track > 0) {
|
||||||
if (++track_ridx == MAX_TRACK)
|
if (++track_ridx == MAX_TRACK)
|
||||||
track_ridx = 0;
|
track_ridx = 0;
|
||||||
if (track_ridx == track_widx && tracks[track_ridx].filerem == 0) {
|
if (tracks[track_ridx].filesize == 0) {
|
||||||
logf("Loading from disk...");
|
logf("Loading from disk...");
|
||||||
new_track = 0;
|
new_track = 0;
|
||||||
queue_post(&audio_queue, AUDIO_PLAY, (void *)(last_offset));
|
queue_post(&audio_queue, AUDIO_PLAY, (void *)(last_offset));
|
||||||
|
|
@ -820,7 +836,7 @@ bool codec_request_next_track_callback(void)
|
||||||
track_ridx = MAX_TRACK-1;
|
track_ridx = MAX_TRACK-1;
|
||||||
if (tracks[track_ridx].filesize == 0 ||
|
if (tracks[track_ridx].filesize == 0 ||
|
||||||
codecbufused+ci.curpos+tracks[track_ridx].filesize
|
codecbufused+ci.curpos+tracks[track_ridx].filesize
|
||||||
+ (off_t)tracks[track_ridx].codecsize > codecbuflen) {
|
/*+ (off_t)tracks[track_ridx].codecsize*/ > codecbuflen) {
|
||||||
logf("Loading from disk...");
|
logf("Loading from disk...");
|
||||||
last_offset -= track_count;
|
last_offset -= track_count;
|
||||||
if (last_offset < 0)
|
if (last_offset < 0)
|
||||||
|
|
@ -946,7 +962,7 @@ void codec_thread(void)
|
||||||
break ;
|
break ;
|
||||||
}
|
}
|
||||||
codecbufused -=codecsize;
|
codecbufused -=codecsize;
|
||||||
cur_ti->codecsize = 0;
|
// cur_ti->codecsize = 0;
|
||||||
|
|
||||||
ci.stop_codec = false;
|
ci.stop_codec = false;
|
||||||
wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf;
|
wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf;
|
||||||
|
|
@ -1136,6 +1152,68 @@ int audio_get_file_pos(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Copied from mpeg.c. Should be moved somewhere else. */
|
||||||
|
int mp3_get_file_pos(void)
|
||||||
|
{
|
||||||
|
int pos = -1;
|
||||||
|
struct mp3entry *id3 = audio_current_track();
|
||||||
|
|
||||||
|
if (id3->vbr)
|
||||||
|
{
|
||||||
|
if (id3->has_toc)
|
||||||
|
{
|
||||||
|
/* Use the TOC to find the new position */
|
||||||
|
unsigned int percent, remainder;
|
||||||
|
int curtoc, nexttoc, plen;
|
||||||
|
|
||||||
|
percent = (id3->elapsed*100)/id3->length;
|
||||||
|
if (percent > 99)
|
||||||
|
percent = 99;
|
||||||
|
|
||||||
|
curtoc = id3->toc[percent];
|
||||||
|
|
||||||
|
if (percent < 99)
|
||||||
|
nexttoc = id3->toc[percent+1];
|
||||||
|
else
|
||||||
|
nexttoc = 256;
|
||||||
|
|
||||||
|
pos = (id3->filesize/256)*curtoc;
|
||||||
|
|
||||||
|
/* Use the remainder to get a more accurate position */
|
||||||
|
remainder = (id3->elapsed*100)%id3->length;
|
||||||
|
remainder = (remainder*100)/id3->length;
|
||||||
|
plen = (nexttoc - curtoc)*(id3->filesize/256);
|
||||||
|
pos += (plen/100)*remainder;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* No TOC exists, estimate the new position */
|
||||||
|
pos = (id3->filesize / (id3->length / 1000)) *
|
||||||
|
(id3->elapsed / 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (id3->bpf && id3->tpf)
|
||||||
|
pos = (id3->elapsed/id3->tpf)*id3->bpf;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos >= (int)(id3->filesize - id3->id3v1len))
|
||||||
|
{
|
||||||
|
/* Don't seek right to the end of the file so that we can
|
||||||
|
transition properly to the next song */
|
||||||
|
pos = id3->filesize - id3->id3v1len - 1;
|
||||||
|
}
|
||||||
|
else if (pos < (int)id3->first_frame_offset)
|
||||||
|
{
|
||||||
|
/* skip past id3v2 tag and other leading garbage */
|
||||||
|
pos = id3->first_frame_offset;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef SIMULATOR
|
#ifndef SIMULATOR
|
||||||
void audio_set_buffer_margin(int seconds)
|
void audio_set_buffer_margin(int seconds)
|
||||||
{
|
{
|
||||||
|
|
@ -1181,6 +1259,7 @@ void audio_init(void)
|
||||||
ci.seek_buffer = codec_seek_buffer_callback;
|
ci.seek_buffer = codec_seek_buffer_callback;
|
||||||
ci.set_elapsed = codec_set_elapsed_callback;
|
ci.set_elapsed = codec_set_elapsed_callback;
|
||||||
|
|
||||||
|
queue_init(&audio_queue);
|
||||||
queue_init(&codec_queue);
|
queue_init(&codec_queue);
|
||||||
|
|
||||||
create_thread(codec_thread, codec_stack, sizeof(codec_stack),
|
create_thread(codec_thread, codec_stack, sizeof(codec_stack),
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||||
|
|
||||||
/* This function sets up the buffers and reads the file into RAM */
|
/* This function sets up the buffers and reads the file into RAM */
|
||||||
|
|
||||||
|
/* We need to flush reserver memory every track load. */
|
||||||
|
next_track:
|
||||||
if (codec_init(api, ci)) {
|
if (codec_init(api, ci)) {
|
||||||
return PLUGIN_ERROR;
|
return PLUGIN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
@ -118,7 +120,6 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||||
callbacks.tell_func=tell_handler;
|
callbacks.tell_func=tell_handler;
|
||||||
callbacks.close_func=close_handler;
|
callbacks.close_func=close_handler;
|
||||||
|
|
||||||
next_track:
|
|
||||||
error=ov_open_callbacks(ci,&vf,NULL,0,callbacks);
|
error=ov_open_callbacks(ci,&vf,NULL,0,callbacks);
|
||||||
|
|
||||||
vi=ov_info(&vf,-1);
|
vi=ov_info(&vf,-1);
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ int pcm_play_num_used_buffers(void);
|
||||||
void pcm_play_set_watermark(int numbytes, void (*callback)(int bytes_left));
|
void pcm_play_set_watermark(int numbytes, void (*callback)(int bytes_left));
|
||||||
|
|
||||||
void pcm_set_boost_mode(bool state);
|
void pcm_set_boost_mode(bool state);
|
||||||
|
bool pcm_is_lowdata(void);
|
||||||
unsigned int audiobuffer_get_latency(void);
|
unsigned int audiobuffer_get_latency(void);
|
||||||
bool audiobuffer_insert(char *buf, size_t length);
|
bool audiobuffer_insert(char *buf, size_t length);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -211,8 +211,7 @@ void pcm_play_data(const unsigned char* start, int size,
|
||||||
callback_for_more = get_more;
|
callback_for_more = get_more;
|
||||||
dma_start(start, size);
|
dma_start(start, size);
|
||||||
|
|
||||||
if (get_more == pcm_play_callback)
|
get_more(&next_start, &next_size);
|
||||||
get_more(&next_start, &next_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_stop(void)
|
void pcm_play_stop(void)
|
||||||
|
|
@ -256,7 +255,6 @@ void DMA0(void) __attribute__ ((interrupt_handler, section(".icode")));
|
||||||
void DMA0(void)
|
void DMA0(void)
|
||||||
{
|
{
|
||||||
int res = DSR0;
|
int res = DSR0;
|
||||||
bool rockboy = callback_for_more != pcm_play_callback;
|
|
||||||
|
|
||||||
DSR0 = 1; /* Clear interrupt */
|
DSR0 = 1; /* Clear interrupt */
|
||||||
|
|
||||||
|
|
@ -267,13 +265,11 @@ void DMA0(void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (callback_for_more && rockboy)
|
|
||||||
callback_for_more(&next_start, &next_size);
|
|
||||||
if(next_size)
|
if(next_size)
|
||||||
{
|
{
|
||||||
SAR0 = (unsigned long)next_start; /* Source address */
|
SAR0 = (unsigned long)next_start; /* Source address */
|
||||||
BCR0 = next_size; /* Bytes to transfer */
|
BCR0 = next_size; /* Bytes to transfer */
|
||||||
if (callback_for_more && !rockboy)
|
if (callback_for_more)
|
||||||
callback_for_more(&next_start, &next_size);
|
callback_for_more(&next_start, &next_size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -366,6 +362,17 @@ unsigned int audiobuffer_get_latency(void)
|
||||||
return latency;
|
return latency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pcm_is_lowdata(void)
|
||||||
|
{
|
||||||
|
if (!pcm_is_playing())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (PCMBUF_SIZE - audiobuffer_free <= PCM_WATERMARK)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool audiobuffer_insert(char *buf, size_t length)
|
bool audiobuffer_insert(char *buf, size_t length)
|
||||||
{
|
{
|
||||||
size_t copy_n = 0;
|
size_t copy_n = 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue