TT#189201 support per-sink media blocking/silencing

Change-Id: I2b71816d97c4f6f1e1b290e5321d8ea1c106772a
pull/1546/head
Richard Fuchs 3 years ago
parent 1efc3d9409
commit 4a19714cd1

@ -2009,6 +2009,13 @@ Analogous to `block DTMF` and `unblock DTMF` but blocks media packets instead of
can still pass through when media blocking is enabled. Media packets can be blocked for an entire call, or
directionally for individual participants. See `block DTMF` above for details.
In addition to blocking media for just one call participant, it's possible to
block media for just a single media flow. This is relevant to scenarios that
involve forked media that were established with one or more `subscribe
request`. To select just one media flow for media blocking, in addition to
selecting a source call participant as above, a destination call participant
must be specified using the `to-tag` key in the message.
`silence media` and `unsilence media` Messages
----------------------------------------------

@ -2590,6 +2590,12 @@ static void __update_init_subscribers(struct call_monologue *ml, GQueue *streams
}
}
/* called with call->master_lock held in W */
void update_init_subscribers(struct call_monologue *ml, enum call_opmode opmode) {
__update_init_subscribers(ml, NULL, NULL, opmode);
}
static void __call_monologue_init_from_flags(struct call_monologue *ml, struct sdp_ng_flags *flags) {
struct call *call = ml->call;

@ -2646,7 +2646,8 @@ const char *call_unblock_dtmf_ng(bencode_item_t *input, bencode_item_t *output)
}
static const char *call_block_silence_media(bencode_item_t *input, bool on_off, const char *ucase_verb,
size_t call_offset, size_t ml_offset)
const char *lcase_verb,
size_t call_offset, size_t ml_offset, size_t attr_offset)
{
AUTO_CLEANUP_NULL(struct call *call, call_unlock_release);
struct call_monologue *monologue;
@ -2658,10 +2659,38 @@ static const char *call_block_silence_media(bencode_item_t *input, bool on_off,
return errstr;
if (monologue) {
ilog(LOG_INFO, "%s directional media (tag '" STR_FORMAT_M "')",
ucase_verb,
STR_FMT_M(&monologue->tag));
G_STRUCT_MEMBER(bool, monologue, ml_offset) = on_off;
if (flags.to_tag.len) {
struct call_monologue *sink = g_hash_table_lookup(call->tags, &flags.to_tag);
if (!sink) {
ilog(LOG_WARN, "Media flow '" STR_FORMAT_M "' -> '" STR_FORMAT_M "' doesn't "
"exist for media %s (to-tag not found)",
STR_FMT_M(&monologue->tag), STR_FMT_M(&flags.to_tag),
lcase_verb);
return "Media flow not found (to-tag not found)";
}
GList *link = g_hash_table_lookup(monologue->subscribers_ht, sink);
if (!link) {
ilog(LOG_WARN, "Media flow '" STR_FORMAT_M "' -> '" STR_FORMAT_M "' doesn't "
"exist for media %s (to-tag not subscribed)",
STR_FMT_M(&monologue->tag), STR_FMT_M(&flags.to_tag),
lcase_verb);
return "Media flow not found (to-tag not subscribed)";
}
struct call_subscription *cs = link->data;
ilog(LOG_INFO, "%s directional media flow "
"(tag '" STR_FORMAT_M "' -> '" STR_FORMAT_M "')",
ucase_verb,
STR_FMT_M(&monologue->tag), STR_FMT_M(&sink->tag));
G_STRUCT_MEMBER(bool, &cs->attrs, attr_offset) = on_off;
update_init_subscribers(monologue, OP_OTHER);
}
else {
ilog(LOG_INFO, "%s directional media (tag '" STR_FORMAT_M "')",
ucase_verb,
STR_FMT_M(&monologue->tag));
G_STRUCT_MEMBER(bool, monologue, ml_offset) = on_off;
}
__monologue_unkernelize(monologue);
}
else {
@ -2683,21 +2712,23 @@ static const char *call_block_silence_media(bencode_item_t *input, bool on_off,
return NULL;
}
#define CALL_BLOCK_SILENCE_MEDIA(input, on_off, ucase_verb, member_name) \
call_block_silence_media(input, on_off, ucase_verb, G_STRUCT_OFFSET(struct call, member_name), \
G_STRUCT_OFFSET(struct call_monologue, member_name))
#define CALL_BLOCK_SILENCE_MEDIA(input, on_off, ucase_verb, lcase_verb, member_name) \
call_block_silence_media(input, on_off, ucase_verb, lcase_verb, \
G_STRUCT_OFFSET(struct call, member_name), \
G_STRUCT_OFFSET(struct call_monologue, member_name), \
G_STRUCT_OFFSET(struct sink_attrs, member_name))
const char *call_block_media_ng(bencode_item_t *input, bencode_item_t *output) {
return CALL_BLOCK_SILENCE_MEDIA(input, true, "Blocking", block_media);
return CALL_BLOCK_SILENCE_MEDIA(input, true, "Blocking", "blocking", block_media);
}
const char *call_unblock_media_ng(bencode_item_t *input, bencode_item_t *output) {
return CALL_BLOCK_SILENCE_MEDIA(input, false, "Unblocking", block_media);
return CALL_BLOCK_SILENCE_MEDIA(input, false, "Unblocking", "unblocking", block_media);
}
const char *call_silence_media_ng(bencode_item_t *input, bencode_item_t *output) {
return CALL_BLOCK_SILENCE_MEDIA(input, true, "Silencing", silence_media);
return CALL_BLOCK_SILENCE_MEDIA(input, true, "Silencing", "silencing", silence_media);
}
const char *call_unsilence_media_ng(bencode_item_t *input, bencode_item_t *output) {
return CALL_BLOCK_SILENCE_MEDIA(input, false, "Unsilencing", silence_media);
return CALL_BLOCK_SILENCE_MEDIA(input, false, "Unsilencing", "unsilencing", silence_media);
}

@ -1483,9 +1483,9 @@ void codec_add_raw_packet(struct media_packet *mp, unsigned int clockrate) {
g_queue_push_tail(&mp->packets_out, p);
}
static bool handler_silence_block(struct codec_handler *h, struct media_packet *mp) {
if (mp->call->block_media || mp->media->monologue->block_media)
if (mp->call->block_media || mp->media->monologue->block_media || mp->sink.attrs.block_media)
return false;
if (mp->call->silence_media || mp->media->monologue->silence_media) {
if (mp->call->silence_media || mp->media->monologue->silence_media || mp->sink.attrs.silence_media) {
if (h->source_pt.codec_def && h->source_pt.codec_def->silence_pattern.len) {
if (h->source_pt.codec_def->silence_pattern.len == 1)
memset(mp->payload.s, h->source_pt.codec_def->silence_pattern.s[0],

@ -1305,7 +1305,8 @@ output:
redi->output.tos = call->tos;
// media silencing
bool silenced = call->silence_media || media->monologue->silence_media;
bool silenced = call->silence_media || media->monologue->silence_media
|| sink_handler->attrs.silence_media;
if (silenced) {
int i = 0;
for (GList *l = *payload_types; l; l = l->next) {
@ -1408,6 +1409,8 @@ void kernelize(struct packet_stream *stream) {
else {
for (GList *l = sinks->head; l; l = l->next) {
struct sink_handler *sh = l->data;
if (sh->attrs.block_media)
continue;
struct packet_stream *sink = sh->sink;
if (PS_ISSET(sink, NAT_WAIT) && !PS_ISSET(sink, RECEIVED))
continue;

@ -684,6 +684,7 @@ void call_media_state_machine(struct call_media *m);
void call_media_unkernelize(struct call_media *media);
void dialogue_unkernelize(struct call_monologue *ml);
void __monologue_unkernelize(struct call_monologue *monologue);
void update_init_subscribers(struct call_monologue *ml, enum call_opmode opmode);
int call_stream_address46(char *o, struct packet_stream *ps, enum stream_address_format format,
int *len, const struct local_intf *ifa, bool keep_unspec);

@ -128,6 +128,9 @@ struct stream_fd {
struct poller *poller;
};
struct sink_attrs {
bool block_media;
bool silence_media;
unsigned int offer_answer:1; // bidirectional, exclusive
unsigned int rtcp_only:1;
unsigned int transcoding:1;

Loading…
Cancel
Save