|
|
|
|
@ -21,30 +21,27 @@ void dtmf_init(void) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void dtmf_bencode_and_notify(struct media_packet *mp,
|
|
|
|
|
struct telephone_event_payload *dtmf, int clockrate)
|
|
|
|
|
static void dtmf_bencode_and_notify(struct call_media *media, unsigned int event, unsigned int volume,
|
|
|
|
|
unsigned int duration, const endpoint_t *fsin, int clockrate)
|
|
|
|
|
{
|
|
|
|
|
struct call *call = media->call;
|
|
|
|
|
struct call_monologue *ml = media->monologue;
|
|
|
|
|
|
|
|
|
|
bencode_buffer_t bencbuf;
|
|
|
|
|
bencode_item_t *notify, *data, *tags;
|
|
|
|
|
str encoded_data;
|
|
|
|
|
int ret = bencode_buffer_init(&bencbuf);
|
|
|
|
|
assert(ret == 0);
|
|
|
|
|
|
|
|
|
|
if (!dtmf->end)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!clockrate)
|
|
|
|
|
clockrate = 8000;
|
|
|
|
|
|
|
|
|
|
notify = bencode_dictionary(&bencbuf);
|
|
|
|
|
bencode_dictionary_add_string(notify, "notify", "onDTMF");
|
|
|
|
|
data = bencode_dictionary_add_dictionary(notify, "data");
|
|
|
|
|
tags = bencode_dictionary_add_list(data, "tags");
|
|
|
|
|
|
|
|
|
|
bencode_dictionary_add_string_len(data, "callid", mp->call->callid.s, mp->call->callid.len);
|
|
|
|
|
bencode_dictionary_add_string_len(data, "source_tag", mp->media->monologue->tag.s, mp->media->monologue->tag.len);
|
|
|
|
|
bencode_dictionary_add_string_len(data, "callid", call->callid.s, call->callid.len);
|
|
|
|
|
bencode_dictionary_add_string_len(data, "source_tag", ml->tag.s, ml->tag.len);
|
|
|
|
|
|
|
|
|
|
GList *tag_values = g_hash_table_get_values(mp->call->tags);
|
|
|
|
|
GList *tag_values = g_hash_table_get_values(call->tags);
|
|
|
|
|
for (GList *tag_it = tag_values; tag_it; tag_it = tag_it->next) {
|
|
|
|
|
struct call_monologue *ml = tag_it->data;
|
|
|
|
|
bencode_list_add_str(tags, &ml->tag);
|
|
|
|
|
@ -52,22 +49,23 @@ static void dtmf_bencode_and_notify(struct media_packet *mp,
|
|
|
|
|
g_list_free(tag_values);
|
|
|
|
|
|
|
|
|
|
bencode_dictionary_add_string(data, "type", "DTMF");
|
|
|
|
|
bencode_dictionary_add_string(data, "source_ip", sockaddr_print_buf(&mp->fsin.address));
|
|
|
|
|
bencode_dictionary_add_string(data, "source_ip", sockaddr_print_buf(&fsin->address));
|
|
|
|
|
bencode_dictionary_add_integer(data, "timestamp", rtpe_now.tv_sec);
|
|
|
|
|
bencode_dictionary_add_integer(data, "event", dtmf->event);
|
|
|
|
|
bencode_dictionary_add_integer(data, "duration", ((long long) ntohs(dtmf->duration) * (1000000LL / clockrate)) / 1000LL);
|
|
|
|
|
bencode_dictionary_add_integer(data, "volume", dtmf->volume);
|
|
|
|
|
bencode_dictionary_add_integer(data, "event", event);
|
|
|
|
|
bencode_dictionary_add_integer(data, "duration", ((long long) ntohs(duration) * (1000000LL / clockrate)) / 1000LL);
|
|
|
|
|
bencode_dictionary_add_integer(data, "volume", volume);
|
|
|
|
|
|
|
|
|
|
bencode_collapse_str(notify, &encoded_data);
|
|
|
|
|
notify_ng_tcp_clients(&encoded_data);
|
|
|
|
|
bencode_buffer_free(&bencbuf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GString *dtmf_json_print(struct media_packet *mp,
|
|
|
|
|
struct telephone_event_payload *dtmf, int clockrate)
|
|
|
|
|
static GString *dtmf_json_print(struct call_media *media, unsigned int event, unsigned int volume,
|
|
|
|
|
unsigned int duration,
|
|
|
|
|
const endpoint_t *fsin, int clockrate)
|
|
|
|
|
{
|
|
|
|
|
if (!dtmf->end)
|
|
|
|
|
return NULL;
|
|
|
|
|
struct call *call = media->call;
|
|
|
|
|
struct call_monologue *ml = media->monologue;
|
|
|
|
|
|
|
|
|
|
GString *buf = g_string_new("");
|
|
|
|
|
|
|
|
|
|
@ -78,10 +76,10 @@ static GString *dtmf_json_print(struct media_packet *mp,
|
|
|
|
|
"\"callid\":\"" STR_FORMAT "\","
|
|
|
|
|
"\"source_tag\":\"" STR_FORMAT "\","
|
|
|
|
|
"\"tags\":[",
|
|
|
|
|
STR_FMT(&mp->call->callid),
|
|
|
|
|
STR_FMT(&mp->media->monologue->tag));
|
|
|
|
|
STR_FMT(&call->callid),
|
|
|
|
|
STR_FMT(&ml->tag));
|
|
|
|
|
|
|
|
|
|
GList *tag_values = g_hash_table_get_values(mp->call->tags);
|
|
|
|
|
GList *tag_values = g_hash_table_get_values(call->tags);
|
|
|
|
|
int i = 0;
|
|
|
|
|
for (GList *tag_it = tag_values; tag_it; tag_it = tag_it->next) {
|
|
|
|
|
struct call_monologue *ml = tag_it->data;
|
|
|
|
|
@ -97,21 +95,42 @@ static GString *dtmf_json_print(struct media_packet *mp,
|
|
|
|
|
"\"type\":\"DTMF\",\"timestamp\":%lu,\"source_ip\":\"%s\","
|
|
|
|
|
"\"event\":%u,\"duration\":%u,\"volume\":%u}",
|
|
|
|
|
(unsigned long) rtpe_now.tv_sec,
|
|
|
|
|
sockaddr_print_buf(&mp->fsin.address),
|
|
|
|
|
(unsigned int) dtmf->event,
|
|
|
|
|
(ntohs(dtmf->duration) * (1000000 / clockrate)) / 1000,
|
|
|
|
|
(unsigned int) dtmf->volume);
|
|
|
|
|
sockaddr_print_buf(&fsin->address),
|
|
|
|
|
(unsigned int) event,
|
|
|
|
|
(ntohs(duration) * (1000000 / clockrate)) / 1000,
|
|
|
|
|
(unsigned int) volume);
|
|
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int dtmf_do_logging(void) {
|
|
|
|
|
bool dtmf_do_logging(void) {
|
|
|
|
|
if (_log_facility_dtmf || dtmf_log_sock.family || rtpe_config.dtmf_via_ng)
|
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int dtmf_event(struct media_packet *mp, str *payload, int clockrate) {
|
|
|
|
|
static void dtmf_end_event(struct call_media *media, unsigned int event, unsigned int volume,
|
|
|
|
|
unsigned int duration, const endpoint_t *fsin, int clockrate, bool rfc_event)
|
|
|
|
|
{
|
|
|
|
|
if (!clockrate)
|
|
|
|
|
clockrate = 8000;
|
|
|
|
|
|
|
|
|
|
GString *buf = dtmf_json_print(media, event, volume, duration, fsin, clockrate);
|
|
|
|
|
|
|
|
|
|
if (_log_facility_dtmf)
|
|
|
|
|
dtmflog(buf);
|
|
|
|
|
if (dtmf_log_sock.family)
|
|
|
|
|
if (send(dtmf_log_sock.fd, buf->str, buf->len, 0) < 0)
|
|
|
|
|
ilog(LOG_ERR, "Error sending DTMF event info to UDP socket: %s",
|
|
|
|
|
strerror(errno));
|
|
|
|
|
|
|
|
|
|
if (rtpe_config.dtmf_via_ng)
|
|
|
|
|
dtmf_bencode_and_notify(media, event, volume, duration, fsin, clockrate);
|
|
|
|
|
g_string_free(buf, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int dtmf_event_packet(struct media_packet *mp, str *payload, int clockrate) {
|
|
|
|
|
struct telephone_event_payload *dtmf;
|
|
|
|
|
if (payload->len < sizeof(*dtmf)) {
|
|
|
|
|
ilog(LOG_WARN | LOG_FLAG_LIMIT, "Short DTMF event packet (len %zu)", payload->len);
|
|
|
|
|
@ -119,30 +138,18 @@ int dtmf_event(struct media_packet *mp, str *payload, int clockrate) {
|
|
|
|
|
}
|
|
|
|
|
dtmf = (void *) payload->s;
|
|
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "DTMF event: event %u, volume %u, end %u, duration %u",
|
|
|
|
|
ilog(LOG_DEBUG, "DTMF event packet: event %u, volume %u, end %u, duration %u",
|
|
|
|
|
dtmf->event, dtmf->volume, dtmf->end, ntohs(dtmf->duration));
|
|
|
|
|
|
|
|
|
|
int ret = dtmf->end ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
GString *buf = NULL;
|
|
|
|
|
|
|
|
|
|
if (dtmf_do_logging())
|
|
|
|
|
buf = dtmf_json_print(mp, dtmf, clockrate);
|
|
|
|
|
if (!dtmf->end)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (buf) {
|
|
|
|
|
if (_log_facility_dtmf)
|
|
|
|
|
dtmflog(buf);
|
|
|
|
|
if (dtmf_log_sock.family)
|
|
|
|
|
if (send(dtmf_log_sock.fd, buf->str, buf->len, 0) < 0)
|
|
|
|
|
ilog(LOG_ERR, "Error sending DTMF event info to UDP socket: %s",
|
|
|
|
|
strerror(errno));
|
|
|
|
|
if (!dtmf_do_logging())
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (rtpe_config.dtmf_via_ng)
|
|
|
|
|
dtmf_bencode_and_notify(mp, dtmf, clockrate);
|
|
|
|
|
g_string_free(buf, TRUE);
|
|
|
|
|
}
|
|
|
|
|
dtmf_end_event(mp->media, dtmf->event, dtmf->volume, dtmf->duration, &mp->fsin, clockrate, true);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dtmf_event_free(void *e) {
|
|
|
|
|
|