rtp_analyze.cc (7732B)
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 <algorithm> 12 #include <cstdint> 13 #include <cstdio> 14 #include <memory> 15 #include <string> 16 #include <vector> 17 18 #include "absl/flags/flag.h" 19 #include "absl/flags/parse.h" 20 #include "api/rtp_headers.h" 21 #include "modules/audio_coding/neteq/tools/rtp_file_source.h" 22 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" 23 #include "modules/rtp_rtcp/source/rtp_header_extensions.h" 24 #include "modules/rtp_rtcp/source/rtp_packet_received.h" 25 #include "rtc_base/checks.h" 26 27 ABSL_FLAG(int, red, 117, "RTP payload type for RED"); 28 ABSL_FLAG(int, 29 audio_level, 30 -1, 31 "Extension ID for audio level (RFC 6464); " 32 "-1 not to print audio level"); 33 ABSL_FLAG(int, 34 abs_send_time, 35 -1, 36 "Extension ID for absolute sender time; " 37 "-1 not to print absolute send time"); 38 39 namespace { 40 41 struct RedHeader { 42 uint32_t rtp_timestamp; 43 int payload_type; 44 }; 45 std::vector<RedHeader> ExtractRedHeaders(const webrtc::RtpPacket& packet) { 46 // 47 // 0 1 2 3 48 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 49 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 50 // |1| block PT | timestamp offset | block length | 51 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 52 // |1| ... | 53 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 54 // |0| block PT | 55 // +-+-+-+-+-+-+-+-+ 56 // 57 const uint8_t* payload_ptr = packet.payload().data(); 58 const uint8_t* payload_end_ptr = 59 packet.payload().data() + packet.payload().size(); 60 61 // Find all RED headers with the extension bit set to 1. That is, all headers 62 // but the last one. 63 std::vector<RedHeader> red_headers; 64 while ((payload_ptr < payload_end_ptr) && (*payload_ptr & 0x80)) { 65 RedHeader header; 66 header.payload_type = payload_ptr[0] & 0x7F; 67 uint32_t offset = (payload_ptr[1] << 6) + ((payload_ptr[2] & 0xFC) >> 2); 68 header.rtp_timestamp = packet.Timestamp() - offset; 69 red_headers.push_back(header); 70 payload_ptr += 4; 71 } 72 // Last header. 73 RTC_DCHECK_LT(payload_ptr, payload_end_ptr); 74 if (payload_ptr >= payload_end_ptr) { 75 return {}; // Payload too short. 76 } 77 RedHeader header; 78 header.payload_type = payload_ptr[0] & 0x7F; 79 header.rtp_timestamp = packet.Timestamp(); 80 red_headers.push_back(header); 81 std::reverse(red_headers.begin(), red_headers.end()); 82 return red_headers; 83 } 84 85 } // namespace 86 87 int main(int argc, char* argv[]) { 88 std::vector<char*> args = absl::ParseCommandLine(argc, argv); 89 std::string usage = 90 "Tool for parsing an RTP dump file to text output.\n" 91 "Example usage:\n" 92 "./rtp_analyze input.rtp output.txt\n\n" 93 "Output is sent to stdout if no output file is given. " 94 "Note that this tool can read files with or without payloads.\n"; 95 if (args.size() != 2 && args.size() != 3) { 96 printf("%s", usage.c_str()); 97 return 1; 98 } 99 100 RTC_CHECK(absl::GetFlag(FLAGS_red) >= 0 && 101 absl::GetFlag(FLAGS_red) <= 127); // Payload type 102 RTC_CHECK(absl::GetFlag(FLAGS_audio_level) == -1 || // Default 103 (absl::GetFlag(FLAGS_audio_level) > 0 && 104 absl::GetFlag(FLAGS_audio_level) <= 255)); // Extension ID 105 RTC_CHECK(absl::GetFlag(FLAGS_abs_send_time) == -1 || // Default 106 (absl::GetFlag(FLAGS_abs_send_time) > 0 && 107 absl::GetFlag(FLAGS_abs_send_time) <= 255)); // Extension ID 108 109 printf("Input file: %s\n", args[1]); 110 std::unique_ptr<webrtc::test::RtpFileSource> file_source( 111 webrtc::test::RtpFileSource::Create(args[1])); 112 RTC_DCHECK(file_source.get()); 113 // Set RTP extension IDs. 114 bool print_audio_level = false; 115 if (absl::GetFlag(FLAGS_audio_level) != -1) { 116 print_audio_level = true; 117 file_source->RegisterRtpHeaderExtension(webrtc::kRtpExtensionAudioLevel, 118 absl::GetFlag(FLAGS_audio_level)); 119 } 120 bool print_abs_send_time = false; 121 if (absl::GetFlag(FLAGS_abs_send_time) != -1) { 122 print_abs_send_time = true; 123 file_source->RegisterRtpHeaderExtension( 124 webrtc::kRtpExtensionAbsoluteSendTime, 125 absl::GetFlag(FLAGS_abs_send_time)); 126 } 127 128 FILE* out_file; 129 if (args.size() == 3) { 130 out_file = fopen(args[2], "wt"); 131 if (!out_file) { 132 printf("Cannot open output file %s\n", args[2]); 133 return -1; 134 } 135 printf("Output file: %s\n\n", args[2]); 136 } else { 137 out_file = stdout; 138 } 139 140 // Print file header. 141 fprintf(out_file, "SeqNo TimeStamp SendTime Size PT M SSRC"); 142 if (print_audio_level) { 143 fprintf(out_file, " AuLvl (V)"); 144 } 145 if (print_abs_send_time) { 146 fprintf(out_file, " AbsSendTime"); 147 } 148 fprintf(out_file, "\n"); 149 150 uint32_t max_abs_send_time = 0; 151 int cycles = -1; 152 std::unique_ptr<webrtc::RtpPacketReceived> packet; 153 while (true) { 154 packet = file_source->NextPacket(); 155 if (!packet) { 156 // End of file reached. 157 break; 158 } 159 // Write packet data to file. Use virtual_packet_length_bytes so that the 160 // correct packet sizes are printed also for RTP header-only dumps. 161 fprintf(out_file, "%5u %10u %10i %5zu %5i %2i %#08X", 162 packet->SequenceNumber(), packet->Timestamp(), 163 packet->arrival_time().ms<int>(), packet->size(), 164 packet->PayloadType(), packet->Marker(), packet->Ssrc()); 165 webrtc::AudioLevel audio_level; 166 if (print_audio_level && 167 packet->GetExtension<webrtc::AudioLevelExtension>(&audio_level)) { 168 fprintf(out_file, " %5d (%1i)", audio_level.level(), 169 audio_level.voice_activity()); 170 } 171 uint32_t abs_sent_time; 172 if (print_abs_send_time && 173 packet->GetExtension<webrtc::AbsoluteSendTime>(&abs_sent_time)) { 174 if (cycles == -1) { 175 // Initialize. 176 max_abs_send_time = abs_sent_time; 177 cycles = 0; 178 } 179 // Abs sender time is 24 bit 6.18 fixed point. Shift by 8 to normalize to 180 // 32 bits (unsigned). Calculate the difference between this packet's 181 // send time and the maximum observed. Cast to signed 32-bit to get the 182 // desired wrap-around behavior. 183 if (static_cast<int32_t>((abs_sent_time << 8) - 184 (max_abs_send_time << 8)) >= 0) { 185 // The difference is non-negative, meaning that this packet is newer 186 // than the previously observed maximum absolute send time. 187 if (abs_sent_time < max_abs_send_time) { 188 // Wrap detected. 189 cycles++; 190 } 191 max_abs_send_time = abs_sent_time; 192 } 193 // Abs sender time is 24 bit 6.18 fixed point. Divide by 2^18 to convert 194 // to floating point representation. 195 double send_time_seconds = 196 static_cast<double>(abs_sent_time) / 262144 + 64.0 * cycles; 197 fprintf(out_file, " %11f", send_time_seconds); 198 } 199 fprintf(out_file, "\n"); 200 201 if (packet->PayloadType() == absl::GetFlag(FLAGS_red)) { 202 for (const RedHeader& red : ExtractRedHeaders(*packet)) { 203 fprintf(out_file, "* %5u %10u %10i %5i\n", packet->SequenceNumber(), 204 red.rtp_timestamp, packet->arrival_time().ms<int>(), 205 red.payload_type); 206 } 207 } 208 } 209 210 fclose(out_file); 211 212 return 0; 213 }