|
|
|
@ -1553,6 +1553,9 @@ typedef struct { |
|
|
|
struct rtpengine_target_info reti; |
|
|
|
struct ssrc_entry_call *ssrc[RTPE_NUM_SSRC_TRACKING]; |
|
|
|
kernel_output_q outputs; |
|
|
|
sink_handler_q *rtp_sinks[RTPE_NUM_OUTPUT_MEDIA]; |
|
|
|
sink_handler_q *rtp_mirrors[RTPE_NUM_OUTPUT_MEDIA]; |
|
|
|
sink_handler_q *rtcp_sinks[RTPE_NUM_OUTPUT_MEDIA]; |
|
|
|
struct rtp_stats *payload_types[RTPE_NUM_PAYLOAD_TYPES]; |
|
|
|
unsigned int num_payload_types; |
|
|
|
bool blackhole; |
|
|
|
@ -1572,6 +1575,10 @@ G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(kernelize_state, kernelize_state_clear) |
|
|
|
__attribute__((nonnull(1, 2))) |
|
|
|
static const char *kernelize_target(kernelize_state *s, struct packet_stream *stream) { |
|
|
|
struct call_media *media = stream->media; |
|
|
|
unsigned int media_idx = media->index - 1; |
|
|
|
|
|
|
|
if (media_idx >= RTPE_NUM_OUTPUT_MEDIA) |
|
|
|
return "media index too large"; |
|
|
|
|
|
|
|
if (MEDIA_ISSET(media, BLACKHOLE)) |
|
|
|
s->blackhole = true; |
|
|
|
@ -1643,7 +1650,7 @@ static const char *kernelize_target(kernelize_state *s, struct packet_stream *st |
|
|
|
|
|
|
|
reti->track_ssrc = 1; |
|
|
|
unsigned int u = 0; |
|
|
|
for (GList *l = stream->media->ssrc_hash_in.nq.head; l; l = l->next) { |
|
|
|
for (GList *l = media->ssrc_hash_in.nq.head; l; l = l->next) { |
|
|
|
struct ssrc_entry_call *se = l->data; |
|
|
|
if (u >= G_N_ELEMENTS(reti->ssrc)) |
|
|
|
break; |
|
|
|
@ -1655,6 +1662,11 @@ static const char *kernelize_target(kernelize_state *s, struct packet_stream *st |
|
|
|
|
|
|
|
recording_stream_kernel_info(stream, reti); |
|
|
|
|
|
|
|
// record our outputs for this media |
|
|
|
s->rtp_sinks[media_idx] = &stream->rtp_sinks; |
|
|
|
s->rtp_mirrors[media_idx] = &stream->rtp_mirrors; |
|
|
|
s->rtcp_sinks[media_idx] = &stream->rtcp_sinks; |
|
|
|
|
|
|
|
if (!proto_is_rtp(media->protocol)) |
|
|
|
return NULL; // everything below is RTP-specific |
|
|
|
|
|
|
|
@ -1712,6 +1724,8 @@ static const char *kernelize_target(kernelize_state *s, struct packet_stream *st |
|
|
|
} |
|
|
|
|
|
|
|
reti->pt_stats[i] = rs; |
|
|
|
reti->pt_media_idx[i] = media_idx; |
|
|
|
|
|
|
|
i++; |
|
|
|
} |
|
|
|
|
|
|
|
@ -1727,7 +1741,8 @@ static const char *kernelize_target(kernelize_state *s, struct packet_stream *st |
|
|
|
*/ |
|
|
|
__attribute__((nonnull(1, 2, 3))) |
|
|
|
static const char *kernelize_one(kernelize_state *s, |
|
|
|
struct packet_stream *stream, struct sink_handler *sink_handler) |
|
|
|
struct packet_stream *stream, struct sink_handler *sink_handler, |
|
|
|
bool rtcp) |
|
|
|
{ |
|
|
|
call_t *call = stream->call; |
|
|
|
struct call_media *media = stream->media; |
|
|
|
@ -1767,6 +1782,7 @@ static const char *kernelize_one(kernelize_state *s, |
|
|
|
__auto_type redi = g_new0(struct rtpengine_destination_info, 1); |
|
|
|
redi->local = reti->local; |
|
|
|
redi->output.tos = call->tos; |
|
|
|
redi->output.rtcp = rtcp; |
|
|
|
|
|
|
|
// PT manipulations |
|
|
|
bool silenced = s->silenced || sink_handler->attrs.silence_media; |
|
|
|
@ -1850,13 +1866,15 @@ static const char *kernelize_one(kernelize_state *s, |
|
|
|
} |
|
|
|
// helper function for kernelize() |
|
|
|
// called with stream->lock held |
|
|
|
__attribute__((nonnull(1, 2, 3))) |
|
|
|
static bool kernelize_one_sink_handler(kernelize_state *s, |
|
|
|
struct packet_stream *stream, struct sink_handler *sink_handler) |
|
|
|
struct packet_stream *stream, struct sink_handler *sink_handler, |
|
|
|
bool rtcp) |
|
|
|
{ |
|
|
|
struct packet_stream *sink = sink_handler->sink; |
|
|
|
if (PS_ISSET(sink, NAT_WAIT) && !PS_ISSET(sink, RECEIVED)) |
|
|
|
return true; |
|
|
|
const char *err = kernelize_one(s, stream, sink_handler); |
|
|
|
const char *err = kernelize_one(s, stream, sink_handler, rtcp); |
|
|
|
if (err) { |
|
|
|
if (!*err) |
|
|
|
return false; // indicate deadlock |
|
|
|
@ -1864,11 +1882,21 @@ static bool kernelize_one_sink_handler(kernelize_state *s, |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
/* called with master_lock held */ |
|
|
|
static void kernelize(struct packet_stream *stream) { |
|
|
|
call_t *call = stream->call; |
|
|
|
struct call_media *media = stream->media; |
|
|
|
|
|
|
|
// act on bundle head if there is one |
|
|
|
if (media->bundle) { |
|
|
|
unsigned int component = stream->component; |
|
|
|
media = media->bundle; |
|
|
|
stream = get_media_component(media, component); |
|
|
|
if (!stream) |
|
|
|
return; // nothing to do? |
|
|
|
} |
|
|
|
|
|
|
|
while (true) { |
|
|
|
|
|
|
|
g_auto(kernelize_state) s = {0}; |
|
|
|
@ -1900,38 +1928,46 @@ static void kernelize(struct packet_stream *stream) { |
|
|
|
if (err) |
|
|
|
ilog(LOG_WARNING, "No support for kernel packet forwarding available (%s)", err); |
|
|
|
|
|
|
|
// primary RTP sinks |
|
|
|
for (__auto_type l = stream->rtp_sinks.head; l; l = l->next) { |
|
|
|
struct sink_handler *sh = l->data; |
|
|
|
if (sh->attrs.block_media) |
|
|
|
continue; |
|
|
|
bool ok = kernelize_one_sink_handler(&s, stream, sh); |
|
|
|
if (!ok) |
|
|
|
continue; // retry |
|
|
|
} |
|
|
|
// RTP egress mirrors |
|
|
|
for (__auto_type l = stream->rtp_mirrors.head; l; l = l->next) { |
|
|
|
struct sink_handler *sh = l->data; |
|
|
|
bool ok = kernelize_one_sink_handler(&s, stream, sh); |
|
|
|
if (!ok) |
|
|
|
continue; // retry |
|
|
|
} |
|
|
|
// RTP -> RTCP sinks |
|
|
|
// record number of RTP destinations up to now |
|
|
|
unsigned int num_rtp_dests = s.reti.num_destinations; |
|
|
|
// ignore RTP payload types |
|
|
|
for (__auto_type l = stream->rtcp_sinks.head; l; l = l->next) { |
|
|
|
struct sink_handler *sh = l->data; |
|
|
|
bool ok = kernelize_one_sink_handler(&s, stream, sh); |
|
|
|
if (!ok) |
|
|
|
continue; // retry |
|
|
|
} |
|
|
|
// mark the start of RTCP outputs |
|
|
|
s.reti.num_rtcp_destinations = s.reti.num_destinations - num_rtp_dests; |
|
|
|
|
|
|
|
if (!s.reti.local.family) |
|
|
|
goto no_kernel; |
|
|
|
|
|
|
|
for (unsigned int mi = 0; mi < RTPE_NUM_OUTPUT_MEDIA; mi++) { |
|
|
|
if (!s.rtp_sinks[mi]) |
|
|
|
continue; // not filled |
|
|
|
|
|
|
|
// primary RTP sinks |
|
|
|
s.reti.media_output_idxs[mi].rtp_start_idx = s.reti.num_destinations; |
|
|
|
for (__auto_type l = s.rtp_sinks[mi]->head; l; l = l->next) { |
|
|
|
struct sink_handler *sh = l->data; |
|
|
|
if (sh->attrs.block_media) |
|
|
|
continue; |
|
|
|
bool ok = kernelize_one_sink_handler(&s, stream, sh, false); |
|
|
|
if (!ok) |
|
|
|
continue; // retry |
|
|
|
} |
|
|
|
// RTP egress mirrors |
|
|
|
for (__auto_type l = s.rtp_mirrors[mi]->head; l; l = l->next) { |
|
|
|
struct sink_handler *sh = l->data; |
|
|
|
bool ok = kernelize_one_sink_handler(&s, stream, sh, false); |
|
|
|
if (!ok) |
|
|
|
continue; // retry |
|
|
|
} |
|
|
|
// RTP -> RTCP sinks |
|
|
|
// record number of RTP destinations up to now |
|
|
|
s.reti.media_output_idxs[mi].rtp_end_idx = s.reti.num_destinations; |
|
|
|
// also marks the start of RTCP outputs |
|
|
|
s.reti.media_output_idxs[mi].rtcp_start_idx = s.reti.num_destinations; |
|
|
|
// ignore RTP payload types |
|
|
|
for (__auto_type l = s.rtcp_sinks[mi]->head; l; l = l->next) { |
|
|
|
struct sink_handler *sh = l->data; |
|
|
|
bool ok = kernelize_one_sink_handler(&s, stream, sh, true); |
|
|
|
if (!ok) |
|
|
|
continue; // retry |
|
|
|
} |
|
|
|
// mark the end of RTCP outputs |
|
|
|
s.reti.media_output_idxs[mi].rtcp_end_idx = s.reti.num_destinations; |
|
|
|
} |
|
|
|
|
|
|
|
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 " |
|
|
|
|