diff test-voice/rtp_rx.c @ 0:35c0d9f03c0a

beginning with sipout-test-voice, a copy of sip-manual-out from themwi-system-sw
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 03 Mar 2024 23:20:19 -0800
parents
children 4f81b959a5f5
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-voice/rtp_rx.c	Sun Mar 03 23:20:19 2024 -0800
@@ -0,0 +1,270 @@
+/*
+ * In this module we implement our RTP handling: obtaining a PSTN-side
+ * RTP endpoint from themwi-rtp-mgr, then handling read select on RTP
+ * and RTCP UDP sockets.
+ */
+
+#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 "../include/tmgw_const.h"
+#include "../include/rtp_defs.h"
+#include "../librtpalloc/rtp_alloc_simple.h"
+
+struct sockaddr_in rtp_local_addr;
+int rtp_udp_fd, rtcp_udp_fd;
+
+static int rtp_start_flag, rtp_bad_flag, rtp_ssrc_chg_flag;
+static int rtp_seq_brk_flag, rtp_seq_zero_flag, rtp_seq_neg_flag;
+static int rtp_ts_brk_flag;
+static uint32_t rtp_ssrc;
+static uint32_t rtp_last_ts;
+static uint16_t rtp_last_seq;
+static int got_some_rtcp;
+
+static const uint8_t hdr_pattern[20] =	{0, 1, 0, 1, 0, 1, 1, 0, 1, 0,
+					 0, 1, 1, 0, 1, 0, 1, 0, 0, 1};
+
+static uint8_t is_hunt_buf[320];
+static int is_state;
+static unsigned is_offset, is_bit_count, is_hunt_fill;
+static uint32_t is_rx_word;
+
+static void
+reset_is_hunt()
+{
+	is_state = 0;
+	is_hunt_fill = 0;
+}
+
+static void
+is_rx_hunt(input_pos)
+	unsigned input_pos;
+{
+	unsigned offset, n;
+
+	for (offset = 0; offset < 16; offset++) {
+		for (n = 0; n < 20; n++)
+			if ((is_hunt_buf[offset + n*16] & 1) != hdr_pattern[n])
+				break;
+		if (n == 20)
+			break;
+	}
+	if (n != 20)
+		return;
+	printf("Found IS_Header, last bit offset %u\n",
+		input_pos * 16 + offset);
+	is_offset = offset;
+	is_state = 1;
+	is_bit_count = 0;
+	is_rx_word = 0;
+	is_hunt_fill = 0;
+}
+
+static void
+is_process_cmd()
+{
+	int cont;
+
+	printf("IS_Command: 0x%03X", is_rx_word);
+	switch (is_rx_word) {
+	case 0x05D:
+		printf(" (REQ)\n");
+		cont = 1;
+		break;
+	case 0x0BA:
+		printf(" (ACK)\n");
+		cont = 1;
+		break;
+	case 0x0E7:
+		printf(" (IPE)\n");
+		cont = 1;
+		break;
+	case 0x129:
+		printf(" (FILL)\n");
+		cont = 0;
+		break;
+	case 0x174:
+		printf(" (DUP)\n");
+		cont = 0;
+		break;
+	case 0x193:
+		printf(" (SYL)\n");
+		cont = 0;
+		break;
+	default:
+		printf(" (bad)\n");
+		cont = 0;
+	}
+	if (cont) {
+		is_state = 2;
+		is_bit_count = 0;
+		is_rx_word = 0;
+	} else
+		is_state = 0;
+}
+
+static void
+is_process_ext()
+{
+	printf("IS_Extension: 0x%05X", is_rx_word);
+	if (is_rx_word & 0x80200) {
+		printf(" (bad sync)\n");
+		is_state = 0;
+		return;
+	}
+	switch (is_rx_word & 3) {
+	case 0:
+		printf(" (final)\n");
+		is_state = 0;
+		return;
+	case 3:
+		printf(" (continue)\n");
+		is_state = 2;
+		is_bit_count = 0;
+		is_rx_word = 0;
+		return;
+	default:
+		printf(" (bad EX)\n");
+		is_state = 0;
+	}
+}
+
+static void
+is_rx_process(input, input_pos)
+	uint8_t *input;
+	unsigned input_pos;
+{
+	unsigned new_bit;
+
+	memmove(is_hunt_buf, is_hunt_buf + 16, 304);
+	memcpy(is_hunt_buf + 304, input, 16);
+	if (!is_state) {
+		if (is_hunt_fill < 20)
+			is_hunt_fill++;
+		if (is_hunt_fill == 20)
+			is_rx_hunt(input_pos);
+		return;
+	}
+	new_bit = input[is_offset] & 1;
+	is_rx_word <<= 1;
+	is_rx_word |= new_bit;
+	is_bit_count++;
+	if (is_state == 1 && is_bit_count == 10)
+		is_process_cmd();
+	else if (is_state == 2 && is_bit_count == 20)
+		is_process_ext();
+}
+
+void
+obtain_rtp_endp()
+{
+	int rc;
+	struct rtp_alloc_simple res;
+
+	rc = rtp_alloc_simple(TMGW_EP_TYPE_PSTN_ONLY, &res);
+	if (rc < 0)
+		exit(1);	/* error msg already printed */
+	bcopy(&res.pstn_addr, &rtp_local_addr, sizeof(struct sockaddr_in));
+	rtp_udp_fd = res.pstn_rtp_fd;
+	rtcp_udp_fd = res.pstn_rtcp_fd;
+	reset_is_hunt();
+}
+
+void
+rtp_rx_select()
+{
+	struct rtp_packet pkt;
+	struct sockaddr_in sin_from;
+	socklen_t addrlen;
+	int16_t seq_delta;
+	int32_t ts_delta;
+	int rc;
+	unsigned is_chunk;
+
+	addrlen = sizeof(struct sockaddr_in);
+	rc = recvfrom(rtp_udp_fd, &pkt, sizeof pkt, 0,
+			(struct sockaddr *) &sin_from, &addrlen);
+	if (rc < 0)
+		return;
+	if (rc != RTP_PACKET_SIZE_PSTN) {
+bad_rtp_pkt:	if (!rtp_bad_flag) {
+			printf("Got a bad RTP packet\n");
+			rtp_bad_flag = 1;
+		}
+		return;
+	}
+	if (pkt.v_p_x_cc != 0x80)
+		goto bad_rtp_pkt;
+	switch (pkt.m_pt & 0x7F) {
+	case PSTN_CODEC_PCMU:
+	case PSTN_CODEC_PCMA:
+		break;
+	default:
+		goto bad_rtp_pkt;
+	}
+	if (rtp_start_flag && pkt.ssrc != rtp_ssrc) {
+		if (!rtp_ssrc_chg_flag) {
+			printf("Rx RTP stream changed SSRC\n");
+			rtp_ssrc_chg_flag = 1;
+		}
+		reset_is_hunt();
+	} else if (rtp_start_flag) {
+		seq_delta = ntohs(pkt.seq) - rtp_last_seq;
+		ts_delta = ntohl(pkt.tstamp) - rtp_last_ts;
+		if (seq_delta == 0) {
+			if (!rtp_seq_zero_flag) {
+				printf("Rx RTP seq zero increment\n");
+				rtp_seq_zero_flag = 1;
+			}
+			return;
+		}
+		if (seq_delta < 0) {
+			if (!rtp_seq_neg_flag) {
+				printf("Rx RTP seq negative increment\n");
+				rtp_seq_neg_flag = 1;
+			}
+			return;
+		}
+		if (seq_delta != 1) {
+			if (!rtp_seq_brk_flag) {
+				printf("Rx RTP stream seq break\n");
+				rtp_seq_brk_flag = 1;
+			}
+			reset_is_hunt();
+		} else if (ts_delta != 160) {
+			if (!rtp_ts_brk_flag) {
+				printf("Rx RTP stream tstamp break\n");
+				rtp_ts_brk_flag = 1;
+			}
+			reset_is_hunt();
+		}
+	}
+	rtp_ssrc = pkt.ssrc;
+	rtp_last_ts = ntohl(pkt.tstamp);
+	rtp_last_seq = ntohs(pkt.seq);
+	if (!rtp_start_flag) {
+		printf("Rx RTP stream begins with seq=%u ts=%u\n",
+			rtp_last_seq, rtp_last_ts);
+		rtp_start_flag = 1;
+	}
+	for (is_chunk = 0; is_chunk < 10; is_chunk++)
+		is_rx_process(pkt.payload + is_chunk * 16, is_chunk);
+}
+
+void
+rtcp_rx_select()
+{
+	u_char buf[512];
+
+	recv(rtcp_udp_fd, buf, sizeof buf, 0);
+	if (!got_some_rtcp) {
+		printf("Got some RTCP\n");
+		got_some_rtcp = 1;
+	}
+}