FreeCalypso > hg > themwi-system-sw
view mgw/gsm2pstn.c @ 118:a4450ae8fd09
sip-manual-out UAC: use the new CSeq parsing function
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 29 Sep 2022 13:03:27 -0800 |
parents | 3b3f07b112f3 |
children | f062c32a5116 |
line wrap: on
line source
/* * 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; }