diff options
Diffstat (limited to 'src/shrub')
| -rw-r--r-- | src/shrub/client.c | 172 | ||||
| -rw-r--r-- | src/shrub/client.h | 3 | ||||
| -rw-r--r-- | src/shrub/common.h | 1 | ||||
| -rw-r--r-- | src/shrub/handler.h | 7 | ||||
| -rw-r--r-- | src/shrub/server.c | 192 | ||||
| -rw-r--r-- | src/shrub/server.h | 34 | ||||
| -rw-r--r-- | src/shrub/vcr.c | 4 |
7 files changed, 189 insertions, 224 deletions
diff --git a/src/shrub/client.c b/src/shrub/client.c index 015f47f..abe2d23 100644 --- a/src/shrub/client.c +++ b/src/shrub/client.c @@ -1,6 +1,7 @@ #include <al/log.h> #include "../codec/ffmpeg/packet_ext.h" +#include "../server/common.h" #include "handlers/codec.h" @@ -8,18 +9,6 @@ #include "handler.h" #include "common.h" -static void data_connection_callback(void *userdata, struct aki_packet_stream *stream) -{ - struct shrb_client *client = (struct shrb_client *)userdata; - (void)stream; - struct aki_packet *packet = aki_packet_create(); - aki_packet_write_u8(packet, SHRUB_CONNECTION_DATA); - aki_packet_write_u16(packet, client->connection_id); - aki_packet_write_u16(packet, client->node_id); - aki_packet_write_u64(packet, client->seek_pos); - aki_packet_stream_send_packet(&client->data, packet); -} - static void send_reconnect_packet(struct shrb_client *client) { struct aki_packet *packet = aki_packet_create(); @@ -33,86 +22,55 @@ static void cleanup_connection_internal(struct shrb_client *client) client->callback(client->userdata, SHRUB_CLIENT_CLOSED, NULL, NULL); } -static void data_packet_callback(void *userdata, struct aki_packet_stream *stream, - struct aki_packet *packet) -{ - struct shrb_client *client = (struct shrb_client *)userdata; - (void)stream; - shrb_vcr_push_packet(&client->vcr, packet); -} - static void packet_sent_callback(void *userdata, struct aki_packet *packet) { (void)userdata; aki_packet_free(packet); } -static void data_connection_closed_callback(void *userdata, struct aki_packet_stream *stream); - -void connect_data(struct shrb_client *client) -{ - if (!client->reconnect) { - client->reconnect = true; - } else { - aki_packet_stream_free(&client->data); - } - aki_packet_stream_init(&client->data, AKI_SOCKET_TCP, data_connection_callback, - data_connection_closed_callback, data_packet_callback, packet_sent_callback, client); - aki_packet_stream_connect(&client->data, client->loop, &client->addr, client->port); -} - -static void parse_pause_packet(struct shrb_client *client, struct aki_packet *packet) -{ - u64 delay = aki_packet_read_u64(packet); - u64 seek_pos = aki_packet_read_u64(packet); - struct shrb_seek_req req = { .base = seek_pos, .ts = UINT64_MAX, .delay = delay }; - // TODO: separare function. - client->callback(client->userdata, SHRUB_CLIENT_SET, NULL, &req); - client->seek_pos = req.base; -} - -void data_connection_closed_callback(void *userdata, struct aki_packet_stream *stream) +static void data_packet_callback(void *userdata, struct aki_packet_stream *stream, + struct aki_packet *packet) { struct shrb_client *client = (struct shrb_client *)userdata; (void)stream; - if (client->closed) { - if (!client->control.connected) cleanup_connection_internal(client); - return; - } - client->callback(client->userdata, SHRUB_CLIENT_REMOVE_BUFFERS, NULL, NULL); - shrb_vcr_flush(&client->vcr); - if (!client->paused) { - send_reconnect_packet(client); - } else { - parse_pause_packet(client, client->paused); - aki_packet_free(client->paused); - client->paused = NULL; - client->callback(client->userdata, SHRUB_CLIENT_PAUSE, NULL, NULL); - connect_data(client); - } + shrb_vcr_push_packet(&client->vcr, packet); } -static void control_connection_callback(void *userdata, struct aki_packet_stream *stream) +static void data_connection_callback(void *userdata, struct aki_packet_stream *stream) { struct shrb_client *client = (struct shrb_client *)userdata; (void)stream; + client->data.packet_callback = data_packet_callback; + client->data.packet_sent_callback = packet_sent_callback; struct aki_packet *packet = aki_packet_create(); - aki_packet_write_u8(packet, SHRUB_CONNECTION_CONTROL); - aki_packet_write_u16(packet, 0); + aki_packet_write_u8(packet, SHRUB_CONNECTION_DATA); + aki_packet_write_u16(packet, client->connection_id); aki_packet_write_u16(packet, client->node_id); - aki_packet_stream_send_packet(&client->control, packet); + aki_packet_write_u64(packet, client->seek_pos); + aki_packet_stream_send_packet(&client->data, packet); } -static void control_connection_closed_callback(void *userdata, struct aki_packet_stream *stream) +static void data_connection_closed_callback(void *userdata, struct aki_packet_stream *stream) { struct shrb_client *client = (struct shrb_client *)userdata; (void)stream; if (client->closed) { - if (!client->data.connected) cleanup_connection_internal(client); + if (!client->control.connected) cleanup_connection_internal(client); return; } - aki_packet_stream_free(&client->control); - // TODO: Reconnect. + client->callback(client->userdata, SHRUB_CLIENT_REMOVE_BUFFERS, NULL, NULL); + shrb_vcr_flush(&client->vcr); + send_reconnect_packet(client); +} + +void connect_data(struct shrb_client *client) +{ + if (!client->reconnect) client->reconnect = true; + else aki_packet_stream_free(&client->data); + aki_packet_stream_init(&client->data, AKI_SOCKET_TCP, data_connection_callback, + data_connection_closed_callback, client); + aki_packet_stream_set_multiplex(&client->data, CAMU_MULTIPLEX_SHRUB); + aki_packet_stream_connect(&client->data, client->loop, &client->addr, client->port); } static void parse_info_packet(struct shrb_client *client, struct aki_packet *packet) @@ -188,22 +146,18 @@ static void parse_start_packet(struct shrb_client *client, struct aki_packet *pa u64 delay = aki_packet_read_u64(packet); u64 seek_pos = aki_packet_read_u64(packet); u8 paused = aki_packet_read_u8(packet); - (void)paused; - struct shrb_seek_req req = { .base = seek_pos, .ts = ts, .delay = delay }; + u64 paused_at = aki_packet_read_u64(packet); + struct shrb_seek_req req = { + .base = seek_pos, + .ts = ts, + .delay = delay, + .paused = paused, + .paused_at = paused_at + }; client->callback(client->userdata, SHRUB_CLIENT_SET, NULL, &req); client->seek_pos = req.base; } -static void parse_resume_packet(struct shrb_client *client, struct aki_packet *packet) -{ - u64 ts = aki_packet_read_u64(packet); - s64 delay = aki_packet_read_s64(packet); - u64 seek_pos = aki_packet_read_u64(packet); - struct shrb_seek_req req = { .base = seek_pos, .ts = ts, .delay = delay }; - client->callback(client->userdata, SHRUB_CLIENT_RESUME, NULL, &req); - client->seek_pos = req.base; -} - static void control_packet_callback(void *userdata, struct aki_packet_stream *stream, struct aki_packet *packet) { @@ -221,17 +175,18 @@ static void control_packet_callback(void *userdata, struct aki_packet_stream *st connect_data(client); break; case SHRUB_CONTROL_PAUSE: { - al_assert(!client->paused); f64 pts = aki_packet_read_u64(packet) / 1000000.f; client->callback(client->userdata, SHRUB_CLIENT_PAUSE, NULL, &pts); - //client->paused = packet; - //disconnect_data_internal(client); break; } case SHRUB_CONTROL_RESUME: { - u64 ts = aki_packet_read_u64(packet); - client->callback(client->userdata, SHRUB_CLIENT_RESUME, NULL, &ts); - //parse_resume_packet(client, packet); + u64 start = aki_packet_read_u64(packet); + u64 offset = aki_packet_read_u64(packet); + struct shrb_resume_req req = { + .start = start, + .offset = offset + }; + client->callback(client->userdata, SHRUB_CLIENT_RESUME, NULL, &req); break; } case SHRUB_CONTROL_SEEK: @@ -245,7 +200,31 @@ static void control_packet_callback(void *userdata, struct aki_packet_stream *st aki_packet_free(packet); } -void shrb_client_connect(struct shrb_client *client, struct aki_event_loop *loop, str *addr, s32 port, u16 node_id) +static void control_connection_callback(void *userdata, struct aki_packet_stream *stream) +{ + struct shrb_client *client = (struct shrb_client *)userdata; + (void)stream; + client->control.packet_callback = control_packet_callback; + client->control.packet_sent_callback = packet_sent_callback; + struct aki_packet *packet = aki_packet_create(); + aki_packet_write_u8(packet, SHRUB_CONNECTION_CONTROL); + aki_packet_write_u16(packet, 0); + aki_packet_write_u16(packet, client->node_id); + aki_packet_stream_send_packet(&client->control, packet); +} + +static void control_connection_closed_callback(void *userdata, struct aki_packet_stream *stream) +{ + struct shrb_client *client = (struct shrb_client *)userdata; + (void)stream; + if (client->closed) { + if (!client->data.connected) cleanup_connection_internal(client); + return; + } + // TODO: Reconnect. +} + +bool shrb_client_connect(struct shrb_client *client, struct aki_event_loop *loop, str *addr, s32 port, u16 node_id) { client->loop = loop; client->node_id = node_id; @@ -255,21 +234,16 @@ void shrb_client_connect(struct shrb_client *client, struct aki_event_loop *loop client->reconnect = false; client->level = 0; client->corked = false; - client->paused = NULL; al_array_init(client->subscribed); shrb_vcr_init(&client->vcr, client->loop, &client->data); - aki_packet_stream_init(&client->control, AKI_SOCKET_TCP, control_connection_callback, - control_connection_closed_callback, control_packet_callback, packet_sent_callback, client); - aki_packet_stream_set_no_delay(&client->control, 1); + if (!aki_packet_stream_init(&client->control, AKI_SOCKET_TCP, control_connection_callback, + control_connection_closed_callback, client)) { + return false; + } + aki_packet_stream_set_nodelay(&client->control, 1); + aki_packet_stream_set_multiplex(&client->control, CAMU_MULTIPLEX_SHRUB); aki_packet_stream_connect(&client->control, client->loop, &client->addr, client->port); -} - -void shrb_client_toggle_pause(struct shrb_client *client, f64 pts) -{ - struct aki_packet *packet = aki_packet_create(); - aki_packet_write_u8(packet, SHRUB_CONTROL_TOGGLE_PAUSE); - aki_packet_write_u64(packet, pts * 1000000L); - aki_packet_stream_send_packet(&client->control, packet); + return true; } void shrb_client_reseek(struct shrb_client *client) diff --git a/src/shrub/client.h b/src/shrub/client.h index cb3250d..14f7da2 100644 --- a/src/shrub/client.h +++ b/src/shrub/client.h @@ -19,14 +19,13 @@ struct shrb_client { bool corked; u64 duration; u64 seek_pos; - struct aki_packet *paused; array(s32) subscribed; struct shrb_vcr vcr; void (*callback)(void *, u8, struct shrb_vcr_stream *stream, void *); void *userdata; }; -void shrb_client_connect(struct shrb_client *client, struct aki_event_loop *loop, str *addr, s32 port, u16 node_id); +bool shrb_client_connect(struct shrb_client *client, struct aki_event_loop *loop, str *addr, s32 port, u16 node_id); void shrb_client_toggle_pause(struct shrb_client *client, f64 pts); void shrb_client_reseek(struct shrb_client *client); void shrb_client_seek(struct shrb_client *client, f64 percent); diff --git a/src/shrub/common.h b/src/shrub/common.h index 0be00e4..882eb49 100644 --- a/src/shrub/common.h +++ b/src/shrub/common.h @@ -16,7 +16,6 @@ enum { SHRUB_CONTROL_SUBSCRIBE, SHRUB_CONTROL_RECONNECT, SHRUB_CONTROL_START, - SHRUB_CONTROL_TOGGLE_PAUSE, SHRUB_CONTROL_PAUSE, SHRUB_CONTROL_RESUME, SHRUB_CONTROL_SEEK diff --git a/src/shrub/handler.h b/src/shrub/handler.h index 4ff2f2d..7242130 100644 --- a/src/shrub/handler.h +++ b/src/shrub/handler.h @@ -34,10 +34,17 @@ enum { SHRUB_CLIENT_CLOSED }; +struct shrb_resume_req { + u64 start; + u64 offset; +}; + struct shrb_seek_req { u64 base; u64 ts; u64 delay; + bool paused; + u64 paused_at; }; struct shrb_client_stream; diff --git a/src/shrub/server.c b/src/shrub/server.c index ba7259c..31d8787 100644 --- a/src/shrub/server.c +++ b/src/shrub/server.c @@ -65,11 +65,12 @@ static u8 packet_pool_callback(void *userdata, struct aki_packet *packet) return AKI_PACKET_POOL_RETURN; } -static void send_resume_packet(struct shrb_node_connection *connection, u64 ts) +static void send_resume_packet(struct shrb_node_connection *connection, u64 start, u64 offset) { struct aki_packet *packet = aki_packet_create(); aki_packet_write_u8(packet, SHRUB_CONTROL_RESUME); - aki_packet_write_u64(packet, ts); + aki_packet_write_u64(packet, start); + aki_packet_write_u64(packet, offset); aki_packet_stream_send_packet(connection->control, packet); } @@ -107,16 +108,21 @@ static void send_start_packet(struct shrb_node_connection *connection) u64 seek_pos = node->seek_pos; u64 delay = SHRUB_BASE_DELAY * powl(3, connection->level); u64 start = node->start; - s64 diff = aki_get_timestamp() - start; - if (diff > (s64)SHRUB_BASE_DELAY) { - start += diff; - seek_pos += diff; + bool paused = node->paused != SHRUB_NOT_PAUSED; + if (!paused) { + s64 diff = aki_get_timestamp() - start; + if (diff > (s64)SHRUB_BASE_DELAY) { + start += diff; + seek_pos += diff; + } } - seek_pos += delay - SHRUB_BASE_DELAY; + // Start is not used if the node is paused. aki_packet_write_u64(packet, start); + seek_pos += delay - SHRUB_BASE_DELAY; aki_packet_write_u64(packet, delay); aki_packet_write_u64(packet, seek_pos); - aki_packet_write_u8(packet, node->paused ? 1 : 0); + aki_packet_write_u8(packet, paused); + aki_packet_write_u64(packet, node->paused_at); aki_packet_stream_send_packet(connection->control, packet); } @@ -147,46 +153,6 @@ static void control_packet_callback(void *userdata, struct aki_packet_stream *st send_start_packet(connection); break; } - case SHRUB_CONTROL_TOGGLE_PAUSE: { - struct shrb_node *node = connection->node; - /* - u64 pos = aki_packet_read_u64(packet); - u8 paused = connection->paused; - if (paused == SHRUB_PLAYING) { - node->seek_pos = pos; - node->flags |= SHRUB_NODE_PAUSED; - // node->start won't be touched while SHRUB_NODE_PAUSED is set. - } else if (paused == SHRUB_PAUSED_AND_RUNNING) { - node->flags &= ~SHRUB_NODE_PAUSED; - // TODO: - node->start = aki_get_timestamp() + DELAY; - } - struct shrb_node_connection *rconnection; - al_array_foreach(node->connections, i, rconnection) { - switch (rconnection->paused) { - case SHRUB_PLAYING: - al_assert(paused == SHRUB_PLAYING || paused == SHRUB_NOT_PAUSED); - rconnection->paused = SHRUB_PAUSED; - send_pause_packet(rconnection, node->seek_pos); - break; - case SHRUB_NOT_PAUSED: - al_assert(paused != SHRUB_PAUSED); - rconnection->paused = SHRUB_PAUSED; - break; - case SHRUB_PAUSED: - al_assert(paused != SHRUB_NOT_PAUSED); - rconnection->paused = SHRUB_NOT_PAUSED; - break; - case SHRUB_PAUSED_AND_RUNNING: - al_assert(paused != SHRUB_NOT_PAUSED); - send_resume_packet(rconnection, node->seek_pos, node->start); - rconnection->paused = SHRUB_PLAYING; - break; - } - } - */ - break; - } case SHRUB_CONTROL_SEEK: { u64 pos = aki_packet_read_u64(packet); connection->node->seek_pos = pos; @@ -207,17 +173,18 @@ static struct shrb_node_connection *get_connection_by_id(struct shrb_node *node, return NULL; } -static void send_control_info_packet(struct shrb_node_connection *connection) +static bool send_control_info_packet(struct shrb_node_connection *connection) { - struct aki_packet *packet = aki_packet_create(); - aki_packet_write_u8(packet, SHRUB_CONTROL_INFO); - aki_packet_write_u16(packet, connection->id); connection->handler = shrb_codec_server_create(); if (!connection->handler->init(connection->handler, &connection->handle, &connection->pool)) { - al_assert(false); + return false; } + struct aki_packet *packet = aki_packet_create(); + aki_packet_write_u8(packet, SHRUB_CONTROL_INFO); + aki_packet_write_u16(packet, connection->id); connection->handler->write_info(connection->handler, packet); aki_packet_stream_send_packet(connection->control, packet); + return true; } static aki_thread_result AKI_THREADCALL handler_thread(void *userdata) @@ -230,19 +197,12 @@ static aki_thread_result AKI_THREADCALL handler_thread(void *userdata) static void maybe_start_handler(struct shrb_node_connection *connection) { al_assert(!connection->running); - // Don't seek to 0 unless NODE_SEEKED is set. + // Don't seek to 0 unless node->seeked is set. if (connection->seek_pos > 0 || connection->node->seeked) { connection->handler->seek(connection->handler, connection->seek_pos); } connection->running = 1; aki_thread_create(&connection->thread, handler_thread, connection); - //struct shrb_node *node = connection->node; - //if (connection->paused == SHRUB_NOT_PAUSED) { - // send_resume_packet(connection, connection->seek_pos, node->start); - // connection->paused = SHRUB_PLAYING; - //} else if (connection->paused == SHRUB_PAUSED) { - // connection->paused = SHRUB_PAUSED_AND_RUNNING; - //} } static void identify_packet_callback(void *userdata, struct aki_packet_stream *stream, struct aki_packet *packet) @@ -254,6 +214,12 @@ static void identify_packet_callback(void *userdata, struct aki_packet_stream *s u16 connection_id = aki_packet_read_u16(packet); u16 node_id = aki_packet_read_u16(packet); + // Before this point: + // - We get socket from accept + // - Create packet_stream + // - connection_closed_callback could have been called before this point + // - the socket exists only to wait for an identify packet + // Disconnecting a stream at any point before setting the new callbacks should // be valid and handled properly by the client. // Generalize erronious connection checking/handling. @@ -276,26 +242,28 @@ static void identify_packet_callback(void *userdata, struct aki_packet_stream *s connection->data = NULL; aki_packet_pool_init(&connection->pool, 16, server->loop, packet_pool_callback, connection); cch_entry_get_handle(connection->node->entry, &connection->handle); - //connection->paused = SHRUB_PLAYING; connection->level = 0; connection->running = 0; } switch (type) { case SHRUB_CONNECTION_CONTROL: - aki_packet_stream_set_no_delay(stream, 1); + aki_packet_stream_set_nodelay(stream, 1); connection->control = stream; stream->packet_callback = control_packet_callback; stream->packet_sent_callback = default_packet_sent_callback; stream->connection_closed_callback = control_connection_closed_callback; stream->userdata = connection; - send_control_info_packet(connection); + if (!send_control_info_packet(connection)) { + aki_packet_stream_disconnect(stream); + } break; case SHRUB_CONNECTION_DATA: // TODO: Account for control connection being in a reconnect state. // TODO: is it possible for data->data to be non-NULL during normal operation // (disconnect and reconnect very fast?). // - Call maybe_cleanup_data in this function? + // ^^^^ Literally any connection could call itself data, this needs to be handled better. al_assert(!connection->data); connection->seek_pos = aki_packet_read_u64(packet); connection->data = stream; @@ -310,32 +278,34 @@ static void identify_packet_callback(void *userdata, struct aki_packet_stream *s aki_packet_free(packet); } -static void connection_closed_callback(void *userdata, struct aki_packet_stream *stream) -{ - (void)userdata; - (void)stream; -} - static void connection_callback(void *userdata, struct aki_packet_stream *stream) { struct shrb_server *server = (struct shrb_server *)userdata; - stream->connection_closed_callback = connection_closed_callback; stream->packet_callback = identify_packet_callback; stream->packet_sent_callback = default_packet_sent_callback; - stream->flushed_callback = NULL; stream->userdata = server; } -bool shrb_server_init(struct shrb_server *server) +bool shrb_server_init(struct shrb_server *server, struct aki_event_loop *loop) { + server->loop = loop; al_array_init(server->nodes); - return aki_packet_stream_init(&server->server, AKI_SOCKET_TCP, connection_callback, NULL, NULL, NULL, server); + return true; } -void shrb_server_listen(struct shrb_server *server, struct aki_event_loop *loop, str *addr, s32 port) +static void connection_closed_callback(void *userdata, struct aki_packet_stream *stream) { - server->loop = loop; - aki_packet_stream_listen(&server->server, loop, addr, port); + (void)userdata; + (void)stream; +} + +void shrb_server_add_socket(struct shrb_server *server, struct aki_socket *s) +{ + struct aki_packet_stream *stream = al_alloc_object(struct aki_packet_stream); + stream->connection_callback = connection_callback; + stream->connection_closed_callback = connection_closed_callback; + stream->userdata = server; + aki_packet_stream_from_socket(stream, server->loop, s); } struct shrb_node *shrb_server_create_node(struct shrb_server *server, u16 prev, struct cch_entry *entry) @@ -344,14 +314,6 @@ struct shrb_node *shrb_server_create_node(struct shrb_server *server, u16 prev, node->id = al_rand_u16(); node->prev = prev; node->entry = entry; - node->paused = false; - node->seeked = false; - node->start = 0; - node->seek_pos = 0; - node->offset = 0; - node->connection_id = 1; - al_array_init(node->connections); - node->server = server; struct cch_handle handle; if (!cch_entry_get_handle(node->entry, &handle)) { al_free(node); @@ -365,47 +327,67 @@ struct shrb_node *shrb_server_create_node(struct shrb_server *server, u16 prev, node->duration = handler->get_duration(handler); handler->free(&handler); cch_entry_return_handle(node->entry, &handle); + node->seeked = false; + node->start = 0; + node->paused = SHRUB_NOT_PAUSED; + node->paused_at = 0; + node->seek_pos = 0; + node->connection_id = 1; + al_array_init(node->connections); + node->server = server; al_array_push(server->nodes, node); return node; } void shrb_node_set_start(struct shrb_node *node, u64 start) { + if (node->paused == SHRUB_PAUSED) { + node->paused = SHRUB_NOT_PAUSED; + } node->start = start; } -void shrb_node_set_offset(struct shrb_node *node, u64 offset) +void shrb_node_user_pause(struct shrb_node *node, u64 pos) { - node->offset = offset; + al_assert(node->paused != SHRUB_USER_PAUSED); + pos += SHRUB_PAUSE_DELAY; + node->seek_pos = pos; + node->paused_at = pos; + struct shrb_node_connection *connection; + al_array_foreach(node->connections, i, connection) { + send_pause_packet(connection, node->seek_pos); + } + node->paused = SHRUB_USER_PAUSED; } -void shrb_node_toggle_pause(struct shrb_node *node, u64 pos) +void shrb_node_user_resume(struct shrb_node *node, struct shrb_resume_req *req) { - if (!node->paused) { - node->seek_pos = pos; - node->seek_pos += SHRUB_PAUSE_DELAY; - } else { - node->start = aki_get_timestamp() + SHRUB_PAUSE_DELAY; - } + al_assert(node->paused == SHRUB_USER_PAUSED); + node->start = req->start + SHRUB_PAUSE_DELAY; struct shrb_node_connection *connection; al_array_foreach(node->connections, i, connection) { - if (!node->paused) { - send_pause_packet(connection, node->seek_pos); - } else { - send_resume_packet(connection, node->start); - } + send_resume_packet(connection, node->start, req->offset); } - if (node->paused) { - node->start -= SHRUB_BASE_DELAY; - node->offset = 0; - } - node->paused = !node->paused; + node->start -= SHRUB_BASE_DELAY; + node->paused = SHRUB_NOT_PAUSED; +} + +void shrb_node_pause(struct shrb_node *node) +{ + return; + if (node->paused != SHRUB_NOT_PAUSED) return; + u64 start = node->start; + s64 pos = node->seek_pos + (aki_get_timestamp() - (start + SHRUB_BASE_DELAY)); + pos += SHRUB_PAUSE_DELAY; + al_assert(pos >= 0); + node->seek_pos = (u64)pos; + node->paused_at = pos; + node->paused = SHRUB_PAUSED; } void shrb_node_seek(struct shrb_node *node, u64 pos) { node->seek_pos = pos; - node->start = aki_get_timestamp(); node->seeked = true; struct shrb_node_connection *connection; al_array_foreach(node->connections, i, connection) { diff --git a/src/shrub/server.h b/src/shrub/server.h index 2bce369..cb901c5 100644 --- a/src/shrub/server.h +++ b/src/shrub/server.h @@ -1,6 +1,7 @@ #pragma once #include <al/array.h> +#include <aki/multiplex.h> #include <aki/packet_stream.h> #include <aki/packet_pool.h> @@ -9,13 +10,6 @@ #include "handler.h" -enum { - SHRUB_PLAYING = 0, - SHRUB_NOT_PAUSED, - SHRUB_PAUSED, - SHRUB_PAUSED_AND_RUNNING -}; - struct shrb_node_connection { u16 id; struct shrb_node *node; @@ -23,7 +17,6 @@ struct shrb_node_connection { struct aki_packet_stream *data; struct aki_packet_pool pool; s32 running; - //u8 paused; u32 level; u64 seek_pos; struct cch_handle handle; @@ -31,16 +24,22 @@ struct shrb_node_connection { struct aki_thread thread; }; +enum { + SHRUB_NOT_PAUSED = 0, + SHRUB_PAUSED, + SHRUB_USER_PAUSED +}; + struct shrb_node { u16 id; u16 prev; struct cch_entry *entry; - bool paused; + u64 duration; bool seeked; - u64 start; + u64 start; // Exact start of the stream minus BASE_DELAY. + u8 paused; + u64 paused_at; u64 seek_pos; - u64 offset; - u64 duration; u16 connection_id; array(struct shrb_node_connection *) connections; struct shrb_server *server; @@ -48,15 +47,16 @@ struct shrb_node { struct shrb_server { struct aki_event_loop *loop; - struct aki_packet_stream server; array(struct shrb_node *) nodes; }; -bool shrb_server_init(struct shrb_server *server); -void shrb_server_listen(struct shrb_server *server, struct aki_event_loop *loop, str *addr, s32 port); +bool shrb_server_init(struct shrb_server *server, struct aki_event_loop *loop); +void shrb_server_add_socket(struct shrb_server *server, struct aki_socket *s); struct shrb_node *shrb_server_create_node(struct shrb_server *server, u16 prev, struct cch_entry *entry); void shrb_node_set_start(struct shrb_node *node, u64 start); -void shrb_node_set_offset(struct shrb_node *node, u64 offset); -void shrb_node_toggle_pause(struct shrb_node *node, u64 pos); +void shrb_node_user_pause(struct shrb_node *node, u64 pos); +void shrb_node_user_resume(struct shrb_node *node, struct shrb_resume_req *req); +void shrb_node_pause(struct shrb_node *node); +void shrb_node_resume(struct shrb_node *node); void shrb_node_seek(struct shrb_node *node, u64 pos); void shrb_server_close(struct shrb_server *server); diff --git a/src/shrub/vcr.c b/src/shrub/vcr.c index 1816142..7f2b058 100644 --- a/src/shrub/vcr.c +++ b/src/shrub/vcr.c @@ -149,6 +149,10 @@ void shrb_vcr_stream_cork(struct shrb_vcr_stream *stream) void shrb_vcr_stream_uncork(struct shrb_vcr_stream *stream) { + if (al_atomic_s32_load(&stream->state, AL_ATOMIC_RELAXED) == SHRUB_STREAM_RUNNING) { + // DEBUG: This will be reached during normal operation. + return; + } al_atomic_s32_store(&stream->state, SHRUB_STREAM_RUNNING, AL_ATOMIC_RELAXED); aki_mutex_lock(&stream->mutex); if (aki_cond_is_waiting(&stream->cond)) { |