1
0
Fork 0
forked from len0rd/rockbox

playback,talk: Share audiobuffer via core_alloc_maximum().

This fixes the radioart crash that was the result of buffering.c working
on a freed buffer at the same time as buflib (radioart uses buffering.c for the
images). With this change the buffer is owned by buflib exclusively so this
cannot happen.

As a result, audio_get_buffer() doesn't exist anymore. Callers should call
core_alloc_maximum() directly. This buffer needs to be protected as usual
against movement if necessary (previously it was not protected at all which
cased the radioart crash), To get most of it they can adjust the willingness of
the talk engine to give its buffer away (at the expense of disabling voice
interface) with the new talk_buffer_set_policy() function.

Change-Id: I52123012208d04967876a304451d634e2bef3a33
This commit is contained in:
Thomas Martitz 2013-05-30 11:24:16 +02:00
parent 64b9e1fa7b
commit 22e802e800
15 changed files with 676 additions and 587 deletions

View file

@ -280,13 +280,11 @@ static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info,
if (do_refresh && aa)
{
int handle = playback_current_aa_hid(data->playback_aa_slot);
#if 0 /* FIXME: FS#12797*/
if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
{
struct dim dim = {aa->width, aa->height};
handle = radio_get_art_hid(&dim);
}
#endif
aa->draw_handle = handle;
}
break;

View file

@ -527,7 +527,13 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
ssize_t size = (ssize_t)old_size - wanted_size;
/* keep at least 256K for the buffering */
if ((size - extradata_size) < AUDIO_BUFFER_RESERVE)
{
/* check if buflib needs the memory really hard. if yes we give
* up playback for now, otherwise refuse to shrink to keep at least
* 256K for the buffering */
if ((hints & BUFLIB_SHRINK_POS_MASK) != BUFLIB_SHRINK_POS_MASK)
return BUFLIB_CB_CANNOT_SHRINK;
}
/* TODO: Do it without stopping playback, if possible */
bool playing = (audio_status() & AUDIO_STATUS_PLAY) == AUDIO_STATUS_PLAY;
long offset = audio_current_track()->offset;
@ -539,7 +545,6 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
}
else
audio_stop();
talk_buffer_steal(); /* we obtain control over the buffer */
switch (hints & BUFLIB_SHRINK_POS_MASK)
{
@ -551,6 +556,12 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
core_shrink(handle, start + wanted_size, size);
audio_reset_buffer_noalloc(start + wanted_size, size);
break;
case BUFLIB_SHRINK_POS_MASK:
audiobuf_handle = core_free(audiobuf_handle);
mpeg_audiobuf = NULL;
talk_buffer_set_policy(TALK_BUFFER_DEFAULT);
playing = false;
break;
}
if (playing)
{ /* safe to call even from the audio thread (due to queue_post()) */
@ -565,45 +576,6 @@ static struct buflib_callbacks ops = {
.shrink_callback = shrink_callback,
};
static size_t audio_talkbuf_init(char *bufstart)
{
size_t ret = talkbuf_init(bufstart);
if (ret > (size_t)audiobuflen) /* does the voice even fit? */
{
talk_buffer_steal();
return 0;
}
return ret;
}
unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size)
{
(void)talk_buf; /* always grab the voice buffer for now */
if (audio_is_initialized)
audio_hard_stop();
if (!buffer_size) /* special case for talk_init() */
return NULL;
if (!audiobuf_handle)
{
size_t bufsize;
/* audio_hard_stop() frees audiobuf, so re-aquire */
audiobuf_handle = core_alloc_maximum("audiobuf", &bufsize, &ops);
audiobuflen = bufsize;
if (buffer_size)
*buffer_size = audiobuflen;
}
mpeg_audiobuf = core_get_data(audiobuf_handle);
/* tell talk about the new buffer, don't re-enable just yet because the
* buffer is stolen */
audio_talkbuf_init(mpeg_audiobuf);
return mpeg_audiobuf;
}
#ifndef SIMULATOR
/* Send callback events to notify about removing old tracks. */
static void generate_unbuffer_events(void)
@ -2755,7 +2727,6 @@ size_t audio_buffer_available(void)
static void audio_reset_buffer_noalloc(void* buf, size_t bufsize)
{
talk_buffer_steal(); /* will use the mp3 buffer */
mpeg_audiobuf = buf;
audiobuflen = bufsize;
if (global_settings.cuesheet)
@ -2764,16 +2735,20 @@ static void audio_reset_buffer_noalloc(void* buf, size_t bufsize)
mpeg_audiobuf = SKIPBYTES(mpeg_audiobuf, sizeof(struct cuesheet));
audiobuflen -= sizeof(struct cuesheet);
}
audio_talkbuf_init(mpeg_audiobuf);
}
static void audio_reset_buffer(void)
{
size_t bufsize = audiobuflen;
/* alloc buffer if it's was never allocated or freed by audio_hard_stop() */
/* alloc buffer if it's was never allocated or freed by audio_hard_stop()
* because voice cannot be played during audio playback make
* talk.c give up all buffers and disable itself */
if (!audiobuf_handle)
{
talk_buffer_set_policy(TALK_BUFFER_LOOSE);
audiobuf_handle = core_alloc_maximum("audiobuf", &bufsize, &ops);
}
audio_reset_buffer_noalloc(core_get_data(audiobuf_handle), bufsize);
}
@ -2818,6 +2793,8 @@ void audio_play(long offset)
void audio_stop(void)
{
if (audiobuf_handle <= 0)
return; /* nothing to do, must be hard-stopped already */
#ifndef SIMULATOR
mpeg_stop_done = false;
queue_post(&mpeg_queue, MPEG_STOP, 0);
@ -2828,8 +2805,6 @@ void audio_stop(void)
is_playing = false;
playing = false;
#endif /* SIMULATOR */
/* give voice our entire buffer */
audio_talkbuf_init(mpeg_audiobuf);
}
/* dummy */
@ -2840,13 +2815,12 @@ void audio_stop_recording(void)
void audio_hard_stop(void)
{
audio_stop();
/* tell voice we obtain the buffer before freeing */
talk_buffer_steal();
if (audiobuf_handle > 0)
{
audio_stop();
audiobuf_handle = core_free(audiobuf_handle);
mpeg_audiobuf = NULL;
talk_buffer_set_policy(TALK_BUFFER_DEFAULT);
}
}

View file

@ -110,7 +110,6 @@ static enum audio_buffer_state
{
AUDIOBUF_STATE_TRASHED = -1, /* trashed; must be reset */
AUDIOBUF_STATE_INITIALIZED = 0, /* voice+audio OR audio-only */
AUDIOBUF_STATE_VOICED_ONLY = 1, /* voice-only */
} buffer_state = AUDIOBUF_STATE_TRASHED; /* (A,O) */
/** Main state control **/
@ -729,35 +728,18 @@ size_t audio_buffer_available(void)
/* Set up the audio buffer for playback
* filebuflen must be pre-initialized with the maximum size */
static void audio_reset_buffer_noalloc(
void *filebuf, enum audio_buffer_state state)
void *filebuf)
{
/*
* Layout audio buffer as follows:
* [[|TALK]|SCRATCH|BUFFERING|PCM]
* [|SCRATCH|BUFFERING|PCM]
*/
/* see audio_get_recording_buffer if this is modified */
logf("%s()", __func__);
/* 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 */
size_t allocsize;
/* Subtract whatever voice needs (we're called when promoting
the state only) */
allocsize = talkbuf_init(filebuf);
allocsize = ALIGN_UP(allocsize, sizeof (intptr_t));
if (allocsize > filebuflen)
goto bufpanic;
filebuf += allocsize;
filebuflen -= allocsize;
if (state == AUDIOBUF_STATE_INITIALIZED)
{
/* Subtract whatever the pcm buffer says it used plus the guard
buffer */
allocsize = pcmbuf_init(filebuf + filebuflen);
@ -780,9 +762,8 @@ static void audio_reset_buffer_noalloc(
filebuflen -= allocsize;
buffering_reset(filebuf, filebuflen);
}
buffer_state = state;
buffer_state = AUDIOBUF_STATE_INITIALIZED;
#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
/* Make sure everything adds up - yes, some info is a bit redundant but
@ -811,15 +792,24 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
/* codec messages */
{ Q_AUDIO_PLAY, Q_AUDIO_PLAY },
};
bool give_up = false;
/* filebuflen is, at this point, the buffering.c buffer size,
* i.e. the audiobuf except voice, scratch mem, pcm, ... */
ssize_t extradata_size = old_size - filebuflen;
/* check what buflib requests */
size_t wanted_size = (hints & BUFLIB_SHRINK_SIZE_MASK);
ssize_t size = (ssize_t)old_size - wanted_size;
/* keep at least 256K for the buffering */
if ((size - extradata_size) < AUDIO_BUFFER_RESERVE)
{
/* check if buflib needs the memory really hard. if yes we give
* up playback for now, otherwise refuse to shrink to keep at least
* 256K for the buffering */
if ((hints & BUFLIB_SHRINK_POS_MASK) == BUFLIB_SHRINK_POS_MASK)
give_up = true;
else
return BUFLIB_CB_CANNOT_SHRINK;
}
/* TODO: Do it without stopping playback, if possible */
@ -852,20 +842,26 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
#ifdef PLAYBACK_VOICE
voice_stop();
#endif
/* we should be free to change the buffer now
* set final buffer size before calling audio_reset_buffer_noalloc()
/* we should be free to change the buffer now */
if (give_up)
{
buffer_state = AUDIOBUF_STATE_TRASHED;
audiobuf_handle = core_free(audiobuf_handle);
return BUFLIB_CB_OK;
}
/* set final buffer size before calling audio_reset_buffer_noalloc()
* (now it's the total size, the call will subtract voice etc) */
filebuflen = size;
switch (hints & BUFLIB_SHRINK_POS_MASK)
{
case BUFLIB_SHRINK_POS_BACK:
core_shrink(handle, start, size);
audio_reset_buffer_noalloc(start, buffer_state);
audio_reset_buffer_noalloc(start);
break;
case BUFLIB_SHRINK_POS_FRONT:
core_shrink(handle, start + wanted_size, size);
audio_reset_buffer_noalloc(start + wanted_size,
buffer_state);
audio_reset_buffer_noalloc(start + wanted_size);
break;
}
if (playing || play_queued)
@ -882,7 +878,7 @@ static struct buflib_callbacks ops = {
.shrink_callback = shrink_callback,
};
static void audio_reset_buffer(enum audio_buffer_state state)
static void audio_reset_buffer(void)
{
if (audiobuf_handle > 0)
{
@ -890,9 +886,13 @@ static void audio_reset_buffer(enum audio_buffer_state state)
audiobuf_handle = 0;
}
audiobuf_handle = core_alloc_maximum("audiobuf", &filebuflen, &ops);
unsigned char *filebuf = core_get_data(audiobuf_handle);
audio_reset_buffer_noalloc(filebuf, state);
if (audiobuf_handle > 0)
audio_reset_buffer_noalloc(core_get_data(audiobuf_handle));
else
/* someone is abusing core_alloc_maximum(). Fix this evil guy instead of
* trying to handle OOM without hope */
panicf("%s(): OOM!\n", __func__);
}
/* Set the buffer margin to begin rebuffering when 'seconds' from empty */
@ -2033,7 +2033,7 @@ static int audio_fill_file_buffer(void)
if (buffer_state != AUDIOBUF_STATE_INITIALIZED ||
!pcmbuf_is_same_size())
{
audio_reset_buffer(AUDIOBUF_STATE_INITIALIZED);
audio_reset_buffer();
}
logf("Starting buffer fill");
@ -2464,7 +2464,7 @@ static void audio_start_playback(size_t offset, unsigned int flags)
/* Mark the buffer dirty - if not playing, it will be reset next
time */
if (buffer_state == AUDIOBUF_STATE_INITIALIZED)
buffer_state = AUDIOBUF_STATE_VOICED_ONLY;
buffer_state = AUDIOBUF_STATE_TRASHED;
}
if (old_status != PLAY_STOPPED)
@ -3511,88 +3511,6 @@ void audio_flush_and_reload_tracks(void)
audio_queue_post(Q_AUDIO_FLUSH, 0);
}
/* Return the pointer to the main audio buffer, optionally preserving
voicing */
unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size)
{
unsigned char *buf;
if (audio_is_initialized && thread_self() != audio_thread_id)
{
audio_hard_stop();
}
/* else buffer_state will be AUDIOBUF_STATE_TRASHED at this point */
if (buffer_size == NULL)
{
/* Special case for talk_init to use since it already knows it's
trashed */
buffer_state = AUDIOBUF_STATE_TRASHED;
return NULL;
}
/* make sure buffer is freed and re-allocated to simplify code below
* (audio_hard_stop() likely has done that already) */
if (audiobuf_handle > 0)
audiobuf_handle = core_free(audiobuf_handle);
audiobuf_handle = core_alloc_maximum("audiobuf", &filebuflen, &ops);
buf = core_get_data(audiobuf_handle);
if (buffer_state == AUDIOBUF_STATE_INITIALIZED)
buffering_reset(NULL, 0); /* mark buffer invalid */
if (talk_buf || !talk_voice_required())
{
logf("get buffer: talk, audio");
/* 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
written without the caller knowing what's going on. Changing certain
settings may move it to a worse condition but the memory in use by
something else will remain undisturbed.
*/
if (buffer_state != AUDIOBUF_STATE_TRASHED)
{
talk_buffer_steal();
buffer_state = AUDIOBUF_STATE_TRASHED;
}
}
else
{
logf("get buffer: audio");
/* Safe to just return this if already AUDIOBUF_STATE_VOICED_ONLY or
still AUDIOBUF_STATE_INITIALIZED */
size_t talkbuf_size = talkbuf_init(buf);
buf += talkbuf_size; /* Skip talk buffer */
filebuflen -= talkbuf_size;
buffer_state = AUDIOBUF_STATE_VOICED_ONLY;
}
*buffer_size = filebuflen;
return buf;
}
/* Restore audio buffer to a particular state (promoting status) */
bool audio_restore_playback(int type)
{
switch (type)
{
case AUDIO_WANT_PLAYBACK:
if (buffer_state != AUDIOBUF_STATE_INITIALIZED)
audio_reset_buffer(AUDIOBUF_STATE_INITIALIZED);
return true;
case AUDIO_WANT_VOICE:
if (buffer_state == AUDIOBUF_STATE_TRASHED)
audio_reset_buffer(AUDIOBUF_STATE_VOICED_ONLY);
return true;
default:
return false;
}
}
/** --- Miscellaneous public interfaces --- **/
#ifdef HAVE_ALBUMART

View file

@ -80,12 +80,6 @@ void audio_set_cuesheet(bool enable);
void audio_set_crossfade(int enable);
#endif
enum
{
AUDIO_WANT_PLAYBACK = 0,
AUDIO_WANT_VOICE,
};
bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */
size_t audio_get_filebuflen(void);
unsigned int playback_status(void);

View file

@ -104,6 +104,7 @@
#include "rbunicode.h"
#include "root_menu.h"
#include "plugin.h" /* To borrow a temp buffer to rewrite a .m3u8 file */
#include "panic.h"
#define PLAYLIST_CONTROL_FILE_VERSION 2
@ -532,13 +533,6 @@ static int add_indices_to_playlist(struct playlist_info* playlist,
splash(0, ID2P(LANG_WAIT));
if (!buffer)
{
/* use mp3 buffer for maximum load speed */
audio_stop();
buffer = audio_get_buffer(false, &buflen);
}
store_index = true;
while(1)
@ -2077,8 +2071,26 @@ int playlist_create(const char *dir, const char *file)
new_playlist(playlist, dir, file);
if (file)
{
/* dummy ops with no callbacks, needed because by
* default buflib buffers can be moved around which must be avoided */
static struct buflib_callbacks dummy_ops;
int handle;
size_t buflen;
/* use mp3 buffer for maximum load speed */
handle = core_alloc_maximum("temp", &buflen, &dummy_ops);
if (handle > 0)
{
/* load the playlist file */
add_indices_to_playlist(playlist, NULL, 0);
add_indices_to_playlist(playlist, core_get_data(handle), buflen);
core_free(handle);
}
else
{
/* should not happen */
panicf("%s(): OOM", __func__);
}
}
return 0;
}
@ -2094,14 +2106,22 @@ int playlist_resume(void)
struct playlist_info* playlist = &current_playlist;
char *buffer;
size_t buflen;
int handle;
int nread;
int total_read = 0;
int control_file_size = 0;
bool first = true;
bool sorted = true;
int result = -1;
/* dummy ops with no callbacks, needed because by
* default buflib buffers can be moved around which must be avoided */
static struct buflib_callbacks dummy_ops;
/* use mp3 buffer for maximum load speed */
buffer = (char *)audio_get_buffer(false, &buflen);
handle = core_alloc_maximum("temp", &buflen, &dummy_ops);
if (handle < 0)
panicf("%s(): OOM", __func__);
buffer = core_get_data(handle);
empty_playlist(playlist, true);
@ -2110,7 +2130,7 @@ int playlist_resume(void)
if (playlist->control_fd < 0)
{
splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR));
return -1;
goto out;
}
playlist->control_created = true;
@ -2118,7 +2138,7 @@ int playlist_resume(void)
if (control_file_size <= 0)
{
splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR));
return -1;
goto out;
}
/* read a small amount first to get the header */
@ -2127,14 +2147,14 @@ int playlist_resume(void)
if(nread <= 0)
{
splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR));
return -1;
goto out;
}
playlist->started = true;
while (1)
{
int result = 0;
result = 0;
int count;
enum playlist_command current_command = PLAYLIST_COMMAND_COMMENT;
int last_newline = 0;
@ -2195,7 +2215,10 @@ int playlist_resume(void)
version = atoi(str1);
if (version != PLAYLIST_CONTROL_FILE_VERSION)
return -1;
{
result = -1;
goto out;
}
update_playlist_filename(playlist, str2, str3);
@ -2204,7 +2227,7 @@ int playlist_resume(void)
/* NOTE: add_indices_to_playlist() overwrites the
audiobuf so we need to reload control file
data */
add_indices_to_playlist(playlist, NULL, 0);
add_indices_to_playlist(playlist, buffer, buflen);
}
else if (str2[0] != '\0')
{
@ -2242,7 +2265,10 @@ int playlist_resume(void)
buffer */
if (add_track_to_playlist(playlist, str3, position,
queue, total_read+(str3-buffer)) < 0)
return -1;
{
result = -1;
goto out;
}
playlist->last_insert_pos = last_position;
@ -2264,7 +2290,10 @@ int playlist_resume(void)
if (remove_track_from_playlist(playlist, position,
false) < 0)
return -1;
{
result = -1;
goto out;
}
break;
}
@ -2291,7 +2320,10 @@ int playlist_resume(void)
if (randomise_playlist(playlist, seed, false,
false) < 0)
return -1;
{
result = -1;
goto out;
}
sorted = false;
break;
}
@ -2308,7 +2340,10 @@ int playlist_resume(void)
playlist->first_index = atoi(str1);
if (sort_playlist(playlist, false, false) < 0)
return -1;
{
result = -1;
goto out;
}
sorted = true;
break;
@ -2421,13 +2456,14 @@ int playlist_resume(void)
if (result < 0)
{
splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_INVALID));
return result;
goto out;
}
if (useraborted)
{
splash(HZ*2, ID2P(LANG_CANCEL));
return -1;
result = -1;
goto out;
}
if (!newline || (exit_loop && count<nread))
{
@ -2435,7 +2471,8 @@ int playlist_resume(void)
{
/* no newline at end of control file */
splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_INVALID));
return -1;
result = -1;
goto out;
}
/* We didn't end on a newline or we exited loop prematurely.
@ -2464,7 +2501,9 @@ int playlist_resume(void)
queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0);
#endif
return 0;
out:
core_free(handle);
return result;
}
/*

View file

@ -801,6 +801,8 @@ static const struct plugin_api rockbox_api = {
the API gets incompatible */
};
static int plugin_buffer_handle;
int plugin_load(const char* plugin, const void* parameter)
{
struct plugin_header *p_hdr;
@ -815,6 +817,8 @@ int plugin_load(const char* plugin, const void* parameter)
}
lc_close(current_plugin_handle);
current_plugin_handle = pfn_tsr_exit = NULL;
if (plugin_buffer_handle > 0)
plugin_buffer_handle = core_free(plugin_buffer_handle);
}
splash(0, ID2P(LANG_WAIT));
@ -878,6 +882,9 @@ int plugin_load(const char* plugin, const void* parameter)
touchscreen_set_mode(TOUCHSCREEN_BUTTON);
#endif
/* allow voice to back off if the plugin needs lots of memory */
talk_buffer_set_policy(TALK_BUFFER_LOOSE);
#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
open_files = 0;
#endif
@ -891,8 +898,12 @@ int plugin_load(const char* plugin, const void* parameter)
{ /* close handle if plugin is no tsr one */
lc_close(current_plugin_handle);
current_plugin_handle = NULL;
if (plugin_buffer_handle > 0)
plugin_buffer_handle = core_free(plugin_buffer_handle);
}
talk_buffer_set_policy(TALK_BUFFER_DEFAULT);
/* Go back to the global setting in case the plugin changed it */
#ifdef HAVE_TOUCHSCREEN
touchscreen_set_mode(global_settings.touch_mode);
@ -984,8 +995,12 @@ void* plugin_get_buffer(size_t *buffer_size)
*/
void* plugin_get_audio_buffer(size_t *buffer_size)
{
audio_stop();
return audio_get_buffer(true, buffer_size);
/* dummy ops with no callbacks, needed because by
* default buflib buffers can be moved around which must be avoided */
static struct buflib_callbacks dummy_ops;
plugin_buffer_handle = core_alloc_maximum("plugin audio buf", buffer_size,
&dummy_ops);
return core_get_data(plugin_buffer_handle);
}
/* The plugin wants to stay resident after leaving its main function, e.g.

View file

@ -112,6 +112,7 @@ void* plugin_get_buffer(size_t *buffer_size);
#include "timefuncs.h"
#include "crc32.h"
#include "rbpaths.h"
#include "core_alloc.h"
#ifdef HAVE_ALBUMART
#include "albumart.h"

View file

@ -32,6 +32,7 @@
#include "kernel.h"
#include "string-extra.h"
#include "filefuncs.h"
#include "core_alloc.h"
#define MAX_RADIOART_IMAGES 10
struct radioart {
@ -158,14 +159,49 @@ static void buffer_reset_handler(void *data)
(void)data;
}
static int shrink_callback(int handle, unsigned hints, void* start, size_t old_size)
{
(void)start;
(void)old_size;
ssize_t old_size_s = old_size;
size_t size_hint = (hints & BUFLIB_SHRINK_SIZE_MASK);
ssize_t wanted_size = old_size_s - size_hint;
if (wanted_size <= 0)
{
core_free(handle);
buffering_reset(NULL, 0);
}
else
{
if (hints & BUFLIB_SHRINK_POS_FRONT)
start += size_hint;
buffering_reset(start, wanted_size);
core_shrink(handle, start, wanted_size);
buf = start;
/* one-shot */
add_event(BUFFER_EVENT_BUFFER_RESET, true, buffer_reset_handler);
}
return BUFLIB_CB_OK;
}
static struct buflib_callbacks radioart_ops = {
.shrink_callback = shrink_callback,
};
void radioart_init(bool entering_screen)
{
if (entering_screen)
{
/* grab control over buffering */
size_t bufsize;
buf = audio_get_buffer(false, &bufsize);
buffering_reset(buf, bufsize);
int handle = core_alloc_maximum("radioart", &bufsize, &radioart_ops);
buffering_reset(core_get_data(handle), bufsize);
buf = core_get_data(handle);
/* one-shot */
add_event(BUFFER_EVENT_BUFFER_RESET, true, buffer_reset_handler);
}

View file

@ -24,6 +24,7 @@
#include "config.h"
#include "system.h"
#include "kernel.h"
#include "panic.h"
#include "string-extra.h"
#include "pcm_record.h"
#include "codecs.h"
@ -40,6 +41,8 @@
#include "spdif.h"
#endif
#include "audio_thread.h"
#include "core_alloc.h"
#include "talk.h"
/* Macros to enable logf for queues
logging on SYS_TIMEOUT can be disabled */
@ -1402,11 +1405,22 @@ static void tally_prerecord_data(void)
/** Event handlers for recording thread **/
static int pcmrec_handle;
/* Q_AUDIO_INIT_RECORDING */
static void on_init_recording(void)
{
send_event(RECORDING_EVENT_START, NULL);
rec_buffer = audio_get_buffer(true, &rec_buffer_size);
/* dummy ops with no callbacks, needed because by
* default buflib buffers can be moved around which must be avoided
* FIXME: This buffer should play nicer and be shrinkable/movable */
static struct buflib_callbacks dummy_ops;
talk_buffer_set_policy(TALK_BUFFER_LOOSE);
pcmrec_handle = core_alloc_maximum("pcmrec", &rec_buffer_size, &dummy_ops);
if (pcmrec_handle)
/* someone is abusing core_alloc_maximum(). Fix this evil guy instead of
* trying to handle OOM without hope */
panicf("%s(): OOM\n", __func__);
rec_buffer = core_get_data(pcmrec_handle);
init_rec_buffers();
init_state();
pcm_init_recording();
@ -1430,6 +1444,10 @@ static void on_close_recording(void)
audio_set_output_source(AUDIO_SRC_PLAYBACK);
pcm_apply_settings();
if (pcmrec_handle > 0)
pcmrec_handle = core_free(pcmrec_handle);
talk_buffer_set_policy(TALK_BUFFER_DEFAULT);
send_event(RECORDING_EVENT_STOP, NULL);
}

View file

@ -691,15 +691,8 @@ void rec_set_source(int source, unsigned flags)
void rec_set_recording_options(struct audio_recording_options *options)
{
#if CONFIG_CODEC != SWCODEC
if (global_settings.rec_prerecord_time)
{
talk_buffer_steal(); /* will use the mp3 buffer */
}
#else /* == SWCODEC */
rec_set_source(options->rec_source,
options->rec_source_flags | SRCF_RECORDING);
#endif /* CONFIG_CODEC != SWCODEC */
audio_set_recording_options(options);
}
@ -724,9 +717,6 @@ void rec_command(enum recording_command cmd)
/* steal mp3 buffer, create unique filename and start recording */
pm_reset_clipcount();
pm_activate_clipcount(true);
#if CONFIG_CODEC != SWCODEC
talk_buffer_steal(); /* we use the mp3 buffer */
#endif
audio_record(rec_create_filename(path_buffer));
break;
case RECORDING_CMD_START_NEWFILE:

File diff suppressed because it is too large Load diff

View file

@ -71,6 +71,26 @@ enum {
/* convenience macro to have both virtual pointer and ID as arguments */
#define STR(id) ID2P(id), id
/* Policy values for how hard to try to keep the talk/voice buffers.
* Affects how genereous talk.c is when it's asked for memory in
* shrink_callbacks().
*
* I.e. setting the policy to TALK_BUFFER_LOOSE, it will happily give its
* entire bufer away if asked for, e.g. due to a another module
* calling core_alloc_maximum(), TALK_BUFFER_HOLD on the other hand will
* make it keep the buffers so that a call to core_alloc_maximum() does not
* stop the speech-interface.
*/
enum talk_buffer_policies {
TALK_BUFFER_DEFAULT,
TALK_BUFFER_LOOSE,
TALK_BUFFER_HOLD,
};
/* This sets the actual policy. Call this before core_alloc_maximum() to
* get the desired outcome */
void talk_buffer_set_policy(int policy);
/* publish these strings, so they're stored only once (better than #define) */
extern const char* const dir_thumbnail_name; /* "_dirname.talk" */
extern const char* const file_thumbnail_ext; /* ".talk" for file voicing */
@ -81,7 +101,6 @@ 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 */
/* play a thumbnail from file */

View file

@ -75,10 +75,6 @@ void audio_error_clear(void);
int audio_get_file_pos(void);
void audio_beep(int duration);
/* 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);
#if CONFIG_CODEC == SWCODEC
void audio_next_dir(void);
void audio_prev_dir(void);

View file

@ -230,21 +230,6 @@ void usb_insert_int(void)
}
#endif /* USB_STATUS_BY_EVENT */
#ifdef HAVE_BOOTLOADER_USB_MODE
/* Replacement function that returns all unused memory after the bootloader
* because the storage driver uses the audio buffer */
extern unsigned char freebuffer[];
extern unsigned char freebufferend[];
unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
{
if (buffer_size)
*buffer_size = freebufferend - freebuffer + 1;
return freebuffer;
(void)talk_buf;
}
#endif /* HAVE_BOOTLOADER_USB_MODE */
void usb_drv_int_enable(bool enable)
{
/* enable/disable USB IRQ in CPU */

View file

@ -34,6 +34,7 @@
#if CONFIG_RTC
#include "timefuncs.h"
#endif
#include "core_alloc.h"
#ifdef USB_USE_RAMDISK
#define RAMDISK_SIZE 2048
@ -430,6 +431,7 @@ int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size)
return (dest - orig_dest);
}
static int usb_handle;
void usb_storage_init_connection(void)
{
logf("ums: set config");
@ -452,13 +454,17 @@ void usb_storage_init_connection(void)
#else
/* TODO : check if bufsize is at least 32K ? */
size_t bufsize;
unsigned char * audio_buffer;
unsigned char * buffer;
/* dummy ops with no callbacks, needed because by
* default buflib buffers can be moved around which must be avoided */
static struct buflib_callbacks dummy_ops;
audio_buffer = audio_get_buffer(false,&bufsize);
usb_handle = core_alloc_maximum("usb storage", &bufsize, &dummy_ops);
buffer = core_get_data(usb_handle);
#if defined(UNCACHED_ADDR) && CONFIG_CPU != AS3525
cbw_buffer = (void *)UNCACHED_ADDR((unsigned int)(audio_buffer+31) & 0xffffffe0);
cbw_buffer = (void *)UNCACHED_ADDR((unsigned int)(buffer+31) & 0xffffffe0);
#else
cbw_buffer = (void *)((unsigned int)(audio_buffer+31) & 0xffffffe0);
cbw_buffer = (void *)((unsigned int)(buffer+31) & 0xffffffe0);
#endif
tb.transfer_buffer = cbw_buffer + MAX_CBW_SIZE;
commit_discard_dcache();
@ -478,7 +484,8 @@ void usb_storage_init_connection(void)
void usb_storage_disconnect(void)
{
/* Empty for now */
if (usb_handle > 0)
usb_handle = core_free(usb_handle);
}
/* called by usb_core_transfer_complete() */