summaryrefslogtreecommitdiff
path: root/src/list
diff options
context:
space:
mode:
Diffstat (limited to 'src/list')
-rw-r--r--src/list/list.c115
-rw-r--r--src/list/list.h25
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);