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