# HG changeset patch # User Mychaela Falconia # Date 1709851181 0 # Node ID d180987db615e85f3f4b209087f8051c1be14ab7 # Parent 9b0613775cf62cf0d9605bc8eb1b89337853a282 new program rtp-stream-gen diff -r 9b0613775cf6 -r d180987db615 .hgignore --- 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$ diff -r 9b0613775cf6 -r d180987db615 Makefile --- 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 diff -r 9b0613775cf6 -r d180987db615 rtp-stream-gen.c --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +}