FreeCalypso > hg > themwi-system-sw
diff mgw/pstn2gsm.c @ 95:f280328e7e2e
themwi-mgw: initial implementation of PSTN to GSM forwarding
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 25 Sep 2022 19:17:44 -0800 |
parents | |
children | f24bbfd23c9d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mgw/pstn2gsm.c Sun Sep 25 19:17:44 2022 -0800 @@ -0,0 +1,140 @@ +/* + * In this module we implement our RTP gateway function + * in the PSTN to GSM 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" + +extern uint16_t pcmu_decode_table[256]; +extern uint16_t pcma_decode_table[256]; + +#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 +pstn2gsm_rtp_in(in_fd, ep) + struct endpoint *ep; +{ + struct rtp_packet pkt; + struct sockaddr_in sin_from; + socklen_t addrlen; + uint16_t *pcm_dec_table; + int16_t seq_delta; + int32_t ts_delta; + int16_t pcm_samples[SAMPLES_PER_FRAME]; + unsigned n; + 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_pstn.remote_addr.sin_addr.s_addr + || sin_from.sin_port != ep->rtp_pstn.remote_addr.sin_port) { + if (!(ep->p2g_err_flags & ERR_WRONG_UDP_SRC)) { + syslog(LOG_ERR, + "PSTN RTP ep got UDP packet from wrong source"); + ep->p2g_err_flags |= ERR_WRONG_UDP_SRC; + } + return; + } + if (rc != RTP_PACKET_SIZE_PSTN) { +bad_rtp_pkt: if (!(ep->p2g_err_flags & ERR_BAD_RTP_PACKET)) { + syslog(LOG_ERR, "Rx bad RTP packet on PSTN side"); + ep->p2g_err_flags |= ERR_BAD_RTP_PACKET; + } + return; + } + if (pkt.v_p_x_cc != 0x80) + goto bad_rtp_pkt; + switch (pkt.m_pt & 0x7F) { + case PSTN_CODEC_PCMU: + pcm_dec_table = pcmu_decode_table; + break; + case PSTN_CODEC_PCMA: + pcm_dec_table = pcma_decode_table; + break; + default: + goto bad_rtp_pkt; + } + if (ep->p2g_state && pkt.ssrc != ep->p2g_ssrc) { + if (!(ep->p2g_err_flags & ERR_SSRC_CHANGE)) { + syslog(LOG_ERR, "PSTN RTP stream changed SSRC"); + ep->p2g_err_flags |= ERR_SSRC_CHANGE; + } + ep->p2g_state = 0; + } + if (ep->p2g_state) { + seq_delta = ntohs(pkt.seq) - ep->p2g_last_seq; + ts_delta = ntohl(pkt.tstamp) - ep->p2g_last_ts; + if (seq_delta <= 0) + return; /* discard old or duplicate */ + if (seq_delta != 1) { + if (!(ep->p2g_err_flags & ERR_SEQ_BREAK)) { + syslog(LOG_ERR, "PSTN RTP stream seq break"); + ep->p2g_err_flags |= ERR_SEQ_BREAK; + } + m_out = 1; + } else if (ts_delta != SAMPLES_PER_FRAME) { + if (!(ep->p2g_err_flags & ERR_TSTAMP_BREAK)) { + syslog(LOG_ERR, "PSTN RTP stream tstamp break"); + ep->p2g_err_flags |= ERR_TSTAMP_BREAK; + } + m_out = 1; + } else + m_out = 0; + } else + m_out = 1; + ep->p2g_state = 1; + ep->p2g_ssrc = pkt.ssrc; + ep->p2g_last_ts = htonl(pkt.tstamp); + ep->p2g_last_seq = htons(pkt.seq); + /* actual transcoding and forwarding */ + for (n = 0; n < SAMPLES_PER_FRAME; n++) + pcm_samples[n] = pcm_dec_table[pkt.payload[n]]; + pkt.m_pt = ep->gsm_payload_type; + if (m_out) + pkt.m_pt |= 0x80; + switch (ep->gsm_payload_msg_type) { + case GSM_TCHF_FRAME: + gsm_encode(ep->gsm_encoder_state, pcm_samples, pkt.payload); + n = RTP_PACKET_SIZE_GSM_FR; + break; + } + addrlen = sizeof(struct sockaddr_in); + sendto(ep->rtp_gsm.rtp_fd, &pkt, n, 0, + (struct sockaddr *) &ep->rtp_gsm.remote_addr, addrlen); +} + +pstn2gsm_init(ep) + struct endpoint *ep; +{ + switch (ep->gsm_payload_msg_type) { + case GSM_TCHF_FRAME: + ep->gsm_encoder_state = gsm_create(); + if (!ep->gsm_encoder_state) + return TMGW_RESP_ERR_RSRC; + break; + } + select_handlers[ep->rtp_pstn.rtp_fd] = pstn2gsm_rtp_in; + return TMGW_RESP_OK; +}