FreeCalypso > hg > rtp-debug-utils
comparison net-traffic/rtp-stream-gen.c @ 10:e686bc92c7d8
revamp for new subdir structure and configure script
| author | Mychaela Falconia <falcon@freecalypso.org> |
|---|---|
| date | Wed, 15 May 2024 01:44:46 +0000 |
| parents | rtp-stream-gen.c@d180987db615 |
| children |
comparison
equal
deleted
inserted
replaced
| 9:c00510e1ae8b | 10:e686bc92c7d8 |
|---|---|
| 1 /* | |
| 2 * This program generates a dummy RTP stream, sending RTP packets with | |
| 3 * a dummy payload to the specified destination IP:port, paced in time | |
| 4 * every 20 ms. The purpose is to test the behaviour of affordably-available | |
| 5 * Internet connections when presented with such traffic: the intent is | |
| 6 * to capture this packet stream on the receiving end with tcpdump and then | |
| 7 * analyze the pcap for problem signs of packet loss, jitter and reordering. | |
| 8 */ | |
| 9 | |
| 10 #include <sys/types.h> | |
| 11 #include <sys/socket.h> | |
| 12 #include <sys/time.h> | |
| 13 #include <netinet/in.h> | |
| 14 #include <arpa/inet.h> | |
| 15 #include <stdio.h> | |
| 16 #include <stdint.h> | |
| 17 #include <stdlib.h> | |
| 18 #include <string.h> | |
| 19 #include <strings.h> | |
| 20 #include <unistd.h> | |
| 21 | |
| 22 #define RTP_PACKET_HDR_SIZE 12 | |
| 23 #define RTP_MAX_PAYLOAD 160 | |
| 24 #define GSM_FR_BYTES 33 | |
| 25 | |
| 26 struct rtp_packet { | |
| 27 uint8_t v_p_x_cc; | |
| 28 uint8_t m_pt; | |
| 29 uint16_t seq; | |
| 30 uint32_t tstamp; | |
| 31 uint32_t ssrc; | |
| 32 uint8_t payload[RTP_MAX_PAYLOAD]; | |
| 33 }; | |
| 34 | |
| 35 static const uint8_t gsmfr_silence_frame[GSM_FR_BYTES] = { | |
| 36 0xDA, 0xA7, 0xAA, 0xA5, 0x1A, | |
| 37 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B, | |
| 38 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B, | |
| 39 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B, | |
| 40 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B, | |
| 41 }; | |
| 42 | |
| 43 static struct sockaddr_in sin_src, sin_dest; | |
| 44 static struct rtp_packet rtp_pkt; | |
| 45 static unsigned rtp_pkt_len, req_packet_count; | |
| 46 static int udp_fd; | |
| 47 | |
| 48 static void | |
| 49 parse_ip_port(arg, sin) | |
| 50 char *arg; | |
| 51 struct sockaddr_in *sin; | |
| 52 { | |
| 53 char *cp; | |
| 54 int rc; | |
| 55 | |
| 56 cp = index(arg, ':'); | |
| 57 if (!cp) { | |
| 58 fprintf(stderr, "error: missing ':' in IP:port argument\n"); | |
| 59 exit(1); | |
| 60 } | |
| 61 *cp++ = '\0'; | |
| 62 sin->sin_family = AF_INET; | |
| 63 rc = inet_aton(arg, &sin->sin_addr); | |
| 64 if (!rc) { | |
| 65 fprintf(stderr, "error: invalid IP address argument\n"); | |
| 66 exit(1); | |
| 67 } | |
| 68 sin->sin_port = htons(atoi(cp)); | |
| 69 } | |
| 70 | |
| 71 static void | |
| 72 prepare_rtp_payload(type_arg) | |
| 73 char *type_arg; | |
| 74 { | |
| 75 unsigned pl_len; | |
| 76 | |
| 77 if (!strcmp(type_arg, "pcmu")) { | |
| 78 rtp_pkt.m_pt = 0; | |
| 79 memset(rtp_pkt.payload, 0xFF, RTP_MAX_PAYLOAD); | |
| 80 pl_len = RTP_MAX_PAYLOAD; | |
| 81 } else if (!strcmp(type_arg, "pcma")) { | |
| 82 rtp_pkt.m_pt = 8; | |
| 83 memset(rtp_pkt.payload, 0xD5, RTP_MAX_PAYLOAD); | |
| 84 pl_len = RTP_MAX_PAYLOAD; | |
| 85 } else if (!strcmp(type_arg, "gsm")) { | |
| 86 rtp_pkt.m_pt = 3; | |
| 87 memcpy(rtp_pkt.payload, gsmfr_silence_frame, GSM_FR_BYTES); | |
| 88 pl_len = GSM_FR_BYTES; | |
| 89 } else { | |
| 90 fprintf(stderr, "error: invalid PL type argument \"%s\"\n", | |
| 91 type_arg); | |
| 92 exit(1); | |
| 93 } | |
| 94 rtp_pkt_len = RTP_PACKET_HDR_SIZE + pl_len; | |
| 95 } | |
| 96 | |
| 97 static void | |
| 98 assign_rtpout_ssrc() | |
| 99 { | |
| 100 struct timeval curtime; | |
| 101 | |
| 102 gettimeofday(&curtime, 0); | |
| 103 rtp_pkt.ssrc = curtime.tv_sec ^ curtime.tv_usec ^ getpid(); | |
| 104 } | |
| 105 | |
| 106 static void | |
| 107 prepare_udp_socket() | |
| 108 { | |
| 109 int rc; | |
| 110 | |
| 111 udp_fd = socket(AF_INET, SOCK_DGRAM, 0); | |
| 112 if (udp_fd < 0) { | |
| 113 perror("socket(AF_INET, SOCK_DGRAM, 0)"); | |
| 114 exit(1); | |
| 115 } | |
| 116 rc = bind(udp_fd, (struct sockaddr *) &sin_src, sizeof sin_src); | |
| 117 if (rc < 0) { | |
| 118 perror("bind"); | |
| 119 exit(1); | |
| 120 } | |
| 121 rc = connect(udp_fd, (struct sockaddr *) &sin_dest, sizeof sin_dest); | |
| 122 if (rc < 0) { | |
| 123 perror("connect"); | |
| 124 exit(1); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 static void | |
| 129 send_out_packets() | |
| 130 { | |
| 131 unsigned n, seq, ts; | |
| 132 | |
| 133 seq = 0; | |
| 134 ts = 0; | |
| 135 for (n = 0; n < req_packet_count; n++) { | |
| 136 rtp_pkt.seq = htons(seq); | |
| 137 rtp_pkt.tstamp = htonl(ts); | |
| 138 send(udp_fd, &rtp_pkt, rtp_pkt_len, 0); | |
| 139 seq++; | |
| 140 ts += 160; | |
| 141 usleep(20000); | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 main(argc, argv) | |
| 146 char **argv; | |
| 147 { | |
| 148 if (argc != 5) { | |
| 149 fprintf(stderr, "usage: %s src-IP:port dest-IP:port type num\n", | |
| 150 argv[0]); | |
| 151 exit(1); | |
| 152 } | |
| 153 parse_ip_port(argv[1], &sin_src); | |
| 154 parse_ip_port(argv[2], &sin_dest); | |
| 155 prepare_rtp_payload(argv[3]); | |
| 156 rtp_pkt.v_p_x_cc = 0x80; | |
| 157 assign_rtpout_ssrc(); | |
| 158 req_packet_count = atoi(argv[4]); | |
| 159 prepare_udp_socket(); | |
| 160 send_out_packets(); | |
| 161 exit(0); | |
| 162 } |
