TT#14008 support media echo and blackhole

Change-Id: I9df4680188709867db2b61d97cc5f1e30c59e0d7
rfuchs/1283
Richard Fuchs 4 years ago
parent cc9fb063eb
commit a009f76456

@ -1433,6 +1433,34 @@ Optionally included keys are:
If specified, then this address will be used as destination address for the XMLRPC timeout
callback (see `b2b-url` option).
* `media echo` or `media-echo`
Contains a string to enable a special media echo mode. Recognised values are:
- `blackhole` or `sinkhole`
Media arriving from either side of the call is simply discarded
and not forwarded.
- `forward`
Enables media echo towards the receiver of this message (e.g.
the called party if the message is an `offer` from the caller).
Media arriving from that side is echoed back to its sender
(with a new SSRC if it's RTP). Media arriving from the opposite
side is discarded.
- `backwards`
Enables media echo towards the sender of this message (i.e. the
opposite of `forward`). Media arriving from the other side is
discarded.
- `both`
Enables media echo towards both the sender and the receiver of
this message.
An example of a complete `offer` request dictionary could be (SDP body abbreviated):
{ "command": "offer", "call-id": "cfBXzDSZqhYNcXM", "from-tag": "mS9rSAn0Cr",

@ -1179,6 +1179,10 @@ static int __init_streams(struct call_media *A, struct call_media *B, const stru
/* RTP */
a->rtp_sink = b;
// reflect media - pretent reflection also for blackhole, as otherwise
// we get SSRC flip-flops on the opposite side
if (MEDIA_ISSET(A, ECHO) || MEDIA_ISSET(A, BLACKHOLE))
a->rtp_sink = a;
PS_SET(a, RTP); /* XXX technically not correct, could be udptl too */
__rtp_stats_update(a->rtp_stats, A->codecs_recv);
@ -1213,6 +1217,8 @@ static int __init_streams(struct call_media *A, struct call_media *B, const stru
}
else {
a->rtcp_sink = b;
if (MEDIA_ISSET(A, ECHO) || MEDIA_ISSET(A, BLACKHOLE))
a->rtcp_sink = a->rtcp_sibling;
PS_SET(a, RTCP);
PS_CLEAR(a, IMPLICIT_RTCP);
}
@ -1227,6 +1233,8 @@ static int __init_streams(struct call_media *A, struct call_media *B, const stru
a->rtp_sink = NULL;
a->rtcp_sink = b;
if (MEDIA_ISSET(A, ECHO) || MEDIA_ISSET(A, BLACKHOLE))
a->rtcp_sink = a;
PS_CLEAR(a, RTP);
PS_SET(a, RTCP);
a->rtcp_sibling = NULL;
@ -2197,6 +2205,36 @@ int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams,
MEDIA_CLEAR(other_media, RTCP_GEN);
}
if (flags) {
switch (flags->media_echo) {
case MEO_FWD:
MEDIA_SET(media, ECHO);
MEDIA_SET(other_media, BLACKHOLE);
MEDIA_CLEAR(media, BLACKHOLE);
MEDIA_CLEAR(other_media, ECHO);
break;
case MEO_BKW:
MEDIA_SET(media, BLACKHOLE);
MEDIA_SET(other_media, ECHO);
MEDIA_CLEAR(media, ECHO);
MEDIA_CLEAR(other_media, BLACKHOLE);
break;
case MEO_BOTH:
MEDIA_SET(media, ECHO);
MEDIA_SET(other_media, ECHO);
MEDIA_CLEAR(media, BLACKHOLE);
MEDIA_CLEAR(other_media, BLACKHOLE);
break;
case MEO_BLACKHOLE:
MEDIA_SET(media, BLACKHOLE);
MEDIA_SET(other_media, BLACKHOLE);
MEDIA_CLEAR(media, ECHO);
MEDIA_CLEAR(other_media, ECHO);
case MEO_DEFAULT:
break;
}
}
__update_media_protocol(media, other_media, sp, flags);
__update_media_id(media, other_media, sp, flags);
__endpoint_loop_protect(sp, other_media);

@ -1154,6 +1154,31 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu
else if (!str_cmp(&s, "off"))
out->generate_rtcp_off = 1;
}
if (bencode_get_alt(input, "media-echo", "media echo", &s)) {
switch (__csh_lookup(&s)) {
case CSH_LOOKUP("blackhole"):
case CSH_LOOKUP("sinkhole"):
out->media_echo = MEO_BLACKHOLE;
break;
case CSH_LOOKUP("forward"):
case CSH_LOOKUP("fwd"):
case CSH_LOOKUP("fw"):
out->media_echo = MEO_FWD;
break;
case CSH_LOOKUP("backward"):
case CSH_LOOKUP("backwards"):
case CSH_LOOKUP("reverse"):
case CSH_LOOKUP("back"):
case CSH_LOOKUP("bkw"):
case CSH_LOOKUP("bk"):
out->media_echo = MEO_BKW;
break;
case CSH_LOOKUP("both"):
out->media_echo = MEO_BOTH;
break;
}
}
}
static void call_ng_free_flags(struct sdp_ng_flags *flags) {
if (flags->codec_strip)

@ -407,7 +407,10 @@ static GList *__delete_send_codec(struct call_media *sender, GList *link) {
// only called from codec_handlers_update()
static void __make_passthrough_gsl(struct codec_handler *handler, GSList **handlers) {
__make_passthrough(handler);
if (MEDIA_ISSET(handler->media, ECHO))
__make_passthrough_ssrc(handler);
else
__make_passthrough(handler);
*handlers = g_slist_prepend(*handlers, handler);
}

@ -1141,6 +1141,8 @@ void kernelize(struct packet_stream *stream) {
goto no_kernel;
if (!stream->endpoint.address.family)
goto no_kernel;
if (MEDIA_ISSET(media, BLACKHOLE))
non_forwarding = 1;
ilog(LOG_INFO, "Kernelizing media stream: %s%s:%d%s",
FMT_M(sockaddr_print_buf(&stream->endpoint.address), stream->endpoint.port));
@ -1183,13 +1185,14 @@ void kernelize(struct packet_stream *stream) {
reti.dtls = MEDIA_ISSET(media, DTLS);
reti.stun = media->ice_agent ? 1 : 0;
reti.non_forwarding = non_forwarding;
reti.blackhole = MEDIA_ISSET(media, BLACKHOLE) ? 1 : 0;
reti.rtp_stats = MEDIA_ISSET(media, RTCP_GEN) ? 1 : 0;
__re_address_translate_ep(&reti.dst_addr, &sink->endpoint);
__re_address_translate_ep(&reti.src_addr, &sink->selected_sfd->socket.local);
if (stream->ssrc_in) {
reti.ssrc = htonl(stream->ssrc_in->parent->h.ssrc);
if (MEDIA_ISSET(media, TRANSCODE)) {
if (MEDIA_ISSET(media, TRANSCODE) || MEDIA_ISSET(media, ECHO)) {
reti.ssrc_out = htonl(stream->ssrc_in->ssrc_map_out);
reti.transcoding = 1;
}
@ -1473,7 +1476,7 @@ static void __stream_ssrc(struct packet_stream *in_srtp, struct packet_stream *o
}
// make sure we reset the output SSRC if we're not transcoding
if (!MEDIA_ISSET(in_srtp->media, TRANSCODE))
if (!MEDIA_ISSET(in_srtp->media, TRANSCODE) && !MEDIA_ISSET(in_srtp->media, ECHO))
(*ssrc_in_p)->ssrc_map_out = in_ssrc;
out_ssrc = (*ssrc_in_p)->ssrc_map_out;
@ -2118,7 +2121,10 @@ static int stream_packet(struct packet_handler_ctx *phc) {
goto drop;
}
ret = media_socket_dequeue(&phc->mp, phc->sink);
if (!MEDIA_ISSET(phc->mp.media, BLACKHOLE))
ret = media_socket_dequeue(&phc->mp, phc->sink);
else
ret = media_socket_dequeue(&phc->mp, NULL);
mutex_unlock(&phc->sink->out_lock);

@ -157,6 +157,8 @@ enum call_stream_state {
#define MEDIA_FLAG_GENERATOR 0x02000000
#define MEDIA_FLAG_ICE_LITE_SELF 0x04000000
#define MEDIA_FLAG_RTCP_GEN 0x08000000
#define MEDIA_FLAG_ECHO 0x10000000
#define MEDIA_FLAG_BLACKHOLE 0x20000000
/* access macros */
#define SP_ISSET(p, f) bf_isset(&(p)->sp_flags, SP_FLAG_ ## f)

@ -64,6 +64,13 @@ struct sdp_ng_flags {
ICE_LITE_BKW,
ICE_LITE_BOTH,
} ice_lite_option:3;
enum {
MEO_DEFAULT = 0,
MEO_BLACKHOLE,
MEO_FWD,
MEO_BKW,
MEO_BOTH,
} media_echo:3;
unsigned int asymmetric:1,
protocol_accept:1,
no_redis_update:1,

@ -1581,8 +1581,10 @@ static int proc_list_show(struct seq_file *f, void *v) {
seq_printf(f, "local ");
seq_addr_print(f, &g->target.local);
seq_printf(f, "\n");
proc_list_addr_print(f, "src", &g->target.src_addr);
proc_list_addr_print(f, "dst", &g->target.dst_addr);
if (!g->target.non_forwarding) {
proc_list_addr_print(f, "src", &g->target.src_addr);
proc_list_addr_print(f, "dst", &g->target.dst_addr);
}
proc_list_addr_print(f, "mirror", &g->target.mirror_addr);
proc_list_addr_print(f, "expect", &g->target.expected_src);
if (g->target.src_mismatch > 0 && g->target.src_mismatch <= ARRAY_SIZE(re_msm_strings))
@ -1612,6 +1614,8 @@ static int proc_list_show(struct seq_file *f, void *v) {
seq_printf(f, " option: transcoding\n");
if (g->target.non_forwarding)
seq_printf(f, " option: non forwarding\n");
if (g->target.blackhole)
seq_printf(f, " option: blackhole\n");
if (g->target.rtp_stats)
seq_printf(f, " option: RTP stats\n");
@ -4273,8 +4277,11 @@ not_stun:
goto skip_error;
src_check_ok:
if (g->target.non_forwarding)
if (g->target.non_forwarding) {
if (g->target.blackhole)
error_nf_action = NF_DROP;
goto skip1;
}
if (g->target.dtls && is_dtls(skb))
goto skip1;

@ -120,6 +120,7 @@ struct rtpengine_target_info {
do_intercept:1,
transcoding:1, // SSRC subst and RTP PT filtering
non_forwarding:1, // empty src/dst addr
blackhole:1,
rtp_stats:1; // requires SSRC and clock_rates to be set
};

@ -89,13 +89,14 @@ GetOptions(
'generate-RTCP' => \$options{'generate RTCP'},
'single-codec' => \$options{'single codec'},
'reorder-codecs' => \$options{'reorder codecs'},
'media-echo=s' => \$options{'media echo'},
) or die;
my $cmd = shift(@ARGV) or die;
my %packet = (command => $cmd);
for my $x (split(/,/, 'from-tag,to-tag,call-id,transport protocol,media address,ICE,address family,DTLS,via-branch,media address,ptime,xmlrpc-callback,metadata,address,file,db-id,code,DTLS-fingerprint,ICE-lite')) {
for my $x (split(/,/, 'from-tag,to-tag,call-id,transport protocol,media address,ICE,address family,DTLS,via-branch,media address,ptime,xmlrpc-callback,metadata,address,file,db-id,code,DTLS-fingerprint,ICE-lite,media echo')) {
defined($options{$x}) and $packet{$x} = \$options{$x};
}
for my $x (split(/,/, 'TOS,delete-delay')) {

Loading…
Cancel
Save