From 78b21a9ac3f975f35ec7b61108531e1495eb91c0 Mon Sep 17 00:00:00 2001 From: cbdev Date: Sun, 12 Jan 2020 17:34:14 +0100 Subject: Rework instance creation --- backends/artnet.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/artnet.h') diff --git a/backends/artnet.h b/backends/artnet.h index 59bd53f..1efdee6 100644 --- a/backends/artnet.h +++ b/backends/artnet.h @@ -6,7 +6,7 @@ MM_PLUGIN_API int init(); static int artnet_configure(char* option, char* value); static int artnet_configure_instance(instance* instance, char* option, char* value); -static instance* artnet_instance(); +static int artnet_instance(instance* inst); static channel* artnet_channel(instance* instance, char* spec, uint8_t flags); static int artnet_set(instance* inst, size_t num, channel** c, channel_value* v); static int artnet_handle(size_t num, managed_fd* fds); -- cgit v1.2.3 From 90b5655a6eb3837ad6f984ce4ffcd3e9aa7480ce Mon Sep 17 00:00:00 2001 From: cbdev Date: Thu, 5 Mar 2020 00:03:12 +0100 Subject: Implement ArtNet rate-limiting to approx. 44 pps --- backends/artnet.c | 52 +++++++++++++++++++++++++++++++++++++++++----------- backends/artnet.h | 15 ++++++++++++--- backends/artnet.md | 3 --- 3 files changed, 53 insertions(+), 17 deletions(-) (limited to 'backends/artnet.h') diff --git a/backends/artnet.c b/backends/artnet.c index ed426b0..77f03dd 100644 --- a/backends/artnet.c +++ b/backends/artnet.c @@ -9,6 +9,7 @@ #define MAX_FDS 255 +static uint32_t next_frame = 0; static uint8_t default_net = 0; static size_t artnet_fds = 0; static artnet_descriptor* artnet_fd = NULL; @@ -37,7 +38,6 @@ static int artnet_listener(char* host, char* port){ artnet_fd[artnet_fds].fd = fd; artnet_fd[artnet_fds].output_instances = 0; artnet_fd[artnet_fds].output_instance = NULL; - artnet_fd[artnet_fds].last_frame = NULL; artnet_fds++; return 0; } @@ -52,6 +52,7 @@ MM_PLUGIN_API int init(){ .handle = artnet_set, .process = artnet_handle, .start = artnet_start, + .interval = artnet_interval, .shutdown = artnet_shutdown }; @@ -68,6 +69,13 @@ MM_PLUGIN_API int init(){ return 0; } +static uint32_t artnet_interval(){ + if(next_frame){ + return next_frame; + } + return ARTNET_KEEPALIVE_INTERVAL; +} + static int artnet_configure(char* option, char* value){ char* host = NULL, *port = NULL, *fd_opts = NULL; if(!strcmp(option, "net")){ @@ -211,7 +219,8 @@ static int artnet_transmit(instance* inst){ //update last frame timestamp for(u = 0; u < artnet_fd[data->fd_index].output_instances; u++){ if(artnet_fd[data->fd_index].output_instance[u].label == inst->ident){ - artnet_fd[data->fd_index].last_frame[u] = mm_timestamp(); + artnet_fd[data->fd_index].output_instance[u].last_frame = mm_timestamp(); + artnet_fd[data->fd_index].output_instance[u].mark = 0; } } return 0; @@ -226,7 +235,6 @@ static int artnet_set(instance* inst, size_t num, channel** c, channel_value* v) return 0; } - //FIXME maybe introduce minimum frame interval for(u = 0; u < num; u++){ if(IS_WIDE(data->data.map[c[u]->ident])){ uint32_t val = v[u].normalised * ((double) 0xFFFF); @@ -248,6 +256,21 @@ static int artnet_set(instance* inst, size_t num, channel** c, channel_value* v) } if(mark){ + //find last frame time + for(u = 0; u < artnet_fd[data->fd_index].output_instances; u++){ + if(artnet_fd[data->fd_index].output_instance[u].label == inst->ident){ + break; + } + } + + //check output rate limit, request next frame + if(mm_timestamp() - artnet_fd[data->fd_index].output_instance[u].last_frame < ARTNET_FRAME_TIMEOUT){ + artnet_fd[data->fd_index].output_instance[u].mark = 1; + if(!next_frame || next_frame < mm_timestamp() - artnet_fd[data->fd_index].output_instance[u].last_frame){ + next_frame = mm_timestamp() - artnet_fd[data->fd_index].output_instance[u].last_frame; + } + return 0; + } return artnet_transmit(inst); } @@ -325,15 +348,23 @@ static int artnet_handle(size_t num, managed_fd* fds){ instance* inst = NULL; artnet_pkt* frame = (artnet_pkt*) recv_buf; - //transmit keepalive frames + //transmit keepalive & synthesized frames + next_frame = 0; for(u = 0; u < artnet_fds; u++){ for(c = 0; c < artnet_fd[u].output_instances; c++){ - if(timestamp - artnet_fd[u].last_frame[c] >= ARTNET_KEEPALIVE_INTERVAL){ + if(timestamp - artnet_fd[u].output_instance[c].last_frame >= ARTNET_KEEPALIVE_INTERVAL //timeout + || (artnet_fd[u].output_instance[c].mark && timestamp - artnet_fd[u].output_instance[c].last_frame >= ARTNET_FRAME_TIMEOUT)){ //synthesized frame inst = mm_instance_find(BACKEND_NAME, artnet_fd[u].output_instance[c].label); if(inst){ artnet_transmit(inst); } } + + //update next_frame + if(artnet_fd[u].output_instance[c].mark + && (!next_frame || next_frame > mm_timestamp() - artnet_fd[u].output_instance[c].last_frame)){ + next_frame = mm_timestamp() - artnet_fd[u].output_instance[c].last_frame; + } } } @@ -407,15 +438,15 @@ static int artnet_start(size_t n, instance** inst){ //if enabled for output, add to keepalive tracking if(data->dest_len){ - artnet_fd[data->fd_index].output_instance = realloc(artnet_fd[data->fd_index].output_instance, (artnet_fd[data->fd_index].output_instances + 1) * sizeof(artnet_instance_id)); - artnet_fd[data->fd_index].last_frame = realloc(artnet_fd[data->fd_index].last_frame, (artnet_fd[data->fd_index].output_instances + 1) * sizeof(uint64_t)); + artnet_fd[data->fd_index].output_instance = realloc(artnet_fd[data->fd_index].output_instance, (artnet_fd[data->fd_index].output_instances + 1) * sizeof(artnet_output_universe)); - if(!artnet_fd[data->fd_index].output_instance || !artnet_fd[data->fd_index].last_frame){ + if(!artnet_fd[data->fd_index].output_instance){ LOG("Failed to allocate memory"); goto bail; } - artnet_fd[data->fd_index].output_instance[artnet_fd[data->fd_index].output_instances] = id; - artnet_fd[data->fd_index].last_frame[artnet_fd[data->fd_index].output_instances] = 0; + artnet_fd[data->fd_index].output_instance[artnet_fd[data->fd_index].output_instances].label = id.label; + artnet_fd[data->fd_index].output_instance[artnet_fd[data->fd_index].output_instances].last_frame = 0; + artnet_fd[data->fd_index].output_instance[artnet_fd[data->fd_index].output_instances].mark = 0; artnet_fd[data->fd_index].output_instances++; } @@ -443,7 +474,6 @@ static int artnet_shutdown(size_t n, instance** inst){ for(p = 0; p < artnet_fds; p++){ close(artnet_fd[p].fd); free(artnet_fd[p].output_instance); - free(artnet_fd[p].last_frame); } free(artnet_fd); diff --git a/backends/artnet.h b/backends/artnet.h index 1efdee6..aac73fe 100644 --- a/backends/artnet.h +++ b/backends/artnet.h @@ -4,6 +4,7 @@ #include "midimonster.h" MM_PLUGIN_API int init(); +static uint32_t artnet_interval(); static int artnet_configure(char* option, char* value); static int artnet_configure_instance(instance* instance, char* option, char* value); static int artnet_instance(instance* inst); @@ -16,7 +17,10 @@ static int artnet_shutdown(size_t n, instance** inst); #define ARTNET_PORT "6454" #define ARTNET_VERSION 14 #define ARTNET_RECV_BUF 4096 -#define ARTNET_KEEPALIVE_INTERVAL 2000 + +#define ARTNET_KEEPALIVE_INTERVAL 1000 +//limit transmit rate to at most 44 packets per second (1000/44 ~= 22) +#define ARTNET_FRAME_TIMEOUT 20 #define MAP_COARSE 0x0200 #define MAP_FINE 0x0400 @@ -52,11 +56,16 @@ typedef union /*_artnet_instance_id*/ { uint64_t label; } artnet_instance_id; +typedef struct /*_artnet_fd_universe*/ { + uint64_t label; + uint64_t last_frame; + uint8_t mark; +} artnet_output_universe; + typedef struct /*_artnet_fd*/ { int fd; size_t output_instances; - artnet_instance_id* output_instance; - uint64_t* last_frame; + artnet_output_universe* output_instance; } artnet_descriptor; #pragma pack(push, 1) diff --git a/backends/artnet.md b/backends/artnet.md index 90a7697..7e1ecff 100644 --- a/backends/artnet.md +++ b/backends/artnet.md @@ -36,6 +36,3 @@ net1.1+2 > net2.5+123 A normal channel that is part of a wide channel can not be mapped individually. #### Known bugs / problems - -The minimum inter-frame-time is disregarded, as the packet rate is determined by the rate of incoming -channel events. \ No newline at end of file -- cgit v1.2.3 From 335196b3d3c80ee4bbe0985fd9a1f8ab5464a27c Mon Sep 17 00:00:00 2001 From: cbdev Date: Thu, 5 Mar 2020 23:46:08 +0100 Subject: Fix artnet rate limiting --- backends/artnet.c | 19 ++++++++++++------- backends/artnet.h | 3 ++- 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'backends/artnet.h') diff --git a/backends/artnet.c b/backends/artnet.c index 77f03dd..f1b8c0e 100644 --- a/backends/artnet.c +++ b/backends/artnet.c @@ -227,6 +227,7 @@ static int artnet_transmit(instance* inst){ } static int artnet_set(instance* inst, size_t num, channel** c, channel_value* v){ + uint32_t frame_delta = 0; size_t u, mark = 0; artnet_instance_data* data = (artnet_instance_data*) inst->impl; @@ -263,11 +264,12 @@ static int artnet_set(instance* inst, size_t num, channel** c, channel_value* v) } } + frame_delta = mm_timestamp() - artnet_fd[data->fd_index].output_instance[u].last_frame; //check output rate limit, request next frame - if(mm_timestamp() - artnet_fd[data->fd_index].output_instance[u].last_frame < ARTNET_FRAME_TIMEOUT){ + if(frame_delta < ARTNET_FRAME_TIMEOUT){ artnet_fd[data->fd_index].output_instance[u].mark = 1; - if(!next_frame || next_frame < mm_timestamp() - artnet_fd[data->fd_index].output_instance[u].last_frame){ - next_frame = mm_timestamp() - artnet_fd[data->fd_index].output_instance[u].last_frame; + if(!next_frame || next_frame > (ARTNET_KEEPALIVE_INTERVAL - frame_delta)){ + next_frame = (ARTNET_KEEPALIVE_INTERVAL - frame_delta); } return 0; } @@ -340,6 +342,7 @@ static inline int artnet_process_frame(instance* inst, artnet_pkt* frame){ static int artnet_handle(size_t num, managed_fd* fds){ size_t u, c; uint64_t timestamp = mm_timestamp(); + uint32_t synthesize_delta = 0; ssize_t bytes_read; char recv_buf[ARTNET_RECV_BUF]; artnet_instance_id inst_id = { @@ -352,8 +355,10 @@ static int artnet_handle(size_t num, managed_fd* fds){ next_frame = 0; for(u = 0; u < artnet_fds; u++){ for(c = 0; c < artnet_fd[u].output_instances; c++){ - if(timestamp - artnet_fd[u].output_instance[c].last_frame >= ARTNET_KEEPALIVE_INTERVAL //timeout - || (artnet_fd[u].output_instance[c].mark && timestamp - artnet_fd[u].output_instance[c].last_frame >= ARTNET_FRAME_TIMEOUT)){ //synthesized frame + synthesize_delta = timestamp - artnet_fd[u].output_instance[c].last_frame; + if((artnet_fd[u].output_instance[c].mark + && synthesize_delta >= ARTNET_FRAME_TIMEOUT + ARTNET_SYNTHESIZE_MARGIN) //synthesize next frame + || synthesize_delta >= ARTNET_KEEPALIVE_INTERVAL){ //keepalive timeout inst = mm_instance_find(BACKEND_NAME, artnet_fd[u].output_instance[c].label); if(inst){ artnet_transmit(inst); @@ -362,8 +367,8 @@ static int artnet_handle(size_t num, managed_fd* fds){ //update next_frame if(artnet_fd[u].output_instance[c].mark - && (!next_frame || next_frame > mm_timestamp() - artnet_fd[u].output_instance[c].last_frame)){ - next_frame = mm_timestamp() - artnet_fd[u].output_instance[c].last_frame; + && (!next_frame || next_frame > ARTNET_FRAME_TIMEOUT + ARTNET_SYNTHESIZE_MARGIN - synthesize_delta)){ + next_frame = ARTNET_FRAME_TIMEOUT + ARTNET_SYNTHESIZE_MARGIN - synthesize_delta; } } } diff --git a/backends/artnet.h b/backends/artnet.h index aac73fe..d83999d 100644 --- a/backends/artnet.h +++ b/backends/artnet.h @@ -20,7 +20,8 @@ static int artnet_shutdown(size_t n, instance** inst); #define ARTNET_KEEPALIVE_INTERVAL 1000 //limit transmit rate to at most 44 packets per second (1000/44 ~= 22) -#define ARTNET_FRAME_TIMEOUT 20 +#define ARTNET_FRAME_TIMEOUT 15 +#define ARTNET_SYNTHESIZE_MARGIN 10 #define MAP_COARSE 0x0200 #define MAP_FINE 0x0400 -- cgit v1.2.3