summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/buffering.c58
-rw-r--r--apps/buffering.h16
-rw-r--r--apps/playback.c32
3 files changed, 70 insertions, 36 deletions
diff --git a/apps/buffering.c b/apps/buffering.c
index 85bbe86cc3..624debc8e1 100644
--- a/apps/buffering.c
+++ b/apps/buffering.c
@@ -153,7 +153,7 @@ static struct mutex llist_mutex;
This is global so that move_handle and rm_handle can invalidate it. */
static struct memory_handle *cached_handle = NULL;
-static buffer_low_callback buffer_low_callback_funcs[MAX_BUF_CALLBACKS];
+static buffering_callback buffering_callback_funcs[MAX_BUF_CALLBACKS];
static int buffer_callback_count = 0;
static struct {
@@ -188,6 +188,9 @@ static struct event_queue buffering_queue;
static struct queue_sender_list buffering_queue_sender_list;
+static void call_buffering_callbacks(enum callback_event ev, int value);
+
+
/*
LINKED LIST MANAGEMENT
======================
@@ -330,6 +333,7 @@ static bool rm_handle(const struct memory_handle *h)
}
} else {
struct memory_handle *m = first_handle;
+ /* Find the previous handle */
while (m && m->next != h) {
m = m->next;
}
@@ -686,6 +690,8 @@ static void rebuffer_handle(int handle_id, size_t newpos)
if (!h)
return;
+ /* When seeking foward off of the buffer, if it is a short seek don't
+ rebuffer the whole track, just read enough to satisfy */
if (newpos > h->offset && newpos - h->offset < BUFFERING_DEFAULT_FILECHUNK)
{
LOGFQUEUE("buffering >| Q_BUFFER_HANDLE");
@@ -693,12 +699,22 @@ static void rebuffer_handle(int handle_id, size_t newpos)
h->ridx = h->data + newpos;
return;
}
-
+
h->offset = newpos;
+ /* Reset the handle to its new offset */
LOGFQUEUE("buffering >| Q_RESET_HANDLE");
queue_send(&buffering_queue, Q_RESET_HANDLE, handle_id);
+ /* There isn't enough space to rebuffer all of the track from its new
+ offset, so we ask the user to free some */
+ if (buffer_len - BUF_USED < h->filesize - newpos)
+ {
+ DEBUGF("rebuffer_handle: space is needed\n");
+ call_buffering_callbacks(EVENT_HANDLE_REBUFFER, handle_id);
+ }
+
+ /* Now we ask for a rebuffer */
LOGFQUEUE("buffering >| Q_BUFFER_HANDLE");
queue_send(&buffering_queue, Q_BUFFER_HANDLE, handle_id);
@@ -737,7 +753,7 @@ static void shrink_handle(struct memory_handle *h)
h->type == TYPE_ATOMIC_AUDIO))
{
/* metadata handle: we can move all of it */
- size_t handle_distance =
+ size_t handle_distance =
RINGBUF_SUB((unsigned)((void *)h->next - (void*)buffer), h->data);
delta = handle_distance - h->available;
@@ -1130,8 +1146,8 @@ buf_handle_offset
buf_request_buffer_handle
buf_set_base_handle
buf_used
-register_buffer_low_callback
-unregister_buffer_low_callback
+register_buffering_callback
+unregister_buffering_callback
These functions are exported, to allow interaction with the buffer.
They take care of the content of the structs, and rely on the linked list
@@ -1180,50 +1196,48 @@ void buf_set_watermark(size_t bytes)
queue_post(&buffering_queue, Q_SET_WATERMARK, bytes);
}
-bool register_buffer_low_callback(buffer_low_callback func)
+bool register_buffering_callback(buffering_callback func)
{
int i;
if (buffer_callback_count >= MAX_BUF_CALLBACKS)
return false;
for (i = 0; i < MAX_BUF_CALLBACKS; i++)
{
- if (buffer_low_callback_funcs[i] == NULL)
+ if (buffering_callback_funcs[i] == NULL)
{
- buffer_low_callback_funcs[i] = func;
+ buffering_callback_funcs[i] = func;
buffer_callback_count++;
return true;
}
- else if (buffer_low_callback_funcs[i] == func)
+ else if (buffering_callback_funcs[i] == func)
return true;
}
return false;
}
-void unregister_buffer_low_callback(buffer_low_callback func)
+void unregister_buffering_callback(buffering_callback func)
{
int i;
for (i = 0; i < MAX_BUF_CALLBACKS; i++)
{
- if (buffer_low_callback_funcs[i] == func)
+ if (buffering_callback_funcs[i] == func)
{
- buffer_low_callback_funcs[i] = NULL;
+ buffering_callback_funcs[i] = NULL;
buffer_callback_count--;
}
}
return;
}
-static void call_buffer_low_callbacks(void)
+static void call_buffering_callbacks(enum callback_event ev, int value)
{
- logf("call_buffer_low_callbacks()");
+ logf("call_buffering_callbacks()");
int i;
for (i = 0; i < MAX_BUF_CALLBACKS; i++)
{
- if (buffer_low_callback_funcs[i])
+ if (buffering_callback_funcs[i])
{
- buffer_low_callback_funcs[i]();
- buffer_low_callback_funcs[i] = NULL;
- buffer_callback_count--;
+ buffering_callback_funcs[i](ev, value);
}
}
}
@@ -1259,7 +1273,7 @@ void buffering_thread(void)
LOGFQUEUE("buffering < Q_START_FILL");
/* Call buffer callbacks here because this is one of two ways
* to begin a full buffer fill */
- call_buffer_low_callbacks();
+ call_buffering_callbacks(EVENT_BUFFER_LOW, 0);
shrink_buffer();
queue_reply(&buffering_queue, 1);
filling |= buffer_handle((int)ev.data);
@@ -1315,7 +1329,7 @@ void buffering_thread(void)
/* If the buffer is low, call the callbacks to get new data */
if (num_handles > 0 && data_counters.useful <= conf_watermark)
- call_buffer_low_callbacks();
+ call_buffering_callbacks(EVENT_BUFFER_LOW, 0);
#if 0
/* TODO: This needs to be fixed to use the idle callback, disable it
@@ -1325,7 +1339,7 @@ void buffering_thread(void)
else if (ata_disk_is_active() && queue_empty(&buffering_queue))
{
if (num_handles > 0 && data_counters.useful <= high_watermark)
- call_buffer_low_callbacks();
+ call_buffering_callbacks(EVENT_BUFFER_LOW, 0);
if (data_counters.remaining > 0 && BUF_USED <= high_watermark)
{
@@ -1390,7 +1404,7 @@ bool buffering_reset(char *buf, size_t buflen)
base_handle_id = -1;
buffer_callback_count = 0;
- memset(buffer_low_callback_funcs, 0, sizeof(buffer_low_callback_funcs));
+ memset(buffering_callback_funcs, 0, sizeof(buffering_callback_funcs));
/* Set the high watermark as 75% full...or 25% empty :) */
#if MEM > 8
diff --git a/apps/buffering.h b/apps/buffering.h
index 06895e7e51..f6a9f7883b 100644
--- a/apps/buffering.h
+++ b/apps/buffering.h
@@ -35,6 +35,14 @@ enum data_type {
TYPE_UNKNOWN,
};
+enum callback_event {
+ EVENT_DEFAULT,
+ EVENT_BUFFER_LOW,
+ EVENT_HANDLE_REBUFFER,
+ EVENT_HANDLE_CLOSED,
+ EVENT_HANDLE_MOVED,
+};
+
/* Error return values */
#define ERR_HANDLE_NOT_FOUND -1
#define ERR_BUFFER_FULL -2
@@ -98,7 +106,7 @@ size_t buf_used(void);
* CALLBACK UTILITIES
* ==================
*
- * register_buffer_low_callback, unregister_buffer_low_callback:
+ * register_buffering_callback, unregister_buffering_callback:
*
* Register/Unregister callback functions that will get executed when the buffer
* goes below the low watermark. They are executed once, then forgotten.
@@ -108,9 +116,9 @@ size_t buf_used(void);
****************************************************************************/
#define MAX_BUF_CALLBACKS 4
-typedef void (*buffer_low_callback)(void);
-bool register_buffer_low_callback(buffer_low_callback func);
-void unregister_buffer_low_callback(buffer_low_callback func);
+typedef void (*buffering_callback)(enum callback_event ev, int value);
+bool register_buffering_callback(buffering_callback func);
+void unregister_buffering_callback(buffering_callback func);
/* Settings */
enum {
diff --git a/apps/playback.c b/apps/playback.c
index 5e42b7629d..a19c2d745a 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -1468,10 +1468,26 @@ static void audio_update_trackinfo(void)
ci.taginfo_ready = &CUR_TI->taginfo_ready;
}
-static void low_buffer_callback(void)
+static void buffering_audio_callback(enum callback_event ev, int value)
{
- LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
- queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
+ (void)value;
+ logf("buffering_audio_callback");
+
+ switch (ev)
+ {
+ case EVENT_BUFFER_LOW:
+ LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
+ queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
+ break;
+
+ case EVENT_HANDLE_REBUFFER:
+ LOGFQUEUE("audio >| audio Q_AUDIO_FLUSH");
+ queue_send(&audio_queue, Q_AUDIO_FLUSH, 0);
+ break;
+
+ default:
+ break;
+ }
}
/* Clear tracks between write and read, non inclusive */
@@ -1481,10 +1497,6 @@ static void audio_clear_track_entries(bool clear_unbuffered)
logf("Clearing tracks:%d/%d, %d", track_ridx, track_widx, clear_unbuffered);
- /* This function is always called in association with a stop or a rebuffer,
- * we will reregister the callback at the end of a rebuffer if needed */
- unregister_buffer_low_callback(low_buffer_callback);
-
/* Loop over all tracks from write-to-read */
while (1)
{
@@ -1919,9 +1931,6 @@ static void audio_fill_file_buffer(bool start_play, size_t offset)
track_changed = true;
audio_generate_postbuffer_events();
-
- if (!continue_buffering)
- register_buffer_low_callback(low_buffer_callback);
}
static void audio_rebuffer(void)
@@ -2179,6 +2188,8 @@ static void audio_stop_playback(void)
/* Close all tracks */
audio_release_tracks();
+ unregister_buffering_callback(buffering_audio_callback);
+
memset(&curtrack_id3, 0, sizeof(struct mp3entry));
}
@@ -2221,6 +2232,7 @@ static void audio_play_start(size_t offset)
set_filebuf_watermark(buffer_margin, 0);
#endif
audio_fill_file_buffer(true, offset);
+ register_buffering_callback(buffering_audio_callback);
LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);