FreeCalypso > hg > themwi-system-sw
diff mgw/gsm2pstn.c @ 103:3b3f07b112f3
mgw: implement GSM to PSTN forwarding
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 26 Sep 2022 20:46:19 -0800 |
parents | |
children | f062c32a5116 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mgw/gsm2pstn.c Mon Sep 26 20:46:19 2022 -0800 @@ -0,0 +1,145 @@ +/* + * In this module we implement our RTP gateway function + * in the GSM to PSTN direction. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <syslog.h> +#include <unistd.h> +#include <gsm.h> /* libgsm dependency */ +#include "../include/tmgw_ctrl.h" +#include "../include/tmgw_const.h" +#include "struct.h" +#include "select.h" +#include "int_defs.h" + +#define ERR_WRONG_UDP_SRC 0x0001 +#define ERR_BAD_RTP_PACKET 0x0002 +#define ERR_SSRC_CHANGE 0x0004 +#define ERR_SEQ_BREAK 0x0008 +#define ERR_TSTAMP_BREAK 0x0010 + +void +gsm2pstn_rtp_in(in_fd, ep) + struct endpoint *ep; +{ + struct rtp_packet pkt; + struct sockaddr_in sin_from; + socklen_t addrlen; + int16_t seq_delta; + int32_t ts_delta; + int16_t pcm_samples[SAMPLES_PER_FRAME]; + int rc, m_out; + + addrlen = sizeof(struct sockaddr_in); + rc = recvfrom(in_fd, &pkt, sizeof pkt, 0, + (struct sockaddr *) &sin_from, &addrlen); + if (rc < 0) + return; + if (sin_from.sin_addr.s_addr != ep->rtp_gsm.remote_addr.sin_addr.s_addr + || sin_from.sin_port != ep->rtp_gsm.remote_addr.sin_port) { + if (!(ep->g2p_err_flags & ERR_WRONG_UDP_SRC)) { + syslog(LOG_ERR, + "GSM RTP ep got UDP packet from wrong source"); + ep->g2p_err_flags |= ERR_WRONG_UDP_SRC; + } + return; + } + if (rc != ep->gsm_rtp_pkt_size) { +bad_rtp_pkt: if (!(ep->g2p_err_flags & ERR_BAD_RTP_PACKET)) { + syslog(LOG_ERR, "Rx bad RTP packet on GSM side"); + ep->g2p_err_flags |= ERR_BAD_RTP_PACKET; + } + return; + } + if (pkt.v_p_x_cc != 0x80) + goto bad_rtp_pkt; + if ((pkt.m_pt & 0x7F) != ep->gsm_payload_type) + goto bad_rtp_pkt; + if ((pkt.payload[0] & 0xF0) != ep->gsm_payload_magic) + goto bad_rtp_pkt; + if (ep->g2p_state && pkt.ssrc != ep->g2p_ssrc) { + if (!(ep->g2p_err_flags & ERR_SSRC_CHANGE)) { + syslog(LOG_ERR, "GSM RTP stream changed SSRC"); + ep->g2p_err_flags |= ERR_SSRC_CHANGE; + } + ep->g2p_state = 0; + } + if (ep->g2p_state) { + seq_delta = ntohs(pkt.seq) - ep->g2p_last_seq; + ts_delta = ntohl(pkt.tstamp) - ep->g2p_last_ts; + if (seq_delta <= 0) + return; /* discard old or duplicate */ + if (seq_delta != 1) { + if (!(ep->g2p_err_flags & ERR_SEQ_BREAK)) { + syslog(LOG_ERR, "GSM RTP stream seq break"); + ep->g2p_err_flags |= ERR_SEQ_BREAK; + } + m_out = 1; + } else { + if (ts_delta == SAMPLES_PER_FRAME) + m_out = 0; + else if (ts_delta > 0 && + ts_delta % SAMPLES_PER_FRAME == 0) + m_out = 1; + else { + if (!(ep->g2p_err_flags & ERR_TSTAMP_BREAK)) { + syslog(LOG_ERR, + "GSM RTP stream tstamp break"); + ep->g2p_err_flags |= ERR_TSTAMP_BREAK; + } + m_out = 1; + } + } + } else + m_out = 1; + ep->g2p_state = 1; + ep->g2p_ssrc = pkt.ssrc; + ep->g2p_last_ts = ntohl(pkt.tstamp); + ep->g2p_last_seq = ntohs(pkt.seq); + /* actual transcoding and forwarding */ + if (!(ep->fwd_mode & TMGW_FWD_ENABLE_GSM2PSTN)) { + ep->g2p_drop_flag = 1; + return; + } + if (ep->g2p_drop_flag) { + ep->g2p_drop_flag = 0; + m_out = 1; + } + switch (ep->gsm_payload_msg_type) { + case GSM_TCHF_FRAME: + gsm_decode(ep->gsm_decoder_state, pkt.payload, pcm_samples); + break; + } + pkt.m_pt = ep->pstn_payload_type; + if (m_out) + pkt.m_pt |= 0x80; + pkt.seq = htons(++ep->g2p_out_seq); + g711_encode_frame(pcm_samples, pkt.payload, ep->pstn_payload_type); + 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); +} + +gsm2pstn_init(ep) + struct endpoint *ep; +{ + if (ep->gsm_decoder_state) + return TMGW_RESP_OK; + switch (ep->gsm_payload_msg_type) { + case GSM_TCHF_FRAME: + ep->gsm_decoder_state = gsm_create(); + if (!ep->gsm_decoder_state) + return TMGW_RESP_ERR_RSRC; + break; + } + select_handlers[ep->rtp_gsm.rtp_fd] = gsm2pstn_rtp_in; + return TMGW_RESP_OK; +}