diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/buffering.c | 58 | ||||
-rw-r--r-- | apps/buffering.h | 16 | ||||
-rw-r--r-- | apps/playback.c | 32 |
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); |