1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <assert.h>
12 #include <stdio.h>
13
14 #include <memory>
15 #include <vector>
16
17 #include "absl/flags/flag.h"
18 #include "absl/flags/parse.h"
19 #include "modules/audio_coding/neteq/tools/packet.h"
20 #include "modules/audio_coding/neteq/tools/rtp_file_source.h"
21
22 ABSL_FLAG(int, red, 117, "RTP payload type for RED");
23 ABSL_FLAG(int,
24 audio_level,
25 -1,
26 "Extension ID for audio level (RFC 6464); "
27 "-1 not to print audio level");
28 ABSL_FLAG(int,
29 abs_send_time,
30 -1,
31 "Extension ID for absolute sender time; "
32 "-1 not to print absolute send time");
33
main(int argc,char * argv[])34 int main(int argc, char* argv[]) {
35 std::vector<char*> args = absl::ParseCommandLine(argc, argv);
36 std::string usage =
37 "Tool for parsing an RTP dump file to text output.\n"
38 "Example usage:\n"
39 "./rtp_analyze input.rtp output.txt\n\n"
40 "Output is sent to stdout if no output file is given. "
41 "Note that this tool can read files with or without payloads.\n";
42 if (args.size() != 2 && args.size() != 3) {
43 printf("%s", usage.c_str());
44 return 1;
45 }
46
47 RTC_CHECK(absl::GetFlag(FLAGS_red) >= 0 &&
48 absl::GetFlag(FLAGS_red) <= 127); // Payload type
49 RTC_CHECK(absl::GetFlag(FLAGS_audio_level) == -1 || // Default
50 (absl::GetFlag(FLAGS_audio_level) > 0 &&
51 absl::GetFlag(FLAGS_audio_level) <= 255)); // Extension ID
52 RTC_CHECK(absl::GetFlag(FLAGS_abs_send_time) == -1 || // Default
53 (absl::GetFlag(FLAGS_abs_send_time) > 0 &&
54 absl::GetFlag(FLAGS_abs_send_time) <= 255)); // Extension ID
55
56 printf("Input file: %s\n", args[1]);
57 std::unique_ptr<webrtc::test::RtpFileSource> file_source(
58 webrtc::test::RtpFileSource::Create(args[1]));
59 assert(file_source.get());
60 // Set RTP extension IDs.
61 bool print_audio_level = false;
62 if (absl::GetFlag(FLAGS_audio_level) != -1) {
63 print_audio_level = true;
64 file_source->RegisterRtpHeaderExtension(webrtc::kRtpExtensionAudioLevel,
65 absl::GetFlag(FLAGS_audio_level));
66 }
67 bool print_abs_send_time = false;
68 if (absl::GetFlag(FLAGS_abs_send_time) != -1) {
69 print_abs_send_time = true;
70 file_source->RegisterRtpHeaderExtension(
71 webrtc::kRtpExtensionAbsoluteSendTime,
72 absl::GetFlag(FLAGS_abs_send_time));
73 }
74
75 FILE* out_file;
76 if (args.size() == 3) {
77 out_file = fopen(args[2], "wt");
78 if (!out_file) {
79 printf("Cannot open output file %s\n", args[2]);
80 return -1;
81 }
82 printf("Output file: %s\n\n", args[2]);
83 } else {
84 out_file = stdout;
85 }
86
87 // Print file header.
88 fprintf(out_file, "SeqNo TimeStamp SendTime Size PT M SSRC");
89 if (print_audio_level) {
90 fprintf(out_file, " AuLvl (V)");
91 }
92 if (print_abs_send_time) {
93 fprintf(out_file, " AbsSendTime");
94 }
95 fprintf(out_file, "\n");
96
97 uint32_t max_abs_send_time = 0;
98 int cycles = -1;
99 std::unique_ptr<webrtc::test::Packet> packet;
100 while (true) {
101 packet = file_source->NextPacket();
102 if (!packet.get()) {
103 // End of file reached.
104 break;
105 }
106 // Write packet data to file. Use virtual_packet_length_bytes so that the
107 // correct packet sizes are printed also for RTP header-only dumps.
108 fprintf(out_file, "%5u %10u %10u %5i %5i %2i %#08X",
109 packet->header().sequenceNumber, packet->header().timestamp,
110 static_cast<unsigned int>(packet->time_ms()),
111 static_cast<int>(packet->virtual_packet_length_bytes()),
112 packet->header().payloadType, packet->header().markerBit,
113 packet->header().ssrc);
114 if (print_audio_level && packet->header().extension.hasAudioLevel) {
115 fprintf(out_file, " %5u (%1i)", packet->header().extension.audioLevel,
116 packet->header().extension.voiceActivity);
117 }
118 if (print_abs_send_time && packet->header().extension.hasAbsoluteSendTime) {
119 if (cycles == -1) {
120 // Initialize.
121 max_abs_send_time = packet->header().extension.absoluteSendTime;
122 cycles = 0;
123 }
124 // Abs sender time is 24 bit 6.18 fixed point. Shift by 8 to normalize to
125 // 32 bits (unsigned). Calculate the difference between this packet's
126 // send time and the maximum observed. Cast to signed 32-bit to get the
127 // desired wrap-around behavior.
128 if (static_cast<int32_t>(
129 (packet->header().extension.absoluteSendTime << 8) -
130 (max_abs_send_time << 8)) >= 0) {
131 // The difference is non-negative, meaning that this packet is newer
132 // than the previously observed maximum absolute send time.
133 if (packet->header().extension.absoluteSendTime < max_abs_send_time) {
134 // Wrap detected.
135 cycles++;
136 }
137 max_abs_send_time = packet->header().extension.absoluteSendTime;
138 }
139 // Abs sender time is 24 bit 6.18 fixed point. Divide by 2^18 to convert
140 // to floating point representation.
141 double send_time_seconds =
142 static_cast<double>(packet->header().extension.absoluteSendTime) /
143 262144 +
144 64.0 * cycles;
145 fprintf(out_file, " %11f", send_time_seconds);
146 }
147 fprintf(out_file, "\n");
148
149 if (packet->header().payloadType == absl::GetFlag(FLAGS_red)) {
150 std::list<webrtc::RTPHeader*> red_headers;
151 packet->ExtractRedHeaders(&red_headers);
152 while (!red_headers.empty()) {
153 webrtc::RTPHeader* red = red_headers.front();
154 assert(red);
155 fprintf(out_file, "* %5u %10u %10u %5i\n", red->sequenceNumber,
156 red->timestamp, static_cast<unsigned int>(packet->time_ms()),
157 red->payloadType);
158 red_headers.pop_front();
159 delete red;
160 }
161 }
162 }
163
164 fclose(out_file);
165
166 return 0;
167 }
168