diff options
Diffstat (limited to 'src/liana')
| -rw-r--r-- | src/liana/client.c | 16 | ||||
| -rw-r--r-- | src/liana/common.h | 3 | ||||
| -rw-r--r-- | src/liana/list.c | 445 | ||||
| -rw-r--r-- | src/liana/list.h | 26 | ||||
| -rw-r--r-- | src/liana/list_cmp.h | 4 | ||||
| -rw-r--r-- | src/liana/vcr.c | 2 |
6 files changed, 245 insertions, 251 deletions
diff --git a/src/liana/client.c b/src/liana/client.c index 9f7940f..380ed26 100644 --- a/src/liana/client.c +++ b/src/liana/client.c @@ -43,7 +43,7 @@ static void collect_streams(struct lia_client *client, struct nn_packet *packet) struct camu_codec_stream stream = { 0 }; str codec; nn_packet_read_str(packet, &codec); - stream.codec_info = camu_codec_info_by_name(&codec); // @TODO: NULL unhandled. + stream.codec_info = camu_codec_info_by_name(&codec); u8 mode = nn_packet_read_u8(packet); u8 type = nn_packet_read_u8(packet); u64 duration = nn_packet_read_u64(packet); @@ -70,9 +70,9 @@ static void collect_streams(struct lia_client *client, struct nn_packet *packet) #ifdef CAMU_HAVE_FFMPEG case CAMU_FFMPEG_COMPAT: { enum AVCodecID codec_id = nn_packet_read_av_codec_id(packet); - const AVCodec *codec = avcodec_find_decoder(codec_id); + const AVCodec *av_codec = avcodec_find_decoder(codec_id); AVFormatContext *format_context = avformat_alloc_context(); - stream.av.stream = nn_packet_read_av_stream(format_context, codec, packet); + stream.av.stream = nn_packet_read_av_stream(format_context, av_codec, packet); switch (type) { case CAMU_STREAM_ATTACHMENT: // Assume all the data we need is in the AVStream object. @@ -108,6 +108,14 @@ static void collect_streams(struct lia_client *client, struct nn_packet *packet) stream.type = type; stream.duration = duration; stream.index = index; + if (!stream.codec_info) { +#ifdef CAMU_HAVE_FFMPEG + if (stream.mode == CAMU_FFMPEG_COMPAT) { + avformat_free_context(stream.av.format_context); + } +#endif + continue; + } al_array_push(client->streams, stream); } // Video streams have to come before subtitle streams. @@ -219,7 +227,7 @@ static bool connection_callback(void *userdata, struct nn_packet_stream *stream) // we still want to call RESUME_AT here. struct lia_timing time = { .at = client->at, - .seek_pos = client->pos, + .pos = client->pos, .pause = LIANA_PAUSE_NONE }; client->callback(client->userdata, LIANA_CLIENT_RESUME_AT, NULL, &time); diff --git a/src/liana/common.h b/src/liana/common.h new file mode 100644 index 0000000..ec6d50a --- /dev/null +++ b/src/liana/common.h @@ -0,0 +1,3 @@ +#pragma once + +#define LIANA_TIMESTAMP_INVALID ((u64)-1) diff --git a/src/liana/list.c b/src/liana/list.c index 2430a9c..b47a30c 100644 --- a/src/liana/list.c +++ b/src/liana/list.c @@ -35,8 +35,8 @@ void lia_list_init(struct lia_list *list, str *name) { al_str_clone(&list->name, name); list->current = -1; - list->queued = -1; list->idle = true; + list->closed = false; list->increment = 0; al_array_init(list->entries); al_array_init(list->sinks); @@ -69,18 +69,45 @@ static inline void entry_free(struct lia_list_entry *entry) al_free(entry); } +static inline void entry_ref(struct lia_list *list, struct lia_list_entry *entry) +{ + list->callback(list->userdata, LIANA_REF_ENTRY, entry, NULL); +} + +static inline void entry_unref(struct lia_list *list, struct lia_list_entry *entry) +{ + list->callback(list->userdata, LIANA_UNREF_ENTRY, entry, NULL); +} + +static void unref_all_entries(struct lia_list *list, s32 trigger) +{ + struct lia_list_entry *entry; + s32 sequence; + al_array_foreach(list->entries, i, entry) { + sequence = (s32)i; + if (sequence != list->current && sequence != trigger) { + entry_unref(list, entry); + } + } +} + static bool entry_load_and_get_duration(struct lia_list *list, struct lia_list_entry *entry, s32 sequence, bool *error) { - u8 status; - list->callback(list->userdata, LIANA_LOAD_ENTRY, entry, &status); - if (status == LIANA_ENTRY_ERRORED) { + u8 last_load = entry->load; + list->callback(list->userdata, LIANA_LOAD_ENTRY, entry, &entry->load); + if (entry->load == LIANA_ENTRY_ERRORED) { // If sequence is <0 that must mean entry is not yet added to list->entries. if (sequence >= 0) { al_array_remove_at(list->entries, (u32)sequence); + // @TODO: Consider this when implementing list_remove(). + // In the case of remove sequence 0, causing a skip to sequence 1, and sequence 1 + // fails to load, do we properly move to -1 and an idle list. if (list->current > sequence) { - // @TODO: Consider this when implementing list_remove(). - // In the case of remove sequence 0, causing a skip to sequence 1, and sequence 1 - // fails to load, do we properly move to -1 and an idle list. + struct lia_list_sink *sink; + al_array_foreach(list->sinks, i, sink) { + al_assert(sink->set == list->current); + sink->set--; + } list->current--; } struct lia_list_cmd *cmd = list->cmd; @@ -102,35 +129,26 @@ static bool entry_load_and_get_duration(struct lia_list *list, struct lia_list_e return false; } *error = false; - if (status == LIANA_ENTRY_LOADED) { + if (entry->load == LIANA_ENTRY_LOADED) { + if (last_load != LIANA_ENTRY_LOADED) { // Newly loaded entry. + unref_all_entries(list, sequence); + } list->callback(list->userdata, LIANA_GET_ENTRY_DURATION, entry, &entry->duration); return true; } return false; } -static inline void entry_ref(struct lia_list *list, struct lia_list_entry *entry) -{ - list->callback(list->userdata, LIANA_REF_ENTRY, entry, NULL); -} - -static inline void entry_unref(struct lia_list *list, struct lia_list_entry *entry) -{ - list->callback(list->userdata, LIANA_UNREF_ENTRY, entry, NULL); -} - -static void unref_all_entries(struct lia_list *list) +static void unload_all_entires(struct lia_list *list) { - if (list->current < 0) return; struct lia_list_entry *entry; al_array_foreach(list->entries, i, entry) { - if (i != (u32)list->current) entry_unref(list, entry); + entry_unload(list, entry); } } static inline void sink_set_entry(struct lia_list_sink *sink, struct lia_list_entry *entry, s32 sequence, struct lia_timing *time) { - sink->set = sequence; sink->callback(sink->userdata, LIANA_SINK_SET, entry, sequence, time); } @@ -149,38 +167,32 @@ static inline void sink_unset_entry(struct lia_list_sink *sink) sink->callback(sink->userdata, LIANA_SINK_UNSET, NULL, -1, NULL); } -static void list_set_current(struct lia_list *list, struct lia_list_entry *entry, s32 sequence, struct lia_timing *time) +static bool list_set_current(struct lia_list *list, struct lia_list_entry *entry, s32 sequence) { + list->idle = false; entry_ref(list, entry); + al_assert(list->current != sequence); list->current = sequence; - list->idle = false; - // @TODO: This is incorrect and unfinished. - // Skipping back and forth between 2 entries will unload everything else. - unref_all_entries(list); - struct lia_list_sink *sink; - al_array_foreach(list->sinks, i, sink) { - sink_set_entry(sink, entry, sequence, time); - } list_signal_meta(list, entry, LIANA_META_CURRENT_CHANGED); + return true; } static void pump_queue(struct lia_list *list); static bool handle_add_sink(struct lia_list *list, struct lia_list_sink *sink) { - // The list being idle is not equivalent to current being unset. + // The list being idle is not equivalent to current = -1. if (list->current >= 0) { struct lia_list_entry *current = al_array_at(list->entries, list->current); - u64 now = nn_get_timestamp(); u8 pause; u64 at = LIANA_TIMESTAMP_INVALID; - u64 seek_pos = current->offset; + u64 pos = current->offset; if (current->paused_at != LIANA_TIMESTAMP_INVALID) { pause = LIANA_PAUSE_NONE; } else { - at = now + LIANA_BASE_DELAY; + at = nn_get_timestamp() + LIANA_BASE_DELAY; if (at > current->start && at - current->start > LIANA_BASE_DELAY) { - seek_pos += at - current->start; + pos += at - current->start; } else { at = current->start; } @@ -192,19 +204,23 @@ static bool handle_add_sink(struct lia_list *list, struct lia_list_sink *sink) } struct lia_timing time = { .at = at, - .seek_pos = seek_pos, - .pause = pause, - .ended = current->ended + .pos = pos, + .pause = pause }; + sink->set = list->current; sink_set_entry(sink, current, list->current, &time); } al_array_push(list->sinks, sink); return true; } + static void handle_remove_sink(struct lia_list *list, void *userdata) { struct lia_list_cmd *cmd = list->cmd; + // handle_remove_sink() runs immediately, so if there's an ADD_SINK + // queued for this sink, remove it. It should only ever be possible to + // have one queued ADD_SINK for each sink. if (cmd && cmd->op == ADD_SINK && cmd->sink->userdata == userdata) { al_free(cmd->sink); al_free(cmd); @@ -224,9 +240,12 @@ static void handle_remove_sink(struct lia_list *list, void *userdata) if (sink->userdata == userdata) { al_array_remove_at(list->sinks, i); al_free(sink); - return; + break; } } + if (list->closed && !list->sinks.count) { + unload_all_entires(list); + } } static struct lia_list_entry *get_entry_from_sequence(struct lia_list *list, s32 sequence) @@ -248,33 +267,11 @@ static s32 get_sequence_from_entry_id(struct lia_list *list, u32 id) return -1; } -static bool handle_skipto(struct lia_list *list, s32 sequence, s32 index) +static u8 skipto_entry(struct lia_list_entry *current, struct lia_list_entry *target, u64 at) { - if (sequence == LIANA_SEQUENCE_ANY) sequence = list->current; - if (sequence < 0) return true; // list->current = -1 - if (sequence == index) return true; - if (sequence != list->current) { - log_warn("Discarding out of date skip()."); - return true; - } - - struct lia_list_entry *current = get_entry_from_sequence(list, sequence); - struct lia_list_entry *target = get_entry_from_sequence(list, index); - al_assert(current && !current->held && current != target); - if (!target) return true; - bool error; - if (!entry_load_and_get_duration(list, target, index, &error)) { - // index might point to a different entry after an error. - if (error) pump_queue(list); - return false; - } + al_assert(at != LIANA_TIMESTAMP_INVALID); - u64 now = nn_get_timestamp(); - u64 at = now + LIANA_BASE_DELAY; - u8 pause; - - // Resume target if it's held. - if (target->held) { + if (target->held) { // Resume target if it's held. al_assert(target->paused_at != LIANA_TIMESTAMP_INVALID); target->paused_at = LIANA_TIMESTAMP_INVALID; target->start = at; @@ -287,6 +284,8 @@ static bool handle_skipto(struct lia_list *list, s32 sequence, s32 index) al_assert(target->duration == 0 || target->paused_at != LIANA_TIMESTAMP_INVALID); } + u8 pause; + // If current->duration = LIANA_TIMESTAMP_INVALID, handling of a static entry happens on the sink. if (current->duration == 0 || current->paused_at != LIANA_TIMESTAMP_INVALID) { if (target->duration == 0 || target->paused_at != LIANA_TIMESTAMP_INVALID) { @@ -310,6 +309,7 @@ static bool handle_skipto(struct lia_list *list, s32 sequence, s32 index) // Pause current to be resumed if it becomes the target of a skip (hold). if (current->duration != 0 && current->paused_at == LIANA_TIMESTAMP_INVALID) { + al_assert(current->start != LIANA_TIMESTAMP_INVALID); current->paused_at = at; if (current->paused_at < current->start) { current->paused_at = current->start; @@ -319,28 +319,70 @@ static bool handle_skipto(struct lia_list *list, s32 sequence, s32 index) current->held = true; } - log_trace("skipto(#%u-#%u): pause: %hhu, held: %s.", current->id, target->id, pause, BOOLSTR(current->held)); + return pause; +} + +static bool handle_skipto(struct lia_list *list, s32 sequence, s32 index) +{ + if (sequence == LIANA_SEQUENCE_ANY) { + sequence = list->current; + } + if (sequence < 0) return true; // list->current = -1 + if (sequence == index) return true; + if (sequence != list->current) { + log_warn("Discarding out of date skip()."); + return true; + } + + struct lia_list_entry *current = get_entry_from_sequence(list, sequence); + struct lia_list_entry *target = get_entry_from_sequence(list, index); + al_assert(current && !current->held && current != target); + if (!target) return true; + bool error; + if (!entry_load_and_get_duration(list, target, index, &error)) { + if (error) { + // index might point to a different entry after an error. + return handle_skipto(list, sequence, index); + } + return false; + } + + u64 at = nn_get_timestamp() + LIANA_PAUSE_DELAY; + u64 pos = target->offset; + u8 pause = skipto_entry(current, target, at); + + log_trace("skipto(#%u-#%u): pause: %s, held: %s.", current->id, target->id, + lia_pause_op_name(pause), BOOLSTR(current->held)); struct lia_timing time = { .at = at, - .seek_pos = target->offset, - .pause = pause, - .ended = target->ended + .pos = pos, + .pause = pause }; - list_set_current(list, target, index, &time); + struct lia_list_sink *sink; + al_array_foreach(list->sinks, i, sink) { + al_assert(sink->set != index); + sink->set = index; + sink_set_entry(sink, target, index, &time); + } + + return list_set_current(list, target, index); +} - return true; +static bool handle_skip(struct lia_list *list, s32 sequence, s32 n) +{ + if (sequence == LIANA_SEQUENCE_ANY) sequence = list->current; + if (sequence < 0) return true; // list->current = -1 + return handle_skipto(list, sequence, sequence + n); } static bool handle_add(struct lia_list *list, struct lia_list_entry *entry) { - // @TODO: This is an easy spot to preload an entry. - // Just fire an entry_load_and_get_duration() but ignore the immediate result. if (list->idle) { bool error; if (!entry_load_and_get_duration(list, entry, -1, &error)) { - // We passed a sequence of -1 so, on error, do not touch list->entries. + // We gave a sequence of -1 so, on error, don't add to list->entries. return error; } } @@ -350,16 +392,18 @@ static bool handle_add(struct lia_list *list, struct lia_list_entry *entry) entry->start = nn_get_timestamp() + LIANA_BASE_DELAY; struct lia_timing time = { .at = entry->start, - .seek_pos = entry->offset, - .pause = LIANA_PAUSE_RESUME, - .ended = false + .pos = entry->offset, + .pause = LIANA_PAUSE_RESUME }; - list_set_current(list, entry, list->current + 1, &time); - } else { // Immediately skip to the added entry. - // Processing this through a SKIPTO is extremely important for consistency. - // We expect current is ended but it still must be held before moving to this entry. - // -2 cause we just added this entry above. - al_assert((u32)list->current == list->entries.count - 2); + struct lia_list_sink *sink; + al_array_foreach(list->sinks, i, sink) { + al_assert(sink->set == -1); + sink->set = 0; + sink_set_entry(sink, entry, 0, &time); + } + return list_set_current(list, entry, 0); + } else { // Skip to the added entry. + // This is done via SKIPTO for consistency. Ended entries must still be held. struct lia_list_cmd *cmd = list->cmd; cmd->op = SKIPTO; cmd->sequence = list->current; @@ -367,20 +411,16 @@ static bool handle_add(struct lia_list *list, struct lia_list_entry *entry) return handle_skipto(list, cmd->sequence, cmd->arg0.i); } } + al_assert(list->current != -1); return true; } -static bool handle_skip(struct lia_list *list, s32 sequence, s32 n) -{ - if (sequence == LIANA_SEQUENCE_ANY) sequence = list->current; - if (sequence < 0) return true; // list->current = -1 - return handle_skipto(list, sequence, sequence + n); -} - static void handle_toggle_pause(struct lia_list *list, s32 sequence, f64 pts) { - if (sequence == LIANA_SEQUENCE_ANY) sequence = list->current; - if (sequence < 0) return; // list->current = -1 + if (sequence == LIANA_SEQUENCE_ANY) { + sequence = list->current; + } + if (sequence < 0) return; if (sequence != list->current) { log_warn("Discarding out of date toggle_pause()."); return; @@ -395,7 +435,7 @@ static void handle_toggle_pause(struct lia_list *list, s32 sequence, f64 pts) u64 at; switch (pause) { - case LIANA_PAUSE_PAUSE: + case LIANA_PAUSE_PAUSE: { al_assert(entry->start != LIANA_TIMESTAMP_INVALID); entry->paused_at = now + LIANA_PAUSE_DELAY; if (entry->paused_at < entry->start) { @@ -405,26 +445,32 @@ static void handle_toggle_pause(struct lia_list *list, s32 sequence, f64 pts) entry->start = LIANA_TIMESTAMP_INVALID; at = entry->paused_at; break; - case LIANA_PAUSE_RESUME: + } + case LIANA_PAUSE_RESUME: { al_assert(entry->start == LIANA_TIMESTAMP_INVALID); - entry->paused_at = LIANA_TIMESTAMP_INVALID; entry->start = now + LIANA_PAUSE_DELAY; + entry->paused_at = LIANA_TIMESTAMP_INVALID; at = entry->start; break; } + } log_trace("toggle_pause(#%u): pts: %f, pause: %hhu.", entry->id, pts, pause); struct lia_timing time = { .at = at, - .seek_pos = LIANA_TIMESTAMP_INVALID, - .pause = pause, - .ended = entry->ended + .pos = entry->offset, + .pause = pause }; struct lia_list_sink *sink; al_array_foreach(list->sinks, i, sink) { - sink_pause_entry(sink, entry, sequence, &time); + if (sequence == list->current && sink->set != sequence) { + sink->set = sequence; + sink_set_entry(sink, entry, sequence, &time); + } else { + sink_pause_entry(sink, entry, sequence, &time); + } } list_signal_meta(list, entry, LIANA_META_ENTRY_PAUSED); @@ -448,52 +494,50 @@ static void handle_seek(struct lia_list *list, s32 sequence, u32 id, u64 pos) } pos = CLAMP(pos, (u64)0, entry->duration); - u64 now = nn_get_timestamp(); - u64 at = now + LIANA_BASE_DELAY; - u8 pause = (entry->paused_at == LIANA_TIMESTAMP_INVALID) ? LIANA_PAUSE_RESUME : LIANA_PAUSE_NONE; - - entry->ended = false; - entry->reset_id = get_incremental_id(list); - entry->offset = pos; - if (pause == LIANA_PAUSE_RESUME) { + u64 at = nn_get_timestamp() + LIANA_BASE_DELAY; + u8 pause; + if (entry->paused_at == LIANA_TIMESTAMP_INVALID) { entry->start = at; + pause = LIANA_PAUSE_RESUME; + } else { + pause = LIANA_PAUSE_NONE; } - list->idle = false; + entry->ended = false; + entry->offset = pos; + entry->reset_token = get_incremental_id(list); log_trace("seek(#%u): pos: %f, pause: %hhu.", entry->id, pos / 1000000.0, pause); + list->idle = false; + struct lia_timing time = { .at = at, - .seek_pos = pos, - .pause = pause, - .ended = entry->ended + .pos = pos, + .pause = pause }; struct lia_list_sink *sink; al_array_foreach(list->sinks, i, sink) { if (sequence == list->current && sink->set != sequence) { - // Entry might not be set if the sink was added after it ended. + sink->set = sequence; sink_set_entry(sink, entry, sequence, &time); + } else { + sink_seek_entry(sink, entry, sequence, &time); } - sink_seek_entry(sink, entry, sequence, &time); } list_signal_meta(list, entry, LIANA_META_ENTRY_SEEKED); } -static bool handle_end(struct lia_list *list, u32 id, u32 reset_id) +static bool handle_end(struct lia_list *list, u32 id, u32 reset_token) { s32 sequence = get_sequence_from_entry_id(list, id); if (sequence < 0) return true; - struct lia_list_entry *entry = get_entry_from_sequence(list, sequence); - // @TODO: Looping. - // Main issue is rolling back an entry that skipped onto queued - // before it's looping state was synced. If we track which sink END - // is coming from, we could probably handle it then. + struct lia_list_entry *entry = get_entry_from_sequence(list, sequence); - if (reset_id != entry->reset_id) { + if (reset_token != entry->reset_token) { log_warn("Got end() with out of order or incorrect reset id, ignoring."); return true; } @@ -521,17 +565,7 @@ static bool handle_end(struct lia_list *list, u32 id, u32 reset_id) s32 size = (s32)list->entries.count; if (sequence == list->current) { s32 next = sequence + 1; - if (list->queued >= 0) { - struct lia_list_entry *queued = al_array_at(list->entries, list->queued); - struct lia_list_sink *sink; - al_array_foreach(list->sinks, i, sink) { - sink->queued = -1; - sink->set = list->queued; - } - list->current = list->queued; - list->queued = -1; - list_signal_meta(list, queued, LIANA_META_CURRENT_CHANGED); - } else if (next < size) { + if (next < size) { struct lia_list_cmd *cmd = list->cmd; cmd->op = SKIPTO; cmd->sequence = sequence; @@ -545,9 +579,10 @@ static bool handle_end(struct lia_list *list, u32 id, u32 reset_id) return true; } -static bool adjust_current(struct lia_list *list, struct lia_list_entry *previous) +static bool adjust_for_order_change(struct lia_list *list, struct lia_list_entry *previous) { al_assert(list->current >= 0); + list_signal_meta(list, previous, LIANA_META_ORDER_PROBABLY_CHANGED); struct lia_list_cmd *cmd = list->cmd; struct lia_list_entry *entry = NULL; al_array_foreach(list->entries, i, entry) { @@ -558,12 +593,16 @@ static bool adjust_current(struct lia_list *list, struct lia_list_entry *previou cmd->op = SKIPTO; cmd->sequence = i; cmd->arg0.i = list->current; + struct lia_list_sink *sink; + al_array_foreach(list->sinks, j, sink) { + al_assert(sink->set == list->current); + sink->set = i; + } list->current = i; break; } } - al_assert(entry && cmd->op == SKIPTO); - list_signal_meta(list, previous, LIANA_META_ORDER_CHANGED); + al_assert(cmd->op == SKIPTO); return handle_skipto(list, cmd->sequence, cmd->arg0.i); } @@ -577,7 +616,8 @@ static bool handle_reverse(struct lia_list *list) if (tail <= i) break; SWAP(al_array_at(list->entries, i), al_array_at(list->entries, tail)); } - return adjust_current(list, previous); + log_trace("reverse()"); + return adjust_for_order_change(list, previous); } static bool handle_sort(struct lia_list *list) @@ -585,14 +625,14 @@ static bool handle_sort(struct lia_list *list) if (list->current < 0) return true; struct lia_list_entry *previous = al_array_at(list->entries, list->current); al_array_sort(list->entries, struct lia_list_entry *, camu_db_compare); - return adjust_current(list, previous); + log_trace("sort()"); + return adjust_for_order_change(list, previous); } static bool handle_shuffle(struct lia_list *list) { - if (list->current < 0) return true; u32 size = list->entries.count; - if (size <= 1) return false; + if (list->current < 0 || size < 2) return true; struct lia_list_entry *previous = al_array_at(list->entries, list->current); /* https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle for i from 0 to n−2 do @@ -609,21 +649,37 @@ static bool handle_shuffle(struct lia_list *list) SWAP(al_array_at(list->entries, i), al_array_at(list->entries, j)); } } - return adjust_current(list, previous); + log_trace("shuffle()"); + return adjust_for_order_change(list, previous); } -static void handle_unset(struct lia_list *list) +static void unset_current(struct lia_list *list) { - // @TODO: Unset behavior (flag on list): - // SKIP: Based on previous current. - // ADD: Skip to added entry. - // SEEK: Set and seek previous current. - // Explicitly ignore all other events. struct lia_list_sink *sink; al_array_foreach(list->sinks, i, sink) { + if (sink->set >= 0) { + sink_unset_entry(sink); + } sink->set = -1; - sink_unset_entry(sink); } + list->idle = true; +} + +static void handle_unset(struct lia_list *list) +{ + unset_current(list); +} + +static void handle_clear(struct lia_list *list) +{ + unset_current(list); + list->current = -1; + unload_all_entires(list); + struct lia_list_entry *entry; + al_array_foreach(list->entries, i, entry) { + entry_free(entry); + } + list->entries.count = 0; } static void run_queue(struct lia_list *list) @@ -693,6 +749,7 @@ static void run_queue(struct lia_list *list) handle_unset(list); break; case CLEAR: + handle_clear(list); break; } al_free(cmd); @@ -714,7 +771,6 @@ void lia_list_add_sink(struct lia_list *list, void (*callback)(void *, u8, struc { struct lia_list_sink *sink = al_alloc_object(struct lia_list_sink); sink->set = -1; - sink->queued = -1; sink->callback = callback; sink->userdata = userdata; struct lia_list_cmd *cmd = al_alloc_object(struct lia_list_cmd); @@ -731,19 +787,20 @@ void lia_list_remove_sink(struct lia_list *list, void *userdata) handle_remove_sink(list, userdata); } -void lia_list_add(struct lia_list *list, void *opaque, u64 duration, str *brief) +void lia_list_add(struct lia_list *list, str *brief, void *opaque, u64 duration, u8 load) { struct lia_list_entry *entry = al_alloc_object(struct lia_list_entry); entry->opaque = opaque; + al_str_clone(&entry->brief, brief); entry->id = get_incremental_id(list); entry->start = LIANA_TIMESTAMP_INVALID; entry->paused_at = LIANA_TIMESTAMP_INVALID; entry->offset = 0; + entry->duration = duration; + entry->load = load; entry->held = false; entry->ended = false; - entry->reset_id = get_incremental_id(list); - entry->duration = duration; - al_str_clone(&entry->brief, brief); + entry->reset_token = get_incremental_id(list); entry->list = list; struct lia_list_cmd *cmd = al_alloc_object(struct lia_list_cmd); cmd->op = ADD; @@ -795,12 +852,12 @@ void lia_list_seek(struct lia_list *list, s32 sequence, u32 id, u64 pos) pump_queue(list); } -void lia_list_end(struct lia_list *list, u32 id, u32 reset_id) +void lia_list_end(struct lia_list *list, u32 id, u32 reset_token) { struct lia_list_cmd *cmd = al_alloc_object(struct lia_list_cmd); cmd->op = END; cmd->arg0.u = id; - cmd->arg1.u = reset_id; + cmd->arg1.u = reset_token; al_array_push(list->command_queue, cmd); pump_queue(list); } @@ -837,7 +894,6 @@ void lia_list_unset(struct lia_list *list) pump_queue(list); } -/* void lia_list_clear(struct lia_list *list) { struct lia_list_cmd *cmd = al_alloc_object(struct lia_list_cmd); @@ -845,20 +901,18 @@ void lia_list_clear(struct lia_list *list) al_array_push(list->command_queue, cmd); pump_queue(list); } -*/ void lia_list_close(struct lia_list *list) { - // @TODO: Consider sinks being in use. - // Delay until list->sinks is empty. - struct lia_list_entry *entry; - al_array_foreach(list->entries, i, entry) { - entry_unload(list, entry); + list->closed = true; + if (!list->sinks.count) { + unload_all_entires(list); } } void lia_list_free(struct lia_list *list) { + al_assert(list->closed); struct lia_list_cmd *cmd; al_array_foreach(list->command_queue, i, cmd) { al_free(cmd); @@ -877,74 +931,3 @@ void lia_list_free(struct lia_list *list) al_array_free(list->sinks); al_str_free(&list->name); } - -/* -static void buffer_ahead(struct lia_list *list) -{ - s32 size = (s32)list->entries.count; - if (list->current >= 0 && list->current + 1 < size) { - s32 ahead = list->current + 1; - for (s32 i = ahead; i < MIN(ahead + LIANA_BUFFER_AHEAD, size); i++) { - struct lia_list_entry *entry = al_array_at(list->entries, i); - struct lia_timing time = { - .at = LIANA_TIMESTAMP_INVALID, - .seek_pos = entry->offset, - .pause = LIANA_PAUSE_NONE, - .ended = false - }; - struct lia_list_sink *sink; - al_array_foreach(list->sinks, i, sink) { - sink->callback(sink->userdata, LIANA_SINK_BUFFER, entry, i, &time); - } - } - } -} - -static void set_queued(struct lia_list *list) -{ - if (list->queued < 0) { - return; - } - - struct lia_list_entry *queued = al_array_at(list->entries, list->queued); - - bool error; - struct lia_list_entry *current = al_array_at(list->entries, list->current); - if (!entry_load_and_get_duration(list, current, list->current, &error)) { - return; - } - - queued->start = current->start + (current->duration - current->offset); - u8 pause = (queued->paused_at == LIANA_TIMESTAMP_INVALID) ? LIANA_PAUSE_RESUME : LIANA_PAUSE_NONE; - struct lia_timing time = { - .at = queued->start, - .seek_pos = queued->offset, - .pause = pause - }; - - struct lia_list_sink *sink; - al_array_foreach(list->sinks, i, sink) { - if (sink->queued != list->queued) { - sink->queued = list->queued; - sink->callback(sink->userdata, LIANA_SINK_BUFFER_AND_QUEUE, queued, list->queued, &time); - } - } -} - -static void evaluate_queued(struct lia_list *list) -{ - s32 size = (s32)list->entries.count; - s32 next = list->current + 1; - if (next >= size || next == list->queued) { - return; - } - - bool error; - struct lia_list_entry *queued = al_array_at(list->entries, next); - if (!entry_load_and_get_duration(list, queued, next, &error)) { - return; - } - - list->queued = next; -} -*/ diff --git a/src/liana/list.h b/src/liana/list.h index 0f09465..61dcb1d 100644 --- a/src/liana/list.h +++ b/src/liana/list.h @@ -4,10 +4,11 @@ #include <al/wstr.h> #include <al/array.h> +#include "common.h" + #define LIANA_SEQUENCE_ANY -1 -#define LIANA_TIMESTAMP_INVALID ((u64)-1) -#define LIANA_BASE_DELAY 600000u // 600ms +#define LIANA_BASE_DELAY 450000u // 450ms #define LIANA_BASE_PING 125000u // 125ms #define LIANA_PAUSE_DELAY LIANA_BASE_PING #define LIANA_DELAY_IGNORE 0u @@ -52,7 +53,7 @@ enum { LIANA_META_ADDED_ENTRY = 0, LIANA_META_REMOVED_ENTRY, LIANA_META_CURRENT_CHANGED, - LIANA_META_ORDER_CHANGED, + LIANA_META_ORDER_PROBABLY_CHANGED, LIANA_META_ENTRY_PAUSED, LIANA_META_ENTRY_SEEKED, LIANA_META_ENTRY_ERRORED @@ -67,28 +68,27 @@ enum { struct lia_timing { u64 at; - u64 seek_pos; + u64 pos; u8 pause; - bool ended; }; struct lia_list_entry { void *opaque; + str brief; u32 id; u64 start; u64 paused_at; u64 offset; + u64 duration; + u8 load; bool held; bool ended; - u32 reset_id; - u64 duration; - str brief; + u32 reset_token; struct lia_list *list; }; struct lia_list_sink { s32 set; - s32 queued; void (*callback)(void *, u8, struct lia_list_entry *, s32, struct lia_timing *); void *userdata; }; @@ -106,8 +106,8 @@ struct lia_list_cmd { struct lia_list { str name; s32 current; - s32 queued; bool idle; + bool closed; u32 increment; array(struct lia_list_entry *) entries; array(struct lia_list_sink *) sinks; @@ -135,18 +135,18 @@ void lia_list_pump(struct lia_list *list); void lia_list_add_sink(struct lia_list *list, void (*callback)(void *, u8, struct lia_list_entry *, s32, struct lia_timing *), void *userdata); void lia_list_remove_sink(struct lia_list *list, void *userdata); -void lia_list_add(struct lia_list *list, void *opaque, u64 duration, str *brief); +void lia_list_add(struct lia_list *list, str *brief, void *opaque, u64 duration, u8 load); void lia_list_unset(struct lia_list *list); void lia_list_skipto(struct lia_list *list, s32 sequence, s32 i); void lia_list_skip(struct lia_list *list, s32 sequence, s32 n); void lia_list_toggle_pause(struct lia_list *list, s32 sequence, f64 pts); void lia_list_seek(struct lia_list *list, s32 sequence, u32 id, u64 pos); -void lia_list_end(struct lia_list *list, u32 id, u32 reset_id); +void lia_list_end(struct lia_list *list, u32 id, u32 reset_token); void lia_list_reverse(struct lia_list *list); void lia_list_sort(struct lia_list *list); void lia_list_shuffle(struct lia_list *list); -//void lia_list_clear(struct lia_list *list); +void lia_list_clear(struct lia_list *list); void lia_list_close(struct lia_list *list); void lia_list_free(struct lia_list *list); diff --git a/src/liana/list_cmp.h b/src/liana/list_cmp.h index 30f6e7d..6bc7c69 100644 --- a/src/liana/list_cmp.h +++ b/src/liana/list_cmp.h @@ -55,8 +55,8 @@ static s32 camu_db_compare(const void *a, const void *b) if (a_index > b_index) return 1; else if (a_index < b_index) return -1; } else { - if (a_id > b_id) return -1; - else if (a_id < b_id) return 1; + if (a_id > b_id) return 1; + else if (a_id < b_id) return -1; } return 0; } diff --git a/src/liana/vcr.c b/src/liana/vcr.c index 32c33cf..13082f5 100644 --- a/src/liana/vcr.c +++ b/src/liana/vcr.c @@ -5,7 +5,7 @@ #include "handlers/handler.h" #include "vcr.h" -#include "list.h" +#include "common.h" #define VCR_BUFFER_BUFFERED MB(4) #define VCR_BUFFER_GROW_FACTOR 8 |