Browse Source

TT#189201 support per-sink media blocking/silencing

Change-Id: I2b71816d97c4f6f1e1b290e5321d8ea1c106772a
pull/1546/head
Richard Fuchs 3 years ago
parent
commit
4a19714cd1
7 changed files with 66 additions and 15 deletions
  1. +7
    -0
      README.md
  2. +6
    -0
      daemon/call.c
  3. +43
    -12
      daemon/call_interfaces.c
  4. +2
    -2
      daemon/codec.c
  5. +4
    -1
      daemon/media_socket.c
  6. +1
    -0
      include/call.h
  7. +3
    -0
      include/media_socket.h

+ 7
- 0
README.md View File

@ -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 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. 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 `silence media` and `unsilence media` Messages
---------------------------------------------- ----------------------------------------------


+ 6
- 0
daemon/call.c View File

@ -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) { static void __call_monologue_init_from_flags(struct call_monologue *ml, struct sdp_ng_flags *flags) {
struct call *call = ml->call; struct call *call = ml->call;


+ 43
- 12
daemon/call_interfaces.c View File

@ -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, 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); AUTO_CLEANUP_NULL(struct call *call, call_unlock_release);
struct call_monologue *monologue; struct call_monologue *monologue;
@ -2658,10 +2659,38 @@ static const char *call_block_silence_media(bencode_item_t *input, bool on_off,
return errstr; return errstr;
if (monologue) { 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); __monologue_unkernelize(monologue);
} }
else { else {
@ -2683,21 +2712,23 @@ static const char *call_block_silence_media(bencode_item_t *input, bool on_off,
return NULL; 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) { 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) { 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) { 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) { 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);
} }


+ 2
- 2
daemon/codec.c View File

@ -1483,9 +1483,9 @@ void codec_add_raw_packet(struct media_packet *mp, unsigned int clockrate) {
g_queue_push_tail(&mp->packets_out, p); g_queue_push_tail(&mp->packets_out, p);
} }
static bool handler_silence_block(struct codec_handler *h, struct media_packet *mp) { 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; 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 && h->source_pt.codec_def->silence_pattern.len) {
if (h->source_pt.codec_def->silence_pattern.len == 1) if (h->source_pt.codec_def->silence_pattern.len == 1)
memset(mp->payload.s, h->source_pt.codec_def->silence_pattern.s[0], memset(mp->payload.s, h->source_pt.codec_def->silence_pattern.s[0],


+ 4
- 1
daemon/media_socket.c View File

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


+ 1
- 0
include/call.h View File

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


+ 3
- 0
include/media_socket.h View File

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


Loading…
Cancel
Save