1 /*
2 * Copyright (c) 2017 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 <string.h>
12
13 #include <iomanip> // setfill, setw
14 #include <iostream>
15 #include <map>
16 #include <sstream>
17 #include <string>
18 #include <utility> // pair
19
20 #include "call/video_config.h"
21 #include "common_types.h" // NOLINT(build/include)
22 #include "logging/rtc_event_log/rtc_event_log_parser.h"
23 #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
24 #include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
25 #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
26 #include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
27 #include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
28 #include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
29 #include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
30 #include "modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h"
31 #include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
32 #include "modules/rtp_rtcp/source/rtcp_packet/remb.h"
33 #include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
34 #include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
35 #include "modules/rtp_rtcp/source/rtcp_packet/tmmbn.h"
36 #include "modules/rtp_rtcp/source/rtcp_packet/tmmbr.h"
37 #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
38 #include "modules/rtp_rtcp/source/rtp_header_extensions.h"
39 #include "modules/rtp_rtcp/source/rtp_utility.h"
40 #include "rtc_base/checks.h"
41 #include "rtc_base/flags.h"
42 #include "rtc_base/logging.h"
43
44 namespace {
45
46 DEFINE_bool(unknown, true, "Use --nounknown to exclude unknown events.");
47 DEFINE_bool(startstop, true, "Use --nostartstop to exclude start/stop events.");
48 DEFINE_bool(config, true, "Use --noconfig to exclude stream configurations.");
49 DEFINE_bool(bwe, true, "Use --nobwe to exclude BWE events.");
50 DEFINE_bool(incoming, true, "Use --noincoming to exclude incoming packets.");
51 DEFINE_bool(outgoing, true, "Use --nooutgoing to exclude packets.");
52 // TODO(terelius): Note that the media type doesn't work with outgoing packets.
53 DEFINE_bool(audio, true, "Use --noaudio to exclude audio packets.");
54 // TODO(terelius): Note that the media type doesn't work with outgoing packets.
55 DEFINE_bool(video, true, "Use --novideo to exclude video packets.");
56 // TODO(terelius): Note that the media type doesn't work with outgoing packets.
57 DEFINE_bool(data, true, "Use --nodata to exclude data packets.");
58 DEFINE_bool(rtp, true, "Use --nortp to exclude RTP packets.");
59 DEFINE_bool(rtcp, true, "Use --nortcp to exclude RTCP packets.");
60 DEFINE_bool(playout, true, "Use --noplayout to exclude audio playout events.");
61 DEFINE_bool(ana, true, "Use --noana to exclude ANA events.");
62 DEFINE_bool(probe, true, "Use --noprobe to exclude probe events.");
63
64 DEFINE_bool(print_full_packets,
65 false,
66 "Print the full RTP headers and RTCP packets in hex.");
67
68 // TODO(terelius): Allow a list of SSRCs.
69 DEFINE_string(ssrc,
70 "",
71 "Print only packets with this SSRC (decimal or hex, the latter "
72 "starting with 0x).");
73 DEFINE_bool(help, false, "Prints this message.");
74
75 using MediaType = webrtc::ParsedRtcEventLog::MediaType;
76
77 static uint32_t filtered_ssrc = 0;
78
79 // Parses the input string for a valid SSRC. If a valid SSRC is found, it is
80 // written to the static global variable |filtered_ssrc|, and true is returned.
81 // Otherwise, false is returned.
82 // The empty string must be validated as true, because it is the default value
83 // of the command-line flag. In this case, no value is written to the output
84 // variable.
ParseSsrc(std::string str)85 bool ParseSsrc(std::string str) {
86 // If the input string starts with 0x or 0X it indicates a hexadecimal number.
87 auto read_mode = std::dec;
88 if (str.size() > 2 &&
89 (str.substr(0, 2) == "0x" || str.substr(0, 2) == "0X")) {
90 read_mode = std::hex;
91 str = str.substr(2);
92 }
93 std::stringstream ss(str);
94 ss >> read_mode >> filtered_ssrc;
95 return str.empty() || (!ss.fail() && ss.eof());
96 }
97
ExcludePacket(webrtc::PacketDirection direction,MediaType media_type,uint32_t packet_ssrc)98 bool ExcludePacket(webrtc::PacketDirection direction,
99 MediaType media_type,
100 uint32_t packet_ssrc) {
101 if (!FLAG_outgoing && direction == webrtc::kOutgoingPacket)
102 return true;
103 if (!FLAG_incoming && direction == webrtc::kIncomingPacket)
104 return true;
105 if (!FLAG_audio && media_type == MediaType::AUDIO)
106 return true;
107 if (!FLAG_video && media_type == MediaType::VIDEO)
108 return true;
109 if (!FLAG_data && media_type == MediaType::DATA)
110 return true;
111 if (strlen(FLAG_ssrc) > 0 && packet_ssrc != filtered_ssrc)
112 return true;
113 return false;
114 }
115
StreamInfo(webrtc::PacketDirection direction,MediaType media_type)116 const char* StreamInfo(webrtc::PacketDirection direction,
117 MediaType media_type) {
118 if (direction == webrtc::kOutgoingPacket) {
119 if (media_type == MediaType::AUDIO)
120 return "(out,audio)";
121 else if (media_type == MediaType::VIDEO)
122 return "(out,video)";
123 else if (media_type == MediaType::DATA)
124 return "(out,data)";
125 else
126 return "(out)";
127 }
128 if (direction == webrtc::kIncomingPacket) {
129 if (media_type == MediaType::AUDIO)
130 return "(in,audio)";
131 else if (media_type == MediaType::VIDEO)
132 return "(in,video)";
133 else if (media_type == MediaType::DATA)
134 return "(in,data)";
135 else
136 return "(in)";
137 }
138 return "(unknown)";
139 }
140
141 // Return default values for header extensions, to use on streams without stored
142 // mapping data. Currently this only applies to audio streams, since the mapping
143 // is not stored in the event log.
144 // TODO(ivoc): Remove this once this mapping is stored in the event log for
145 // audio streams. Tracking bug: webrtc:6399
GetDefaultHeaderExtensionMap()146 webrtc::RtpHeaderExtensionMap GetDefaultHeaderExtensionMap() {
147 webrtc::RtpHeaderExtensionMap default_map;
148 default_map.Register<webrtc::AudioLevel>(
149 webrtc::RtpExtension::kAudioLevelDefaultId);
150 default_map.Register<webrtc::TransmissionOffset>(
151 webrtc::RtpExtension::kTimestampOffsetDefaultId);
152 default_map.Register<webrtc::AbsoluteSendTime>(
153 webrtc::RtpExtension::kAbsSendTimeDefaultId);
154 default_map.Register<webrtc::VideoOrientation>(
155 webrtc::RtpExtension::kVideoRotationDefaultId);
156 default_map.Register<webrtc::VideoContentTypeExtension>(
157 webrtc::RtpExtension::kVideoContentTypeDefaultId);
158 default_map.Register<webrtc::VideoTimingExtension>(
159 webrtc::RtpExtension::kVideoTimingDefaultId);
160 default_map.Register<webrtc::TransportSequenceNumber>(
161 webrtc::RtpExtension::kTransportSequenceNumberDefaultId);
162 default_map.Register<webrtc::PlayoutDelayLimits>(
163 webrtc::RtpExtension::kPlayoutDelayDefaultId);
164 return default_map;
165 }
166
PrintSenderReport(const webrtc::ParsedRtcEventLog & parsed_stream,const webrtc::rtcp::CommonHeader & rtcp_block,uint64_t log_timestamp,webrtc::PacketDirection direction)167 void PrintSenderReport(const webrtc::ParsedRtcEventLog& parsed_stream,
168 const webrtc::rtcp::CommonHeader& rtcp_block,
169 uint64_t log_timestamp,
170 webrtc::PacketDirection direction) {
171 webrtc::rtcp::SenderReport sr;
172 if (!sr.Parse(rtcp_block))
173 return;
174 MediaType media_type =
175 parsed_stream.GetMediaType(sr.sender_ssrc(), direction);
176 if (ExcludePacket(direction, media_type, sr.sender_ssrc()))
177 return;
178 std::cout << log_timestamp << "\t"
179 << "RTCP_SR" << StreamInfo(direction, media_type)
180 << "\tssrc=" << sr.sender_ssrc()
181 << "\ttimestamp=" << sr.rtp_timestamp() << std::endl;
182 }
183
PrintReceiverReport(const webrtc::ParsedRtcEventLog & parsed_stream,const webrtc::rtcp::CommonHeader & rtcp_block,uint64_t log_timestamp,webrtc::PacketDirection direction)184 void PrintReceiverReport(const webrtc::ParsedRtcEventLog& parsed_stream,
185 const webrtc::rtcp::CommonHeader& rtcp_block,
186 uint64_t log_timestamp,
187 webrtc::PacketDirection direction) {
188 webrtc::rtcp::ReceiverReport rr;
189 if (!rr.Parse(rtcp_block))
190 return;
191 MediaType media_type =
192 parsed_stream.GetMediaType(rr.sender_ssrc(), direction);
193 if (ExcludePacket(direction, media_type, rr.sender_ssrc()))
194 return;
195 std::cout << log_timestamp << "\t"
196 << "RTCP_RR" << StreamInfo(direction, media_type)
197 << "\tssrc=" << rr.sender_ssrc() << std::endl;
198 }
199
PrintXr(const webrtc::ParsedRtcEventLog & parsed_stream,const webrtc::rtcp::CommonHeader & rtcp_block,uint64_t log_timestamp,webrtc::PacketDirection direction)200 void PrintXr(const webrtc::ParsedRtcEventLog& parsed_stream,
201 const webrtc::rtcp::CommonHeader& rtcp_block,
202 uint64_t log_timestamp,
203 webrtc::PacketDirection direction) {
204 webrtc::rtcp::ExtendedReports xr;
205 if (!xr.Parse(rtcp_block))
206 return;
207 MediaType media_type =
208 parsed_stream.GetMediaType(xr.sender_ssrc(), direction);
209 if (ExcludePacket(direction, media_type, xr.sender_ssrc()))
210 return;
211 std::cout << log_timestamp << "\t"
212 << "RTCP_XR" << StreamInfo(direction, media_type)
213 << "\tssrc=" << xr.sender_ssrc() << std::endl;
214 }
215
PrintSdes(const webrtc::rtcp::CommonHeader & rtcp_block,uint64_t log_timestamp,webrtc::PacketDirection direction)216 void PrintSdes(const webrtc::rtcp::CommonHeader& rtcp_block,
217 uint64_t log_timestamp,
218 webrtc::PacketDirection direction) {
219 std::cout << log_timestamp << "\t"
220 << "RTCP_SDES" << StreamInfo(direction, MediaType::ANY)
221 << std::endl;
222 RTC_NOTREACHED() << "SDES should have been redacted when writing the log";
223 }
224
PrintBye(const webrtc::ParsedRtcEventLog & parsed_stream,const webrtc::rtcp::CommonHeader & rtcp_block,uint64_t log_timestamp,webrtc::PacketDirection direction)225 void PrintBye(const webrtc::ParsedRtcEventLog& parsed_stream,
226 const webrtc::rtcp::CommonHeader& rtcp_block,
227 uint64_t log_timestamp,
228 webrtc::PacketDirection direction) {
229 webrtc::rtcp::Bye bye;
230 if (!bye.Parse(rtcp_block))
231 return;
232 MediaType media_type =
233 parsed_stream.GetMediaType(bye.sender_ssrc(), direction);
234 if (ExcludePacket(direction, media_type, bye.sender_ssrc()))
235 return;
236 std::cout << log_timestamp << "\t"
237 << "RTCP_BYE" << StreamInfo(direction, media_type)
238 << "\tssrc=" << bye.sender_ssrc() << std::endl;
239 }
240
PrintRtpFeedback(const webrtc::ParsedRtcEventLog & parsed_stream,const webrtc::rtcp::CommonHeader & rtcp_block,uint64_t log_timestamp,webrtc::PacketDirection direction)241 void PrintRtpFeedback(const webrtc::ParsedRtcEventLog& parsed_stream,
242 const webrtc::rtcp::CommonHeader& rtcp_block,
243 uint64_t log_timestamp,
244 webrtc::PacketDirection direction) {
245 switch (rtcp_block.fmt()) {
246 case webrtc::rtcp::Nack::kFeedbackMessageType: {
247 webrtc::rtcp::Nack nack;
248 if (!nack.Parse(rtcp_block))
249 return;
250 MediaType media_type =
251 parsed_stream.GetMediaType(nack.sender_ssrc(), direction);
252 if (ExcludePacket(direction, media_type, nack.sender_ssrc()))
253 return;
254 std::cout << log_timestamp << "\t"
255 << "RTCP_NACK" << StreamInfo(direction, media_type)
256 << "\tssrc=" << nack.sender_ssrc() << std::endl;
257 break;
258 }
259 case webrtc::rtcp::Tmmbr::kFeedbackMessageType: {
260 webrtc::rtcp::Tmmbr tmmbr;
261 if (!tmmbr.Parse(rtcp_block))
262 return;
263 MediaType media_type =
264 parsed_stream.GetMediaType(tmmbr.sender_ssrc(), direction);
265 if (ExcludePacket(direction, media_type, tmmbr.sender_ssrc()))
266 return;
267 std::cout << log_timestamp << "\t"
268 << "RTCP_TMMBR" << StreamInfo(direction, media_type)
269 << "\tssrc=" << tmmbr.sender_ssrc() << std::endl;
270 break;
271 }
272 case webrtc::rtcp::Tmmbn::kFeedbackMessageType: {
273 webrtc::rtcp::Tmmbn tmmbn;
274 if (!tmmbn.Parse(rtcp_block))
275 return;
276 MediaType media_type =
277 parsed_stream.GetMediaType(tmmbn.sender_ssrc(), direction);
278 if (ExcludePacket(direction, media_type, tmmbn.sender_ssrc()))
279 return;
280 std::cout << log_timestamp << "\t"
281 << "RTCP_TMMBN" << StreamInfo(direction, media_type)
282 << "\tssrc=" << tmmbn.sender_ssrc() << std::endl;
283 break;
284 }
285 case webrtc::rtcp::RapidResyncRequest::kFeedbackMessageType: {
286 webrtc::rtcp::RapidResyncRequest sr_req;
287 if (!sr_req.Parse(rtcp_block))
288 return;
289 MediaType media_type =
290 parsed_stream.GetMediaType(sr_req.sender_ssrc(), direction);
291 if (ExcludePacket(direction, media_type, sr_req.sender_ssrc()))
292 return;
293 std::cout << log_timestamp << "\t"
294 << "RTCP_SRREQ" << StreamInfo(direction, media_type)
295 << "\tssrc=" << sr_req.sender_ssrc() << std::endl;
296 break;
297 }
298 case webrtc::rtcp::TransportFeedback::kFeedbackMessageType: {
299 webrtc::rtcp::TransportFeedback transport_feedback;
300 if (!transport_feedback.Parse(rtcp_block))
301 return;
302 MediaType media_type = parsed_stream.GetMediaType(
303 transport_feedback.sender_ssrc(), direction);
304 if (ExcludePacket(direction, media_type,
305 transport_feedback.sender_ssrc()))
306 return;
307 std::cout << log_timestamp << "\t"
308 << "RTCP_NEWFB" << StreamInfo(direction, media_type)
309 << "\tsender_ssrc=" << transport_feedback.sender_ssrc()
310 << "\tmedia_ssrc=" << transport_feedback.media_ssrc()
311 << std::endl;
312 break;
313 }
314 default:
315 std::cout << log_timestamp << "\t"
316 << "RTCP_RTPFB(UNKNOWN)" << std::endl;
317 break;
318 }
319 }
320
PrintPsFeedback(const webrtc::ParsedRtcEventLog & parsed_stream,const webrtc::rtcp::CommonHeader & rtcp_block,uint64_t log_timestamp,webrtc::PacketDirection direction)321 void PrintPsFeedback(const webrtc::ParsedRtcEventLog& parsed_stream,
322 const webrtc::rtcp::CommonHeader& rtcp_block,
323 uint64_t log_timestamp,
324 webrtc::PacketDirection direction) {
325 switch (rtcp_block.fmt()) {
326 case webrtc::rtcp::Pli::kFeedbackMessageType: {
327 webrtc::rtcp::Pli pli;
328 if (!pli.Parse(rtcp_block))
329 return;
330 MediaType media_type =
331 parsed_stream.GetMediaType(pli.sender_ssrc(), direction);
332 if (ExcludePacket(direction, media_type, pli.sender_ssrc()))
333 return;
334 std::cout << log_timestamp << "\t"
335 << "RTCP_PLI" << StreamInfo(direction, media_type)
336 << "\tssrc=" << pli.sender_ssrc() << std::endl;
337 break;
338 }
339 case webrtc::rtcp::Fir::kFeedbackMessageType: {
340 webrtc::rtcp::Fir fir;
341 if (!fir.Parse(rtcp_block))
342 return;
343 MediaType media_type =
344 parsed_stream.GetMediaType(fir.sender_ssrc(), direction);
345 if (ExcludePacket(direction, media_type, fir.sender_ssrc()))
346 return;
347 std::cout << log_timestamp << "\t"
348 << "RTCP_FIR" << StreamInfo(direction, media_type)
349 << "\tssrc=" << fir.sender_ssrc() << std::endl;
350 break;
351 }
352 case webrtc::rtcp::Remb::kFeedbackMessageType: {
353 webrtc::rtcp::Remb remb;
354 if (!remb.Parse(rtcp_block))
355 return;
356 MediaType media_type =
357 parsed_stream.GetMediaType(remb.sender_ssrc(), direction);
358 if (ExcludePacket(direction, media_type, remb.sender_ssrc()))
359 return;
360 std::cout << log_timestamp << "\t"
361 << "RTCP_REMB" << StreamInfo(direction, media_type)
362 << "\tssrc=" << remb.sender_ssrc() << std::endl;
363 break;
364 }
365 default:
366 std::cout << log_timestamp << "\t"
367 << "RTCP_PSFB(UNKNOWN)" << std::endl;
368 break;
369 }
370 }
371
372 } // namespace
373
374 // This utility will print basic information about each packet to stdout.
375 // Note that parser will assert if the protobuf event is missing some required
376 // fields and we attempt to access them. We don't handle this at the moment.
main(int argc,char * argv[])377 int main(int argc, char* argv[]) {
378 std::string program_name = argv[0];
379 std::string usage =
380 "Tool for printing packet information from an RtcEventLog as text.\n"
381 "Run " +
382 program_name +
383 " --help for usage.\n"
384 "Example usage:\n" +
385 program_name + " input.rel\n";
386 if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true) ||
387 FLAG_help || argc != 2) {
388 std::cout << usage;
389 if (FLAG_help) {
390 rtc::FlagList::Print(nullptr, false);
391 return 0;
392 }
393 return 1;
394 }
395 std::string input_file = argv[1];
396
397 if (strlen(FLAG_ssrc) > 0)
398 RTC_CHECK(ParseSsrc(FLAG_ssrc)) << "Flag verification has failed.";
399
400 webrtc::RtpHeaderExtensionMap default_map = GetDefaultHeaderExtensionMap();
401 bool default_map_used = false;
402
403 webrtc::ParsedRtcEventLog parsed_stream;
404 if (!parsed_stream.ParseFile(input_file)) {
405 std::cerr << "Error while parsing input file: " << input_file << std::endl;
406 return -1;
407 }
408
409 for (size_t i = 0; i < parsed_stream.GetNumberOfEvents(); i++) {
410 bool event_recognized = false;
411 switch (parsed_stream.GetEventType(i)) {
412 case webrtc::ParsedRtcEventLog::UNKNOWN_EVENT: {
413 if (FLAG_unknown) {
414 std::cout << parsed_stream.GetTimestamp(i) << "\tUNKNOWN_EVENT"
415 << std::endl;
416 }
417 event_recognized = true;
418 break;
419 }
420
421 case webrtc::ParsedRtcEventLog::LOG_START: {
422 if (FLAG_startstop) {
423 std::cout << parsed_stream.GetTimestamp(i) << "\tLOG_START"
424 << std::endl;
425 }
426 event_recognized = true;
427 break;
428 }
429
430 case webrtc::ParsedRtcEventLog::LOG_END: {
431 if (FLAG_startstop) {
432 std::cout << parsed_stream.GetTimestamp(i) << "\tLOG_END"
433 << std::endl;
434 }
435 event_recognized = true;
436 break;
437 }
438
439 case webrtc::ParsedRtcEventLog::RTP_EVENT: {
440 if (FLAG_rtp) {
441 size_t header_length;
442 size_t total_length;
443 uint8_t header[IP_PACKET_SIZE];
444 webrtc::PacketDirection direction;
445 webrtc::RtpHeaderExtensionMap* extension_map =
446 parsed_stream.GetRtpHeader(i, &direction, header, &header_length,
447 &total_length, nullptr);
448
449 if (extension_map == nullptr) {
450 extension_map = &default_map;
451 if (!default_map_used)
452 RTC_LOG(LS_WARNING) << "Using default header extension map";
453 default_map_used = true;
454 }
455
456 // Parse header to get SSRC and RTP time.
457 webrtc::RtpUtility::RtpHeaderParser rtp_parser(header, header_length);
458 webrtc::RTPHeader parsed_header;
459 rtp_parser.Parse(&parsed_header, extension_map);
460 MediaType media_type =
461 parsed_stream.GetMediaType(parsed_header.ssrc, direction);
462
463 if (ExcludePacket(direction, media_type, parsed_header.ssrc)) {
464 event_recognized = true;
465 break;
466 }
467
468 std::cout << parsed_stream.GetTimestamp(i) << "\tRTP"
469 << StreamInfo(direction, media_type)
470 << "\tssrc=" << parsed_header.ssrc
471 << "\ttimestamp=" << parsed_header.timestamp;
472 if (parsed_header.extension.hasAbsoluteSendTime) {
473 std::cout << "\tAbsSendTime="
474 << parsed_header.extension.absoluteSendTime;
475 }
476 if (parsed_header.extension.hasVideoContentType) {
477 std::cout << "\tContentType="
478 << static_cast<int>(
479 parsed_header.extension.videoContentType);
480 }
481 if (parsed_header.extension.hasVideoRotation) {
482 std::cout << "\tRotation="
483 << static_cast<int>(
484 parsed_header.extension.videoRotation);
485 }
486 if (parsed_header.extension.hasTransportSequenceNumber) {
487 std::cout << "\tTransportSeq="
488 << parsed_header.extension.transportSequenceNumber;
489 }
490 if (parsed_header.extension.hasTransmissionTimeOffset) {
491 std::cout << "\tTransmTimeOffset="
492 << parsed_header.extension.transmissionTimeOffset;
493 }
494 if (parsed_header.extension.hasAudioLevel) {
495 std::cout << "\tAudioLevel=" <<
496 static_cast<int>(parsed_header.extension.audioLevel);
497 }
498 std::cout << std::endl;
499 if (FLAG_print_full_packets) {
500 // TODO(terelius): Rewrite this file to use printf instead of cout.
501 std::cout << "\t\t" << std::hex;
502 char prev_fill = std::cout.fill('0');
503 for (size_t i = 0; i < header_length; i++) {
504 std::cout << std::setw(2) << static_cast<unsigned>(header[i]);
505 if (i % 4 == 3)
506 std::cout << " "; // Separator between 32-bit words.
507 }
508 std::cout.fill(prev_fill);
509 std::cout << std::dec << std::endl;
510 }
511 }
512 event_recognized = true;
513 break;
514 }
515
516 case webrtc::ParsedRtcEventLog::RTCP_EVENT: {
517 if (FLAG_rtcp) {
518 size_t length;
519 uint8_t packet[IP_PACKET_SIZE];
520 webrtc::PacketDirection direction;
521 parsed_stream.GetRtcpPacket(i, &direction, packet, &length);
522
523 webrtc::rtcp::CommonHeader rtcp_block;
524 const uint8_t* packet_end = packet + length;
525 for (const uint8_t* next_block = packet; next_block != packet_end;
526 next_block = rtcp_block.NextPacket()) {
527 ptrdiff_t remaining_blocks_size = packet_end - next_block;
528 RTC_DCHECK_GT(remaining_blocks_size, 0);
529 if (!rtcp_block.Parse(next_block, remaining_blocks_size)) {
530 RTC_LOG(LS_WARNING) << "Failed to parse RTCP";
531 break;
532 }
533
534 uint64_t log_timestamp = parsed_stream.GetTimestamp(i);
535 switch (rtcp_block.type()) {
536 case webrtc::rtcp::SenderReport::kPacketType:
537 PrintSenderReport(parsed_stream, rtcp_block, log_timestamp,
538 direction);
539 break;
540 case webrtc::rtcp::ReceiverReport::kPacketType:
541 PrintReceiverReport(parsed_stream, rtcp_block, log_timestamp,
542 direction);
543 break;
544 case webrtc::rtcp::Sdes::kPacketType:
545 PrintSdes(rtcp_block, log_timestamp, direction);
546 break;
547 case webrtc::rtcp::ExtendedReports::kPacketType:
548 PrintXr(parsed_stream, rtcp_block, log_timestamp, direction);
549 break;
550 case webrtc::rtcp::Bye::kPacketType:
551 PrintBye(parsed_stream, rtcp_block, log_timestamp, direction);
552 break;
553 case webrtc::rtcp::Rtpfb::kPacketType:
554 PrintRtpFeedback(parsed_stream, rtcp_block, log_timestamp,
555 direction);
556 break;
557 case webrtc::rtcp::Psfb::kPacketType:
558 PrintPsFeedback(parsed_stream, rtcp_block, log_timestamp,
559 direction);
560 break;
561 default:
562 break;
563 }
564 if (FLAG_print_full_packets) {
565 std::cout << "\t\t" << std::hex;
566 char prev_fill = std::cout.fill('0');
567 for (const uint8_t* p = next_block; p < rtcp_block.NextPacket();
568 p++) {
569 std::cout << std::setw(2) << static_cast<unsigned>(*p);
570 ptrdiff_t chars_printed = p - next_block;
571 if (chars_printed % 4 == 3)
572 std::cout << " "; // Separator between 32-bit words.
573 }
574 std::cout.fill(prev_fill);
575 std::cout << std::dec << std::endl;
576 }
577 }
578 }
579 event_recognized = true;
580 break;
581 }
582
583 case webrtc::ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT: {
584 if (FLAG_playout) {
585 uint32_t ssrc;
586 parsed_stream.GetAudioPlayout(i, &ssrc);
587 std::cout << parsed_stream.GetTimestamp(i) << "\tAUDIO_PLAYOUT"
588 << "\tssrc=" << ssrc << std::endl;
589 }
590 event_recognized = true;
591 break;
592 }
593
594 case webrtc::ParsedRtcEventLog::LOSS_BASED_BWE_UPDATE: {
595 if (FLAG_bwe) {
596 int32_t bitrate_bps;
597 uint8_t fraction_loss;
598 int32_t total_packets;
599 parsed_stream.GetLossBasedBweUpdate(i, &bitrate_bps, &fraction_loss,
600 &total_packets);
601 std::cout << parsed_stream.GetTimestamp(i) << "\tBWE(LOSS_BASED)"
602 << "\tbitrate_bps=" << bitrate_bps << "\tfraction_loss="
603 << static_cast<unsigned>(fraction_loss)
604 << "\ttotal_packets=" << total_packets << std::endl;
605 }
606 event_recognized = true;
607 break;
608 }
609
610 case webrtc::ParsedRtcEventLog::DELAY_BASED_BWE_UPDATE: {
611 if (FLAG_bwe) {
612 auto bwe_update = parsed_stream.GetDelayBasedBweUpdate(i);
613 std::cout << parsed_stream.GetTimestamp(i) << "\tBWE(DELAY_BASED)"
614 << "\tbitrate_bps=" << bwe_update.bitrate_bps
615 << "\tdetector_state="
616 << static_cast<int>(bwe_update.detector_state) << std::endl;
617 }
618 event_recognized = true;
619 break;
620 }
621
622 case webrtc::ParsedRtcEventLog::VIDEO_RECEIVER_CONFIG_EVENT: {
623 if (FLAG_config && FLAG_video && FLAG_incoming) {
624 webrtc::rtclog::StreamConfig config =
625 parsed_stream.GetVideoReceiveConfig(i);
626 std::cout << parsed_stream.GetTimestamp(i) << "\tVIDEO_RECV_CONFIG"
627 << "\tssrc=" << config.remote_ssrc
628 << "\tfeedback_ssrc=" << config.local_ssrc;
629 std::cout << "\textensions={";
630 for (const auto& extension : config.rtp_extensions) {
631 std::cout << extension.ToString() << ",";
632 }
633 std::cout << "}";
634 std::cout << "\tcodecs={";
635 for (const auto& codec : config.codecs) {
636 std::cout << "{name: " << codec.payload_name
637 << ", payload_type: " << codec.payload_type
638 << ", rtx_payload_type: " << codec.rtx_payload_type
639 << "}";
640 }
641 std::cout << "}" << std::endl;
642 }
643 event_recognized = true;
644 break;
645 }
646
647 case webrtc::ParsedRtcEventLog::VIDEO_SENDER_CONFIG_EVENT: {
648 if (FLAG_config && FLAG_video && FLAG_outgoing) {
649 std::vector<webrtc::rtclog::StreamConfig> configs =
650 parsed_stream.GetVideoSendConfig(i);
651 for (const auto& config : configs) {
652 std::cout << parsed_stream.GetTimestamp(i) << "\tVIDEO_SEND_CONFIG";
653 std::cout << "\tssrcs=" << config.local_ssrc;
654 std::cout << "\trtx_ssrcs=" << config.rtx_ssrc;
655 std::cout << "\textensions={";
656 for (const auto& extension : config.rtp_extensions) {
657 std::cout << extension.ToString() << ",";
658 }
659 std::cout << "}";
660 std::cout << "\tcodecs={";
661 for (const auto& codec : config.codecs) {
662 std::cout << "{name: " << codec.payload_name
663 << ", payload_type: " << codec.payload_type
664 << ", rtx_payload_type: " << codec.rtx_payload_type
665 << "}";
666 }
667 std::cout << "}" << std::endl;
668 }
669 }
670 event_recognized = true;
671 break;
672 }
673
674 case webrtc::ParsedRtcEventLog::AUDIO_RECEIVER_CONFIG_EVENT: {
675 if (FLAG_config && FLAG_audio && FLAG_incoming) {
676 webrtc::rtclog::StreamConfig config =
677 parsed_stream.GetAudioReceiveConfig(i);
678 std::cout << parsed_stream.GetTimestamp(i) << "\tAUDIO_RECV_CONFIG"
679 << "\tssrc=" << config.remote_ssrc
680 << "\tfeedback_ssrc=" << config.local_ssrc;
681 std::cout << "\textensions={";
682 for (const auto& extension : config.rtp_extensions) {
683 std::cout << extension.ToString() << ",";
684 }
685 std::cout << "}";
686 std::cout << "\tcodecs={";
687 for (const auto& codec : config.codecs) {
688 std::cout << "{name: " << codec.payload_name
689 << ", payload_type: " << codec.payload_type
690 << ", rtx_payload_type: " << codec.rtx_payload_type
691 << "}";
692 }
693 std::cout << "}" << std::endl;
694 }
695 event_recognized = true;
696 break;
697 }
698
699 case webrtc::ParsedRtcEventLog::AUDIO_SENDER_CONFIG_EVENT: {
700 if (FLAG_config && FLAG_audio && FLAG_outgoing) {
701 webrtc::rtclog::StreamConfig config =
702 parsed_stream.GetAudioSendConfig(i);
703 std::cout << parsed_stream.GetTimestamp(i) << "\tAUDIO_SEND_CONFIG"
704 << "\tssrc=" << config.local_ssrc;
705 std::cout << "\textensions={";
706 for (const auto& extension : config.rtp_extensions) {
707 std::cout << extension.ToString() << ",";
708 }
709 std::cout << "}";
710 std::cout << "\tcodecs={";
711 for (const auto& codec : config.codecs) {
712 std::cout << "{name: " << codec.payload_name
713 << ", payload_type: " << codec.payload_type
714 << ", rtx_payload_type: " << codec.rtx_payload_type
715 << "}";
716 }
717 std::cout << "}" << std::endl;
718 }
719 event_recognized = true;
720 break;
721 }
722
723 case webrtc::ParsedRtcEventLog::AUDIO_NETWORK_ADAPTATION_EVENT: {
724 if (FLAG_ana) {
725 webrtc::AudioEncoderRuntimeConfig ana_config;
726 parsed_stream.GetAudioNetworkAdaptation(i, &ana_config);
727 std::stringstream ss;
728 ss << parsed_stream.GetTimestamp(i) << "\tANA_UPDATE";
729 if (ana_config.bitrate_bps) {
730 ss << "\tbitrate_bps=" << *ana_config.bitrate_bps;
731 }
732 if (ana_config.frame_length_ms) {
733 ss << "\tframe_length_ms=" << *ana_config.frame_length_ms;
734 }
735 if (ana_config.uplink_packet_loss_fraction) {
736 ss << "\tuplink_packet_loss_fraction="
737 << *ana_config.uplink_packet_loss_fraction;
738 }
739 if (ana_config.enable_fec) {
740 ss << "\tenable_fec=" << *ana_config.enable_fec;
741 }
742 if (ana_config.enable_dtx) {
743 ss << "\tenable_dtx=" << *ana_config.enable_dtx;
744 }
745 if (ana_config.num_channels) {
746 ss << "\tnum_channels=" << *ana_config.num_channels;
747 }
748 std::cout << ss.str() << std::endl;
749 }
750 event_recognized = true;
751 break;
752 }
753
754 case webrtc::ParsedRtcEventLog::BWE_PROBE_CLUSTER_CREATED_EVENT: {
755 if (FLAG_probe) {
756 webrtc::ParsedRtcEventLog::BweProbeClusterCreatedEvent probe_event =
757 parsed_stream.GetBweProbeClusterCreated(i);
758 std::cout << parsed_stream.GetTimestamp(i) << "\tPROBE_CREATED("
759 << probe_event.id << ")"
760 << "\tbitrate_bps=" << probe_event.bitrate_bps
761 << "\tmin_packets=" << probe_event.min_packets
762 << "\tmin_bytes=" << probe_event.min_bytes << std::endl;
763 }
764 event_recognized = true;
765 break;
766 }
767
768 case webrtc::ParsedRtcEventLog::BWE_PROBE_RESULT_EVENT: {
769 if (FLAG_probe) {
770 webrtc::ParsedRtcEventLog::BweProbeResultEvent probe_result =
771 parsed_stream.GetBweProbeResult(i);
772 if (probe_result.failure_reason) {
773 std::cout << parsed_stream.GetTimestamp(i) << "\tPROBE_SUCCESS("
774 << probe_result.id << ")"
775 << "\tfailure_reason="
776 << static_cast<int>(*probe_result.failure_reason)
777 << std::endl;
778 } else {
779 std::cout << parsed_stream.GetTimestamp(i) << "\tPROBE_SUCCESS("
780 << probe_result.id << ")"
781 << "\tbitrate_bps=" << *probe_result.bitrate_bps
782 << std::endl;
783 }
784 }
785 event_recognized = true;
786 break;
787 }
788 }
789
790 if (!event_recognized) {
791 std::cout << "Unrecognized event (" << parsed_stream.GetEventType(i)
792 << ")" << std::endl;
793 }
794 }
795 return 0;
796 }
797