diff options
Diffstat (limited to 'src/list')
| -rw-r--r-- | src/list/list.c | 115 | ||||
| -rw-r--r-- | src/list/list.h | 25 |
2 files changed, 114 insertions, 26 deletions
diff --git a/src/list/list.c b/src/list/list.c index 3af75e4..d5be3dc 100644 --- a/src/list/list.c +++ b/src/list/list.c @@ -2,6 +2,7 @@ #include <aki/thread.h> #include "../libsink/common.h" +#include "../shrub/handler.h" #include "list.h" @@ -9,6 +10,7 @@ void camu_list_init(struct camu_list *list, str *name) { al_str_clone(&list->name, name); list->current = -1; + list->prev = -1; list->idle = true; list->sequence = 0; al_array_init(list->entries); @@ -24,19 +26,26 @@ static void camu_list_pump(struct camu_list *list) if (list->current + 1 < size) { upcoming = al_array_at(list->entries, list->current + 1); } + struct camu_list_entry *prev = NULL; + if (list->prev >= 0) { + prev = al_array_at(list->entries, list->prev); + list->prev = -1; + } struct camu_list_sink *sink; al_array_foreach(list->sinks, i, sink) { if (sink->set != list->current) { - sink->callback(sink->userdata, CAMU_SINK_SET, entry->opaque, entry->sequence); + void *prev_opaque = NULL; + if (prev) prev_opaque = prev->opaque; + sink->callback(sink->userdata, CAMU_SINK_SET, entry->opaque, prev_opaque, entry->sequence); sink->set = list->current; } if (upcoming) { - sink->callback(sink->userdata, CAMU_SINK_QUEUE, upcoming->opaque, upcoming->sequence); + sink->callback(sink->userdata, CAMU_SINK_QUEUE, upcoming->opaque, entry->opaque, upcoming->sequence); } } } -void camu_list_add_sink(struct camu_list *list, void (*callback)(void *, u8, void *, s32), +void camu_list_add_sink(struct camu_list *list, void (*callback)(void *, u8, void *, void *, s32), void *userdata) { struct camu_list_sink *sink = al_alloc_object(struct camu_list_sink); @@ -68,12 +77,12 @@ void camu_list_add(struct camu_list *list, void *opaque, void (*callback)(void * entry->callback = callback; entry->duration = duration; entry->start = aki_get_timestamp(); + entry->paused = false; if (!list->idle) { struct camu_list_entry *prev = al_array_at(list->entries, size - 1); u64 end = prev->start + prev->duration; if (end > entry->start) { - u64 diff = end - entry->start; - entry->start += diff; + entry->start += end - entry->start; } } al_array_push(list->entries, entry); @@ -83,10 +92,7 @@ void camu_list_add(struct camu_list *list, void *opaque, void (*callback)(void * list->idle = false; } camu_list_pump(list); - struct camu_list_timing timing = { - .start = entry->start - }; - entry->callback(entry->opaque, CAMU_LIST_ENTRY_IMPULSE, &timing); + entry->callback(entry->opaque, CAMU_LIST_IMPULSE, &entry->start); } static s32 index_of_entry_from_sequence(struct camu_list *list, s32 sequence) @@ -106,12 +112,13 @@ void camu_list_skip(struct camu_list *list, s32 sequence, s32 n) s32 index = index_of_entry_from_sequence(list, sequence); if (index == CAMU_SEQUENCE_INVALID) index = list->current; if (index + n < 0 || index + n >= size || index + n == list->current) return; + list->prev = list->current; + struct camu_list_entry *prev = al_array_at(list->entries, list->prev); + prev->callback(prev->opaque, CAMU_LIST_PAUSE, NULL); list->current = index + n; struct camu_list_entry *entry = al_array_at(list->entries, list->current); - struct camu_list_timing timing = { - .start = aki_get_timestamp() - }; - entry->callback(entry->opaque, CAMU_LIST_ENTRY_IMPULSE, &timing); + entry->start = aki_get_timestamp(); + entry->callback(entry->opaque, CAMU_LIST_IMPULSE, &entry->start); camu_list_pump(list); } @@ -128,7 +135,20 @@ void camu_list_toggle_pause(struct camu_list *list, s32 sequence, u64 pos) s32 index = index_of_entry_from_sequence(list, sequence); if (index == CAMU_SEQUENCE_INVALID) return; struct camu_list_entry *entry = al_array_at(list->entries, index); - entry->callback(entry->opaque, CAMU_LIST_ENTRY_TOGGLE_PAUSE, &pos); + if (entry->paused) { + u64 ts = aki_get_timestamp(); + struct shrb_resume_req req = { + .start = ts, + .offset = ts - entry->start + }; + entry->start = ts; + entry->callback(entry->opaque, CAMU_LIST_USER_RESUME, &req); + entry->paused = false; + } else { + entry->start = aki_get_timestamp(); + entry->callback(entry->opaque, CAMU_LIST_USER_PAUSE, &pos); + entry->paused = true; + } } void camu_list_seek(struct camu_list *list, s32 sequence, f64 percent) @@ -137,8 +157,10 @@ void camu_list_seek(struct camu_list *list, s32 sequence, f64 percent) if (index == CAMU_SEQUENCE_INVALID) return; list->idle = false; struct camu_list_entry *entry = al_array_at(list->entries, index); + entry->start = aki_get_timestamp(); + entry->callback(entry->opaque, CAMU_LIST_IMPULSE, &entry->start); u64 pos = percent * entry->duration; - entry->callback(entry->opaque, CAMU_LIST_ENTRY_SEEK, &pos); + entry->callback(entry->opaque, CAMU_LIST_SEEK, &pos); } void camu_list_finished(struct camu_list *list, s32 sequence) @@ -170,3 +192,66 @@ void camu_list_shuffle(struct camu_list *list) } camu_list_pump(list); } + +static s64 camu_db_num_from_path(str *path) +{ + s32 slash = al_str_rfind(path, '/'); + if (slash < 0) return -1; + str s = *al_str_substr(path, slash + 1, path->len); + s32 underscore = al_str_find(&s, '_'); + if (underscore < 0) return -1; + s = *al_str_substr(&s, underscore + 1, s.len); + underscore = al_str_find(&s, '_'); + if (underscore < 0) return -1; + s = *al_str_substr(&s, underscore + 1, s.len); + underscore = al_str_find(&s, '_'); + if (underscore < 0) return -1; + s = *al_str_substr(&s, 0, underscore); + s64 num = al_str_to_long(&s, 10); + if (num == INT64_MIN || num == INT64_MAX) { + return -1; + } + return num; +} + +static s32 camu_db_compare(void *a, void *b) +{ + struct camu_list_entry *aa = *((struct camu_list_entry **)a); + struct camu_list_entry *bb = *((struct camu_list_entry **)b); + str *astr = NULL, *bstr = NULL; + aa->callback(aa->opaque, CAMU_LIST_ENTRY_ID, &astr); + bb->callback(bb->opaque, CAMU_LIST_ENTRY_ID, &bstr); + s64 anum = camu_db_num_from_path(astr); + s64 bnum = camu_db_num_from_path(bstr); + if (anum > bnum) { + return -1; + } else if (anum < bnum) { + return 1; + } + return 0; +} + +void camu_list_sort(struct camu_list *list) +{ + al_array_sort(list->entries, struct camu_list_entry *, camu_db_compare); + struct camu_list_sink *sink; + al_array_foreach(list->sinks, i, sink) { + sink->set = -1; + } + camu_list_pump(list); +} + +void camu_list_reverse(struct camu_list *list) +{ + u32 size = list->entries.size; + for (u32 i = 0; i < size; i++) { + u32 tail = size - (i + 1); + if (tail <= i) break; + AL_SWAP(al_array_at(list->entries, i), al_array_at(list->entries, tail), struct camu_list_entry *); + } + struct camu_list_sink *sink; + al_array_foreach(list->sinks, i, sink) { + sink->set = -1; + } + camu_list_pump(list); +} diff --git a/src/list/list.h b/src/list/list.h index edd0218..4873265 100644 --- a/src/list/list.h +++ b/src/list/list.h @@ -5,14 +5,14 @@ #define CAMU_SEQUENCE_INVALID INT32_MAX +// TODO: Improve naming between this and server LIST_ACTION's enum { - CAMU_LIST_ENTRY_IMPULSE = 0, - CAMU_LIST_ENTRY_TOGGLE_PAUSE, - CAMU_LIST_ENTRY_SEEK -}; - -struct camu_list_timing { - u64 start; + CAMU_LIST_ENTRY_ID = 0, + CAMU_LIST_IMPULSE, + CAMU_LIST_USER_PAUSE, + CAMU_LIST_USER_RESUME, + CAMU_LIST_PAUSE, // Pause at current position. + CAMU_LIST_SEEK }; struct camu_list_entry { @@ -21,27 +21,28 @@ struct camu_list_entry { void (*callback)(void *, u8, void *); u64 duration; u64 start; - u64 paused_at; + bool paused; }; struct camu_list_sink { s32 set; bool (*action)(void *, u8, void *); - void (*callback)(void *, u8, void *, s32); + void (*callback)(void *, u8, void *, void *, s32); void *userdata; }; struct camu_list { str name; s32 current; + s32 prev; bool idle; - s32 sequence; // Next entry sequence. + s32 sequence; // Holds the next entry sequence. array(struct camu_list_entry *) entries; array(struct camu_list_sink *) sinks; }; void camu_list_init(struct camu_list *list, str *name); -void camu_list_add_sink(struct camu_list *list, void (*callback)(void *, u8, void *, s32), +void camu_list_add_sink(struct camu_list *list, void (*callback)(void *, u8, void *, void *, s32), void *userdata); void camu_list_remove_sink(struct camu_list *list, void *userdata); void camu_list_add(struct camu_list *list, void *opaque, void (*callback)(void *, u8, void *), @@ -52,3 +53,5 @@ void camu_list_toggle_pause(struct camu_list *list, s32 sequence, u64 pos); void camu_list_seek(struct camu_list *list, s32 sequence, f64 percent); void camu_list_finished(struct camu_list *list, s32 sequence); void camu_list_shuffle(struct camu_list *list); +void camu_list_sort(struct camu_list *list); +void camu_list_reverse(struct camu_list *list); |