📄 rtpdump.c
字号:
printf("flags=0x%x type=0x%x confid=%u\n", v->flags, v->type, v->confid); } else if (r->common.version == RTP_VERSION) { printf("\n"); while (len > 0) { len -= (ntohs(r->common.length) + 1) << 2; if (len < 0) { /* something wrong with packet format */ printf("Illegal RTCP packet length %d words.\n", ntohs(r->common.length)); return -1; } switch (r->common.pt) { case RTCP_SR: printf(" (SR ssrc=0x%lx p=%d count=%d len=%d\n", ntohl(r->r.rr.ssrc), r->common.p, r->common.count, ntohs(r->common.length)); printf("ntp=%lu.%lu ts=%lu psent=%lu osent=%lu\n", ntohl(r->r.sr.ntp_sec), ntohl(r->r.sr.ntp_frac), ntohl(r->r.sr.rtp_ts), ntohl(r->r.sr.psent), ntohl(r->r.sr.osent)); for (i = 0; i < r->common.count; i++) { printf(" (ssrc=%0lx fraction=%g lost=%lu last_seq=%lu jit=%lu lsr=%lu dlsr=%lu)\n", ntohl(r->r.sr.rr[i].ssrc), r->r.sr.rr[i].fraction / 256., ntohl(r->r.sr.rr[i].lost), /* XXX I'm pretty sure this is wrong */ ntohl(r->r.sr.rr[i].last_seq), ntohl(r->r.sr.rr[i].jitter), ntohl(r->r.sr.rr[i].lsr), ntohl(r->r.sr.rr[i].dlsr)); } printf(" )\n"); break; case RTCP_RR: printf(" (RR ssrc=0x%lx p=%d count=%d len=%d\n", ntohl(r->r.rr.ssrc), r->common.p, r->common.count, ntohs(r->common.length)); for (i = 0; i < r->common.count; i++) { printf("(ssrc=%0lx fraction=%g lost=%lu last_seq=%lu jit=%lu lsr=%lu dlsr=%lu)\n", ntohl(r->r.rr.rr[i].ssrc), r->r.rr.rr[i].fraction / 256., ntohl(r->r.rr.rr[i].lost), ntohl(r->r.rr.rr[i].last_seq), ntohl(r->r.rr.rr[i].jitter), ntohl(r->r.rr.rr[i].lsr), ntohl(r->r.rr.rr[i].dlsr)); } printf(" )\n"); break; case RTCP_SDES: printf(" (SDES p=%d count=%d len=%d\n", r->common.p, r->common.count, ntohs(r->common.length)); buf = (char *)&r->r.sdes; for (i = 0; i < r->common.count; i++) { int remaining = (ntohs(r->common.length) << 2) - (buf - (char *)&r->r.sdes); printf(" (src=0x%lx ", ntohl(((struct rtcp_sdes *)buf)->src)); if (remaining > 0) { buf = rtp_read_sdes(buf, (ntohs(r->common.length) << 2) - (buf - (char *)&r->r.sdes)); if (!buf) return -1; } else { fprintf(stderr, "Missing at least %d bytes.\n", -remaining); return -1; } printf(")\n"); } printf(" )\n"); break; case RTCP_BYE: printf(" (BYE p=%d count=%d len=%d\n", r->common.p, r->common.count, ntohs(r->common.length)); for (i = 0; i < r->common.count; i++) { printf("ssrc[%d]=%0lx ", i, ntohl(r->r.bye.src[i])); } if (ntohs(r->common.length) > r->common.count) { buf = (char *)&r->r.bye.src[r->common.count]; printf("reason=\"%*.*s\"", *buf, *buf, buf+1); } printf(")\n"); break; /* invalid type */ default: printf("(? pt=%d src=0x%lx)\n", r->common.pt, ntohl(r->r.sdes.src)); break; } r = (rtcp_t *)((u_int32 *)r + ntohs(r->common.length) + 1); } } else { printf("invalid version %d\n", r->common.version); } return len;} /* parse_control *//** Process one packet.*/void packet_handler(t_format format, int trunc, double dstart, struct timeval now, int ctrl, struct sockaddr_in sin, int len, RD_buffer_t packet){ double dnow = tdbl(&now); int hlen; /* header length */ switch(format) { case F_header: packet.p.hdr.offset = htonl((dnow - dstart)*1000); packet.p.hdr.plen = ctrl ? 0 : len; /* leave only header */ if (ctrl == 0) len = parse_header(packet.p.data); packet.p.hdr.length = htons(len + sizeof(packet.p.hdr)); if (fwrite((char *)&packet, len + sizeof(packet.p.hdr), 1, stdout) == 0) { perror("fwrite"); exit(1); } break; case F_dump: hlen = ctrl ? len : parse_header(packet.p.data); packet.p.hdr.offset = htonl((dnow - dstart)*1000); packet.p.hdr.plen = ctrl ? 0 : len; /* truncation of payload */ if (!ctrl && (len - hlen > trunc)) len = hlen + trunc; packet.p.hdr.length = htons(len + sizeof(packet.p.hdr)); if (fwrite((char *)&packet, len + sizeof(packet.p.hdr), 1, stdout) == 0) { perror("fwrite"); exit(1); } break; case F_payload: /* XXX should check header format. */ if (ctrl == 0) { if (fwrite(&packet.p.data[12], len - 12, 1, stdout) == 0) { perror("fwrite"); exit(1); } } break; case F_short: if (ctrl == 0) parse_short(now, packet.p.data, len); break; case F_rtcp: case F_hex: case F_ascii: printf("%8ld.%06ld %s len=%d from=%s:%u ", now.tv_sec, now.tv_usec, parse_type(ctrl, packet.p.data), len, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); if (format == F_hex) { hex(packet.p.data, trunc < len ? trunc : len); } ctrl ? parse_control(packet.p.data, len) : parse_data(packet.p.data, len); break; case F_invalid: break; }} /* packet_handler */int main(int argc, char *argv[]){ int c; static struct { char *name; t_format format; } formats[] = { {"dump", F_dump}, {"header", F_header}, {"hex", F_hex}, {"rtcp", F_rtcp}, {"short", F_short}, {"payload", F_payload}, {"ascii", F_ascii}, {0,0} }; t_format format = F_ascii; struct sockaddr_in sin; struct timeval start; struct timeval timeout; /* timeout to limit recording */ double dstart; /* time as double */ int duration = 1000000; /* maximum duration in seconds */ int trunc = 1000000; /* bytes to show for F_hex and F_dump */ enum {FromFile, FromNetwork} source; int sock[2]; FILE *in = stdin; /* input file to use instead of sockets */ fd_set readfds; extern char *optarg; extern int optind; int i; int nfds = 0; extern double tdbl(struct timeval *); while ((c = getopt(argc, argv, "b:F:f:t:x:")) != EOF) { switch(c) { /* output format */ case 'F': format = F_invalid; for (i = 0; formats[i].name; i++) { if (strncasecmp(formats[i].name, optarg, strlen(optarg)) == 0) { format = formats[i].format; break; } } if (format == F_invalid) { usage(argv[1]); exit(1); } break; /* input file (instead of network connection) */ case 'f': if (!(in = fopen(optarg, "r"))) { perror(optarg); exit(1); } break; /* recording duration in minutes or fractions thereof */ case 't': duration = atof(optarg) * 60; break; /* bytes to show for F_hex or F_dump */ case 'x': trunc = atoi(optarg); break; case '?': case 'h': usage(argv[0]); exit(1); break; } } /* * Set up payload type map. We should be able to read this in * from a file. */ for (i = 0; i < 256; i++) { pt_map[i].enc = "????"; pt_map[i].rate = 0; pt_map[i].ch = 0; } /* Updated 25 Jul 1997 to reflect IANA assignments: */ /* <ftp://ftp.isi.edu/in-notes/iana/assignments/rtp-av-payload-types> */ /* Marked items are indicated as 'reserved' by the IANA */ pt_map[ 0].enc = "PCMU"; pt_map[ 0].rate = 8000; pt_map[ 0].ch = 1; pt_map[ 1].enc = "1016"; pt_map[ 1].rate = 8000; pt_map[ 1].ch = 1; pt_map[ 2].enc = "G721"; pt_map[ 2].rate = 8000; pt_map[ 2].ch = 1; pt_map[ 3].enc = "GSM "; pt_map[ 3].rate = 8000; pt_map[ 3].ch = 1; pt_map[ 4].enc = "G723"; pt_map[ 4].rate = 8000; pt_map[ 4].ch = 1; pt_map[ 5].enc = "DVI4"; pt_map[ 5].rate = 8000; pt_map[ 5].ch = 1; pt_map[ 6].enc = "DVI4"; pt_map[ 6].rate = 16000; pt_map[ 6].ch = 1; pt_map[ 7].enc = "LPC "; pt_map[ 7].rate = 8000; pt_map[ 7].ch = 1; pt_map[ 8].enc = "PCMA"; pt_map[ 8].rate = 8000; pt_map[ 7].ch = 1; pt_map[ 9].enc = "G722"; pt_map[ 9].rate = 8000; pt_map[ 7].ch = 1; pt_map[ 10].enc = "L16 "; pt_map[ 10].rate = 44100; pt_map[ 10].ch = 2; pt_map[ 11].enc = "L16 "; pt_map[ 11].rate = 44100; pt_map[ 11].ch = 1; pt_map[ 14].enc = "MPA "; pt_map[ 14].rate = 90000; pt_map[ 14].ch = 0; pt_map[ 15].enc = "G728"; pt_map[ 15].rate = 8000; pt_map[ 15].ch = 1; pt_map[ 16].enc = "DVI4"; pt_map[ 16].rate = 11025; pt_map[ 16].ch = 1; pt_map[ 17].enc = "DVI4"; pt_map[ 17].rate = 22050; pt_map[ 17].ch = 1; pt_map[ 23].enc = "SCR "; pt_map[ 23].rate = 90000; pt_map[ 23].ch = 0; /**/ pt_map[ 24].enc = "MPEG"; pt_map[ 24].rate = 90000; pt_map[ 24].ch = 0; /**/ pt_map[ 25].enc = "CelB"; pt_map[ 25].rate = 90000; pt_map[ 26].ch = 0; pt_map[ 26].enc = "JPEG"; pt_map[ 26].rate = 90000; pt_map[ 26].ch = 0; pt_map[ 27].enc = "CUSM"; pt_map[ 27].rate = 90000; pt_map[ 27].ch = 0; /**/ pt_map[ 28].enc = "nv "; pt_map[ 28].rate = 90000; pt_map[ 28].ch = 0; pt_map[ 29].enc = "PicW"; pt_map[ 29].rate = 90000; pt_map[ 29].ch = 0; /**/ pt_map[ 30].enc = "CPV "; pt_map[ 30].rate = 90000; pt_map[ 30].ch = 0; /**/ pt_map[ 31].enc = "H261"; pt_map[ 31].rate = 90000; pt_map[ 31].ch = 0; pt_map[ 32].enc = "MPV "; pt_map[ 32].rate = 90000; pt_map[ 32].ch = 0; pt_map[ 33].enc = "MP2T"; pt_map[ 33].rate = 90000; pt_map[ 33].ch = 0; /* set maximum time to gather packets */ timeout.tv_usec = 0; timeout.tv_sec = duration; /* if no optional arguments, we are reading from a file */ if (optind == argc) { source = FromFile; sock[0] = fileno(in); /* stdin */ sock[1] = -1; /* not used */ RD_header(in, &sin, 0); dstart = 0.; } else { source = FromNetwork; nfds = open_network(argv[optind], format != F_rtcp, sock, &sin); gettimeofday(&start, 0); dstart = tdbl(&start); } /* write header for dump file */ if (format == F_dump || format == F_header) rtpdump_header(stdout, &sin, &start); /* signal handler */ signal(SIGINT, done); /* main loop */ while (1) { int len; RD_buffer_t packet; struct timeval now; double dnow; if (source == FromNetwork) { FD_ZERO(&readfds); if (sock[0] >= 0) FD_SET(sock[0], &readfds); if (sock[1] >= 0) FD_SET(sock[1], &readfds); c = select(nfds+1, &readfds, 0, 0, &timeout); if (c < 0) { perror("select"); exit(1); } /* end of recording time reached */ else if (c == 0) { if (verbose) fprintf(stderr, "Time limit reached.\n"); exit(0); } for (i = 0; i < 2; i++) { if (sock[i] >= 0 && FD_ISSET(sock[i], &readfds)) { int alen = sizeof(sin); /* subtract elapsed time from remaining timeout */ gettimeofday(&now, 0); dnow = tdbl(&now); timeout.tv_sec = duration - (dnow - dstart); if (timeout.tv_sec < 0) timeout.tv_sec = 0; len = recvfrom(sock[i], packet.p.data, sizeof(packet.p.data), 0, (struct sockaddr *)&sin, &alen); packet_handler(format, trunc, dstart, now, i, sin, len, packet); } } } else { len = RD_read(in, &packet); now.tv_sec = packet.p.hdr.offset / 1000.; now.tv_usec = (packet.p.hdr.offset % 1000) * 1000; dnow = tdbl(&now); /* plen>0: data =0: control */ i = (packet.p.hdr.plen == 0); /* arbitrary, obviously invalid value */ sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = 0; packet_handler(format, trunc, dstart, now, i, sin, len, packet); } } return 0;} /* main */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -