FreeCalypso > hg > rtp-debug-utils
view rtp-stream-gen.c @ 8:d180987db615
new program rtp-stream-gen
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 07 Mar 2024 22:39:41 +0000 |
parents | |
children |
line wrap: on
line source
/* * 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); }