diff mgw/dtmf_ctrl.c @ 127:f062c32a5116

mgw: implement DTMF
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 01 Oct 2022 20:31:15 -0800
parents
children 529906fddcfa
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mgw/dtmf_ctrl.c	Sat Oct 01 20:31:15 2022 -0800
@@ -0,0 +1,137 @@
+/*
+ * In this module we implement start/stop control of DTMF generation
+ * toward PSTN on GSM-to-PSTN gateway endpoints.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <syslog.h>
+#include "../include/tmgw_ctrl.h"
+#include "../include/tmgw_const.h"
+#include "struct.h"
+#include "int_defs.h"
+#include "dtmf_defs.h"
+
+extern struct endpoint *find_ep_by_id();
+
+extern struct timeval cur_event_time;
+extern struct dtmf_desc dtmf_table[];
+extern int dtmf_timer_running;
+
+struct endpoint *dtmf_list_head;
+
+static void
+add_to_dtmf_list(new_ep)
+	struct endpoint *new_ep;
+{
+	struct endpoint *ep, **epp;
+
+	for (epp = &dtmf_list_head; *epp; epp = &ep->dtmf_next)
+		;
+	*epp = new_ep;
+	new_ep->dtmf_pp = epp;
+}
+
+void
+dtmf_stop_immediate(ep)
+	struct endpoint *ep;
+{
+	if (ep->dtmf_frames_sent)
+		ep->dtmf_aftermath = 1;
+	*ep->dtmf_pp = ep->dtmf_next;
+	if (ep->dtmf_next)
+		ep->dtmf_next->dtmf_pp = ep->dtmf_pp;
+	ep->dtmf_pp = 0;
+	ep->dtmf_next = 0;
+	if (!dtmf_list_head)
+		dtmf_timer_running = 0;
+}
+
+void
+process_dtmf_start(conn, req, resp)
+	struct ctrl_conn *conn;
+	struct tmgw_ctrl_req *req;
+	struct tmgw_ctrl_resp *resp;
+{
+	struct endpoint *ep;
+	struct dtmf_desc *desc;
+	struct timeval tv_diff;
+	unsigned delta_frames;
+
+	ep = find_ep_by_id(conn, req->ep_id);
+	if (!ep) {
+protocol_err:	resp->res = TMGW_RESP_ERR_PROT;
+		return;
+	}
+	if (ep->ep_type != TMGW_EP_TYPE_GATEWAY)
+		goto protocol_err;
+	if (!(ep->fwd_mode & TMGW_FWD_ENABLE_GSM2PSTN))
+		goto protocol_err;
+	for (desc = dtmf_table; desc->digit; desc++)
+		if (desc->digit == req->fwd_mode)
+			break;
+	if (!desc->digit) {
+		resp->res = TMGW_RESP_ERR_PARAM;
+		return;
+	}
+	if (ep->dtmf_pp) {
+		resp->res = TMGW_RESP_ERR_BUSY;
+		return;
+	}
+	if (!ep->g2p_state) {
+		resp->res = TMGW_RESP_ERR_NOTRDY;
+		return;
+	}
+	/* figure out starting timestamp */
+	if (!ep->dtmf_aftermath)
+		ep->dtmf_last_ts = ep->g2p_last_ts;
+	ep->dtmf_m_bit = 0;
+	if (timercmp(&cur_event_time, &ep->g2p_local_time, >)) {
+		timersub(&cur_event_time, &ep->g2p_local_time, &tv_diff);
+		delta_frames = tv_diff.tv_sec * 50 + tv_diff.tv_usec / 20000;
+		if (delta_frames) {
+			ep->dtmf_last_ts += delta_frames * SAMPLES_PER_FRAME;
+			ep->dtmf_m_bit = 1;
+		}
+	}
+	/* initialize other state vars */
+	ep->dtmf_frames_sent = 0;
+	ep->dtmf_sample_ptr = desc->samples;
+	ep->dtmf_stop_req = 0;
+	/* link it and start it */
+	add_to_dtmf_list(ep);
+	start_dtmf_timer();
+	/* return success */
+	resp->res = TMGW_RESP_OK;
+}
+
+void
+process_dtmf_stop(conn, req, resp)
+	struct ctrl_conn *conn;
+	struct tmgw_ctrl_req *req;
+	struct tmgw_ctrl_resp *resp;
+{
+	struct endpoint *ep;
+
+	ep = find_ep_by_id(conn, req->ep_id);
+	if (!ep) {
+protocol_err:	resp->res = TMGW_RESP_ERR_PROT;
+		return;
+	}
+	if (ep->ep_type != TMGW_EP_TYPE_GATEWAY)
+		goto protocol_err;
+	/* return OK whether we stop a tone or if there was none running */
+	resp->res = TMGW_RESP_OK;
+	if (ep->dtmf_pp) {
+		ep->dtmf_stop_req = 1;
+		if (ep->dtmf_frames_sent >= DTMF_MIN_FRAMES)
+			dtmf_stop_immediate(ep);
+	}
+}