comparison 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
comparison
equal deleted inserted replaced
126:815e4c59162e 127:f062c32a5116
1 /*
2 * In this module we implement start/stop control of DTMF generation
3 * toward PSTN on GSM-to-PSTN gateway endpoints.
4 */
5
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <sys/time.h>
9 #include <netinet/in.h>
10 #include <stdio.h>
11 #include <stdint.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <strings.h>
15 #include <syslog.h>
16 #include "../include/tmgw_ctrl.h"
17 #include "../include/tmgw_const.h"
18 #include "struct.h"
19 #include "int_defs.h"
20 #include "dtmf_defs.h"
21
22 extern struct endpoint *find_ep_by_id();
23
24 extern struct timeval cur_event_time;
25 extern struct dtmf_desc dtmf_table[];
26 extern int dtmf_timer_running;
27
28 struct endpoint *dtmf_list_head;
29
30 static void
31 add_to_dtmf_list(new_ep)
32 struct endpoint *new_ep;
33 {
34 struct endpoint *ep, **epp;
35
36 for (epp = &dtmf_list_head; *epp; epp = &ep->dtmf_next)
37 ;
38 *epp = new_ep;
39 new_ep->dtmf_pp = epp;
40 }
41
42 void
43 dtmf_stop_immediate(ep)
44 struct endpoint *ep;
45 {
46 if (ep->dtmf_frames_sent)
47 ep->dtmf_aftermath = 1;
48 *ep->dtmf_pp = ep->dtmf_next;
49 if (ep->dtmf_next)
50 ep->dtmf_next->dtmf_pp = ep->dtmf_pp;
51 ep->dtmf_pp = 0;
52 ep->dtmf_next = 0;
53 if (!dtmf_list_head)
54 dtmf_timer_running = 0;
55 }
56
57 void
58 process_dtmf_start(conn, req, resp)
59 struct ctrl_conn *conn;
60 struct tmgw_ctrl_req *req;
61 struct tmgw_ctrl_resp *resp;
62 {
63 struct endpoint *ep;
64 struct dtmf_desc *desc;
65 struct timeval tv_diff;
66 unsigned delta_frames;
67
68 ep = find_ep_by_id(conn, req->ep_id);
69 if (!ep) {
70 protocol_err: resp->res = TMGW_RESP_ERR_PROT;
71 return;
72 }
73 if (ep->ep_type != TMGW_EP_TYPE_GATEWAY)
74 goto protocol_err;
75 if (!(ep->fwd_mode & TMGW_FWD_ENABLE_GSM2PSTN))
76 goto protocol_err;
77 for (desc = dtmf_table; desc->digit; desc++)
78 if (desc->digit == req->fwd_mode)
79 break;
80 if (!desc->digit) {
81 resp->res = TMGW_RESP_ERR_PARAM;
82 return;
83 }
84 if (ep->dtmf_pp) {
85 resp->res = TMGW_RESP_ERR_BUSY;
86 return;
87 }
88 if (!ep->g2p_state) {
89 resp->res = TMGW_RESP_ERR_NOTRDY;
90 return;
91 }
92 /* figure out starting timestamp */
93 if (!ep->dtmf_aftermath)
94 ep->dtmf_last_ts = ep->g2p_last_ts;
95 ep->dtmf_m_bit = 0;
96 if (timercmp(&cur_event_time, &ep->g2p_local_time, >)) {
97 timersub(&cur_event_time, &ep->g2p_local_time, &tv_diff);
98 delta_frames = tv_diff.tv_sec * 50 + tv_diff.tv_usec / 20000;
99 if (delta_frames) {
100 ep->dtmf_last_ts += delta_frames * SAMPLES_PER_FRAME;
101 ep->dtmf_m_bit = 1;
102 }
103 }
104 /* initialize other state vars */
105 ep->dtmf_frames_sent = 0;
106 ep->dtmf_sample_ptr = desc->samples;
107 ep->dtmf_stop_req = 0;
108 /* link it and start it */
109 add_to_dtmf_list(ep);
110 start_dtmf_timer();
111 /* return success */
112 resp->res = TMGW_RESP_OK;
113 }
114
115 void
116 process_dtmf_stop(conn, req, resp)
117 struct ctrl_conn *conn;
118 struct tmgw_ctrl_req *req;
119 struct tmgw_ctrl_resp *resp;
120 {
121 struct endpoint *ep;
122
123 ep = find_ep_by_id(conn, req->ep_id);
124 if (!ep) {
125 protocol_err: resp->res = TMGW_RESP_ERR_PROT;
126 return;
127 }
128 if (ep->ep_type != TMGW_EP_TYPE_GATEWAY)
129 goto protocol_err;
130 /* return OK whether we stop a tone or if there was none running */
131 resp->res = TMGW_RESP_OK;
132 if (ep->dtmf_pp) {
133 ep->dtmf_stop_req = 1;
134 if (ep->dtmf_frames_sent >= DTMF_MIN_FRAMES)
135 dtmf_stop_immediate(ep);
136 }
137 }