Browse Source

TT#50652 add label= option to match call participants

Change-Id: Ifc6cf8f630e9e5eb8cfb9b284e671a5ce4470963
changes/35/28035/1
Richard Fuchs 7 years ago
parent
commit
357474df6f
6 changed files with 183 additions and 48 deletions
  1. +5
    -4
      README.md
  2. +7
    -0
      daemon/call.c
  3. +50
    -44
      daemon/call_interfaces.c
  4. +1
    -0
      include/call.h
  5. +6
    -0
      include/call_interfaces.h
  6. +114
    -0
      t/auto-daemon-tests.pl

+ 5
- 4
README.md View File

@ -1389,8 +1389,9 @@ events (RFC 4733 type packets), respectively.
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
is included in the message, they can be selected by their SDP media address if the `address` key is included
in the message, or they can be selected by the user-provided `label` if the `label` key is included in the
message. For an address, it 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 RTP
packets blocked (or unblocked).
@ -1422,8 +1423,8 @@ and stopped independently of each other.
--------------------
Only available if compiled with transcoding support. The message must contain the key `call-id` and one
of the participant selection keys described under the `block DTMF` message (such as `from-tag` or
`address`).
of the participant selection keys described under the `block DTMF` message (such as `from-tag`,
`address`, or `label`).
Starts playback of a provided media file to the selected call participant. The format of the media file
can be anything that is supported by *ffmpeg*, for example a `.wav` or `.mp3` file. It will automatically


+ 7
- 0
daemon/call.c View File

@ -1798,6 +1798,11 @@ int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams,
__tos_change(call, flags);
if (flags && flags->label.s) {
call_str_cpy(call, &other_ml->label, &flags->label);
g_hash_table_replace(call->labels, &other_ml->label, other_ml);
}
ml_media = other_ml_media = NULL;
for (media_iter = streams->head; media_iter; media_iter = media_iter->next) {
@ -2316,6 +2321,7 @@ static void __call_free(void *p) {
g_hash_table_destroy(c->tags);
g_hash_table_destroy(c->viabranches);
g_hash_table_destroy(c->labels);
free_ssrc_hash(&c->ssrc_hash);
while (c->streams.head) {
@ -2347,6 +2353,7 @@ static struct call *call_create(const str *callid) {
rwlock_init(&c->master_lock);
c->tags = g_hash_table_new(str_hash, str_equal);
c->viabranches = g_hash_table_new(str_hash, str_equal);
c->labels = g_hash_table_new(str_hash, str_equal);
call_str_cpy(c, &c->callid, callid);
c->created = rtpe_now;
c->dtls_cert = dtls_cert();


+ 50
- 44
daemon/call_interfaces.c View File

@ -746,6 +746,13 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu
call_ng_flags_list(out, input, "replace", call_ng_flags_replace, NULL);
call_ng_flags_list(out, input, "supports", call_ng_flags_supports, NULL);
bencode_dictionary_get_str(input, "call-id", &out->call_id);
bencode_dictionary_get_str(input, "from-tag", &out->from_tag);
bencode_dictionary_get_str(input, "to-tag", &out->to_tag);
bencode_dictionary_get_str(input, "via-branch", &out->via_branch);
bencode_dictionary_get_str(input, "label", &out->label);
bencode_dictionary_get_str(input, "address", &out->address);
diridx = 0;
if ((list = bencode_dictionary_get_expect(input, "direction", BENCODE_LIST))) {
for (it = list->child; it && diridx < 2; it = it->sibling)
@ -900,8 +907,7 @@ static const char *call_offer_answer_ng(bencode_item_t *input,
bencode_item_t *output, enum call_opmode opmode, const char* addr,
const endpoint_t *sin)
{
str sdp, fromtag, totag = STR_NULL, callid, viabranch;
str label = STR_NULL;
str sdp;
const char *errstr;
GQueue parsed = G_QUEUE_INIT;
GQueue streams = G_QUEUE_INIT;
@ -913,20 +919,18 @@ static const char *call_offer_answer_ng(bencode_item_t *input,
if (!bencode_dictionary_get_str(input, "sdp", &sdp))
return "No SDP body in message";
if (!bencode_dictionary_get_str(input, "call-id", &callid))
call_ng_process_flags(&flags, input, opmode);
if (!flags.call_id.s)
return "No call-id in message";
if (!bencode_dictionary_get_str(input, "from-tag", &fromtag))
if (!flags.from_tag.s)
return "No from-tag in message";
bencode_dictionary_get_str(input, "to-tag", &totag);
if (opmode == OP_ANSWER) {
if (!totag.s)
if (!flags.to_tag.s)
return "No to-tag in message";
str_swap(&totag, &fromtag);
str_swap(&flags.to_tag, &flags.from_tag);
}
bencode_dictionary_get_str(input, "via-branch", &viabranch);
bencode_dictionary_get_str(input, "label", &label);
call_ng_process_flags(&flags, input, opmode);
if (opmode == OP_OFFER) {
enum load_limit_reasons limit = call_offer_session_limit();
@ -955,7 +959,7 @@ static const char *call_offer_answer_ng(bencode_item_t *input,
goto out;
/* OP_ANSWER; OP_OFFER && !IS_FOREIGN_CALL */
call = call_get(&callid);
call = call_get(&flags.call_id);
/* Failover scenario because of timeout on offer response: siprouter tries
* to establish session with another rtpengine2 even though rtpengine1
@ -969,12 +973,12 @@ static const char *call_offer_answer_ng(bencode_item_t *input,
rwlock_unlock_w(&call->master_lock);
call_destroy(call);
obj_put(call);
call = call_get_or_create(&callid, CT_OWN_CALL);
call = call_get_or_create(&flags.call_id, CT_OWN_CALL);
}
}
else {
/* call == NULL, should create call */
call = call_get_or_create(&callid, CT_OWN_CALL);
call = call_get_or_create(&flags.call_id, CT_OWN_CALL);
}
}
@ -993,7 +997,8 @@ static const char *call_offer_answer_ng(bencode_item_t *input,
* need to hold a ref until we're done sending the reply */
call_bencode_hold_ref(call, output);
monologue = call_get_mono_dialogue(call, &fromtag, &totag, viabranch.s ? &viabranch : NULL);
monologue = call_get_mono_dialogue(call, &flags.from_tag, &flags.to_tag,
flags.via_branch.s ? &flags.via_branch : NULL);
errstr = "Invalid dialogue association";
if (!monologue) {
rwlock_unlock_w(&call->master_lock);
@ -1006,8 +1011,6 @@ static const char *call_offer_answer_ng(bencode_item_t *input,
} else {
monologue->tagtype = TO_TAG;
}
if (label.s && !monologue->label.s)
call_str_cpy(call, &monologue->label, &label);
chopper = sdp_chopper_new(&sdp);
bencode_buffer_destroy_add(output->buffer, (free_func_t) sdp_chopper_destroy, chopper);
@ -1478,24 +1481,33 @@ const char *call_stop_recording_ng(bencode_item_t *input, bencode_item_t *output
}
static const char *media_block_match(struct call **call, struct call_monologue **monologue,
bencode_item_t *input)
struct sdp_ng_flags *flags, bencode_item_t *input)
{
str callid;
str s;
struct sdp_ng_flags flags_store;
if (!flags)
flags = &flags_store;
*call = NULL;
*monologue = NULL;
if (!bencode_dictionary_get_str(input, "call-id", &callid))
call_ng_process_flags(flags, input, OP_OTHER);
if (!flags->call_id.s)
return "No call-id in message";
*call = call_get_opmode(&callid, OP_OTHER);
*call = call_get_opmode(&flags->call_id, OP_OTHER);
if (!*call)
return "Unknown call-id";
// directional block?
if (bencode_dictionary_get_str(input, "address", &s)) {
// directional?
if (flags->label.s) {
*monologue = g_hash_table_lookup((*call)->labels, &flags->label);
if (!*monologue)
return "No monologue matching the given label";
}
else if (flags->address.s) {
sockaddr_t addr;
if (sockaddr_parse_any_str(&addr, &s))
if (sockaddr_parse_any_str(&addr, &flags->address))
return "Failed to parse network address";
// walk our structures to find a matching stream
for (GList *l = (*call)->monologues.head; l; l = l->next) {
@ -1516,8 +1528,8 @@ static const char *media_block_match(struct call **call, struct call_monologue *
found:
;
}
else if (bencode_dictionary_get_str(input, "from-tag", &s)) {
*monologue = call_get_mono_dialogue(*call, &s, NULL, NULL);
else if (flags->from_tag.s) {
*monologue = call_get_mono_dialogue(*call, &flags->from_tag, NULL, NULL);
if (!*monologue)
return "From-tag given, but no such tag exists";
}
@ -1530,14 +1542,12 @@ const char *call_start_forwarding_ng(bencode_item_t *input, bencode_item_t *outp
struct call *call;
struct call_monologue *monologue;
const char *errstr = NULL;
str metadata;
struct sdp_ng_flags flags;
errstr = media_block_match(&call, &monologue, input);
errstr = media_block_match(&call, &monologue, &flags, input);
if (errstr)
goto out;
bencode_dictionary_get_str(input, "metadata", &metadata);
if (monologue) {
ilog(LOG_INFO, "Start forwarding for single party (tag '" STR_FORMAT ")",
STR_FMT(&monologue->tag));
@ -1548,7 +1558,7 @@ const char *call_start_forwarding_ng(bencode_item_t *input, bencode_item_t *outp
call->rec_forwarding = 1;
}
recording_start(call, NULL, &metadata);
recording_start(call, NULL, &flags.metadata);
errstr = NULL;
out:
if (call) {
@ -1565,12 +1575,10 @@ const char *call_stop_forwarding_ng(bencode_item_t *input, bencode_item_t *outpu
const char *errstr = NULL;
struct sdp_ng_flags flags;
errstr = media_block_match(&call, &monologue, input);
errstr = media_block_match(&call, &monologue, &flags, input);
if (errstr)
goto out;
call_ng_process_flags(&flags, input, OP_OTHER);
if (monologue) {
ilog(LOG_INFO, "Stop forwarding for single party (tag '" STR_FORMAT ")",
STR_FMT(&monologue->tag));
@ -1603,8 +1611,9 @@ const char *call_block_dtmf_ng(bencode_item_t *input, bencode_item_t *output) {
struct call *call;
struct call_monologue *monologue;
const char *errstr = NULL;
struct sdp_ng_flags flags;
errstr = media_block_match(&call, &monologue, input);
errstr = media_block_match(&call, &monologue, &flags, input);
if (errstr)
goto out;
@ -1634,12 +1643,10 @@ const char *call_unblock_dtmf_ng(bencode_item_t *input, bencode_item_t *output)
const char *errstr = NULL;
struct sdp_ng_flags flags;
errstr = media_block_match(&call, &monologue, input);
errstr = media_block_match(&call, &monologue, &flags, input);
if (errstr)
goto out;
call_ng_process_flags(&flags, input, OP_OTHER);
if (monologue) {
ilog(LOG_INFO, "Unblocking directional DTMF (tag '" STR_FORMAT ")",
STR_FMT(&monologue->tag));
@ -1670,8 +1677,9 @@ const char *call_block_media_ng(bencode_item_t *input, bencode_item_t *output) {
struct call *call;
struct call_monologue *monologue;
const char *errstr = NULL;
struct sdp_ng_flags flags;
errstr = media_block_match(&call, &monologue, input);
errstr = media_block_match(&call, &monologue, &flags, input);
if (errstr)
goto out;
@ -1703,12 +1711,10 @@ const char *call_unblock_media_ng(bencode_item_t *input, bencode_item_t *output)
const char *errstr = NULL;
struct sdp_ng_flags flags;
errstr = media_block_match(&call, &monologue, input);
errstr = media_block_match(&call, &monologue, &flags, input);
if (errstr)
goto out;
call_ng_process_flags(&flags, input, OP_OTHER);
if (monologue) {
ilog(LOG_INFO, "Unblocking directional media (tag '" STR_FORMAT ")",
STR_FMT(&monologue->tag));
@ -1742,7 +1748,7 @@ out:
static const char *play_media_select_party(struct call **call, struct call_monologue **monologue,
bencode_item_t *input)
{
const char *err = media_block_match(call, monologue, input);
const char *err = media_block_match(call, monologue, NULL, input);
if (err)
return err;
if (!*monologue)


+ 1
- 0
include/call.h View File

@ -362,6 +362,7 @@ struct call {
GQueue medias;
GHashTable *tags;
GHashTable *viabranches;
GHashTable *labels;
GQueue streams;
GQueue stream_fds;
GQueue endpoint_maps;


+ 6
- 0
include/call_interfaces.h View File

@ -18,6 +18,10 @@ struct sockaddr_in6;
struct sdp_ng_flags {
enum call_opmode opmode;
str call_id;
str from_tag;
str to_tag;
str via_branch;
str received_from_family;
str received_from_address;
str media_address;
@ -31,6 +35,8 @@ struct sdp_ng_flags {
int tos;
str record_call_str;
str metadata;
str label;
str address;
sockaddr_t xmlrpc_callback;
GHashTable *codec_strip;
GQueue codec_offer;


+ 114
- 0
t/auto-daemon-tests.pl View File

@ -1564,6 +1564,120 @@ rcv($sock_b, -1, rtpm(8, $seq + 9, $ts + 160 * 4, $ssrc, $pcma_5));
($sock_a, $sock_b) = new_call([qw(198.51.100.9 2020)], [qw(198.51.100.9 2022)]);
offer('media playback, side A, select by label', { ICE => 'remove', replace => ['origin'],
label => 'foobar' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.9
s=tester
t=0 0
m=audio 2020 RTP/AVP 8
c=IN IP4 198.51.100.9
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
answer('media playback, side A, select by label', { replace => ['origin'], label => 'blah' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.9
s=tester
t=0 0
m=audio 2022 RTP/AVP 8
c=IN IP4 198.51.100.9
a=sendrecv
--------------------------------------
v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
$resp = rtpe_req('play media', 'media playback, side A, select by label', { label => 'foobar',
blob => $wav_file });
is $resp->{duration}, 100, 'media duration';
($seq, $ts, $ssrc) = rcv($sock_a, -1, rtpm(8 | 0x80, -1, -1, -1, $pcma_1));
rcv($sock_a, -1, rtpm(8, $seq + 1, $ts + 160 * 1, $ssrc, $pcma_2));
rcv($sock_a, -1, rtpm(8, $seq + 2, $ts + 160 * 2, $ssrc, $pcma_3));
rcv($sock_a, -1, rtpm(8, $seq + 3, $ts + 160 * 3, $ssrc, $pcma_4));
rcv($sock_a, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5));
($sock_a, $sock_b) = new_call([qw(198.51.100.9 2030)], [qw(198.51.100.9 2032)]);
offer('media playback, side B, select by label', { ICE => 'remove', replace => ['origin'],
label => 'quux' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.9
s=tester
t=0 0
m=audio 2030 RTP/AVP 8
c=IN IP4 198.51.100.9
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
answer('media playback, side B, select by label', { replace => ['origin'], label => 'meh' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.9
s=tester
t=0 0
m=audio 2032 RTP/AVP 8
c=IN IP4 198.51.100.9
a=sendrecv
--------------------------------------
v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
$resp = rtpe_req('play media', 'media playback, side B, select by label', { label => 'meh', blob => $wav_file });
is $resp->{duration}, 100, 'media duration';
($seq, $ts, $ssrc) = rcv($sock_b, -1, rtpm(8 | 0x80, -1, -1, -1, $pcma_1));
rcv($sock_b, -1, rtpm(8, $seq + 1, $ts + 160 * 1, $ssrc, $pcma_2));
rcv($sock_b, -1, rtpm(8, $seq + 2, $ts + 160 * 2, $ssrc, $pcma_3));
rcv($sock_b, -1, rtpm(8, $seq + 3, $ts + 160 * 3, $ssrc, $pcma_4));
rcv($sock_b, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5));
($sock_a, $sock_b) = new_call([qw(198.51.100.1 2050)], [qw(198.51.100.3 2052)]);
offer('media playback, SRTP', { ICE => 'remove', replace => ['origin'], DTLS => 'off' }, <<SDP);


Loading…
Cancel
Save