# HG changeset patch # User Mychaela Falconia # Date 1664685075 28800 # Node ID f062c32a5116d579c2aba3ebb555d84415df3fa7 # Parent 815e4c59162e33507596dc0daf12e8e34369a29e mgw: implement DTMF diff -r 815e4c59162e -r f062c32a5116 include/tmgw_ctrl.h --- a/include/tmgw_ctrl.h Sat Oct 01 17:09:51 2022 -0800 +++ b/include/tmgw_ctrl.h Sat Oct 01 20:31:15 2022 -0800 @@ -40,3 +40,5 @@ #define TMGW_RESP_ERR_OPCODE 3 #define TMGW_RESP_ERR_PARAM 4 #define TMGW_RESP_ERR_NOTSUP 5 +#define TMGW_RESP_ERR_BUSY 6 +#define TMGW_RESP_ERR_NOTRDY 7 diff -r 815e4c59162e -r f062c32a5116 mgw/Makefile --- a/mgw/Makefile Sat Oct 01 17:09:51 2022 -0800 +++ b/mgw/Makefile Sat Oct 01 20:31:15 2022 -0800 @@ -1,9 +1,9 @@ CC= gcc CFLAGS= -O2 PROG= themwi-mgw -OBJS= crcx.o ctrl_prot.o ctrl_sock.o dlcx.o dtmf_init.o dtmf_table.o \ - g711_decode.o g711_encode.o gsm2pstn.o main.o mdcx.o pstn2gsm.o \ - readconf.o udpsink.o +OBJS= crcx.o ctrl_prot.o ctrl_sock.o dlcx.o dtmf_ctrl.o dtmf_init.o \ + dtmf_table.o dtmf_timer.o g711_decode.o g711_encode.o gsm2pstn.o main.o\ + mdcx.o pstn2gsm.o readconf.o udpsink.o LIBS= ../libutil/libutil.a INSTBIN=/usr/local/bin diff -r 815e4c59162e -r f062c32a5116 mgw/crcx.c --- a/mgw/crcx.c Sat Oct 01 17:09:51 2022 -0800 +++ b/mgw/crcx.c Sat Oct 01 20:31:15 2022 -0800 @@ -4,6 +4,7 @@ #include #include +#include #include #include #include diff -r 815e4c59162e -r f062c32a5116 mgw/ctrl_prot.c --- a/mgw/ctrl_prot.c Sat Oct 01 17:09:51 2022 -0800 +++ b/mgw/ctrl_prot.c Sat Oct 01 20:31:15 2022 -0800 @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -59,6 +60,12 @@ case TMGW_CTRL_OP_DLCX: process_dlcx(conn, &req, &resp); break; + case TMGW_CTRL_OP_DTMF_START: + process_dtmf_start(conn, &req, &resp); + break; + case TMGW_CTRL_OP_DTMF_STOP: + process_dtmf_stop(conn, &req, &resp); + break; default: resp.res = TMGW_RESP_ERR_OPCODE; } diff -r 815e4c59162e -r f062c32a5116 mgw/ctrl_sock.c --- a/mgw/ctrl_sock.c Sat Oct 01 17:09:51 2022 -0800 +++ b/mgw/ctrl_sock.c Sat Oct 01 20:31:15 2022 -0800 @@ -4,7 +4,7 @@ */ #include -#include +#include #include #include #include diff -r 815e4c59162e -r f062c32a5116 mgw/dlcx.c --- a/mgw/dlcx.c Sat Oct 01 17:09:51 2022 -0800 +++ b/mgw/dlcx.c Sat Oct 01 20:31:15 2022 -0800 @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -79,6 +80,8 @@ for (ep = delq; ep; ep = np) { np = ep->next; + if (ep->dtmf_pp) + dtmf_stop_immediate(ep); if (ep->ep_type & TMGW_EP_HAS_GSM_SOCK) free_rtp_end(&ep->rtp_gsm); if (ep->ep_type & TMGW_EP_HAS_PSTN_SOCK) diff -r 815e4c59162e -r f062c32a5116 mgw/dtmf_ctrl.c --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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); + } +} diff -r 815e4c59162e -r f062c32a5116 mgw/dtmf_timer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mgw/dtmf_timer.c Sat Oct 01 20:31:15 2022 -0800 @@ -0,0 +1,90 @@ +/* + * In this module we implement the timer function of DTMF generation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "struct.h" +#include "int_defs.h" +#include "dtmf_defs.h" + +extern struct timeval cur_event_time; +extern struct endpoint *dtmf_list_head; + +int dtmf_timer_running; +struct timeval dtmf_next_time; + +void +start_dtmf_timer() +{ + if (dtmf_timer_running) + return; + dtmf_next_time = cur_event_time; + dtmf_timer_running = 1; +} + +dtmf_timer_one(ep) + struct endpoint *ep; +{ + struct rtp_packet pkt; + socklen_t addrlen; + unsigned frame_limit; + + pkt.v_p_x_cc = 0x80; + pkt.m_pt = ep->pstn_payload_type; + if (ep->dtmf_m_bit) { + pkt.m_pt |= 0x80; + ep->dtmf_m_bit = 0; + } + pkt.seq = htons(++ep->g2p_out_seq); + ep->dtmf_last_ts += SAMPLES_PER_FRAME; + pkt.tstamp = htonl(ep->dtmf_last_ts); + pkt.ssrc = ep->g2p_ssrc; + g711_encode_frame(ep->dtmf_sample_ptr, pkt.payload, + ep->pstn_payload_type); + ep->dtmf_sample_ptr += SAMPLES_PER_FRAME; + addrlen = sizeof(struct sockaddr_in); + sendto(ep->rtp_pstn.rtp_fd, &pkt, RTP_PACKET_SIZE_PSTN, 0, + (struct sockaddr *) &ep->rtp_pstn.remote_addr, addrlen); + ep->dtmf_frames_sent++; + frame_limit = ep->dtmf_stop_req ? DTMF_MIN_FRAMES : DTMF_MAX_FRAMES; + if (ep->dtmf_frames_sent >= frame_limit) + return 1; + else + return 0; +} + +void +dtmf_timer_process() +{ + struct endpoint *ep; + int fin; + + for (ep = dtmf_list_head; ep; ep = ep->dtmf_next) { + fin = dtmf_timer_one(ep); + if (!fin) + continue; + 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_next_time.tv_usec += 20000; + if (dtmf_next_time.tv_usec >= 1000000) { + dtmf_next_time.tv_usec -= 1000000; + dtmf_next_time.tv_sec++; + } + } else + dtmf_timer_running = 0; +} diff -r 815e4c59162e -r f062c32a5116 mgw/gsm2pstn.c --- a/mgw/gsm2pstn.c Sat Oct 01 17:09:51 2022 -0800 +++ b/mgw/gsm2pstn.c Sat Oct 01 20:31:15 2022 -0800 @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -20,6 +21,8 @@ #include "select.h" #include "int_defs.h" +extern struct timeval cur_event_time; + #define ERR_WRONG_UDP_SRC 0x0001 #define ERR_BAD_RTP_PACKET 0x0002 #define ERR_SSRC_CHANGE 0x0004 @@ -71,6 +74,8 @@ ep->g2p_err_flags |= ERR_SSRC_CHANGE; } ep->g2p_state = 0; + if (ep->dtmf_pp) + dtmf_stop_immediate(ep); } if (ep->g2p_state) { seq_delta = ntohs(pkt.seq) - ep->g2p_last_seq; @@ -104,15 +109,28 @@ ep->g2p_ssrc = pkt.ssrc; ep->g2p_last_ts = ntohl(pkt.tstamp); ep->g2p_last_seq = ntohs(pkt.seq); + ep->g2p_local_time = cur_event_time; /* actual transcoding and forwarding */ if (!(ep->fwd_mode & TMGW_FWD_ENABLE_GSM2PSTN)) { ep->g2p_drop_flag = 1; return; } + if (ep->dtmf_pp) + return; if (ep->g2p_drop_flag) { ep->g2p_drop_flag = 0; m_out = 1; } + if (ep->dtmf_aftermath) { + ts_delta = ep->g2p_last_ts - ep->dtmf_last_ts; + if (ts_delta <= 0) + return; + ep->dtmf_aftermath = 0; + if (ts_delta == SAMPLES_PER_FRAME) + m_out = 0; + else + m_out = 1; + } switch (ep->gsm_payload_msg_type) { case GSM_TCHF_FRAME: gsm_decode(ep->gsm_decoder_state, pkt.payload, pcm_samples); diff -r 815e4c59162e -r f062c32a5116 mgw/main.c --- a/mgw/main.c Sat Oct 01 17:09:51 2022 -0800 +++ b/mgw/main.c Sat Oct 01 20:31:15 2022 -0800 @@ -3,6 +3,7 @@ */ #include +#include #include #include #include @@ -13,9 +14,13 @@ #include #include +extern int dtmf_timer_running; +extern struct timeval dtmf_next_time; + fd_set select_for_read; void (*select_handlers[FD_SETSIZE])(); void *select_data[FD_SETSIZE]; +struct timeval cur_event_time; static int max_fd; @@ -34,6 +39,7 @@ char **argv; { fd_set fds; + struct timeval timeout; int cc, i; openlog("themwi-mgw", 0, LOG_LOCAL5); @@ -47,19 +53,31 @@ /* main select loop */ for (;;) { bcopy(&select_for_read, &fds, sizeof(fd_set)); - cc = select(max_fd+1, &fds, 0, 0, 0); + if (dtmf_timer_running) { + if (timercmp(&dtmf_next_time, &cur_event_time, >)) + timersub(&dtmf_next_time, &cur_event_time, + &timeout); + else + timerclear(&timeout); + cc = select(max_fd+1, &fds, 0, 0, &timeout); + } else + cc = select(max_fd+1, &fds, 0, 0, 0); if (cc < 0) { if (errno == EINTR) continue; syslog(LOG_CRIT, "select: %m"); exit(1); } + gettimeofday(&cur_event_time, 0); for (i = 0; cc && i <= max_fd; i++) { if (FD_ISSET(i, &fds)) { select_handlers[i](i, select_data[i]); cc--; } } + if (dtmf_timer_running && + !timercmp(&cur_event_time, &dtmf_next_time, <)) + dtmf_timer_process(); free_deleted_endpoints(); } } diff -r 815e4c59162e -r f062c32a5116 mgw/mdcx.c --- a/mgw/mdcx.c Sat Oct 01 17:09:51 2022 -0800 +++ b/mgw/mdcx.c Sat Oct 01 20:31:15 2022 -0800 @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -87,14 +88,13 @@ ep->rtp_gsm.remote_addr.sin_family != AF_INET || ep->rtp_pstn.remote_addr.sin_family != AF_INET) return TMGW_RESP_ERR_PROT; - if ((req->fwd_mode & TMGW_FWD_ENABLE_GSM2PSTN) && - !(ep->fwd_mode & TMGW_FWD_ENABLE_GSM2PSTN)) { + if (req->fwd_mode & TMGW_FWD_ENABLE_GSM2PSTN) { rc = gsm2pstn_init(ep); if (rc != TMGW_RESP_OK) return rc; - } - if ((req->fwd_mode & TMGW_FWD_ENABLE_PSTN2GSM) && - !(ep->fwd_mode & TMGW_FWD_ENABLE_PSTN2GSM)) { + } else if (ep->dtmf_pp) + dtmf_stop_immediate(ep); + if (req->fwd_mode & TMGW_FWD_ENABLE_PSTN2GSM) { rc = pstn2gsm_init(ep); if (rc != TMGW_RESP_OK) return rc; @@ -111,7 +111,6 @@ struct tmgw_ctrl_resp *resp; { struct endpoint *ep; - int rc; ep = find_ep_by_id(conn, req->ep_id); if (!ep) { diff -r 815e4c59162e -r f062c32a5116 mgw/pstn2gsm.c --- a/mgw/pstn2gsm.c Sat Oct 01 17:09:51 2022 -0800 +++ b/mgw/pstn2gsm.c Sat Oct 01 20:31:15 2022 -0800 @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff -r 815e4c59162e -r f062c32a5116 mgw/readconf.c --- a/mgw/readconf.c Sat Oct 01 17:09:51 2022 -0800 +++ b/mgw/readconf.c Sat Oct 01 20:31:15 2022 -0800 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff -r 815e4c59162e -r f062c32a5116 mgw/struct.h --- a/mgw/struct.h Sat Oct 01 17:09:51 2022 -0800 +++ b/mgw/struct.h Sat Oct 01 20:31:15 2022 -0800 @@ -38,6 +38,14 @@ uint16_t g2p_out_seq; int g2p_drop_flag; int g2p_err_flags; + struct timeval g2p_local_time; + /* DTMF generation toward PSTN */ + unsigned dtmf_frames_sent; + uint32_t dtmf_last_ts; + int16_t *dtmf_sample_ptr; + int dtmf_m_bit; + int dtmf_stop_req; + int dtmf_aftermath; /* PSTN to GSM forwarding */ int p2g_state; uint32_t p2g_ssrc; @@ -49,6 +57,8 @@ /* linked list management */ unsigned ep_id; struct endpoint *next; + struct endpoint *dtmf_next; + struct endpoint **dtmf_pp; }; struct ctrl_conn {