Calculate watermark from bitrate and harddisk spinup time.

Use a smaller PCM buffer on targets with 2MB or less ram.
(FS#9703)


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19743 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Björn Stenberg 2009-01-10 21:10:56 +00:00
parent 12b8f8de89
commit 6427d127aa
27 changed files with 85 additions and 121 deletions

View file

@ -56,11 +56,7 @@
#include "albumart.h"
#endif
#if MEM > 1
#define GUARD_BUFSIZE (32*1024)
#else
#define GUARD_BUFSIZE (8*1024)
#endif
/* Define LOGF_ENABLE to enable logf output in this file */
/*#define LOGF_ENABLE*/
@ -88,11 +84,9 @@
#endif
/* default point to start buffer refill */
#define BUFFERING_DEFAULT_WATERMARK (1024*512)
#define BUFFERING_DEFAULT_WATERMARK (1024*128)
/* amount of data to read in one read() call */
#define BUFFERING_DEFAULT_FILECHUNK (1024*32)
/* point at which the file buffer will fight for CPU time */
#define BUFFERING_CRITICAL_LEVEL (1024*128)
#define BUF_HANDLE_MASK 0x7FFFFFFF
@ -173,7 +167,6 @@ enum {
Q_BASE_HANDLE, /* Set the reference handle for buf_useful_data */
/* Configuration: */
Q_SET_WATERMARK,
Q_START_FILL, /* Request that the buffering thread initiate a buffer
fill at its earliest convenience */
Q_HANDLE_ADDED, /* Inform the buffering thread that a handle was added,
@ -555,7 +548,7 @@ static void update_data_counters(void)
static inline bool buffer_is_low(void)
{
update_data_counters();
return data_counters.useful < BUFFERING_CRITICAL_LEVEL;
return data_counters.useful < (conf_watermark / 2);
}
/* Buffer data for the given handle.
@ -1313,8 +1306,7 @@ size_t buf_used(void)
void buf_set_watermark(size_t bytes)
{
LOGFQUEUE("buffering > Q_SET_WATERMARK %ld", (long)bytes);
queue_post(&buffering_queue, Q_SET_WATERMARK, bytes);
conf_watermark = bytes;
}
static void shrink_buffer_inner(struct memory_handle *h)
@ -1386,17 +1378,6 @@ void buffering_thread(void)
base_handle_id = (int)ev.data;
break;
case Q_SET_WATERMARK:
LOGFQUEUE("buffering < Q_SET_WATERMARK");
conf_watermark = (size_t)ev.data;
if (conf_watermark < BUFFERING_DEFAULT_FILECHUNK)
{
logf("wmark<chunk %ld<%d",
(long)conf_watermark, BUFFERING_DEFAULT_FILECHUNK);
conf_watermark = BUFFERING_DEFAULT_FILECHUNK;
}
break;
#ifndef SIMULATOR
case SYS_USB_CONNECTED:
LOGFQUEUE("buffering < SYS_USB_CONNECTED");

View file

@ -55,8 +55,6 @@ enum codec_status codec_main(void)
unsigned char c = 0;
/* Generic codec initialisation */
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, 29);

View file

@ -66,7 +66,6 @@ enum codec_status codec_main(void)
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
next_track:
if (codec_init()) {

View file

@ -44,8 +44,6 @@ enum codec_status codec_main(void)
int retval;
/* Generic codec initialisation */
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, ALAC_OUTPUT_DEPTH-1);

View file

@ -147,8 +147,6 @@ enum codec_status codec_main(void)
size_t resume_offset;
/* Generic codec initialisation */
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1);
next_track:

View file

@ -38,9 +38,6 @@ enum codec_status codec_main(void)
char* module;
int bytesPerSample =2;
/* Generic codec initialisation */
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
next_track:
if (codec_init()) {
DEBUGF("codec init failed\n");

View file

@ -2,7 +2,7 @@
libdemac - A Monkey's Audio decoder
$Id:$
$Id$
Copyright (C) Dave Chapman 2007

View file

@ -2,7 +2,7 @@
libdemac - A Monkey's Audio decoder
$Id:$
$Id$
Copyright (C) Dave Chapman 2007

View file

@ -2,7 +2,7 @@
libdemac - A Monkey's Audio decoder
$Id:$
$Id$
Copyright (C) Dave Chapman 2007

View file

@ -2,7 +2,7 @@
libdemac - A Monkey's Audio decoder
$Id:$
$Id$
Copyright (C) Dave Chapman 2007

View file

@ -2,7 +2,7 @@
libdemac - A Monkey's Audio decoder
$Id:$
$Id$
Copyright (C) Dave Chapman 2007

View file

@ -2,7 +2,7 @@
libdemac - A Monkey's Audio decoder
$Id:$
$Id$
Copyright (C) Dave Chapman 2007

View file

@ -2,7 +2,7 @@
libdemac - A Monkey's Audio decoder
$Id:$
$Id$
Copyright (C) Dave Chapman 2007

View file

@ -2,7 +2,7 @@
demac - A Monkey's Audio decoder
$Id:$
$Id$
Copyright (C) Dave Chapman 2007

View file

@ -423,8 +423,6 @@ enum codec_status codec_main(void)
int retval;
/* Generic codec initialisation */
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
ci->configure(DSP_SET_SAMPLE_DEPTH, FLAC_OUTPUT_DEPTH-1);
next_track:

View file

@ -1229,9 +1229,6 @@ enum codec_status codec_main(void)
int bytesdone;
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
next_track:
if (codec_init()) {
return CODEC_ERROR;

View file

@ -47,8 +47,6 @@ enum codec_status codec_main(void)
size_t bytesleft;
/* Generic codec initialisation */
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, SHN_OUTPUT_DEPTH-1);

View file

@ -1215,9 +1215,6 @@ enum codec_status codec_main(void)
int nSamplesPerCall = 882; /* This is PAL SID single speed (44100/50Hz) */
int nSamplesToRender = 0;
/* Generic codec initialisation */
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
next_track:
if (codec_init()) {
return CODEC_ERROR;

View file

@ -559,8 +559,6 @@ enum codec_status codec_main(void)
/* Read the entire file */
DEBUGF("SPC: request initial buffer\n");
ci->configure(CODEC_SET_FILEBUF_WATERMARK, ci->filesize);
ci->seek_buffer(0);
size_t buffersize;
uint8_t* buffer = ci->request_buffer(&buffersize, ci->filesize);

View file

@ -228,7 +228,6 @@ enum codec_status codec_main(void)
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
next_track:
if (codec_init()) {

View file

@ -44,8 +44,6 @@ enum codec_status codec_main(void)
int retval;
/* Generic codec initialisation */
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
next_track:

View file

@ -468,8 +468,6 @@ enum codec_status codec_main(void)
int errcount = 0;
/* Generic codec initialisation */
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
next_track:

View file

@ -329,14 +329,14 @@ static bool dbg_buffering_thread(void)
bufused = bufsize - pcmbuf_free();
snprintf(buf, sizeof(buf), "pcm: %7ld/%7ld", (long) bufused, (long) bufsize);
snprintf(buf, sizeof(buf), "pcm: %6ld/%ld", (long) bufused, (long) bufsize);
lcd_puts(0, line++, buf);
gui_scrollbar_draw(&screens[SCREEN_MAIN],0, line*8, LCD_WIDTH, 6,
bufsize, 0, bufused, HORIZONTAL);
line++;
snprintf(buf, sizeof(buf), "alloc: %8ld/%8ld", audio_filebufused(),
snprintf(buf, sizeof(buf), "alloc: %6ld/%ld", audio_filebufused(),
(long) filebuflen);
lcd_puts(0, line++, buf);
@ -345,7 +345,7 @@ static bool dbg_buffering_thread(void)
filebuflen, 0, audio_filebufused(), HORIZONTAL);
line++;
snprintf(buf, sizeof(buf), "real: %8ld/%8ld", (long)d.buffered_data,
snprintf(buf, sizeof(buf), "real: %6ld/%ld", (long)d.buffered_data,
(long)filebuflen);
lcd_puts(0, line++, buf);
@ -354,7 +354,7 @@ static bool dbg_buffering_thread(void)
line++;
#endif
snprintf(buf, sizeof(buf), "usefl: %8ld/%8ld", (long)(d.useful_data),
snprintf(buf, sizeof(buf), "usefl: %6ld/%ld", (long)(d.useful_data),
(long)filebuflen);
lcd_puts(0, line++, buf);
@ -383,7 +383,7 @@ static bool dbg_buffering_thread(void)
{
int boostquota = boost_ticks * 1000 / ticks; /* in 0.1 % */
int avgclock = freq_sum * 10 / ticks; /* in 100 kHz */
snprintf(buf, sizeof(buf), "boost ratio: %3d.%d%% (%2d.%dMHz)",
snprintf(buf, sizeof(buf), "boost:%3d.%d%% (%d.%dMHz)",
boostquota/10, boostquota%10, avgclock/10, avgclock%10);
lcd_puts(0, line++, buf);
}

View file

@ -42,8 +42,7 @@ enum
enum
{
CODEC_SET_FILEBUF_WATERMARK = 1,
DSP_MYDSP,
DSP_MYDSP = 1,
DSP_SET_FREQUENCY,
DSP_SWITCH_FREQUENCY,
DSP_SET_SAMPLE_DEPTH,

View file

@ -48,8 +48,12 @@ static inline int32_t clip_sample_16(int32_t sample)
return sample;
}
#if MEMORYSIZE > 2
/* Keep watermark high for iPods at least (2s) */
#define PCMBUF_WATERMARK (NATIVE_FREQUENCY * 4 * 2)
#else
#define PCMBUF_WATERMARK (NATIVE_FREQUENCY * 1) /* 0.25 seconds */
#endif
/* Structure we can use to queue pcm chunks in memory to be played
* by the driver code. */
@ -125,7 +129,7 @@ extern unsigned int codec_thread_id;
(pcmbuf_unplayed_bytes < NATIVE_FREQUENCY * quarter_secs)
static bool prepare_insert(size_t length);
static void pcmbuf_under_watermark(void);
static void pcmbuf_under_watermark(bool under);
static bool pcmbuf_flush_fillpos(void);
#define CALL_IF_EXISTS(function, args...) if (function) function(args)
@ -194,7 +198,7 @@ static void pcmbuf_set_watermark_bytes(void)
pcmbuf_watermark = (crossfade_enabled && pcmbuf_size) ?
/* If crossfading, try to keep the buffer full other than 1 second */
(pcmbuf_size - (NATIVE_FREQUENCY * 4 * 1)) :
/* Otherwise, just keep it above 2 second */
/* Otherwise, just use the default */
PCMBUF_WATERMARK;
}
@ -271,7 +275,7 @@ static void boost_codec_thread(bool boost)
}
#endif /* HAVE_PRIORITY_SCHEDULING */
static void pcmbuf_under_watermark(void)
static void pcmbuf_under_watermark(bool under)
{
/* Only codec thread initiates boost - voice boosts the cpu when playing
a clip */
@ -279,13 +283,21 @@ static void pcmbuf_under_watermark(void)
if (thread_get_current() == codec_thread_id)
#endif /* SIMULATOR */
{
if (under)
{
#ifdef HAVE_PRIORITY_SCHEDULING
/* If buffer is critically low, override UI priority, else
set back to the original priority. */
boost_codec_thread(LOW_DATA(2) && pcm_is_playing());
/* If buffer is critically low, override UI priority, else
set back to the original priority. */
boost_codec_thread(LOW_DATA(2) && pcm_is_playing());
#endif
/* Fill audio buffer by boosting cpu */
trigger_cpu_boost();
/* Fill audio buffer by boosting cpu */
trigger_cpu_boost();
}
else
{
boost_codec_thread(false);
cancel_cpu_boost();
}
}
/* Disable crossfade if < .5s of audio */
@ -318,8 +330,13 @@ bool pcmbuf_is_lowdata(void)
crossfade_init || crossfade_active)
return false;
#if MEMORYSIZE > 2
/* 1 seconds of buffer is low data */
return LOW_DATA(4);
#else
/* under watermark is low data */
return (pcmbuf_unplayed_bytes < pcmbuf_watermark);
#endif
}
/* Amount of bytes left in the buffer. */
@ -421,20 +438,18 @@ static void pcmbuf_init_pcmbuffers(void)
static size_t pcmbuf_get_next_required_pcmbuf_size(void)
{
#if MEM > 1
size_t seconds = 1;
if (crossfade_enabled_pending)
seconds += global_settings.crossfade_fade_out_delay
+ global_settings.crossfade_fade_out_duration;
#if MEMORYSIZE > 2
/* Buffer has to be at least 2s long. */
seconds += 2;
logf("pcmbuf len: %ld", seconds);
return seconds * (NATIVE_FREQUENCY*4);
#else
return NATIVE_FREQUENCY*2;
#endif
logf("pcmbuf len: %ld", seconds);
return seconds * (NATIVE_FREQUENCY*4); /* 2 channels + 2 bytes/sample */
}
static char *pcmbuf_calc_audiobuffer_ptr(size_t bufsize)
@ -817,8 +832,7 @@ static bool prepare_insert(size_t length)
if (low_latency_mode)
{
/* 1/4s latency. */
if (pcmbuf_unplayed_bytes > NATIVE_FREQUENCY * 4 / 2
&& pcm_is_playing())
if (!LOW_DATA(1) && pcm_is_playing())
return false;
}
@ -830,11 +844,11 @@ static bool prepare_insert(size_t length)
{
trigger_cpu_boost();
/* Pre-buffer 1s. */
#if MEM <= 1
if (!LOW_DATA(1))
#else
/* Pre-buffer up to watermark */
#if MEMORYSIZE > 2
if (!LOW_DATA(4))
#else
if (pcmbuf_unplayed_bytes > pcmbuf_watermark)
#endif
{
logf("pcm starting");
@ -842,8 +856,8 @@ static bool prepare_insert(size_t length)
pcmbuf_play_start();
}
}
else if (pcmbuf_unplayed_bytes <= pcmbuf_watermark)
pcmbuf_under_watermark();
else
pcmbuf_under_watermark(pcmbuf_unplayed_bytes <= pcmbuf_watermark);
return true;
}
@ -1119,11 +1133,8 @@ void pcmbuf_write_voice_complete(int count)
void pcmbuf_crossfade_enable(bool on_off)
{
#if MEM > 1
/* Next setting to be used, not applied now */
crossfade_enabled_pending = on_off;
#endif
(void)on_off;
}
void pcmbuf_crossfade_enable_finished(void)

View file

@ -21,18 +21,12 @@
#ifndef PCMBUF_H
#define PCMBUF_H
#if MEM > 1
#define PCMBUF_TARGET_CHUNK 32768 /* This is the target fill size of chunks
on the pcm buffer */
#define PCMBUF_MINAVG_CHUNK 24576 /* This is the minimum average size of
chunks on the pcm buffer (or we run out
of buffer descriptors, which is
non-fatal) */
#else
#define PCMBUF_TARGET_CHUNK 16384
#define PCMBUF_MINAVG_CHUNK 12288
#endif
#define PCMBUF_MIN_CHUNK 4096 /* We try to never feed a chunk smaller than
this to the DMA */
#define PCMBUF_MIX_CHUNK 8192 /* This is the maximum size of one packet

View file

@ -88,8 +88,6 @@
#define PLAYBACK_VOICE
/* default point to start buffer refill */
#define AUDIO_DEFAULT_WATERMARK (1024*512)
/* amount of guess-space to allow for codecs that must hunt and peck
* for their correct seeek target, 32k seems a good size */
#define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
@ -162,20 +160,12 @@ enum filling_state {
STATE_FINISHED, /* all remaining tracks are fully buffered */
};
#if MEM > 1
#define MAX_TRACK 128
#else
#define MAX_TRACK 32
#endif
#define MAX_TRACK_MASK (MAX_TRACK-1)
/* As defined in plugins/lib/xxx2wav.h */
#if MEM > 1
#define GUARD_BUFSIZE (32*1024)
#else
#define GUARD_BUFSIZE (8*1024)
#endif
/* As defined in plugin.lds */
#if defined(CPU_PP)
@ -277,11 +267,13 @@ static bool track_load_started = false;
*/
static bool codec_requested_stop = false;
#ifdef HAVE_DISK_STORAGE
static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */
#endif
/* Multiple threads */
/* Set the watermark to trigger buffer fill (A/C) FIXME */
static void set_filebuf_watermark(int seconds, size_t max);
/* Set the watermark to trigger buffer fill (A/C) */
static void set_filebuf_watermark(void);
/* Audio thread */
static struct event_queue audio_queue SHAREDBSS_ATTR;
@ -797,7 +789,7 @@ void audio_set_buffer_margin(int setting)
static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
buffer_margin = lookup[setting];
logf("buffer margin: %ld", (long)buffer_margin);
set_filebuf_watermark(buffer_margin, 0);
set_filebuf_watermark();
}
#endif
@ -843,16 +835,35 @@ void audio_set_crossfade(int enable)
/* --- Routines called from multiple threads --- */
static void set_filebuf_watermark(int seconds, size_t max)
static void set_filebuf_watermark(void)
{
size_t bytes;
if (!filebuf)
return; /* Audio buffers not yet set up */
bytes = seconds?MAX(curtrack_id3.bitrate * seconds * (1000/8), max):max;
bytes = MIN(bytes, filebuflen / 2);
#ifdef HAVE_FLASH_STORAGE
int seconds = 1;
#else
int seconds;
int spinup = ata_spinup_time();
if (spinup)
seconds = (spinup / HZ) + 1;
else
seconds = 3;
#endif
/* bitrate of last track in buffer dictates watermark */
struct mp3entry* id3 = NULL;
if (tracks[track_widx].taginfo_ready)
id3 = bufgetid3(tracks[track_widx].id3_hid);
else
id3 = bufgetid3(tracks[track_widx-1].id3_hid);
if (!id3) {
logf("fwmark: No id3 for last track (r%d/w%d), aborting!", track_ridx, track_widx);
return;
}
size_t bytes = id3->bitrate * (1000/8) * seconds;
buf_set_watermark(bytes);
logf("fwmark: %d", bytes);
}
const char *get_codec_filename(int cod_spec)
@ -1106,10 +1117,6 @@ static bool codec_seek_buffer_callback(size_t newpos)
static void codec_configure_callback(int setting, intptr_t value)
{
switch (setting) {
case CODEC_SET_FILEBUF_WATERMARK:
set_filebuf_watermark(buffer_margin, value);
break;
default:
if (!dsp_configure(ci.dsp, setting, value))
{ logf("Illegal key:%d", setting); }
@ -1709,7 +1716,7 @@ static bool audio_load_track(size_t offset, bool start_play)
/* Set default values */
if (start_play)
{
buf_set_watermark(AUDIO_DEFAULT_WATERMARK);
buf_set_watermark(filebuflen/2);
dsp_configure(ci.dsp, DSP_RESET, 0);
track_changed = true;
playlist_update_resume_info(audio_current_track());
@ -2223,10 +2230,6 @@ static void audio_play_start(size_t offset)
/* Officially playing */
queue_reply(&audio_queue, 1);
#ifdef HAVE_DISK_STORAGE
set_filebuf_watermark(buffer_margin, 0);
#endif
audio_fill_file_buffer(true, offset);
add_event(BUFFER_EVENT_BUFFER_LOW, false, buffering_low_buffer_callback);
@ -2358,11 +2361,13 @@ static void audio_reset_buffer(void)
/* Subtract whatever the pcm buffer says it used plus the guard buffer */
const size_t pcmbuf_size = pcmbuf_init(filebuf + filebuflen) +GUARD_BUFSIZE;
#ifdef DEBUG
if(pcmbuf_size > filebuflen)
panicf("Not enough memory for pcmbuf_init() : %d > %d",
(int)pcmbuf_size, (int)filebuflen);
#endif
filebuflen -= pcmbuf_size;
/* Make sure filebuflen is a longword multiple after adjustment - filebuf
@ -2414,6 +2419,7 @@ static void audio_thread(void)
case Q_AUDIO_FILL_BUFFER:
LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER %d", (int)ev.data);
audio_fill_file_buffer((bool)ev.data, 0);
set_filebuf_watermark();
break;
case Q_AUDIO_FINISH_LOAD: