diff --git a/daemon/media_socket.c b/daemon/media_socket.c index 1d378d5fe..75933f71c 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -1509,15 +1509,29 @@ static int __rtp_stats_pt_sort(const struct rtp_stats **a, const struct rtp_stat } +typedef struct { + struct rtpengine_target_info reti; + GQueue outputs; + rtp_stats_arr *payload_types; + bool ignore_payload_types; // temporary until refactor +} kernelize_state; + +static void kernelize_state_clear(kernelize_state *s) { + rtp_stats_arr_destroy_ptr(s->payload_types); + g_queue_clear(&s->outputs); // should always be empty +} + +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(kernelize_state, kernelize_state_clear) + + /** * The linkage between userspace and kernel module is in the kernelize_one(). * * Called with in_lock held. * sink_handler can be NULL. */ -static const char *kernelize_one(struct rtpengine_target_info *reti, GQueue *outputs, - struct packet_stream *stream, struct sink_handler *sink_handler, sink_handler_q *sinks, - rtp_stats_arr **payload_types) +static const char *kernelize_one(kernelize_state *s, + struct packet_stream *stream, struct sink_handler *sink_handler, sink_handler_q *sinks) { struct rtpengine_destination_info *redi = NULL; call_t *call = stream->call; @@ -1561,6 +1575,9 @@ static const char *kernelize_one(struct rtpengine_target_info *reti, GQueue *out // fill input if needed + __auto_type reti = &s->reti; + __auto_type payload_types = s->ignore_payload_types ? NULL : &s->payload_types; + if (reti->local.family) goto output; @@ -1740,21 +1757,19 @@ output: redi->num = reti->num_destinations; reti->num_destinations++; sink_handler->kernel_output_idx = redi->num; - g_queue_push_tail(outputs, redi); - assert(outputs->length == reti->num_destinations); + g_queue_push_tail(&s->outputs, redi); + assert(s->outputs.length == reti->num_destinations); return NULL; } // helper function for kernelize() -static void kernelize_one_sink_handler(struct rtpengine_target_info *reti, GQueue *outputs, - struct packet_stream *stream, struct sink_handler *sink_handler, sink_handler_q *sinks, - rtp_stats_arr **payload_types) +static void kernelize_one_sink_handler(kernelize_state *s, + struct packet_stream *stream, struct sink_handler *sink_handler, sink_handler_q *sinks) { struct packet_stream *sink = sink_handler->sink; if (PS_ISSET(sink, NAT_WAIT) && !PS_ISSET(sink, RECEIVED)) return; - const char *err = kernelize_one(reti, outputs, stream, sink_handler, &stream->rtp_sinks, - payload_types); + const char *err = kernelize_one(s, stream, sink_handler, &stream->rtp_sinks); if (err) ilog(LOG_WARNING, "No support for kernel packet forwarding available (%s)", err); } @@ -1763,7 +1778,7 @@ void kernelize(struct packet_stream *stream) { call_t *call = stream->call; const char *nk_warn_msg; struct call_media *media = stream->media; - g_autoptr(rtp_stats_arr) payload_types = NULL; + g_auto(kernelize_state) s = {0}; if (PS_ISSET(stream, KERNELIZED)) return; @@ -1784,15 +1799,11 @@ void kernelize(struct packet_stream *stream) { if (!stream->endpoint.address.family) goto no_kernel; - struct rtpengine_target_info reti; - ZERO(reti); // reti.local.family determines if anything can be done - GQueue outputs = G_QUEUE_INIT; - unsigned int num_sinks = stream->rtp_sinks.length + stream->rtcp_sinks.length; if (num_sinks == 0) { // add blackhole kernel rule - const char *err = kernelize_one(&reti, &outputs, stream, NULL, NULL, &payload_types); + const char *err = kernelize_one(&s, stream, NULL, NULL); if (err) ilog(LOG_WARNING, "No support for kernel packet forwarding available (%s)", err); } @@ -1801,35 +1812,34 @@ void kernelize(struct packet_stream *stream) { struct sink_handler *sh = l->data; if (sh->attrs.block_media) continue; - kernelize_one_sink_handler(&reti, &outputs, stream, sh, &stream->rtp_sinks, - &payload_types); + kernelize_one_sink_handler(&s, stream, sh, &stream->rtp_sinks); } for (__auto_type l = stream->rtp_mirrors.head; l; l = l->next) { struct sink_handler *sh = l->data; - kernelize_one_sink_handler(&reti, &outputs, stream, sh, &stream->rtp_sinks, - &payload_types); + kernelize_one_sink_handler(&s, stream, sh, &stream->rtp_sinks); } // record number of RTP destinations - unsigned int num_rtp_dests = reti.num_destinations; + unsigned int num_rtp_dests = s.reti.num_destinations; for (__auto_type l = stream->rtcp_sinks.head; l; l = l->next) { struct sink_handler *sh = l->data; - kernelize_one_sink_handler(&reti, &outputs, stream, sh, &stream->rtp_sinks, NULL); + s.ignore_payload_types = true; + kernelize_one_sink_handler(&s, stream, sh, &stream->rtp_sinks); } - reti.num_rtcp_destinations = reti.num_destinations - num_rtp_dests; + s.reti.num_rtcp_destinations = s.reti.num_destinations - num_rtp_dests; } - if (!reti.local.family) + if (!s.reti.local.family) goto no_kernel; - if (!outputs.length && !reti.non_forwarding) { - reti.non_forwarding = 1; + if (!s.outputs.length && !s.reti.non_forwarding) { + s.reti.non_forwarding = 1; ilog(LOG_NOTICE | LOG_FLAG_LIMIT, "Setting 'non-forwarding' flag for kernel stream due to " "lack of sinks"); } - kernel_add_stream(&reti); + kernel_add_stream(&s.reti); struct rtpengine_destination_info *redi; - while ((redi = g_queue_pop_head(&outputs))) { + while ((redi = g_queue_pop_head(&s.outputs))) { kernel_add_destination(redi); g_slice_free1(sizeof(*redi), redi); }