1
0
Fork 0
forked from len0rd/rockbox

Some re-desing to buffer filling and track loading code and a few bug

fixes.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6766 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Miika Pekkarinen 2005-06-19 18:41:53 +00:00
parent 6b3a14a7fd
commit 431e813532
2 changed files with 124 additions and 113 deletions

View file

@ -71,6 +71,7 @@ static volatile bool paused;
#define CODEC_MPC "/.rockbox/codecs/codecmpc.rock"; #define CODEC_MPC "/.rockbox/codecs/codecmpc.rock";
#define CODEC_WAVPACK "/.rockbox/codecs/codecwavpack.rock"; #define CODEC_WAVPACK "/.rockbox/codecs/codecwavpack.rock";
#define AUDIO_FILL_CYCLE (1024*256)
#define AUDIO_DEFAULT_WATERMARK (1024*256) #define AUDIO_DEFAULT_WATERMARK (1024*256)
#define AUDIO_DEFAULT_FILECHUNK (1024*32) #define AUDIO_DEFAULT_FILECHUNK (1024*32)
@ -84,6 +85,7 @@ static volatile bool paused;
#define AUDIO_FLUSH_RELOAD 8 #define AUDIO_FLUSH_RELOAD 8
#define AUDIO_CODEC_DONE 9 #define AUDIO_CODEC_DONE 9
#define AUDIO_FLUSH 10 #define AUDIO_FLUSH 10
#define AUDIO_TRACK_CHANGED 11
#define CODEC_LOAD 1 #define CODEC_LOAD 1
#define CODEC_LOAD_DISK 2 #define CODEC_LOAD_DISK 2
@ -125,6 +127,8 @@ static volatile int codecbufused;
static volatile int buf_ridx; static volatile int buf_ridx;
static volatile int buf_widx; static volatile int buf_widx;
static int last_peek_offset;
/* 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;
@ -424,6 +428,7 @@ void codec_configure_callback(int setting, void *value)
void codec_track_changed(void) void codec_track_changed(void)
{ {
track_changed = true; track_changed = true;
// queue_post(&audio_queue, AUDIO_TRACK_CHANGED, 0);
} }
void yield_codecs(void) void yield_codecs(void)
@ -438,25 +443,22 @@ void yield_codecs(void)
void audio_fill_file_buffer(void) void audio_fill_file_buffer(void)
{ {
size_t i; size_t i, size;
int rc; int rc;
tracks[track_widx].start_pos = ci.curpos; if (current_fd < 0)
logf("Filling buffer..."); return ;
i = 0; i = 0;
while ((off_t)i < tracks[track_widx].filerem) { size = MIN(tracks[track_widx].filerem, AUDIO_FILL_CYCLE);
while (i < size) {
/* Give codecs some processing time. */ /* Give codecs some processing time. */
yield_codecs(); yield_codecs();
if (!queue_empty(&audio_queue)) { if (fill_bytesleft == 0)
logf("Filling interrupted");
return ;
}
if (fill_bytesleft < MIN((unsigned int)conf_filechunk,
tracks[track_widx].filerem - i))
break ; break ;
rc = MIN(conf_filechunk, codecbuflen - buf_widx); rc = MIN(conf_filechunk, codecbuflen - buf_widx);
rc = MIN(rc, (off_t)fill_bytesleft);
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;
@ -474,7 +476,8 @@ void audio_fill_file_buffer(void)
codecbufused += i; codecbufused += i;
tracks[track_widx].filerem -= i; tracks[track_widx].filerem -= i;
tracks[track_widx].filepos += i; tracks[track_widx].filepos += i;
logf("Done:%d", tracks[track_widx].available); /*logf("Filled:%d/%d", tracks[track_widx].available,
tracks[track_widx].filerem);*/
if (tracks[track_widx].filerem == 0) { if (tracks[track_widx].filerem == 0) {
close(current_fd); close(current_fd);
current_fd = -1; current_fd = -1;
@ -569,6 +572,7 @@ bool loadcodec(const char *trackname, bool start_play)
size = filesize(fd); size = filesize(fd);
if ((off_t)fill_bytesleft < size + conf_watermark) { if ((off_t)fill_bytesleft < size + conf_watermark) {
logf("Not enough space"); logf("Not enough space");
fill_bytesleft = 0;
close(fd); close(fd);
return false; return false;
} }
@ -576,11 +580,6 @@ bool loadcodec(const char *trackname, bool start_play)
i = 0; i = 0;
while (i < size) { while (i < size) {
yield_codecs(); yield_codecs();
if (!queue_empty(&audio_queue)) {
logf("Buffering interrupted");
close(fd);
return false;
}
copy_n = MIN(conf_filechunk, codecbuflen - buf_widx); copy_n = MIN(conf_filechunk, codecbuflen - buf_widx);
rc = read(fd, &codecbuf[buf_widx], copy_n); rc = read(fd, &codecbuf[buf_widx], copy_n);
@ -609,7 +608,8 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
int rc, i; int rc, i;
int copy_n; int copy_n;
if (track_count >= MAX_TRACK) if (track_count >= MAX_TRACK || tracks[track_widx].filesize != 0
|| current_fd >= 0)
return false; return false;
trackname = playlist_peek(peek_offset); trackname = playlist_peek(peek_offset);
@ -653,13 +653,6 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
//logf("%s", trackname); //logf("%s", trackname);
logf("Buffering track:%d/%d", track_widx, track_ridx); logf("Buffering track:%d/%d", track_widx, track_ridx);
if (!queue_empty(&audio_queue)) {
logf("Interrupted!");
//ci.stop_codec = true;
close(fd);
return false;
}
if (!get_metadata(&tracks[track_widx],fd,trackname,v1first)) { if (!get_metadata(&tracks[track_widx],fd,trackname,v1first)) {
close(fd); close(fd);
return false; return false;
@ -685,22 +678,11 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
} }
i = tracks[track_widx].start_pos; i = tracks[track_widx].start_pos;
size = MIN(size, AUDIO_FILL_CYCLE);
while (i < size) { while (i < size) {
/* Give codecs some processing time to prevent glitches. */ /* Give codecs some processing time to prevent glitches. */
yield_codecs(); yield_codecs();
/* Limit buffering size at first run. */
if (conf_bufferlimit && (int)fill_bytesleft >= conf_bufferlimit) {
fill_bytesleft = conf_bufferlimit;
conf_bufferlimit = 0;
}
if (!queue_empty(&audio_queue)) {
logf("Buffering interrupted");
close(fd);
return false;
}
if (fill_bytesleft == 0) if (fill_bytesleft == 0)
break ; break ;
@ -737,7 +719,6 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
if (tracks[track_widx].filerem != 0) { if (tracks[track_widx].filerem != 0) {
current_fd = fd; current_fd = fd;
logf("Partially buf:%d", tracks[track_widx].available); logf("Partially buf:%d", tracks[track_widx].available);
return false;
} else { } else {
logf("Completely buf."); logf("Completely buf.");
close(fd); close(fd);
@ -750,20 +731,13 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
return true; return true;
} }
void audio_insert_tracks(int offset, bool start_playing, int peek_offset)
{
fill_bytesleft = codecbuflen - codecbufused;
filling = true;
while (audio_load_track(offset, start_playing, peek_offset)) {
start_playing = false;
offset = 0;
peek_offset++;
}
filling = false;
}
void audio_play_start(int offset) void audio_play_start(int offset)
{ {
if (current_fd >= 0) {
close(current_fd);
current_fd = -1;
}
memset(&tracks, 0, sizeof(struct track_info) * MAX_TRACK); memset(&tracks, 0, sizeof(struct track_info) * MAX_TRACK);
sound_set(SOUND_VOLUME, global_settings.volume); sound_set(SOUND_VOLUME, global_settings.volume);
track_count = 0; track_count = 0;
@ -773,9 +747,17 @@ void audio_play_start(int offset)
buf_widx = 0; buf_widx = 0;
codecbufused = 0; codecbufused = 0;
pcm_set_boost_mode(true); pcm_set_boost_mode(true);
audio_insert_tracks(offset, true, 0);
pcm_set_boost_mode(false); fill_bytesleft = codecbuflen;
filling = true;
last_peek_offset = 0;
if (audio_load_track(offset, true, 0)) {
last_peek_offset++;
ata_sleep(); ata_sleep();
} else {
logf("Failure");
}
pcm_set_boost_mode(false);
} }
void audio_clear_track_entries(void) void audio_clear_track_entries(void)
@ -791,25 +773,14 @@ void audio_clear_track_entries(void)
} }
} }
void audio_check_buffer(void) void initialize_buffer_fill(void)
{ {
int i; int cur_idx, i;
int cur_idx;
/* Fill buffer as full as possible for cross-fader. */
if (pcm_is_crossfade_enabled() && cur_ti->id3.length > 0
&& cur_ti->id3.length - cur_ti->id3.elapsed < 20000 && playing)
pcm_set_boost_mode(true);
/* Start buffer filling as necessary. */
if (codecbufused > conf_watermark || !queue_empty(&audio_queue)
|| !playing || ci.stop_codec || ci.reload_codec)
return ;
filling = true;
pcm_set_boost_mode(true); pcm_set_boost_mode(true);
fill_bytesleft = codecbuflen - codecbufused; fill_bytesleft = codecbuflen - codecbufused;
tracks[track_widx].start_pos = ci.curpos;
/* Calculate real track count after throwing away old tracks. */ /* Calculate real track count after throwing away old tracks. */
cur_idx = track_ridx; cur_idx = track_ridx;
@ -827,6 +798,30 @@ void audio_check_buffer(void)
/* Mark all other entries null. */ /* Mark all other entries null. */
audio_clear_track_entries(); audio_clear_track_entries();
}
void audio_check_buffer(void)
{
/* Fill buffer as full as possible for cross-fader. */
if (pcm_is_crossfade_enabled() && cur_ti->id3.length > 0
&& cur_ti->id3.length - cur_ti->id3.elapsed < 20000 && playing)
pcm_set_boost_mode(true);
/* Start buffer filling as necessary. */
if ((codecbufused > conf_watermark || !queue_empty(&audio_queue)
|| !playing || ci.stop_codec || ci.reload_codec) && !filling)
return ;
if (!filling) {
initialize_buffer_fill();
filling = true;
}
/* Limit buffering size at first run. */
if (conf_bufferlimit && (int)fill_bytesleft >= conf_bufferlimit) {
fill_bytesleft = conf_bufferlimit;
conf_bufferlimit = 0;
}
/* Try to load remainings of the file. */ /* Try to load remainings of the file. */
if (tracks[track_widx].filerem > 0) if (tracks[track_widx].filerem > 0)
@ -836,18 +831,17 @@ void audio_check_buffer(void)
if (tracks[track_widx].filerem == 0 && tracks[track_widx].filesize != 0) { if (tracks[track_widx].filerem == 0 && tracks[track_widx].filesize != 0) {
if (++track_widx == MAX_TRACK) if (++track_widx == MAX_TRACK)
track_widx = 0; track_widx = 0;
logf("new ti: %d", track_widx);
} }
logf("ti: %d", track_widx);
/* Load new files to fill the entire buffer. */ /* Load new files to fill the entire buffer. */
if (tracks[track_widx].filerem == 0) if (audio_load_track(0, false, last_peek_offset)) {
audio_insert_tracks(0, false, 1); last_peek_offset++;
} else if (tracks[track_widx].filerem == 0 || fill_bytesleft == 0) {
filling = false;
pcm_set_boost_mode(false); pcm_set_boost_mode(false);
if (playing) if (playing)
ata_sleep(); ata_sleep();
filling = false; }
} }
void audio_update_trackinfo(void) void audio_update_trackinfo(void)
@ -890,6 +884,7 @@ void audio_update_trackinfo(void)
void audio_change_track(void) void audio_change_track(void)
{ {
logf("change track");
if (track_ridx == track_widx) { if (track_ridx == track_widx) {
logf("No more tracks"); logf("No more tracks");
while (pcm_is_playing()) while (pcm_is_playing())
@ -914,6 +909,9 @@ bool codec_request_next_track_callback(void)
/* Advance to next track. */ /* Advance to next track. */
if (ci.reload_codec && new_track > 0) { if (ci.reload_codec && new_track > 0) {
last_peek_offset--;
if (!playlist_check(1))
return false;
playlist_next(1); playlist_next(1);
if (++track_ridx == MAX_TRACK) if (++track_ridx == MAX_TRACK)
track_ridx = 0; track_ridx = 0;
@ -927,6 +925,9 @@ bool codec_request_next_track_callback(void)
/* Advance to previous track. */ /* Advance to previous track. */
else if (ci.reload_codec && new_track < 0) { else if (ci.reload_codec && new_track < 0) {
last_peek_offset++;
if (!playlist_check(-1))
return false;
playlist_next(-1); playlist_next(-1);
if (--track_ridx < 0) if (--track_ridx < 0)
track_ridx = MAX_TRACK-1; track_ridx = MAX_TRACK-1;
@ -942,6 +943,9 @@ bool codec_request_next_track_callback(void)
/* Codec requested track change (next track). */ /* Codec requested track change (next track). */
else { else {
last_peek_offset--;
if (!playlist_check(1))
return false;
playlist_next(1); playlist_next(1);
if (++track_ridx >= MAX_TRACK) if (++track_ridx >= MAX_TRACK)
track_ridx = 0; track_ridx = 0;
@ -992,19 +996,28 @@ void audio_thread(void)
struct event ev; struct event ev;
while (1) { while (1) {
yield_codecs();
audio_check_buffer(); audio_check_buffer();
queue_wait_w_tmo(&audio_queue, &ev, 100); queue_wait_w_tmo(&audio_queue, &ev, 0);
switch (ev.id) { switch (ev.id) {
case AUDIO_PLAY: case AUDIO_PLAY:
logf("starting...");
ci.stop_codec = true; ci.stop_codec = true;
ci.reload_codec = false; ci.reload_codec = false;
ci.seek_time = 0; ci.seek_time = 0;
pcm_play_stop(); //pcm_play_stop();
audio_play_start((int)ev.data); audio_play_start((int)ev.data);
break ; break ;
case AUDIO_STOP: case AUDIO_STOP:
paused = false; paused = false;
filling = false;
playing = false;
ci.stop_codec = true;
if (current_fd >= 0) {
close(current_fd);
current_fd = -1;
}
pcm_play_stop(); pcm_play_stop();
pcm_play_pause(true); pcm_play_pause(true);
break ; break ;
@ -1022,6 +1035,9 @@ void audio_thread(void)
audio_invalidate_tracks(); audio_invalidate_tracks();
break ; break ;
case AUDIO_TRACK_CHANGED:
break ;
case AUDIO_CODEC_DONE: case AUDIO_CODEC_DONE:
//if (playing) //if (playing)
// audio_change_track(); // audio_change_track();
@ -1156,15 +1172,7 @@ void audio_play(int offset)
void audio_stop(void) void audio_stop(void)
{ {
logf("audio_stop"); logf("audio_stop");
playing = false;
paused = false;
ci.stop_codec = true;
if (current_fd >= 0) {
close(current_fd);
current_fd = -1;
}
queue_post(&audio_queue, AUDIO_STOP, 0); queue_post(&audio_queue, AUDIO_STOP, 0);
pcm_play_pause(true);
} }
void audio_pause(void) void audio_pause(void)
@ -1183,37 +1191,36 @@ void audio_resume(void)
//queue_post(&audio_queue, AUDIO_RESUME, 0); //queue_post(&audio_queue, AUDIO_RESUME, 0);
} }
void audio_next(void) static void initiate_track_change(int peek_index)
{ {
logf("audio_next"); if (!playlist_check(peek_index))
new_track = 1; return ;
new_track = peek_index;
ci.reload_codec = true; ci.reload_codec = true;
/* Detect if disk is spinning.. */ /* Detect if disk is spinning.. */
if (filling) { if (filling) {
ci.stop_codec = true; ci.stop_codec = true;
playlist_next(1); playlist_next(peek_index);
queue_post(&audio_queue, AUDIO_PLAY, 0); queue_post(&audio_queue, AUDIO_PLAY, 0);
} }
else if (!pcm_crossfade_start()) { else if (!pcm_crossfade_start()) {
pcm_play_stop(); //pcm_play_stop();
} }
} }
void audio_next(void)
{
logf("audio_next");
initiate_track_change(1);
}
void audio_prev(void) void audio_prev(void)
{ {
logf("audio_prev"); logf("audio_prev");
new_track = -1; initiate_track_change(-1);
ci.reload_codec = true;
pcm_play_stop();
if (filling) {
ci.stop_codec = true;
playlist_next(-1);
queue_post(&audio_queue, AUDIO_PLAY, 0);
}
//queue_post(&audio_queue, AUDIO_PREV, 0);
} }
void audio_ff_rewind(int newpos) void audio_ff_rewind(int newpos)

View file

@ -27,6 +27,7 @@
#include "uda1380.h" #include "uda1380.h"
#include "system.h" #include "system.h"
#endif #endif
#include "logf.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -225,6 +226,7 @@ void pcm_play_stop(void)
if (pcm_playing) { if (pcm_playing) {
uda1380_enable_output(false); uda1380_enable_output(false);
pcm_boost(false); pcm_boost(false);
sleep(HZ/16);
dma_stop(); dma_stop();
} }
pcmbuf_unplayed_bytes = 0; pcmbuf_unplayed_bytes = 0;
@ -384,36 +386,38 @@ bool pcm_is_lowdata(void)
bool pcm_crossfade_start(void) bool pcm_crossfade_start(void)
{ {
//logf("cf:%d", audiobuffer_free / CHUNK_SIZE); if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 4 || !crossfade_enabled) {
if (audiobuffer_free > CHUNK_SIZE * 4 || !crossfade_enabled) {
return false; return false;
} }
logf("crossfading!");
pcm_boost(true); pcm_boost(true);
crossfade_active = true; crossfade_active = true;
crossfade_pos = audiobuffer_pos; crossfade_pos = audiobuffer_pos;
crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - CHUNK_SIZE * 22)/2; crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 4))/2;
crossfade_rem = crossfade_amount; crossfade_rem = crossfade_amount;
audiobuffer_fillpos = 0; audiobuffer_fillpos = 0;
crossfade_pos -= crossfade_amount*2; crossfade_pos -= crossfade_amount*2;
if (crossfade_pos < 0) if (crossfade_pos < 0)
crossfade_pos = PCMBUF_SIZE + crossfade_pos; crossfade_pos += PCMBUF_SIZE;
return true; return true;
} }
static __inline static __inline
void crossfade(short *buf, const short *buf2, int length) void crossfade(short *buf, const short *buf2, int length)
{ {
while (length--) { int i, size;
*buf = (int)((*buf * ((crossfade_rem)*1000/crossfade_amount))/1000);
*buf += (int)((*buf2 * ((crossfade_amount-crossfade_rem)*1000/crossfade_amount))/1000); logf("cfi: %d/%d", length, crossfade_rem);
buf++; size = MIN(length, crossfade_rem);
buf2++; for (i = 0; i < length; i++) {
if (--crossfade_rem <= 0) { /* This is not yet realtime, needs optimizations for crossfade to work. */
buf[i] = ((buf[i] * ((crossfade_rem)*1000/crossfade_amount))/1000)
+ ((buf2[i] * ((crossfade_amount-crossfade_rem)*1000/crossfade_amount))/1000);
}
if (--crossfade_rem <= 0)
crossfade_active = false; crossfade_active = false;
break ;
}
}
} }
bool audiobuffer_insert(char *buf, size_t length) bool audiobuffer_insert(char *buf, size_t length)