diff --git a/src/connection.c b/src/connection.c index 807ce3dd..3ad7e8e2 100644 --- a/src/connection.c +++ b/src/connection.c @@ -936,6 +936,9 @@ static void __add_listener_to_source(source_t *source, client_t *client) { size_t loop = 10; + if (navigation_history_navigate_to(&(client->history), source->identifier, NAVIGATION_DIRECTION_REPLACE_ALL) != 0) + ICECAST_LOG_ERROR("Can not change history: navigation of client=%p{.con.id=%llu, ...} to source=%p{.mount=%#H, ...} failed", client, (unsigned long long int)client->con->id, source, source->mount); + do { ICECAST_LOG_DEBUG("max on %s is %ld (cur %lu)", source->mount, source->max_listeners, source->listeners); @@ -954,6 +957,7 @@ static void __add_listener_to_source(source_t *source, client_t *client) } ICECAST_LOG_INFO("stream full, trying %s", next->mount); source = next; + navigation_history_navigate_to(&(client->history), source->identifier, NAVIGATION_DIRECTION_DOWN); loop--; continue; } @@ -967,9 +971,6 @@ static void __add_listener_to_source(source_t *source, client_t *client) client->refbuf->len = PER_CLIENT_REFBUF_SIZE; memset(client->refbuf->data, 0, PER_CLIENT_REFBUF_SIZE); - if (navigation_history_navigate_to(&(client->history), source->identifier, NAVIGATION_DIRECTION_REPLACE_ALL) != 0) - ICECAST_LOG_ERROR("Can not change history: navigation of client=%p{.con.id=%llu, ...} to source=%p{.mount=%#H, ...} failed", client, (unsigned long long int)client->con->id, source, source->mount); - /* lets add the client to the active list */ avl_tree_wlock(source->pending_tree); avl_insert(source->pending_tree, client); diff --git a/src/navigation.c b/src/navigation.c index 3eca889a..f93597da 100644 --- a/src/navigation.c +++ b/src/navigation.c @@ -90,6 +90,9 @@ static inline int navigation_history_pop(navigation_history_t *history) static inline int navigation_history_push(navigation_history_t *history, mount_identifier_t *identifier) { + if (history->fill > 0 && mount_identifier_compare(history->history[history->fill - 1], identifier) == 0) + return 0; + if (refobject_ref(identifier) != 0) return -1; @@ -132,6 +135,9 @@ int navigation_history_navigate_to(navigation_history_t *his if (!history || !identifier) return -1; + if (direction == NAVIGATION_DIRECTION_UP && history->fill < 2) + direction = NAVIGATION_DIRECTION_REPLACE_ALL; + switch (direction) { case NAVIGATION_DIRECTION_UP: if (history->fill < 2) @@ -147,6 +153,10 @@ int navigation_history_navigate_to(navigation_history_t *his if (history->fill == 0) { return navigation_history_push(history, identifier); } else { + if (history->fill > 1 && mount_identifier_compare(history->history[history->fill - 2], identifier) == 0) { + return navigation_history_pop(history); + } + if (refobject_ref(identifier) != 0) return -1; refobject_unref(history->history[history->fill - 1]); diff --git a/src/slave.c b/src/slave.c index cb4a5f7f..361d7083 100644 --- a/src/slave.c +++ b/src/slave.c @@ -469,7 +469,7 @@ static void *start_relay_stream (void *arg) fallback_source = source_find_mount(relay->source->fallback_mount); if (fallback_source != NULL) - source_move_clients(relay->source, fallback_source, NULL); + source_move_clients(relay->source, fallback_source, NULL, NAVIGATION_DIRECTION_DOWN); avl_tree_unlock(global.source_tree); } diff --git a/src/source.c b/src/source.c index 93851cd2..f16d6b46 100644 --- a/src/source.c +++ b/src/source.c @@ -345,7 +345,7 @@ client_t *source_find_client(source_t *source, connection_id_t id) return NULL; } -static inline void source_move_clients__single(source_t *source, avl_tree *from, avl_tree *to, client_t *client) { +static inline void source_move_clients__single(source_t *source, source_t *dest, avl_tree *from, avl_tree *to, client_t *client, navigation_direction_t direction) { avl_delete(from, client, NULL); /* when switching a client to a different queue, be wary of the @@ -360,6 +360,7 @@ static inline void source_move_clients__single(source_t *source, avl_tree *from, } avl_insert(to, (void *)client); + navigation_history_navigate_to(&(client->history), dest->identifier, direction); } /* Move clients from source to dest provided dest is running @@ -367,7 +368,7 @@ static inline void source_move_clients__single(source_t *source, avl_tree *from, * The only lock that should be held when this is called is the * source tree lock */ -void source_move_clients(source_t *source, source_t *dest, connection_id_t *id) +void source_move_clients(source_t *source, source_t *dest, connection_id_t *id, navigation_direction_t direction) { unsigned long count = 0; if (strcmp(source->mount, dest->mount) == 0) { @@ -414,7 +415,7 @@ void source_move_clients(source_t *source, source_t *dest, connection_id_t *id) fakeclient.con->id = *id; if (avl_get_by_key(source->client_tree, &fakeclient, &result) == 0) { - source_move_clients__single(source, source->client_tree, dest->pending_tree, result); + source_move_clients__single(source, dest, source->client_tree, dest->pending_tree, result, direction); count++; } } else { @@ -422,7 +423,7 @@ void source_move_clients(source_t *source, source_t *dest, connection_id_t *id) avl_node *node = avl_get_first(source->pending_tree); if (node == NULL) break; - source_move_clients__single(source, source->pending_tree, dest->pending_tree, node->key); + source_move_clients__single(source, dest, source->pending_tree, dest->pending_tree, node->key, direction); count++; } @@ -430,7 +431,7 @@ void source_move_clients(source_t *source, source_t *dest, connection_id_t *id) avl_node *node = avl_get_first(source->client_tree); if (node == NULL) break; - source_move_clients__single(source, source->client_tree, dest->pending_tree, node->key); + source_move_clients__single(source, dest, source->client_tree, dest->pending_tree, node->key, direction); count++; } } @@ -667,7 +668,7 @@ static void source_init (source_t *source) fallback_source = source_find_mount(source->fallback_mount); if (fallback_source) - source_move_clients(fallback_source, source, NULL); + source_move_clients(fallback_source, source, NULL, NAVIGATION_DIRECTION_UP); avl_tree_unlock(global.source_tree); } @@ -866,7 +867,7 @@ static void source_shutdown (source_t *source) fallback_source = source_find_mount(source->fallback_mount); if (fallback_source != NULL) - source_move_clients(source, fallback_source, NULL); + source_move_clients(source, fallback_source, NULL, NAVIGATION_DIRECTION_DOWN); avl_tree_unlock(global.source_tree); } diff --git a/src/source.h b/src/source.h index 51babaa3..42a380a5 100644 --- a/src/source.h +++ b/src/source.h @@ -97,7 +97,7 @@ source_t *source_find_mount_raw(const char *mount); client_t *source_find_client(source_t *source, connection_id_t id); int source_compare_sources(void *arg, void *a, void *b); void source_free_source(source_t *source); -void source_move_clients(source_t *source, source_t *dest, connection_id_t *id); +void source_move_clients(source_t *source, source_t *dest, connection_id_t *id, navigation_direction_t direction); int source_remove_client(void *key); void source_main(source_t *source); void source_recheck_mounts (int update_all);