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/sacn.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'backends/sacn.c') diff --git a/backends/sacn.c b/backends/sacn.c index ff2b61e..5096123 100644 --- a/backends/sacn.c +++ b/backends/sacn.c @@ -195,19 +195,14 @@ static int sacn_configure_instance(instance* inst, char* option, char* value){ return 1; } -static instance* sacn_instance(){ - instance* inst = mm_instance(); - if(!inst){ - return NULL; - } - +static int sacn_instance(instance* inst){ inst->impl = calloc(1, sizeof(sacn_instance_data)); if(!inst->impl){ LOG("Failed to allocate memory"); - return NULL; + return 1; } - return inst; + return 0; } static channel* sacn_channel(instance* inst, char* spec, uint8_t flags){ -- cgit v1.2.3 From f12fb1e2f88e29c8060dfe673b65a315a84c1b29 Mon Sep 17 00:00:00 2001 From: cbdev Date: Fri, 6 Mar 2020 00:44:26 +0100 Subject: Implement (optional) rate-limiting for sACN --- backends/sacn.c | 78 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 19 deletions(-) (limited to 'backends/sacn.c') diff --git a/backends/sacn.c b/backends/sacn.c index 5096123..6c08b5a 100644 --- a/backends/sacn.c +++ b/backends/sacn.c @@ -28,12 +28,14 @@ static struct /*_sacn_global_config*/ { size_t fds; sacn_fd* fd; uint64_t last_announce; + uint32_t next_frame; } global_cfg = { .source_name = "MIDIMonster", .cid = {'M', 'I', 'D', 'I', 'M', 'o', 'n', 's', 't', 'e', 'r'}, .fds = 0, .fd = NULL, - .last_announce = 0 + .last_announce = 0, + .next_frame = 0 }; MM_PLUGIN_API int init(){ @@ -46,6 +48,7 @@ MM_PLUGIN_API int init(){ .handle = sacn_set, .process = sacn_handle, .start = sacn_start, + .interval = sacn_interval, .shutdown = sacn_shutdown }; @@ -63,6 +66,13 @@ MM_PLUGIN_API int init(){ return 0; } +static uint32_t sacn_interval(){ + if(global_cfg.next_frame){ + return global_cfg.next_frame; + } + return SACN_KEEPALIVE_INTERVAL; +} + static int sacn_listener(char* host, char* port, uint8_t flags){ int fd = -1, yes = 1; if(global_cfg.fds >= MAX_FDS){ @@ -87,7 +97,6 @@ static int sacn_listener(char* host, char* port, uint8_t flags){ global_cfg.fd[global_cfg.fds].fd = fd; global_cfg.fd[global_cfg.fds].universes = 0; global_cfg.fd[global_cfg.fds].universe = NULL; - global_cfg.fd[global_cfg.fds].last_frame = NULL; if(flags & mcast_loop){ //set IP_MCAST_LOOP to allow local applications to receive output @@ -190,6 +199,10 @@ static int sacn_configure_instance(instance* inst, char* option, char* value){ data->unicast_input = strtoul(value, NULL, 10); return 0; } + else if(!strcmp(option, "realtime")){ + data->realtime = strtoul(value, NULL, 10); + return 0; + } LOGPF("Unknown instance configuration option %s for instance %s", option, inst->name); return 1; @@ -289,10 +302,11 @@ static int sacn_transmit(instance* inst){ LOGPF("Failed to output frame for instance %s: %s", inst->name, strerror(errno)); } - //update last transmit timestamp + //update last transmit timestamp, unmark instance for(u = 0; u < global_cfg.fd[data->fd_index].universes; u++){ - if(global_cfg.fd[data->fd_index].universe[u] == data->uni){ - global_cfg.fd[data->fd_index].last_frame[u] = mm_timestamp(); + if(global_cfg.fd[data->fd_index].universe[u].universe == data->uni){ + global_cfg.fd[data->fd_index].universe[u].last_frame = mm_timestamp(); + global_cfg.fd[data->fd_index].universe[u].mark = 0; } } return 0; @@ -300,6 +314,7 @@ static int sacn_transmit(instance* inst){ static int sacn_set(instance* inst, size_t num, channel** c, channel_value* v){ size_t u, mark = 0; + uint32_t frame_delta = 0; sacn_instance_data* data = (sacn_instance_data*) inst->impl; if(!num){ @@ -333,6 +348,25 @@ static int sacn_set(instance* inst, size_t num, channel** c, channel_value* v){ //send packet if required if(mark){ + if(!data->realtime){ + //find output instance data + for(u = 0; u < global_cfg.fd[data->fd_index].universes; u++){ + if(global_cfg.fd[data->fd_index].universe[u].universe == data->uni){ + break; + } + } + + frame_delta = mm_timestamp() - global_cfg.fd[data->fd_index].universe[u].last_frame; + + //check if ratelimiting engaged + if(frame_delta < SACN_FRAME_TIMEOUT){ + global_cfg.fd[data->fd_index].universe[u].mark = 1; + if(!global_cfg.next_frame || global_cfg.next_frame > (SACN_KEEPALIVE_INTERVAL - frame_delta)){ + global_cfg.next_frame = (SACN_KEEPALIVE_INTERVAL - frame_delta); + } + return 0; + } + } sacn_transmit(inst); } @@ -468,6 +502,7 @@ static void sacn_discovery(size_t fd){ static int sacn_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[SACN_RECV_BUF]; instance* inst = NULL; @@ -477,7 +512,7 @@ static int sacn_handle(size_t num, managed_fd* fds){ sacn_frame_root* frame = (sacn_frame_root*) recv_buf; sacn_frame_data* data = (sacn_frame_data*) (recv_buf + sizeof(sacn_frame_root)); - if(mm_timestamp() - global_cfg.last_announce > SACN_DISCOVERY_TIMEOUT){ + if(timestamp - global_cfg.last_announce > SACN_DISCOVERY_TIMEOUT){ //send universe discovery pdu for(u = 0; u < global_cfg.fds; u++){ if(global_cfg.fd[u].universes){ @@ -487,17 +522,28 @@ static int sacn_handle(size_t num, managed_fd* fds){ global_cfg.last_announce = timestamp; } - //check for keepalive frames + //check for keepalive frames, synthesize frames if necessary for(u = 0; u < global_cfg.fds; u++){ for(c = 0; c < global_cfg.fd[u].universes; c++){ - if(timestamp - global_cfg.fd[u].last_frame[c] >= SACN_KEEPALIVE_INTERVAL){ + synthesize_delta = timestamp - global_cfg.fd[u].universe[c].last_frame; + + if((global_cfg.fd[u].universe[c].mark + && synthesize_delta >= SACN_FRAME_TIMEOUT + SACN_SYNTHESIZE_MARGIN) + || synthesize_delta >= SACN_KEEPALIVE_INTERVAL){ instance_id.fields.fd_index = u; - instance_id.fields.uni = global_cfg.fd[u].universe[c]; + instance_id.fields.uni = global_cfg.fd[u].universe[c].universe; inst = mm_instance_find(BACKEND_NAME, instance_id.label); if(inst){ sacn_transmit(inst); } } + + //update next frame request + if(global_cfg.fd[u].universe[c].mark + && (!global_cfg.next_frame || global_cfg.next_frame > SACN_FRAME_TIMEOUT + SACN_SYNTHESIZE_MARGIN - synthesize_delta)){ + global_cfg.next_frame = SACN_FRAME_TIMEOUT + SACN_SYNTHESIZE_MARGIN - synthesize_delta; + } + } } @@ -557,7 +603,6 @@ static int sacn_start(size_t n, instance** inst){ if(!global_cfg.fds){ LOG("Failed to start, no descriptors bound"); - free(inst); return 1; } @@ -590,13 +635,15 @@ static int sacn_start(size_t n, instance** inst){ if(data->xmit_prio){ //add to list of advertised universes for this fd - global_cfg.fd[data->fd_index].universe = realloc(global_cfg.fd[data->fd_index].universe, (global_cfg.fd[data->fd_index].universes + 1) * sizeof(uint16_t)); + global_cfg.fd[data->fd_index].universe = realloc(global_cfg.fd[data->fd_index].universe, (global_cfg.fd[data->fd_index].universes + 1) * sizeof(sacn_output_universe)); if(!global_cfg.fd[data->fd_index].universe){ LOG("Failed to allocate memory"); goto bail; } - global_cfg.fd[data->fd_index].universe[global_cfg.fd[data->fd_index].universes] = data->uni; + global_cfg.fd[data->fd_index].universe[global_cfg.fd[data->fd_index].universes].universe = data->uni; + global_cfg.fd[data->fd_index].universe[global_cfg.fd[data->fd_index].universes].last_frame = 0; + global_cfg.fd[data->fd_index].universe[global_cfg.fd[data->fd_index].universes].mark = 0; global_cfg.fd[data->fd_index].universes++; //generate multicast destination address if none set @@ -612,12 +659,6 @@ static int sacn_start(size_t n, instance** inst){ LOGPF("Registering %" PRIsize_t " descriptors to core", global_cfg.fds); for(u = 0; u < global_cfg.fds; u++){ - //allocate memory for storing last frame transmission timestamp - global_cfg.fd[u].last_frame = calloc(global_cfg.fd[u].universes, sizeof(uint64_t)); - if(!global_cfg.fd[u].last_frame){ - LOG("Failed to allocate memory"); - goto bail; - } if(mm_manage_fd(global_cfg.fd[u].fd, BACKEND_NAME, 1, (void*) u)){ goto bail; } @@ -638,7 +679,6 @@ static int sacn_shutdown(size_t n, instance** inst){ for(p = 0; p < global_cfg.fds; p++){ close(global_cfg.fd[p].fd); free(global_cfg.fd[p].universe); - free(global_cfg.fd[p].last_frame); } free(global_cfg.fd); LOG("Backend shut down"); -- cgit v1.2.3 From 3a53a29df4c762a1ea3891be24615f74469b6be2 Mon Sep 17 00:00:00 2001 From: cbdev Date: Fri, 6 Mar 2020 23:47:03 +0100 Subject: Minor fixes --- backends/sacn.c | 1 + 1 file changed, 1 insertion(+) (limited to 'backends/sacn.c') diff --git a/backends/sacn.c b/backends/sacn.c index 6c08b5a..54cc7b5 100644 --- a/backends/sacn.c +++ b/backends/sacn.c @@ -523,6 +523,7 @@ static int sacn_handle(size_t num, managed_fd* fds){ } //check for keepalive frames, synthesize frames if necessary + global_cfg.next_frame = 0; for(u = 0; u < global_cfg.fds; u++){ for(c = 0; c < global_cfg.fd[u].universes; c++){ synthesize_delta = timestamp - global_cfg.fd[u].universe[c].last_frame; -- cgit v1.2.3 From d72d7cc6366f901eb9503bac613e3bc280ac8fc5 Mon Sep 17 00:00:00 2001 From: cbdev Date: Sat, 7 Mar 2020 00:01:35 +0100 Subject: Whitespace fixes --- backends/sacn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'backends/sacn.c') diff --git a/backends/sacn.c b/backends/sacn.c index 54cc7b5..79ffb46 100644 --- a/backends/sacn.c +++ b/backends/sacn.c @@ -223,7 +223,7 @@ static channel* sacn_channel(instance* inst, char* spec, uint8_t flags){ char* spec_next = spec; unsigned chan_a = strtoul(spec, &spec_next, 10), chan_b = 0; - + //range check if(!chan_a || chan_a > 512){ LOGPF("Channel out of range on instance %s: %s", inst->name, spec); @@ -540,7 +540,7 @@ static int sacn_handle(size_t num, managed_fd* fds){ } //update next frame request - if(global_cfg.fd[u].universe[c].mark + if(global_cfg.fd[u].universe[c].mark && (!global_cfg.next_frame || global_cfg.next_frame > SACN_FRAME_TIMEOUT + SACN_SYNTHESIZE_MARGIN - synthesize_delta)){ global_cfg.next_frame = SACN_FRAME_TIMEOUT + SACN_SYNTHESIZE_MARGIN - synthesize_delta; } -- cgit v1.2.3 From e48583db0e02336381a1626af814549bf12b1214 Mon Sep 17 00:00:00 2001 From: cbdev Date: Tue, 10 Mar 2020 20:44:38 +0100 Subject: Check ArtNet/sACN channel direction at map time --- backends/sacn.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'backends/sacn.c') diff --git a/backends/sacn.c b/backends/sacn.c index 79ffb46..9c7f890 100644 --- a/backends/sacn.c +++ b/backends/sacn.c @@ -231,6 +231,11 @@ static channel* sacn_channel(instance* inst, char* spec, uint8_t flags){ } chan_a--; + //check output capabilities + if((flags & mmchannel_output) && !data->xmit_prio){ + LOGPF("Channel %s.%s mapped for output, but instance is not configured for output (no priority set)", inst->name, spec); + } + //if wide channel, mark fine if(*spec_next == '+'){ chan_b = strtoul(spec_next + 1, NULL, 10); -- cgit v1.2.3 From 04494e4543150567a461dd478ce9ccdc067131b2 Mon Sep 17 00:00:00 2001 From: cbdev Date: Tue, 10 Mar 2020 21:57:47 +0100 Subject: Move ArtNet and sACN to local channel stores --- backends/sacn.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'backends/sacn.c') diff --git a/backends/sacn.c b/backends/sacn.c index 9c7f890..dd05dc7 100644 --- a/backends/sacn.c +++ b/backends/sacn.c @@ -209,12 +209,20 @@ static int sacn_configure_instance(instance* inst, char* option, char* value){ } static int sacn_instance(instance* inst){ - inst->impl = calloc(1, sizeof(sacn_instance_data)); - if(!inst->impl){ + sacn_instance_data* data = calloc(1, sizeof(sacn_instance_data)); + size_t u; + + if(!data){ LOG("Failed to allocate memory"); return 1; } + for(u = 0; u < sizeof(data->data.channel) / sizeof(channel); u++){ + data->data.channel[u].ident = u; + data->data.channel[u].instance = inst; + } + + inst->impl = data; return 0; } @@ -264,7 +272,7 @@ static channel* sacn_channel(instance* inst, char* spec, uint8_t flags){ } data->data.map[chan_a] = (*spec_next == '+') ? (MAP_COARSE | chan_b) : (MAP_SINGLE | chan_a); - return mm_channel(inst, chan_a, 1); + return data->data.channel + chan_a; } static int sacn_transmit(instance* inst){ @@ -424,10 +432,10 @@ static int sacn_process_frame(instance* inst, sacn_frame_root* frame, sacn_frame //unmark and get channel inst_data->data.map[u] &= ~MAP_MARK; if(inst_data->data.map[u] & MAP_FINE){ - chan = mm_channel(inst, MAPPED_CHANNEL(inst_data->data.map[u]), 0); + chan = inst_data->data.channel + MAPPED_CHANNEL(inst_data->data.map[u]); } else{ - chan = mm_channel(inst, u, 0); + chan = inst_data->data.channel + u; } if(!chan){ -- cgit v1.2.3 From 678cc465124ad81dcec47c44cc30827e5246bd3b Mon Sep 17 00:00:00 2001 From: cbdev Date: Wed, 11 Mar 2020 20:50:29 +0100 Subject: Simplify ArtNet & sACN --- backends/sacn.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'backends/sacn.c') diff --git a/backends/sacn.c b/backends/sacn.c index dd05dc7..c9be8ff 100644 --- a/backends/sacn.c +++ b/backends/sacn.c @@ -431,12 +431,10 @@ static int sacn_process_frame(instance* inst, sacn_frame_root* frame, sacn_frame if(inst_data->data.map[u] & MAP_MARK){ //unmark and get channel inst_data->data.map[u] &= ~MAP_MARK; + chan = inst_data->data.channel + u; if(inst_data->data.map[u] & MAP_FINE){ chan = inst_data->data.channel + MAPPED_CHANNEL(inst_data->data.map[u]); } - else{ - chan = inst_data->data.channel + u; - } if(!chan){ LOGPF("Active channel %" PRIsize_t " on %s not known to core", u, inst->name); -- cgit v1.2.3 From 4b120a64f68fd7f36e8080981d68d0830d113205 Mon Sep 17 00:00:00 2001 From: cbdev Date: Thu, 12 Mar 2020 21:51:43 +0100 Subject: Fix rate-limited frame synthesis --- backends/sacn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'backends/sacn.c') diff --git a/backends/sacn.c b/backends/sacn.c index c9be8ff..495bdf3 100644 --- a/backends/sacn.c +++ b/backends/sacn.c @@ -374,8 +374,8 @@ static int sacn_set(instance* inst, size_t num, channel** c, channel_value* v){ //check if ratelimiting engaged if(frame_delta < SACN_FRAME_TIMEOUT){ global_cfg.fd[data->fd_index].universe[u].mark = 1; - if(!global_cfg.next_frame || global_cfg.next_frame > (SACN_KEEPALIVE_INTERVAL - frame_delta)){ - global_cfg.next_frame = (SACN_KEEPALIVE_INTERVAL - frame_delta); + if(!global_cfg.next_frame || global_cfg.next_frame > (SACN_FRAME_TIMEOUT - frame_delta)){ + global_cfg.next_frame = (SACN_FRAME_TIMEOUT - frame_delta); } return 0; } -- cgit v1.2.3 From 05cdf563fcc4c7835ec422fa5d7ee86b68a9f1df Mon Sep 17 00:00:00 2001 From: cbdev Date: Sat, 14 Mar 2020 21:45:09 +0100 Subject: Restructure backend and instance registry --- backends/sacn.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'backends/sacn.c') diff --git a/backends/sacn.c b/backends/sacn.c index 495bdf3..bd5c75a 100644 --- a/backends/sacn.c +++ b/backends/sacn.c @@ -436,11 +436,6 @@ static int sacn_process_frame(instance* inst, sacn_frame_root* frame, sacn_frame chan = inst_data->data.channel + MAPPED_CHANNEL(inst_data->data.map[u]); } - if(!chan){ - LOGPF("Active channel %" PRIsize_t " on %s not known to core", u, inst->name); - return 1; - } - //generate value if(IS_WIDE(inst_data->data.map[u])){ inst_data->data.map[MAPPED_CHANNEL(inst_data->data.map[u])] &= ~MAP_MARK; -- cgit v1.2.3