diff --git a/README.md b/README.md index 3ee6f2641..afdebe14a 100644 --- a/README.md +++ b/README.md @@ -1907,24 +1907,25 @@ Disables call recording for the call. This can be sent during a call to imediatl `block DTMF` and `unblock DTMF` Messages ---------------------------------------- These message types must include the key `call-id` in the message. They enable and disable blocking of DTMF -events (RFC 4733 type packets) for a call, respectively. +events (RFC 4733 type packets), respectively. -When DTMF blocking is enabled for a call, DTMF event packets will not be forwarded to the receiving peer. -If DTMF logging is enabled, DTMF events will still be logged to syslog while blocking is enabled. Blocking -of DTMF events happens for an entire call and can be enabled and disabled at any time during call runtime. - -`block media` and `unblock media` Messages ------------------------------------------- -Analogous to `block DTMF` and `unblock DTMF` but blocks media packets instead of DTMF packets. DTMF packets -can still pass through when media blocking is enabled. - -Media can be blocked for an entire call if only the `call-id` key is present in the message, or can be blocked +Packets can be blocked for an entire call if only the `call-id` key is present in the message, or can be blocked directionally for individual participants. Participants can be selected by their SIP tag if the `from-tag` key is included in the message, or they can be selected by their SDP media address if the `address` key is included in the message. In the latter case, the address can be an IPv4 or IPv6 address, and any participant that is -found to have a matching address advertised as their SDP media address will have their originating media +found to have a matching address advertised as their SDP media address will have their originating RTP packets blocked (or unblocked). -Unblocking media for the entire call (i.e. only `call-id` is given) does not automatically unblock media for -participants which had their media blocked directionally, unless the string `all` is included in the `flags` +Unblocking packets for the entire call (i.e. only `call-id` is given) does not automatically unblock packets for +participants which had their packets blocked directionally, unless the string `all` is included in the `flags` section of the message. + +When DTMF blocking is enabled, DTMF event packets will not be forwarded to the receiving peer. +If DTMF logging is enabled, DTMF events will still be logged to syslog while blocking is enabled. Blocking +of DTMF events can be enabled and disabled at any time during call runtime. + +`block media` and `unblock media` Messages +------------------------------------------ +Analogous to `block DTMF` and `unblock DTMF` but blocks media packets instead of DTMF packets. DTMF packets +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. diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 0c628079c..500024186 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -1406,39 +1406,68 @@ found: } const char *call_block_dtmf_ng(bencode_item_t *input, bencode_item_t *output) { - str callid; struct call *call; + struct call_monologue *monologue; + const char *errstr = NULL; - if (!bencode_dictionary_get_str(input, "call-id", &callid)) - return "No call-id in message"; - call = call_get_opmode(&callid, OP_OTHER); - if (!call) - return "Unknown call-id"; + errstr = media_block_match(&call, &monologue, input); + if (errstr) + goto out; - ilog(LOG_INFO, "Blocking DTMF"); - call->block_dtmf = 1; + if (monologue) { + ilog(LOG_INFO, "Blocking directional DTMF (tag '" STR_FORMAT ")", + STR_FMT(&monologue->tag)); + monologue->block_dtmf = 1; + } + else { + ilog(LOG_INFO, "Blocking DTMF (entire call)"); + call->block_dtmf = 1; + } - rwlock_unlock_w(&call->master_lock); - obj_put(call); + errstr = NULL; +out: + if (call) { + rwlock_unlock_w(&call->master_lock); + obj_put(call); + } - return NULL; + return errstr; } const char *call_unblock_dtmf_ng(bencode_item_t *input, bencode_item_t *output) { - str callid; struct call *call; + struct call_monologue *monologue; + const char *errstr = NULL; + struct sdp_ng_flags flags; - if (!bencode_dictionary_get_str(input, "call-id", &callid)) - return "No call-id in message"; - call = call_get_opmode(&callid, OP_OTHER); - if (!call) - return "Unknown call-id"; + errstr = media_block_match(&call, &monologue, input); + if (errstr) + goto out; - ilog(LOG_INFO, "Unblocking DTMF"); - call->block_dtmf = 0; + call_ng_process_flags(&flags, input); - rwlock_unlock_w(&call->master_lock); - obj_put(call); + if (monologue) { + ilog(LOG_INFO, "Unblocking directional DTMF (tag '" STR_FORMAT ")", + STR_FMT(&monologue->tag)); + monologue->block_dtmf = 0; + } + else { + ilog(LOG_INFO, "Unblocking DTMF (entire call)"); + call->block_dtmf = 0; + if (flags.all) { + for (GList *l = call->monologues.head; l; l = l->next) { + monologue = l->data; + monologue->block_dtmf = 0; + } + } + } + + errstr = NULL; +out: + if (call) { + rwlock_unlock_w(&call->master_lock); + obj_put(call); + } return NULL; } @@ -1511,8 +1540,6 @@ out: obj_put(call); } - - return NULL; } diff --git a/daemon/codec.c b/daemon/codec.c index 36c3fbf41..eafa8f84b 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -650,14 +650,14 @@ static int packet_dtmf(struct codec_ssrc_handler *ch, struct transcode_packet *p } } - if (!mp->call->block_dtmf) + if (!mp->call->block_dtmf && !mp->media->monologue->block_dtmf) packet_dtmf_fwd(ch, packet, mp, 1); return 0; } static void packet_dtmf_dup(struct codec_ssrc_handler *ch, struct transcode_packet *packet, struct media_packet *mp) { - if (!mp->call->block_dtmf) + if (!mp->call->block_dtmf && !mp->media->monologue->block_dtmf) packet_dtmf_fwd(ch, packet, mp, 0); } diff --git a/daemon/redis.c b/daemon/redis.c index 2b2fc72bd..b25d4bf7d 100644 --- a/daemon/redis.c +++ b/daemon/redis.c @@ -1220,6 +1220,8 @@ static int redis_tags(struct call *c, struct redis_list *tags) { if (!redis_hash_get_str(&s, rh, "label")) call_str_cpy(c, &ml->label, &s); redis_hash_get_time_t(&ml->deleted, rh, "deleted"); + if (!redis_hash_get_int(&ii, rh, "block_dtmf")) + ml->block_dtmf = ii ? 1 : 0; if (!redis_hash_get_int(&ii, rh, "block_media")) ml->block_media = ii ? 1 : 0; @@ -1965,6 +1967,7 @@ char* redis_encode_json(struct call *c) { JSON_SET_SIMPLE("created","%llu",(long long unsigned) ml->created); JSON_SET_SIMPLE("active","%u",ml->active_dialogue ? ml->active_dialogue->unique_id : -1); JSON_SET_SIMPLE("deleted","%llu",(long long unsigned) ml->deleted); + JSON_SET_SIMPLE("block_dtmf","%i",ml->block_dtmf ? 1 : 0); JSON_SET_SIMPLE("block_media","%i",ml->block_media ? 1 : 0); if (ml->tag.s) diff --git a/include/call.h b/include/call.h index 5bef7ccfc..5db4a16b4 100644 --- a/include/call.h +++ b/include/call.h @@ -365,6 +365,7 @@ struct call_monologue { struct call_monologue *active_dialogue; GQueue medias; + int block_dtmf:1; int block_media:1; };