FreeCalypso > hg > themwi-system-sw
view mgw/pstn2gsm.c @ 170:a6eb2de277f6
mgw: massive simplification for continuous RTP stream from BTS
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 20 Nov 2022 01:58:47 -0800 |
parents | f062c32a5116 |
children | c985c33baeac |
line wrap: on
line source
/* * In this module we implement our RTP gateway function * in the PSTN to GSM direction. */ #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 <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 = ntohl(pkt.tstamp); ep->p2g_last_seq = ntohs(pkt.seq); /* actual transcoding and forwarding */ if (!(ep->fwd_mode & TMGW_FWD_ENABLE_PSTN2GSM)) { ep->p2g_drop_flag = 1; return; } if (ep->p2g_drop_flag) { ep->p2g_drop_flag = 0; m_out = 1; } 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; pkt.seq = htons(++ep->p2g_out_seq); switch (ep->gsm_payload_msg_type) { case GSM_TCHF_FRAME: gsm_encode(ep->gsm_encoder_state, pcm_samples, pkt.payload); break; } addrlen = sizeof(struct sockaddr_in); sendto(ep->rtp_gsm.rtp_fd, &pkt, ep->gsm_rtp_pkt_size, 0, (struct sockaddr *) &ep->rtp_gsm.remote_addr, addrlen); } pstn2gsm_init(ep) struct endpoint *ep; { if (ep->gsm_encoder_state) return TMGW_RESP_OK; 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; }