|
|
|
|
@ -125,14 +125,16 @@ bool dtmf_do_logging(void) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// media->dtmf_lock must be held
|
|
|
|
|
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, uint64_t ts)
|
|
|
|
|
{
|
|
|
|
|
if (!clockrate)
|
|
|
|
|
clockrate = 8000;
|
|
|
|
|
|
|
|
|
|
media->dtmf_code = 0;
|
|
|
|
|
media->dtmf_end = ts;
|
|
|
|
|
struct dtmf_event *ev = g_slice_alloc0(sizeof(*ev));
|
|
|
|
|
*ev = (struct dtmf_event) { .code = 0, .ts = ts, .volume = 0 };
|
|
|
|
|
g_queue_push_tail(&media->dtmf_recv, ev);
|
|
|
|
|
|
|
|
|
|
if (!dtmf_do_logging())
|
|
|
|
|
return;
|
|
|
|
|
@ -186,6 +188,7 @@ static void dtmf_trigger_unset(struct call *c, void *mlp) {
|
|
|
|
|
rwlock_unlock_w(&c->master_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// dtmf_lock must be held
|
|
|
|
|
static void dtmf_check_trigger(struct call_media *media, char event, uint64_t ts, int clockrate) {
|
|
|
|
|
struct call_monologue *ml = media->monologue;
|
|
|
|
|
|
|
|
|
|
@ -198,8 +201,10 @@ static void dtmf_check_trigger(struct call_media *media, char event, uint64_t ts
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// check delay from previous event
|
|
|
|
|
if (media->dtmf_start) {
|
|
|
|
|
uint32_t ts_diff = ts - media->dtmf_start;
|
|
|
|
|
// dtmf_lock already held
|
|
|
|
|
struct dtmf_event *last_ev = g_queue_peek_tail(&media->dtmf_recv);
|
|
|
|
|
if (last_ev) {
|
|
|
|
|
uint32_t ts_diff = ts - last_ev->ts;
|
|
|
|
|
uint64_t ts_diff_ms = ts_diff * 1000 / clockrate;
|
|
|
|
|
if (ts_diff_ms > rtpe_config.dtmf_digit_delay) {
|
|
|
|
|
// delay too long: restart event trigger
|
|
|
|
|
@ -259,8 +264,10 @@ static void dtmf_check_trigger(struct call_media *media, char event, uint64_t ts
|
|
|
|
|
ml->dtmf_trigger_match = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void dtmf_code_event(struct call_media *media, char event, uint64_t ts, int clockrate) {
|
|
|
|
|
if (media->dtmf_code == event) // old/ongoing event
|
|
|
|
|
// media->dtmf_lock must be held
|
|
|
|
|
static void dtmf_code_event(struct call_media *media, char event, uint64_t ts, int clockrate, int volume) {
|
|
|
|
|
struct dtmf_event *ev = g_queue_peek_tail(&media->dtmf_recv);
|
|
|
|
|
if (ev && ev->code == event)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// start of new event
|
|
|
|
|
@ -268,41 +275,61 @@ static void dtmf_code_event(struct call_media *media, char event, uint64_t ts, i
|
|
|
|
|
// check trigger before setting new dtmf_start
|
|
|
|
|
dtmf_check_trigger(media, event, ts, clockrate);
|
|
|
|
|
|
|
|
|
|
media->dtmf_code = event;
|
|
|
|
|
media->dtmf_start = ts;
|
|
|
|
|
media->dtmf_end = 0;
|
|
|
|
|
media->dtmf_event_state = 0;
|
|
|
|
|
ev = g_slice_alloc0(sizeof(*ev));
|
|
|
|
|
*ev = (struct dtmf_event) { .code = event, .ts = ts, .volume = volume };
|
|
|
|
|
g_queue_push_tail(&media->dtmf_recv, ev);
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&media->dtmf_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool is_in_dtmf_event(struct call_media *media, uint32_t ts, int clockrate, unsigned int head,
|
|
|
|
|
bool is_in_dtmf_event(GQueue *events, uint32_t ts, int clockrate, unsigned int head,
|
|
|
|
|
unsigned int trail)
|
|
|
|
|
{
|
|
|
|
|
if (!clockrate)
|
|
|
|
|
clockrate = 8000;
|
|
|
|
|
uint32_t cutoff = clockrate * 10;
|
|
|
|
|
uint32_t neg = ~(clockrate * 100);
|
|
|
|
|
|
|
|
|
|
uint32_t start_ts = ts + head * clockrate / 1000;
|
|
|
|
|
uint32_t end_ts = ts - trail * clockrate / 1000;
|
|
|
|
|
|
|
|
|
|
if (!media->dtmf_start)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (media->dtmf_code) {
|
|
|
|
|
// active event. is it current?
|
|
|
|
|
uint32_t start_diff = start_ts - media->dtmf_start;
|
|
|
|
|
if (start_diff > clockrate * 10)
|
|
|
|
|
return false; // outdated start TS
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// event has already ended. did it just end now?
|
|
|
|
|
uint32_t end_diff = media->dtmf_end - end_ts;
|
|
|
|
|
if (end_diff > clockrate * 10)
|
|
|
|
|
return false; // bad or old end TS
|
|
|
|
|
// go backwards through our list of DTMF events
|
|
|
|
|
for (GList *l = events->tail; l; l = l->prev) {
|
|
|
|
|
struct dtmf_event *ev = l->data;
|
|
|
|
|
uint32_t ts = ev->ts; // truncate to 32 bits
|
|
|
|
|
if (ev->code) {
|
|
|
|
|
// start event: check TS against our shifted start TS.
|
|
|
|
|
// start_ts must be larger than ts, but not much larger.
|
|
|
|
|
uint32_t start_diff = start_ts - ts;
|
|
|
|
|
// much too large? that means start_ts < ts. keep looking, we're close.
|
|
|
|
|
if (start_diff >= neg)
|
|
|
|
|
continue;
|
|
|
|
|
// diff >= 0 and less than 10 seconds? that's a match.
|
|
|
|
|
if (start_diff <= cutoff)
|
|
|
|
|
return true;
|
|
|
|
|
// anything else is a bad/outdated TS. stop.
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// stop event: check TS against our shifted end TS.
|
|
|
|
|
uint32_t end_diff = end_ts - ts;
|
|
|
|
|
if (end_diff >= neg)
|
|
|
|
|
continue;
|
|
|
|
|
if (end_diff == 0) // for end events, we wait until after the end
|
|
|
|
|
continue;
|
|
|
|
|
if (end_diff <= cutoff)
|
|
|
|
|
return false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// media->dtmf_lock must be held
|
|
|
|
|
int dtmf_event_packet(struct media_packet *mp, str *payload, int clockrate, uint64_t ts) {
|
|
|
|
|
struct telephone_event_payload *dtmf;
|
|
|
|
|
if (payload->len < sizeof(*dtmf)) {
|
|
|
|
|
@ -315,7 +342,7 @@ int dtmf_event_packet(struct media_packet *mp, str *payload, int clockrate, uint
|
|
|
|
|
dtmf->event, dtmf->volume, dtmf->end, ntohs(dtmf->duration));
|
|
|
|
|
|
|
|
|
|
if (!dtmf->end) {
|
|
|
|
|
dtmf_code_event(mp->media, dtmf_code_to_char(dtmf->event), ts, clockrate);
|
|
|
|
|
dtmf_code_event(mp->media, dtmf_code_to_char(dtmf->event), ts, clockrate, dtmf->volume);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -350,6 +377,8 @@ void dtmf_dsp_event(const struct dtmf_event *new_event, struct dtmf_event *cur_e
|
|
|
|
|
|
|
|
|
|
unsigned int duration = cur_event.ts - new_event->ts;
|
|
|
|
|
|
|
|
|
|
LOCK(&media->dtmf_lock);
|
|
|
|
|
|
|
|
|
|
if (end_event) {
|
|
|
|
|
ilog(LOG_DEBUG, "DTMF DSP end event: event %u, volume %u, duration %u",
|
|
|
|
|
cur_event.code, cur_event.volume, duration);
|
|
|
|
|
@ -362,7 +391,7 @@ void dtmf_dsp_event(const struct dtmf_event *new_event, struct dtmf_event *cur_e
|
|
|
|
|
new_event->code, new_event->volume, duration);
|
|
|
|
|
int code = dtmf_code_from_char(new_event->code); // for validation
|
|
|
|
|
if (code != -1)
|
|
|
|
|
dtmf_code_event(media, (char) new_event->code, ts, clockrate);
|
|
|
|
|
dtmf_code_event(media, (char) new_event->code, ts, clockrate, new_event->volume);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|