FreeCalypso > hg > themwi-system-sw
view mgw/gsm2pstn.c @ 216:6aa2cd650943
tcpserv-dump: specify bind IP on the command line
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 24 Jul 2023 22:19:08 -0800 |
parents | 0047c4c08d9e |
children |
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 <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 <gsm_fr_preproc.h> #include <gsm_efr.h> #include "../include/codec_defs.h" #include "../include/rtp_defs.h" #include "../include/tmgw_ctrl.h" #include "../include/tmgw_const.h" #include "struct.h" #include "select.h" #include "int_defs.h" #include "dtmf_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; unsigned pktsize; int16_t seq_delta; int32_t ts_delta; uint8_t codec_frame[GSM_FR_BYTES]; int16_t pcm_samples[SAMPLES_PER_FRAME]; int rc, bfi, bfi_nodata, taf, m_out; addrlen = sizeof(struct sockaddr_in); rc = recvfrom(in_fd, &pkt, sizeof pkt, 0, (struct sockaddr *) &sin_from, &addrlen); if (rc < 0) return; pktsize = rc; 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 (pktsize < RTP_PACKET_HDR_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; pktsize -= RTP_PACKET_HDR_SIZE; if (!pktsize) { /* zero length payload */ bfi = bfi_nodata = 1; taf = 0; } else if (pktsize == ep->gsm_payload_len && (pkt.payload[0] & 0xF0) == ep->gsm_payload_magic) { /* standard RFC 3551 or TS 101 318 payload */ bfi = bfi_nodata = 0; taf = 0; bcopy(pkt.payload, codec_frame, pktsize); } else if (pktsize == 2 && pkt.payload[0] == 0xBF) { /* old BFI marker */ bfi = bfi_nodata = 1; taf = pkt.payload[1] & 1; } else if ((pkt.payload[0] & 0xF0) == 0xE0) { /* new TRAUlike RTP payload format */ bfi_nodata = (pkt.payload[0] & 0x04) >> 2; bfi = (pkt.payload[0] & 0x02) >> 1; taf = pkt.payload[0] & 0x01; if (bfi_nodata) { if (!bfi) goto bad_rtp_pkt; if (pktsize != 1) goto bad_rtp_pkt; } else { if (pktsize != ep->gsm_payload_len + 1) goto bad_rtp_pkt; if ((pkt.payload[1] & 0xF0) != ep->gsm_payload_magic) goto bad_rtp_pkt; bcopy(pkt.payload+1, codec_frame, ep->gsm_payload_len); } } else 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) { 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 = 0; } 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: if (bfi) gsmfr_preproc_bfi(ep->gsm_decoder_extra_state, taf, codec_frame); else gsmfr_preproc_good_frame(ep->gsm_decoder_extra_state, codec_frame); gsm_decode(ep->gsm_decoder_state, codec_frame, pcm_samples); break; case GSM_TCHF_FRAME_EFR: if (bfi_nodata) EFR_decode_bfi_nodata(ep->gsm_decoder_state, taf, pcm_samples); else EFR_decode_frame(ep->gsm_decoder_state, codec_frame, bfi, taf, pcm_samples); break; } if (ep->dtmf_sample_ptr) { bcopy(ep->dtmf_sample_ptr, pcm_samples, SAMPLES_PER_FRAME*2); ep->dtmf_sample_ptr += SAMPLES_PER_FRAME; ep->dtmf_frames_sent++; if (ep->dtmf_frames_sent >= DTMF_MAX_FRAMES) ep->dtmf_sample_ptr = 0; } 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; ep->gsm_decoder_extra_state = gsmfr_preproc_create(); if (!ep->gsm_decoder_extra_state) { free(ep->gsm_decoder_state); ep->gsm_decoder_state = 0; return TMGW_RESP_ERR_RSRC; } break; case GSM_TCHF_FRAME_EFR: ep->gsm_decoder_state = EFR_decoder_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; }