summaryrefslogtreecommitdiff
path: root/src/liana/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/liana/client.c')
-rw-r--r--src/liana/client.c64
1 files changed, 45 insertions, 19 deletions
diff --git a/src/liana/client.c b/src/liana/client.c
index 4d5689f..2b62612 100644
--- a/src/liana/client.c
+++ b/src/liana/client.c
@@ -13,8 +13,10 @@
enum {
RECONNECT_NONE = 0,
- RECONNECT_ON_CONNECTION_CLOSED,
+ RECONNECT_RECOVER,
+ RECONNECT_SEEK,
RECONNECT_SIGNAL_CLIENT,
+ RECONNECT_DISREGUARD,
RECONNECT_DISCONNECTED
};
@@ -48,7 +50,7 @@ static void collect_streams(struct lia_client *client, struct nn_packet *packet)
u8 type = nn_packet_read_u8(packet);
u64 duration = nn_packet_read_u64(packet);
s32 index = nn_packet_read_s32(packet);
- al_assert(index < 32);
+ al_assert(index < 64);
switch (mode) {
case CAMU_NORMAL: {
if (type == CAMU_STREAM_AUDIO) {
@@ -147,10 +149,6 @@ static void parse_info_packet(struct lia_client *client, struct nn_packet *packe
struct camu_codec_stream *stream;
al_array_foreach_ptr(client->streams, i, stream) {
u8 type = stream->type;
- if (type == CAMU_STREAM_SUBTITLE && client->mask == 0) {
- log_warn("Ignoring subtitle-only resource.");
- goto out;
- }
if ((selected & (1 << type)) || !(prefs->enabled & (1 << type))) {
continue;
}
@@ -198,6 +196,10 @@ static void parse_info_packet(struct lia_client *client, struct nn_packet *packe
lia_vcr_add_track(&client->vcr, track);
}
}
+ if (client->mask == (1 << CAMU_STREAM_SUBTITLE)) {
+ log_warn("Ignoring subtitle-only resource.");
+ client->mask = 0;
+ }
out:
client->callback(client->userdata, LIANA_CLIENT_CONFIGURE_COMPLETE, NULL, NULL);
}
@@ -211,13 +213,15 @@ static void info_packet_callback(void *userdata, struct nn_packet_stream *stream
if (client->mask == 0 || lia_vcr_is_empty(&client->vcr)) {
log_warn("Discarding resource with no applicable streams.");
al_assert(client->reconnect == RECONNECT_NONE);
+ client->reconnect = RECONNECT_DISREGUARD;
nn_packet_stream_disconnect(&client->data);
return;
}
stream->packet_callback = data_packet_callback;
struct nn_packet *rpacket = nn_packet_create();
- nn_packet_write_u32(rpacket, client->mask);
+ nn_packet_write_u64(rpacket, client->mask);
nn_packet_stream_send_packet(stream, rpacket);
+ client->reconnect = RECONNECT_RECOVER;
lia_vcr_start(&client->vcr);
}
@@ -239,6 +243,7 @@ static bool connection_callback(void *userdata, struct nn_packet_stream *stream)
.pos = client->pos,
.pause = LIANA_PAUSE_NONE
};
+ client->at = LIANA_TIMESTAMP_INVALID;
client->callback(client->userdata, LIANA_CLIENT_RESUME_AT, NULL, &time);
// The value of client->mask will not have changed since connection_closed_callback().
if (client->rec.unconfigured) {
@@ -247,18 +252,19 @@ static bool connection_callback(void *userdata, struct nn_packet_stream *stream)
}
client->callback(client->userdata, LIANA_CLIENT_RECONNECTED, NULL, &client->rec);
} else {
- al_assert(client->connection_id == 0);
+ al_assert(client->connection_id == 0 && client->reconnect == RECONNECT_NONE);
}
stream->packet_sent_callback = packet_sent_callback;
struct nn_packet *packet = nn_packet_create();
nn_packet_write_u32(packet, client->node_id);
nn_packet_write_u32(packet, client->connection_id);
- nn_packet_write_u32(packet, client->mask);
+ nn_packet_write_u64(packet, client->mask);
nn_packet_write_u64(packet, client->pos);
if (client->mask == 0) {
stream->packet_callback = info_packet_callback;
} else {
stream->packet_callback = data_packet_callback;
+ client->reconnect = RECONNECT_RECOVER;
lia_vcr_start(&client->vcr);
}
nn_packet_stream_send_packet(stream, packet);
@@ -268,15 +274,26 @@ static bool connection_callback(void *userdata, struct nn_packet_stream *stream)
static void connection_closed_callback(void *userdata, struct nn_packet_stream *stream)
{
struct lia_client *client = (struct lia_client *)userdata;
- if (client->reconnect == RECONNECT_ON_CONNECTION_CLOSED) {
+
+ bool reconnect = client->reconnect == RECONNECT_RECOVER || client->reconnect == RECONNECT_SEEK;
+ if (client->reconnect == RECONNECT_RECOVER) {
+ al_assert(client->at == LIANA_TIMESTAMP_INVALID);
+ struct lia_timing time;
+ client->callback(client->userdata, LIANA_CLIENT_RECOVER_TO, NULL, &time);
+ client->pos = time.pos;
+ client->at = time.at;
+ }
+
+ if (reconnect) {
lia_vcr_flush(&client->vcr);
} else {
lia_vcr_close_all(&client->vcr);
}
+
// If reconnect = SIGNAL_CLIENT, we either never connected or recursed at the reconnect step.
if (client->reconnect != RECONNECT_SIGNAL_CLIENT) {
client->rec = (struct lia_reconnect_info){
- .reconnect = client->reconnect == RECONNECT_ON_CONNECTION_CLOSED,
+ .reconnect = reconnect,
.unconfigured = client->mask == 0,
.mask = client->mask
};
@@ -295,10 +312,13 @@ static void connection_closed_callback(void *userdata, struct nn_packet_stream *
}
al_array_free(client->rec.detached);
}
- if (client->reconnect == RECONNECT_ON_CONNECTION_CLOSED) {
- // If stream_reconnect() errors, the client will be closed on recursion.
+
+ if (reconnect) {
+ // If stream_reconnect() errors or is aborted, the client will be closed on recursion.
client->reconnect = RECONNECT_SIGNAL_CLIENT;
- if (!client->mask) {
+ // A client being seeked before an info packet is another reason mask may
+ // be unset here. In that case we don't want to forcefully close.
+ if (!client->rec.unconfigured && !client->mask) {
connection_closed_callback(userdata, stream);
} else {
#ifdef CAMU_DIRECT_MODE
@@ -318,6 +338,7 @@ void lia_client_connect(struct lia_client *client, struct nn_event_loop *loop,
client->loop = loop;
client->node_id = node_id;
client->pos = pos;
+ client->at = LIANA_TIMESTAMP_INVALID;
client->mask = 0;
al_array_init(client->streams);
client->reconnect = RECONNECT_NONE;
@@ -336,13 +357,16 @@ void lia_client_connect(struct lia_client *client, struct nn_event_loop *loop,
void lia_client_seek(struct lia_client *client, u64 pos, u64 at)
{
- if (client->reconnect == RECONNECT_DISCONNECTED) return;
- // If reconnect = ON_CONNECTION_CLOSED or SIGNAL_CLIENT, we are safe to edit pos
+ u8 reconnect = client->reconnect;
+ if (reconnect == RECONNECT_DISCONNECTED || reconnect == RECONNECT_DISREGUARD) {
+ return;
+ }
+ // If reconnect = SEEK, RECOVER or SIGNAL_CLIENT, we are safe to edit pos
// and at in-place because they aren't evaluated until connection_callback().
client->pos = pos;
client->at = at;
- if (client->reconnect == RECONNECT_NONE) {
- client->reconnect = RECONNECT_ON_CONNECTION_CLOSED;
+ if (reconnect == RECONNECT_NONE || reconnect == RECONNECT_RECOVER) {
+ client->reconnect = RECONNECT_SEEK;
nn_packet_stream_disconnect(&client->data);
}
}
@@ -352,7 +376,9 @@ void lia_client_disconnect(struct lia_client *client)
u8 reconnect = client->reconnect;
al_assert(reconnect != RECONNECT_DISCONNECTED);
client->reconnect = RECONNECT_DISCONNECTED;
- if (reconnect != RECONNECT_ON_CONNECTION_CLOSED) {
+ // If reconnect == SIGNAL_CLIENT, stream_disconnect() needs to ensure
+ // connection_callback() is never called.
+ if (reconnect != RECONNECT_SEEK && reconnect != RECONNECT_DISREGUARD) {
nn_packet_stream_disconnect(&client->data);
}
}