GSoC/Buflib: Replace all direct accesses to audiobuf with buffer API functions.

Namely, introduce buffer_get_buffer() and buffer_release_buffer().
buffer_get_buffer() aquires all available and grabs a lock, attempting to
call buffer_alloc() or buffer_get_buffer() while this lock is locked will cause
a panicf() (doesn't actually happen, but is for debugging purpose).
buffer_release_buffer() unlocks that lock and can additionally increment the
audiobuf buffer to make an allocation. Pass 0 to only unlock if buffer was
used temporarily only.
buffer_available() is a replacement function to query audiobuflen, i.e. what's
left in the buffer.
Buffer init is moved up in the init chain and handles ipodvideo64mb internally.

Further changes happened to mp3data.c and talk.c as to not call the above API
functions, but get the buffer from callers. The caller is the audio system
which has the buffer lock while mp3data.c and talk mess with the buffer.
mpeg.c now implements some buffer related functions of playback.h, especially
audio_get_buffer(), allowing to reduce #ifdef hell a tiny bit.

audiobuf and audiobufend are local to buffer.c now.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30308 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Thomas Martitz 2011-08-14 15:13:00 +00:00
parent 9b9bd73dfb
commit d1322b7159
24 changed files with 352 additions and 193 deletions

View file

@ -600,6 +600,7 @@ int ft_enter(struct tree_context* c)
/* firmware file */
case FILE_ATTR_MOD:
splash(0, ID2P(LANG_WAIT));
audio_hard_stop();
rolo_load(buf);
break;
#endif

View file

@ -337,11 +337,11 @@ static void init_tagcache(void)
static void init(void)
{
system_init();
buffer_init();
kernel_init();
#ifdef APPLICATION
paths_init();
#endif
buffer_init();
enable_irq();
lcd_init();
#ifdef HAVE_REMOTE_LCD
@ -428,13 +428,7 @@ static void init(void)
#endif
system_init();
#if defined(IPOD_VIDEO)
audiobufend=(unsigned char *)audiobufend_lds;
if(MEMORYSIZE==64 && probed_ramsize!=64)
{
audiobufend -= (32<<20);
}
#endif
buffer_init();
kernel_init();
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
@ -445,7 +439,6 @@ static void init(void)
cpu_boost(true);
#endif
buffer_init();
settings_reset();

View file

@ -182,7 +182,7 @@ static const char* info_getname(int selected_item, void *data,
case INFO_BUFFER: /* buffer */
{
long kib = (audiobufend - audiobuf) / 1024; /* to KiB */
long kib = buffer_available() / 1024; /* to KiB */
output_dyn_value(s1, sizeof(s1), kib, kbyte_units, true);
snprintf(buffer, buffer_len, "%s %s", str(LANG_BUFFER_STAT), s1);
}
@ -272,7 +272,7 @@ static int info_speak_item(int selected_item, void * data)
case INFO_BUFFER: /* buffer */
{
talk_id(LANG_BUFFER_STAT, false);
long kib = (audiobufend - audiobuf) / 1024; /* to KiB */
long kib = buffer_available() / 1024; /* to KiB */
output_dyn_value(NULL, 0, kib, kbyte_units, true);
break;
}

View file

@ -766,7 +766,10 @@ void check_bootfile(bool do_rolo)
static const struct text_message message={ lines, 2 };
button_clear_queue(); /* Empty the keyboard buffer */
if(gui_syncyesno_run(&message, NULL, NULL) == YESNO_YES)
{
audio_hard_stop();
rolo_load(BOOTDIR "/" BOOTFILE);
}
}
}
wrtdate = info.wrtdate;

View file

@ -311,17 +311,18 @@ unsigned long find_next_frame(int fd,
#ifndef __PCTOOL__
static int fnf_read_index;
static int fnf_buf_len;
static unsigned char *fnf_buf;
static int buf_getbyte(int fd, unsigned char *c)
{
if(fnf_read_index < fnf_buf_len)
{
*c = audiobuf[fnf_read_index++];
*c = fnf_buf[fnf_read_index++];
return 1;
}
else
{
fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf);
fnf_buf_len = read(fd, fnf_buf, fnf_buf_len);
if(fnf_buf_len < 0)
return -1;
@ -329,7 +330,7 @@ static int buf_getbyte(int fd, unsigned char *c)
if(fnf_buf_len > 0)
{
*c = audiobuf[fnf_read_index++];
*c = fnf_buf[fnf_read_index++];
return 1;
}
else
@ -345,7 +346,7 @@ static int buf_seek(int fd, int len)
{
len = fnf_read_index - fnf_buf_len;
fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf);
fnf_buf_len = read(fd, fnf_buf, fnf_buf_len);
if(fnf_buf_len < 0)
return -1;
@ -361,9 +362,10 @@ static int buf_seek(int fd, int len)
return 0;
}
static void buf_init(void)
static void buf_init(unsigned char* buf, size_t buflen)
{
fnf_buf_len = 0;
fnf_buf = buf;
fnf_buf_len = buflen;
fnf_read_index = 0;
}
@ -372,8 +374,9 @@ static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset)
return __find_next_frame(fd, offset, max_offset, 0, buf_getbyte, true);
}
static int audiobuflen;
static int mem_pos;
static size_t mem_buflen;
static unsigned char* mem_buf;
static size_t mem_pos;
static int mem_cnt;
static int mem_maxlen;
@ -381,8 +384,8 @@ static int mem_getbyte(int dummy, unsigned char *c)
{
dummy = dummy;
*c = audiobuf[mem_pos++];
if(mem_pos >= audiobuflen)
*c = mem_buf[mem_pos++];
if(mem_pos >= mem_buflen)
mem_pos = 0;
if(mem_cnt++ >= mem_maxlen)
@ -394,9 +397,11 @@ static int mem_getbyte(int dummy, unsigned char *c)
unsigned long mem_find_next_frame(int startpos,
long *offset,
long max_offset,
unsigned long reference_header)
unsigned long reference_header,
unsigned char* buf, size_t buflen)
{
audiobuflen = audiobufend - audiobuf;
mem_buf = buf;
mem_buflen = buflen;
mem_pos = startpos;
mem_cnt = 0;
mem_maxlen = max_offset;
@ -620,8 +625,9 @@ static void long2bytes(unsigned char *buf, long val)
buf[3] = val & 0xff;
}
int count_mp3_frames(int fd, int startpos, int filesize,
void (*progressfunc)(int))
int count_mp3_frames(int fd, int startpos, int filesize,
void (*progressfunc)(int),
unsigned char* buf, size_t buflen)
{
unsigned long header = 0;
struct mp3info info;
@ -637,7 +643,7 @@ int count_mp3_frames(int fd, int startpos, int filesize,
if(lseek(fd, startpos, SEEK_SET) < 0)
return -1;
buf_init();
buf_init(buf, buflen);
/* Find out the total number of frames */
num_frames = 0;
@ -687,7 +693,8 @@ static const char cooltext[] = "Rockbox - rocks your box";
int create_xing_header(int fd, long startpos, long filesize,
unsigned char *buf, unsigned long num_frames,
unsigned long rec_time, unsigned long header_template,
void (*progressfunc)(int), bool generate_toc)
void (*progressfunc)(int), bool generate_toc,
unsigned char *tempbuf, size_t tempbuflen )
{
struct mp3info info;
unsigned char toc[100];
@ -705,7 +712,7 @@ int create_xing_header(int fd, long startpos, long filesize,
if(generate_toc)
{
lseek(fd, startpos, SEEK_SET);
buf_init();
buf_init(tempbuf, tempbuflen);
/* Generate filepos table */
last_pos = 0;

View file

@ -26,6 +26,8 @@
#define MPEG_VERSION2 1
#define MPEG_VERSION2_5 2
#include <string.h> /* size_t */
struct mp3info {
/* Standard MP3 frame header fields */
int version;
@ -63,23 +65,21 @@ unsigned long find_next_frame(int fd,
unsigned long reference_header);
unsigned long mem_find_next_frame(int startpos,
long *offset,
long max_offset,
unsigned long reference_header);
long max_offset,
unsigned long reference_header,
unsigned char* buf, size_t buflen);
int get_mp3file_info(int fd,
struct mp3info *info);
int count_mp3_frames(int fd,
int startpos,
int filesize,
void (*progressfunc)(int));
int create_xing_header(int fd,
long startpos,
long filesize,
unsigned char *buf,
unsigned long num_frames,
unsigned long rec_time,
unsigned long header_template,
void (*progressfunc)(int),
bool generate_toc);
int count_mp3_frames(int fd, int startpos, int filesize,
void (*progressfunc)(int),
unsigned char* buf, size_t buflen);
int create_xing_header(int fd, long startpos, long filesize,
unsigned char *buf, unsigned long num_frames,
unsigned long rec_time, unsigned long header_template,
void (*progressfunc)(int), bool generate_toc,
unsigned char *tempbuf, size_t tempbuflen );
extern unsigned long bytes2int(unsigned long b0,
unsigned long b1,

View file

@ -37,6 +37,7 @@
#include "mp3data.h"
#include "buffer.h"
#include "mp3_playback.h"
#include "talk.h"
#include "sound.h"
#include "bitswap.h"
#include "appevents.h"
@ -144,19 +145,19 @@ static unsigned int mpeg_errno;
static bool playing = false; /* We are playing an MP3 stream */
static bool is_playing = false; /* We are (attempting to) playing MP3 files */
static bool paused; /* playback is paused */
static char* mpeg_audiobuf; /* the audio buffer */
static long audiobuflen; /* length of the audio buffer */
#ifdef SIMULATOR
static char mpeg_stack[DEFAULT_STACK_SIZE];
static struct mp3entry taginfo;
#else /* !SIMULATOR */
static struct event_queue mpeg_queue SHAREDBSS_ATTR;
static long mpeg_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
static int audiobuflen;
static int audiobuf_write;
static int audiobuf_swapwrite;
static int audiobuf_read;
static long audiobuf_read;
static int mpeg_file;
@ -490,6 +491,18 @@ unsigned long mpeg_get_last_header(void)
#endif /* !SIMULATOR */
}
unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size)
{
(void)talk_buf; /* always grab the voice buffer for now */
audio_hard_stop();
if (buffer_size) /* special case for talk_init() */
return buffer_get_buffer(buffer_size);
return NULL;
}
#ifndef SIMULATOR
/* Send callback events to notify about removing old tracks. */
static void generate_unbuffer_events(void)
@ -708,7 +721,7 @@ void rec_tick(void)
xor_b(0x08, &PADRH); /* Set PR inactive */
audiobuf[audiobuf_write++] = data;
mpeg_audiobuf[audiobuf_write++] = data;
if (audiobuf_write >= audiobuflen)
audiobuf_write = 0;
@ -825,7 +838,7 @@ static void transfer_end(unsigned char** ppbuf, size_t* psize)
}
*psize = last_dma_chunk_size & 0xffff;
*ppbuf = audiobuf + audiobuf_read;
*ppbuf = mpeg_audiobuf + audiobuf_read;
track = get_trackdata(0);
if(track)
track->id3.offset += last_dma_chunk_size;
@ -1128,7 +1141,7 @@ static void start_playback_if_ready(void)
playing = true;
last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song());
mp3_play_data(audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end);
mp3_play_data(mpeg_audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end);
dma_underrun = false;
if (!paused)
@ -1173,7 +1186,7 @@ static bool swap_one_chunk(void)
amount_to_swap = MIN(audiobuf_write - audiobuf_swapwrite,
amount_to_swap);
bitswap(audiobuf + audiobuf_swapwrite, amount_to_swap);
bitswap(mpeg_audiobuf + audiobuf_swapwrite, amount_to_swap);
audiobuf_swapwrite += amount_to_swap;
if(audiobuf_swapwrite >= audiobuflen)
@ -1341,7 +1354,7 @@ static void mpeg_thread(void)
track_change();
audiobuf_read = get_trackdata(0)->mempos;
last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song());
mp3_play_data(audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end);
mp3_play_data(mpeg_audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end);
dma_underrun = false;
last_dma_tick = current_tick;
@ -1501,7 +1514,7 @@ static void mpeg_thread(void)
/* resume will start at new position */
last_dma_chunk_size =
MIN(0x2000, get_unplayed_space_current_song());
mp3_play_data(audiobuf + audiobuf_read,
mp3_play_data(mpeg_audiobuf + audiobuf_read,
last_dma_chunk_size, transfer_end);
dma_underrun = false;
}
@ -1632,7 +1645,7 @@ static void mpeg_thread(void)
{
DEBUGF("R\n");
t1 = current_tick;
len = read(mpeg_file, audiobuf + audiobuf_write,
len = read(mpeg_file, mpeg_audiobuf + audiobuf_write,
amount_to_read);
if(len > 0)
{
@ -1659,7 +1672,7 @@ static void mpeg_thread(void)
if(tagptr >= audiobuflen)
tagptr -= audiobuflen;
if(audiobuf[tagptr] != tag[i])
if(mpeg_audiobuf[tagptr] != tag[i])
{
taglen = 0;
break;
@ -1773,19 +1786,20 @@ static void mpeg_thread(void)
startpos = prerecord_buffer[startpos].mempos;
DEBUGF("Start looking at address %x (%x)\n",
audiobuf+startpos, startpos);
mpeg_audiobuf+startpos, startpos);
saved_header = mpeg_get_last_header();
mem_find_next_frame(startpos, &offset, 1800,
saved_header);
saved_header, mpeg_audiobuf,
audiobuflen);
audiobuf_read = startpos + offset;
if(audiobuf_read >= audiobuflen)
audiobuf_read -= audiobuflen;
DEBUGF("New audiobuf_read address: %x (%x)\n",
audiobuf+audiobuf_read, audiobuf_read);
mpeg_audiobuf+audiobuf_read, audiobuf_read);
level = disable_irq_save();
num_rec_bytes = get_unsaved_space();
@ -1894,7 +1908,8 @@ static void mpeg_thread(void)
save_endpos += audiobuflen;
rc = mem_find_next_frame(save_endpos, &offset, 1800,
saved_header);
saved_header, mpeg_audiobuf,
audiobuflen);
if (!rc) /* No header found, save whole buffer */
offset = 1800;
@ -1936,7 +1951,7 @@ static void mpeg_thread(void)
#elif MEMORYSIZE == 8
amount_to_save = MIN(0x100000, amount_to_save);
#endif
rc = write(mpeg_file, audiobuf + audiobuf_read,
rc = write(mpeg_file, mpeg_audiobuf + audiobuf_read,
amount_to_save);
if (rc < 0)
{
@ -2256,21 +2271,21 @@ static void prepend_header(void)
if(audiobuf_read < 0)
{
/* Clear the bottom half */
memset(audiobuf, 0, audiobuf_read + MPEG_RESERVED_HEADER_SPACE);
memset(mpeg_audiobuf, 0, audiobuf_read + MPEG_RESERVED_HEADER_SPACE);
/* And the top half */
audiobuf_read += audiobuflen;
memset(audiobuf + audiobuf_read, 0, audiobuflen - audiobuf_read);
memset(mpeg_audiobuf + audiobuf_read, 0, audiobuflen - audiobuf_read);
}
else
{
memset(audiobuf + audiobuf_read, 0, MPEG_RESERVED_HEADER_SPACE);
memset(mpeg_audiobuf + audiobuf_read, 0, MPEG_RESERVED_HEADER_SPACE);
}
/* Copy the empty ID3 header */
startpos = audiobuf_read;
for(i = 0; i < sizeof(empty_id3_header); i++)
{
audiobuf[startpos++] = empty_id3_header[i];
mpeg_audiobuf[startpos++] = empty_id3_header[i];
if(startpos == audiobuflen)
startpos = 0;
}
@ -2297,7 +2312,8 @@ static void update_header(void)
/* saved_header is saved right before stopping the MAS */
framelen = create_xing_header(fd, 0, last_rec_bytes, xing_buffer,
frames, last_rec_time * (1000/HZ),
saved_header, NULL, false);
saved_header, NULL, false,
mpeg_audiobuf, audiobuflen);
lseek(fd, MPEG_RESERVED_HEADER_SPACE - framelen, SEEK_SET);
write(fd, xing_buffer, framelen);
@ -2645,8 +2661,22 @@ void audio_set_recording_options(struct audio_recording_options *options)
#endif /* SIMULATOR */
#endif /* CONFIG_CODEC == MAS3587F */
static void audio_reset_buffer(void)
{
size_t bufsize; /* dont break strict-aliasing */
talk_buffer_steal(); /* will use the mp3 buffer */
/* release buffer on behalf of any audio_get_buffer() caller,
* non-fatal if there was none */
buffer_release_buffer(0);
/* re-aquire */
mpeg_audiobuf = buffer_get_buffer(&bufsize);
audiobuflen = bufsize;
}
void audio_play(long offset)
{
audio_reset_buffer();
#ifdef SIMULATOR
char name_buf[MAX_PATH+1];
const char* trackname;
@ -2676,7 +2706,6 @@ void audio_play(long offset)
} while(1);
#else /* !SIMULATOR */
is_playing = true;
queue_post(&mpeg_queue, MPEG_PLAY, offset);
#endif /* !SIMULATOR */
@ -2700,6 +2729,8 @@ void audio_stop(void)
is_playing = false;
playing = false;
#endif /* SIMULATOR */
/* give voice our entire buffer */
talkbuf_init(mpeg_audiobuf);
}
/* dummy */
@ -2708,6 +2739,14 @@ void audio_stop_recording(void)
audio_stop();
}
void audio_hard_stop(void)
{
audio_stop();
/* tell voice we obtain the buffer before freeing */
talk_buffer_steal();
buffer_release_buffer(0);
}
void audio_pause(void)
{
#ifndef SIMULATOR
@ -2864,8 +2903,12 @@ void audio_init(void)
if (global_settings.cuesheet)
curr_cuesheet = (struct cuesheet*)buffer_alloc(sizeof(struct cuesheet));
size_t bufsize; /* don't break strict-aliasing */
mpeg_audiobuf = buffer_get_buffer(&bufsize);
audiobuflen = bufsize;
/* give voice buffer until we start to play */
talkbuf_init(mpeg_audiobuf);
#ifndef SIMULATOR
audiobuflen = audiobufend - audiobuf;
queue_init(&mpeg_queue, true);
#endif /* !SIMULATOR */
create_thread(mpeg_thread, mpeg_stack,

View file

@ -744,16 +744,25 @@ static void audio_reset_buffer(void)
/* see audio_get_recording_buffer if this is modified */
logf("%s()", __func__);
/* release the buffer on behalf of any caller of audio_get_buffer() */
buffer_release_buffer(0);
/* If the setup of anything allocated before the file buffer is
changed, do check the adjustments after the buffer_alloc call
as it will likely be affected and need sliding over */
/* Initially set up file buffer as all space available */
unsigned char *filebuf = audiobuf + talk_get_bufsize();
size_t filebuflen = audiobufend - filebuf;
size_t allocsize;
size_t filebuflen, allocsize;
unsigned char *filebuf = buffer_get_buffer(&filebuflen);
ALIGN_BUFFER(filebuf, filebuflen, sizeof (intptr_t));
/* Subtract whatever voice needs */
allocsize = talkbuf_init(filebuf);
allocsize = ALIGN_UP(allocsize, sizeof (intptr_t));
if (allocsize > filebuflen)
goto bufpanic;
filebuf += allocsize;
filebuflen -= allocsize;
if (talk_voice_required())
{
@ -3335,6 +3344,7 @@ void audio_hard_stop(void)
#ifdef PLAYBACK_VOICE
voice_stop();
#endif
buffer_release_buffer(0);
}
/* Resume playback if paused */
@ -3441,7 +3451,7 @@ void audio_flush_and_reload_tracks(void)
voicing */
unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size)
{
unsigned char *buf, *end;
unsigned char *buf;
if (audio_is_initialized)
{
@ -3461,7 +3471,7 @@ unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size)
|| !talk_voice_required())
{
logf("get buffer: talk, audio");
/* Ok to use everything from audiobuf to audiobufend - voice is loaded,
/* Ok to use everything from audiobuf - voice is loaded,
the talk buffer is not needed because voice isn't being used, or
could be AUDIOBUF_STATE_TRASHED already. If state is
AUDIOBUF_STATE_VOICED_ONLY, no problem as long as memory isn't
@ -3474,9 +3484,7 @@ unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size)
talk_buffer_steal();
buffer_state = AUDIOBUF_STATE_TRASHED;
}
buf = audiobuf;
end = audiobufend;
buf = buffer_get_buffer(buffer_size);
}
else
{
@ -3485,14 +3493,18 @@ unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size)
/* Skip talk buffer and move pcm buffer to end to maximize available
contiguous memory - no audio running means voice will not need the
swap space */
size_t siz, talkbuf_size;
logf("get buffer: audio");
buf = audiobuf + talk_get_bufsize();
end = audiobufend - voicebuf_init(audiobufend);
/* call buffer_get_buffer() to make use of the locking mechanism */
buf = buffer_get_buffer(&siz);
buf += talkbuf_size = talkbuf_init(buf);
siz -= talkbuf_size;
siz -= voicebuf_init(buf + siz);
*buffer_size = siz;
buffer_state = AUDIOBUF_STATE_VOICED_ONLY;
}
*buffer_size = end - buf;
return buf;
}
@ -3500,14 +3512,11 @@ unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size)
/* Stop audio, voice and obtain all available buffer space */
unsigned char * audio_get_recording_buffer(size_t *buffer_size)
{
audio_hard_stop();
talk_buffer_steal();
audio_hard_stop();
unsigned char *end = audiobufend;
buffer_state = AUDIOBUF_STATE_TRASHED;
*buffer_size = end - audiobuf;
return (unsigned char *)audiobuf;
return buffer_get_buffer(buffer_size);
}
#endif /* HAVE_RECORDING */

View file

@ -75,7 +75,6 @@ int audio_track_count(void);
long audio_filebufused(void);
void audio_pre_ff_rewind(void);
void audio_skip(int direction);
void audio_hard_stop(void); /* Stops audio from serving playback */
void audio_set_cuesheet(int enable);
#ifdef HAVE_CROSSFADE

View file

@ -533,13 +533,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist,
{
/* use mp3 buffer for maximum load speed */
audio_stop();
#if CONFIG_CODEC != SWCODEC
talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
buflen = (audiobufend - audiobuf);
buffer = (char *)audiobuf;
#else
buffer = (char *)audio_get_buffer(false, &buflen);
#endif
buffer = audio_get_buffer(false, &buflen);
}
store_index = true;
@ -2018,13 +2012,7 @@ int playlist_resume(void)
bool sorted = true;
/* use mp3 buffer for maximum load speed */
#if CONFIG_CODEC != SWCODEC
talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
buflen = (audiobufend - audiobuf);
buffer = (char *)audiobuf;
#else
buffer = (char *)audio_get_buffer(false, &buflen);
#endif
empty_playlist(playlist, true);
@ -2449,10 +2437,6 @@ void playlist_start(int start_index, int offset)
playlist->index = start_index;
#if CONFIG_CODEC != SWCODEC
talk_buffer_steal(); /* will use the mp3 buffer */
#endif
playlist->started = true;
sync_control(playlist, false);
audio_play(offset);

View file

@ -493,9 +493,6 @@ static int onplay_menu(int index)
if (current_track->display_index!=viewer.num_tracks ||
global_settings.repeat_mode == REPEAT_ALL)
{
#if CONFIG_CODEC != SWCODEC
talk_buffer_steal(); /* will use the mp3 buffer */
#endif
audio_play(0);
viewer.current_playing_track = -1;
}

View file

@ -979,14 +979,8 @@ void* plugin_get_buffer(size_t *buffer_size)
*/
void* plugin_get_audio_buffer(size_t *buffer_size)
{
#if CONFIG_CODEC == SWCODEC
return audio_get_buffer(true, buffer_size);
#else
audio_stop();
talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
*buffer_size = audiobufend - audiobuf;
return audiobuf;
#endif
return audio_get_buffer(true, buffer_size);
}
/* The plugin wants to stay resident after leaving its main function, e.g.

View file

@ -828,12 +828,14 @@ struct plugin_api {
#endif /* CONFIG_CODEC == SWCODEC */
bool (*get_metadata)(struct mp3entry* id3, int fd, const char* trackname);
bool (*mp3info)(struct mp3entry *entry, const char *filename);
int (*count_mp3_frames)(int fd, int startpos, int filesize,
void (*progressfunc)(int));
int (*count_mp3_frames)(int fd, int startpos, int filesize,
void (*progressfunc)(int),
unsigned char* buf, size_t buflen);
int (*create_xing_header)(int fd, long startpos, long filesize,
unsigned char *buf, unsigned long num_frames,
unsigned long rec_time, unsigned long header_template,
void (*progressfunc)(int), bool generate_toc);
void (*progressfunc)(int), bool generate_toc,
unsigned char* tempbuf, size_t tempbuf_len);
unsigned long (*find_next_frame)(int fd, long *offset,
long max_offset, unsigned long reference_header);

View file

@ -157,14 +157,15 @@ static bool vbr_fix(const char *selected_file)
xingupdate(0);
num_frames = rb->count_mp3_frames(fd, entry.first_frame_offset,
flen, xingupdate);
flen, xingupdate, audiobuf, audiobuflen);
if(num_frames) {
/* Note: We don't need to pass a template header because it will be
taken from the mpeg stream */
framelen = rb->create_xing_header(fd, entry.first_frame_offset,
flen, xingbuf, num_frames, 0,
0, xingupdate, true);
0, xingupdate, true,
audiobuf, audiobuflen);
/* Try to fit the Xing header first in the stream. Replace the existing
VBR header if there is one, else see if there is room between the

View file

@ -1643,14 +1643,12 @@ void enc_set_parameters(struct enc_parameters *params)
logf("fnq files:%ld", fnq_size / MAX_PATH);
#if defined(DEBUG)
logf("ab :%08lX", (uintptr_t)audiobuf);
logf("pcm:%08lX", (uintptr_t)pcm_buffer);
logf("enc:%08lX", (uintptr_t)enc_buffer);
logf("res:%08lX", (uintptr_t)params->reserve_buffer);
logf("wip:%08lX", (uintptr_t)wrap_id_p);
logf("fnq:%08lX", (uintptr_t)fn_queue);
logf("end:%08lX", (uintptr_t)fn_queue + fnq_size);
logf("abe:%08lX", (uintptr_t)audiobufend);
#endif
/* init all chunk headers and reset indexes */

View file

@ -107,7 +107,7 @@ static char curpath[TAG_MAXLEN+32];
/* Used when removing duplicates. */
static char *tempbuf; /* Allocated when needed. */
static long tempbufidx; /* Current location in buffer. */
static long tempbuf_size; /* Buffer size (TEMPBUF_SIZE). */
static size_t tempbuf_size; /* Buffer size (TEMPBUF_SIZE). */
static long tempbuf_left; /* Buffer space left. */
static long tempbuf_pos;
@ -3089,9 +3089,7 @@ static void allocate_tempbuf(void)
tempbuf_size = 32*1024*1024;
tempbuf = malloc(tempbuf_size);
#else
tempbuf = (char *)(((long)audiobuf & ~0x03) + 0x04);
tempbuf_size = (long)audiobufend - (long)audiobuf - 4;
audiobuf += tempbuf_size;
buffer_get_buffer(&tempbuf_size);
#endif
}
@ -3103,7 +3101,7 @@ static void free_tempbuf(void)
#ifdef __PCTOOL__
free(tempbuf);
#else
audiobuf -= tempbuf_size;
buffer_release_buffer(0);
#endif
tempbuf = NULL;
tempbuf_size = 0;

View file

@ -49,7 +49,7 @@
MASCODEC | MASCODEC | SWCODEC
(playing) | (stopped) |
audiobuf-----------+-----------+------------
voicebuf-----------+-----------+------------
audio | voice | thumbnail
|-----------|------------
| thumbnail | voice
@ -57,7 +57,7 @@
| | filebuf
| |------------
| | audio
audiobufend----------+-----------+------------
voicebufend----------+-----------+------------
SWCODEC allocates dedicated buffers, MASCODEC reuses audiobuf. */
@ -128,6 +128,7 @@ static uint8_t clip_age[QUEUE_SIZE];
#endif
#endif
static char* voicebuf; /* root pointer to our buffer */
static unsigned char* p_thumbnail = NULL; /* buffer for thumbnails */
/* Multiple thumbnails can be loaded back-to-back in this buffer. */
static volatile int thumbnail_buf_used SHAREDBSS_ATTR; /* length of data in
@ -281,12 +282,18 @@ static unsigned char* get_clip(long id, long* p_size)
/* load the voice file into the mp3 buffer */
static void load_voicefile(bool probe)
static void load_voicefile(bool probe, char* buf, size_t bufsize)
{
int load_size;
union voicebuf {
unsigned char* buf;
struct voicefile* file;
};
union voicebuf voicebuf;
int load_size, alloc_size;
int got_size;
#ifndef TALK_PARTIAL_LOAD
int file_size;
size_t file_size;
#endif
#ifdef ROCKBOX_LITTLE_ENDIAN
int i;
@ -297,37 +304,43 @@ static void load_voicefile(bool probe)
if (filehandle < 0) /* failed to open */
goto load_err;
voicebuf.buf = buf;
if (!voicebuf.buf)
goto load_err;
#ifndef TALK_PARTIAL_LOAD
file_size = filesize(filehandle);
if (file_size > audiobufend - audiobuf) /* won't fit? */
if (file_size > bufsize) /* won't fit? */
goto load_err;
#endif
#if defined(TALK_PROGRESSIVE_LOAD) || defined(TALK_PARTIAL_LOAD)
/* load only the header for now */
load_size = offsetof(struct voicefile, index);
load_size = sizeof(struct voicefile);
#else /* load the full file */
load_size = file_size;
#endif
#ifdef TALK_PARTIAL_LOAD
if (load_size > audiobufend - audiobuf) /* won't fit? */
if (load_size > bufsize) /* won't fit? */
goto load_err;
#endif
got_size = read(filehandle, audiobuf, load_size);
got_size = read(filehandle, voicebuf.buf, load_size);
if (got_size != load_size /* failure */)
goto load_err;
alloc_size = load_size;
#ifdef ROCKBOX_LITTLE_ENDIAN
logf("Byte swapping voice file");
structec_convert(audiobuf, "lllll", 1, true);
structec_convert(voicebuf.buf, "lllll", 1, true);
#endif
if (((struct voicefile*)audiobuf)->table /* format check */
== offsetof(struct voicefile, index))
/* format check */
if (voicebuf.file->table == sizeof(struct voicefile))
{
p_voicefile = (struct voicefile*)audiobuf;
p_voicefile = voicebuf.file;
if (p_voicefile->version != VOICE_VERSION ||
p_voicefile->target_id != TARGET_ID)
@ -337,9 +350,9 @@ static void load_voicefile(bool probe)
}
#if CONFIG_CODEC != SWCODEC
/* MASCODEC: now use audiobuf for voice then thumbnail */
p_thumbnail = audiobuf + file_size;
p_thumbnail = voicebuf.buf + file_size;
p_thumbnail += (long)p_thumbnail % 2; /* 16-bit align */
size_for_thumbnail = audiobufend - p_thumbnail;
size_for_thumbnail = voicebuf.buf + bufsize - p_thumbnail;
#endif
}
else
@ -351,14 +364,15 @@ static void load_voicefile(bool probe)
* sizeof(struct clip_entry);
#ifdef TALK_PARTIAL_LOAD
if (load_size > audiobufend - audiobuf) /* won't fit? */
if (load_size > bufsize) /* won't fit? */
goto load_err;
#endif
got_size = read(filehandle,
(unsigned char *) p_voicefile + offsetof(struct voicefile, index), load_size);
got_size = read(filehandle, &p_voicefile->index[0], load_size);
if (got_size != load_size) /* read error */
goto load_err;
alloc_size += load_size;
#else
close(filehandle);
filehandle = -1;
@ -379,6 +393,11 @@ static void load_voicefile(bool probe)
p_silence = get_clip(VOICE_PAUSE, &silence_len);
}
#ifdef TALK_PARTIAL_LOAD
alloc_size += silence_len + QUEUE_SIZE;
#endif
if ((size_t)alloc_size > bufsize)
goto load_err;
return;
load_err:
@ -582,24 +601,31 @@ static void queue_clip(unsigned char* buf, long size, bool enqueue)
}
/* common code for talk_init() and talk_buffer_steal() */
static void reset_state(void)
static void alloc_thumbnail_buf(void)
{
queue_write = queue_read = 0; /* reset the queue */
p_voicefile = NULL; /* indicate no voicefile (trashed) */
#if CONFIG_CODEC == SWCODEC
/* Allocate a dedicated thumbnail buffer - once */
if (p_thumbnail == NULL)
{
size_for_thumbnail = audiobufend - audiobuf;
size_for_thumbnail = buffer_available();
if (size_for_thumbnail > MAX_THUMBNAIL_BUFSIZE)
size_for_thumbnail = MAX_THUMBNAIL_BUFSIZE;
p_thumbnail = buffer_alloc(size_for_thumbnail);
}
#else
/* Just use the audiobuf, without allocating anything */
p_thumbnail = audiobuf;
size_for_thumbnail = audiobufend - audiobuf;
/* use the audio buffer now, need to release before loading a voice */
p_thumbnail = voicebuf;
#endif
thumbnail_buf_used = 0;
}
/* common code for talk_init() and talk_buffer_steal() */
static void reset_state(void)
{
queue_write = queue_read = 0; /* reset the queue */
p_voicefile = NULL; /* indicate no voicefile (trashed) */
#if CONFIG_CODEC != SWCODEC
p_thumbnail = NULL; /* don't leak buffer_alloc() for swcodec */
#endif
#ifdef TALK_PARTIAL_LOAD
@ -608,8 +634,8 @@ static void reset_state(void)
buffered_id[i] = -1;
#endif
thumbnail_buf_used = 0;
p_silence = NULL; /* pause clip not accessible */
voicebuf = NULL;
}
@ -655,12 +681,11 @@ void talk_init(void)
#endif
reset_state(); /* use this for most of our inits */
/* test if we can open and if it fits in the audiobuffer */
size_t audiobufsz = audiobufend - audiobuf;
#ifdef TALK_PARTIAL_LOAD
size_t bufsize;
char* buf = plugin_get_buffer(&bufsize);
/* we won't load the full file, we only need the index */
load_voicefile(true);
load_voicefile(true, buf, bufsize);
if (!p_voicefile)
return;
@ -681,6 +706,9 @@ void talk_init(void)
p_voicefile = NULL; /* Don't pretend we can load talk clips just yet */
#endif
/* test if we can open and if it fits in the audiobuffer */
size_t audiobufsz = buffer_available();
if (voicefile_size <= audiobufsz) {
has_voicefile = true;
} else {
@ -688,6 +716,7 @@ void talk_init(void)
voicefile_size = 0;
}
alloc_thumbnail_buf();
close(filehandle); /* close again, this was just to detect presence */
filehandle = -1;
}
@ -703,11 +732,25 @@ bool talk_voice_required(void)
#endif
/* return size of voice file */
int talk_get_bufsize(void)
int talk_get_buffer(void)
{
return voicefile_size;
}
/* Sets the buffer for the voicefile and returns how many bytes of this
* buffer we will use for the voicefile */
size_t talkbuf_init(char *bufstart)
{
bool changed = voicebuf != bufstart;
if (bufstart)
voicebuf = bufstart;
if (changed) /* must reload voice file */
reset_state();
return voicefile_size;
}
/* somebody else claims the mp3 buffer, e.g. for regular play/record */
void talk_buffer_steal(void)
{
@ -741,7 +784,7 @@ int talk_id(int32_t id, bool enqueue)
#endif
if (p_voicefile == NULL && has_voicefile)
load_voicefile(false); /* reload needed */
load_voicefile(false, voicebuf, voicefile_size); /* reload needed */
if (p_voicefile == NULL) /* still no voices? */
return -1;
@ -819,7 +862,7 @@ static int _talk_file(const char* filename,
#endif
if (p_thumbnail == NULL || size_for_thumbnail <= 0)
return -1;
alloc_thumbnail_buf();
#if CONFIG_CODEC != SWCODEC
if(mp3info(&info, filename)) /* use this to find real start */

View file

@ -80,6 +80,7 @@ void talk_init(void);
bool talk_voice_required(void); /* returns true if voice codec required */
#endif
int talk_get_bufsize(void); /* get the loaded voice file size */
size_t talkbuf_init(char* bufstart);
void talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */
bool is_voice_queued(void); /* Are there more voice clips to be spoken? */
int talk_id(int32_t id, bool enqueue); /* play a voice ID from voicefont */

View file

@ -19,19 +19,33 @@
*
****************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include "system.h"
#include "buffer.h"
#include "panic.h"
#include "logf.h"
#if (CONFIG_PLATFORM & PLATFORM_HOSTED)
unsigned char audiobuffer[(MEMORYSIZE*1024-256)*1024];
unsigned char *audiobufend = audiobuffer + sizeof(audiobuffer);
#else
/* defined in linker script */
extern unsigned char audiobuffer[];
#endif
unsigned char *audiobuf;
/* defined in linker script */
#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
#if defined(IPOD_VIDEO)
extern unsigned char *audiobufend_lds[];
unsigned char *audiobufend;
#else /* !IPOD_VIDEO */
extern unsigned char audiobufend[];
#endif
/* defined in linker script */
extern unsigned char audiobuffer[];
#else /* PLATFORM_HOSTED */
unsigned char audiobuffer[(MEMORYSIZE*1024-256)*1024];
unsigned char *audiobufend = audiobuffer + sizeof(audiobuffer);
extern unsigned char *audiobufend;
#endif
static unsigned char *audiobuf;
#ifdef BUFFER_ALLOC_DEBUG
static unsigned char *audiobuf_orig_start;
@ -54,13 +68,68 @@ void buffer_init(void)
{
/* 32-bit aligned */
audiobuf = (void *)(((unsigned long)audiobuffer + 3) & ~3);
#if defined(IPOD_VIDEO)
audiobufend=(unsigned char *)audiobufend_lds;
if(MEMORYSIZE==64 && probed_ramsize!=64)
{
audiobufend -= (32<<20);
}
#endif
#ifdef BUFFER_ALLOC_DEBUG
audiobuf_orig_start = audiobuf;
#endif /* BUFFER_ALLOC_DEBUG */
}
/* protect concurrent access */
static volatile int lock;
/*
* Give the entire buffer, return the size in size.
* The caller needs to make sure audiobuf is not otherwise used
*
* Note that this does not modify the buffer position (buffer_release_buffer()
* does), so call this if you want to aquire temporary memory
**/
#define _ALIGN (sizeof(char*))
void *buffer_get_buffer(size_t *size)
{
if (lock)
panicf("concurrent audiobuf access");
lock = 1;
audiobuf = ALIGN_UP(audiobuf, sizeof(intptr_t));
*size = (audiobufend - audiobuf);
return audiobuf;
}
/*
* Release the buffer gotten with buffer_get_buffer
*
* size should have the amount of bytes (from the front) that caller keeps for
* its own, 0 if the entire buffer is to be released
*
* safe to be called with size=0 even if the buffer wasn't claimed before
**/
void buffer_release_buffer(size_t size)
{
audiobuf += size;
/* ensure alignment */
audiobuf = ALIGN_UP(audiobuf, sizeof(intptr_t));
lock = 0;
}
/*
* Query how much free space the buffer has */
size_t buffer_available(void)
{
return audiobufend - audiobuf;
}
void *buffer_alloc(size_t size)
{
if (lock) /* it's not save to call this here */
panicf("buffer_alloc(): exclusive buffer owner");
void *retval;
#ifdef BUFFER_ALLOC_DEBUG
struct buffer_start_marker *start;

View file

@ -862,22 +862,26 @@ int dircache_build(int last_size)
* and their corresponding d_name from the end
* after generation the buffer will be compacted with DIRCACHE_RESERVE
* free bytes inbetween */
audiobuf = ALIGN_UP(audiobuf, sizeof(struct dircache_entry));
dircache_root = (struct dircache_entry*)audiobuf;
d_names_start = d_names_end = audiobufend - 1;
size_t got_size;
char* buf = buffer_get_buffer(&got_size);
ALIGN_BUFFER(buf, got_size, sizeof(struct dircache_entry));
d_names_start = d_names_end = (char*)dircache_root + got_size - 1;
dircache_size = 0;
generate_dot_d_names();
/* Start a non-transparent rebuild. */
int res = dircache_do_rebuild();
if (res < 0)
return res;
goto fail;
/* now compact the dircache buffer */
char* dst = ((char*)&dircache_root[entry_count] + DIRCACHE_RESERVE);
ptrdiff_t offset = d_names_start - dst;
if (offset <= 0) /* something went wrong */
return -1;
{
res = -1;
goto fail;
}
/* memmove d_names down, there's a possibility of overlap
* equivaent to dircache_size - entry_count*sizeof(struct dircache_entry) */
@ -896,15 +900,19 @@ int dircache_build(int last_size)
/* equivalent to dircache_size + DIRCACHE_RESERVE */
allocated_size = (d_names_end - (char*)dircache_root);
reserve_used = 0;
audiobuf += allocated_size;
buffer_release_buffer(allocated_size);
return res;
fail:
dircache_disable();
buffer_release_buffer(0);
return res;
}
/**
* Steal the allocated dircache buffer and disable dircache.
*/
void* dircache_steal_buffer(long *size)
void* dircache_steal_buffer(size_t *size)
{
dircache_disable();
if (dircache_size == 0)

View file

@ -51,6 +51,8 @@
void audio_init(void) INIT_ATTR;
void audio_play(long offset);
void audio_stop(void);
/* Stops audio from serving playback and frees resources*/
void audio_hard_stop(void);
void audio_pause(void);
void audio_resume(void);
void audio_next(void);
@ -68,11 +70,11 @@ void audio_error_clear(void);
int audio_get_file_pos(void);
void audio_beep(int duration);
#if CONFIG_CODEC == SWCODEC
/* Required call when audio buffer is required for some other purpose */
/* implemented in apps but called from firmware(!) */
unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size);
/* only implemented in playback.c, but called from firmware */
#if CONFIG_CODEC == SWCODEC
void audio_next_dir(void);
void audio_prev_dir(void);

View file

@ -22,21 +22,13 @@
#define BUFFER_H
#include "config.h"
/* defined in linker script */
#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
#if defined(IPOD_VIDEO)
extern unsigned char *audiobufend_lds[];
unsigned char *audiobufend;
#else
extern unsigned char audiobufend[];
#endif
#else
extern unsigned char *audiobufend;
#endif
extern unsigned char *audiobuf;
void buffer_init(void) INIT_ATTR;
void* buffer_get_buffer(size_t *size);
void buffer_release_buffer(size_t size);
size_t buffer_available(void);
void *buffer_alloc(size_t size);
#ifdef BUFFER_ALLOC_DEBUG

View file

@ -23,6 +23,7 @@
#include "config.h"
#include "dir_uncached.h"
#include <string.h> /* size_t */
#ifdef HAVE_DIRCACHE
@ -65,7 +66,7 @@ void dircache_init(void) INIT_ATTR;
int dircache_load(void);
int dircache_save(void);
int dircache_build(int last_size);
void* dircache_steal_buffer(long *size);
void* dircache_steal_buffer(size_t *size);
bool dircache_is_enabled(void);
bool dircache_is_initializing(void);
void dircache_set_appflag(long mask);

View file

@ -99,6 +99,7 @@ void rolo_restart_cop(void)
static void rolo_error(const char *text)
{
buffer_release_buffer(0);
lcd_clear_display();
lcd_puts(0, 0, "ROLO error:");
lcd_puts_scroll(0, 1, text);
@ -213,6 +214,8 @@ int rolo_load(const char* filename)
unsigned short checksum,file_checksum;
#endif
unsigned char* ramstart = (void*)&loadaddress;
unsigned char* filebuf;
size_t filebuf_size;
lcd_clear_display();
lcd_puts(0, 0, "ROLO...");
@ -235,6 +238,10 @@ int rolo_load(const char* filename)
length = filesize(fd) - FIRMWARE_OFFSET_FILE_DATA;
/* get the system buffer. release only in case of error, otherwise
* we don't return anyway */
filebuf = buffer_get_buffer(&filebuf_size);
#if CONFIG_CPU != SH7034
/* Read and save checksum */
lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET);
@ -260,7 +267,14 @@ int rolo_load(const char* filename)
lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET);
if (read(fd, audiobuf, length) != length) {
/* this shouldn't happen, but well */
if ((long)filebuf_size < length)
{
rolo_error("File too big");
return -1;
}
if (read(fd, filebuf, length) != length) {
rolo_error("Error Reading File");
return -1;
}
@ -268,12 +282,12 @@ int rolo_load(const char* filename)
#ifdef MI4_FORMAT
/* Check CRC32 to see if we have a valid file */
chksum_crc32gentab();
checksum = chksum_crc32 (audiobuf, length);
checksum = chksum_crc32 (filebuf, length);
#else
checksum = MODEL_NUMBER;
for(i = 0;i < length;i++) {
checksum += audiobuf[i];
checksum += filebuf[i];
}
#endif
@ -329,12 +343,12 @@ int rolo_load(const char* filename)
lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET);
/* verify that file can be read and descrambled */
if ((audiobuf + (2*length)+4) >= audiobufend) {
if ((size_t)((2*length)+4) >= filebuf_size) {
rolo_error("Not enough room to load file");
return -1;
}
if (read(fd, &audiobuf[length], length) != (int)length) {
if (read(fd, &filebuf[length], length) != (int)length) {
rolo_error("Error Reading File");
return -1;
}
@ -342,7 +356,7 @@ int rolo_load(const char* filename)
lcd_puts(0, 1, "Descramble");
lcd_update();
checksum = descramble(audiobuf + length, audiobuf, length);
checksum = descramble(filebuf + length, filebuf, length);
/* Verify checksum against file header */
if (checksum != file_checksum) {
@ -374,7 +388,7 @@ int rolo_load(const char* filename)
PAIOR = 0x0FA0;
#endif
#endif
rolo_restart(audiobuf, ramstart, length);
rolo_restart(filebuf, ramstart, length);
return 0; /* this is never reached */
(void)checksum; (void)file_checksum;