changeset 8:d180987db615

new program rtp-stream-gen
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 07 Mar 2024 22:39:41 +0000
parents 9b0613775cf6
children c00510e1ae8b
files .hgignore Makefile rtp-stream-gen.c
diffstat 3 files changed, 167 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Sat Jul 08 20:47:29 2023 +0000
+++ b/.hgignore	Thu Mar 07 22:39:41 2024 +0000
@@ -8,4 +8,5 @@
 ^rtp-gsmfr-extr$
 ^rtp-jitter-view$
 ^rtp-stream-dump$
+^rtp-stream-gen$
 ^rtp-tfo-trace$
--- a/Makefile	Sat Jul 08 20:47:29 2023 +0000
+++ b/Makefile	Thu Mar 07 22:39:41 2024 +0000
@@ -1,7 +1,7 @@
 CC=	gcc
 CFLAGS=	-O2
 PROGS=	rtp-cont-check rtp-g711-extr rtp-gsmfr-dump rtp-gsmfr-extr \
-	rtp-jitter-view rtp-stream-dump rtp-tfo-trace
+	rtp-jitter-view rtp-stream-dump rtp-stream-gen rtp-tfo-trace
 INSTBIN=/opt/freecalypso/bin
 
 all:	${PROGS}
@@ -24,6 +24,9 @@
 rtp-stream-dump:	rtp-stream-dump.c
 	${CC} ${CFLAGS} -o $@ $@.c -lpcap
 
+rtp-stream-gen:	rtp-stream-gen.c
+	${CC} ${CFLAGS} -o $@ $@.c
+
 rtp-tfo-trace:	rtp-tfo-trace.c
 	${CC} ${CFLAGS} -o $@ $@.c -lpcap
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rtp-stream-gen.c	Thu Mar 07 22:39:41 2024 +0000
@@ -0,0 +1,162 @@
+/*
+ * This program generates a dummy RTP stream, sending RTP packets with
+ * a dummy payload to the specified destination IP:port, paced in time
+ * every 20 ms.  The purpose is to test the behaviour of affordably-available
+ * Internet connections when presented with such traffic: the intent is
+ * to capture this packet stream on the receiving end with tcpdump and then
+ * analyze the pcap for problem signs of packet loss, jitter and reordering.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#define	RTP_PACKET_HDR_SIZE	12
+#define	RTP_MAX_PAYLOAD		160
+#define	GSM_FR_BYTES		33
+
+struct rtp_packet {
+	uint8_t		v_p_x_cc;
+	uint8_t		m_pt;
+	uint16_t	seq;
+	uint32_t	tstamp;
+	uint32_t	ssrc;
+	uint8_t		payload[RTP_MAX_PAYLOAD];
+};
+
+static const uint8_t gsmfr_silence_frame[GSM_FR_BYTES] = {
+	0xDA, 0xA7, 0xAA, 0xA5, 0x1A,
+	0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B,
+	0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B,
+	0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B,
+	0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B,
+};
+
+static struct sockaddr_in sin_src, sin_dest;
+static struct rtp_packet rtp_pkt;
+static unsigned rtp_pkt_len, req_packet_count;
+static int udp_fd;
+
+static void
+parse_ip_port(arg, sin)
+	char *arg;
+	struct sockaddr_in *sin;
+{
+	char *cp;
+	int rc;
+
+	cp = index(arg, ':');
+	if (!cp) {
+		fprintf(stderr, "error: missing ':' in IP:port argument\n");
+		exit(1);
+	}
+	*cp++ = '\0';
+	sin->sin_family = AF_INET;
+	rc = inet_aton(arg, &sin->sin_addr);
+	if (!rc) {
+		fprintf(stderr, "error: invalid IP address argument\n");
+		exit(1);
+	}
+	sin->sin_port = htons(atoi(cp));
+}
+
+static void
+prepare_rtp_payload(type_arg)
+	char *type_arg;
+{
+	unsigned pl_len;
+
+	if (!strcmp(type_arg, "pcmu")) {
+		rtp_pkt.m_pt = 0;
+		memset(rtp_pkt.payload, 0xFF, RTP_MAX_PAYLOAD);
+		pl_len = RTP_MAX_PAYLOAD;
+	} else if (!strcmp(type_arg, "pcma")) {
+		rtp_pkt.m_pt = 8;
+		memset(rtp_pkt.payload, 0xD5, RTP_MAX_PAYLOAD);
+		pl_len = RTP_MAX_PAYLOAD;
+	} else if (!strcmp(type_arg, "gsm")) {
+		rtp_pkt.m_pt = 3;
+		memcpy(rtp_pkt.payload, gsmfr_silence_frame, GSM_FR_BYTES);
+		pl_len = GSM_FR_BYTES;
+	} else {
+		fprintf(stderr, "error: invalid PL type argument \"%s\"\n",
+			type_arg);
+		exit(1);
+	}
+	rtp_pkt_len = RTP_PACKET_HDR_SIZE + pl_len;
+}
+
+static void
+assign_rtpout_ssrc()
+{
+	struct timeval curtime;
+
+	gettimeofday(&curtime, 0);
+	rtp_pkt.ssrc = curtime.tv_sec ^ curtime.tv_usec ^ getpid();
+}
+
+static void
+prepare_udp_socket()
+{
+	int rc;
+
+	udp_fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (udp_fd < 0) {
+		perror("socket(AF_INET, SOCK_DGRAM, 0)");
+		exit(1);
+	}
+	rc = bind(udp_fd, (struct sockaddr *) &sin_src, sizeof sin_src);
+	if (rc < 0) {
+		perror("bind");
+		exit(1);
+	}
+	rc = connect(udp_fd, (struct sockaddr *) &sin_dest, sizeof sin_dest);
+	if (rc < 0) {
+		perror("connect");
+		exit(1);
+	}
+}
+
+static void
+send_out_packets()
+{
+	unsigned n, seq, ts;
+
+	seq = 0;
+	ts = 0;
+	for (n = 0; n < req_packet_count; n++) {
+		rtp_pkt.seq = htons(seq);
+		rtp_pkt.tstamp = htonl(ts);
+		send(udp_fd, &rtp_pkt, rtp_pkt_len, 0);
+		seq++;
+		ts += 160;
+		usleep(20000);
+	}
+}
+
+main(argc, argv)
+	char **argv;
+{
+	if (argc != 5) {
+		fprintf(stderr, "usage: %s src-IP:port dest-IP:port type num\n",
+			argv[0]);
+		exit(1);
+	}
+	parse_ip_port(argv[1], &sin_src);
+	parse_ip_port(argv[2], &sin_dest);
+	prepare_rtp_payload(argv[3]);
+	rtp_pkt.v_p_x_cc = 0x80;
+	assign_rtpout_ssrc();
+	req_packet_count = atoi(argv[4]);
+	prepare_udp_socket();
+	send_out_packets();
+	exit(0);
+}