From 0e7000b20a5a3f7a420dfe1ef4fa7f3347cded75 Mon Sep 17 00:00:00 2001 From: aleloi Date: Tue, 5 Jul 2016 07:53:35 -0700 Subject: [PATCH] Changes in UI and minor extra functionality for rtp_analyzer. 1. The tool now displays packet loss in %. 2. It can print header information to stdout like rtp_analyze. 3. It has a command-line switch that lets you override the sample rate guessing. With the flag "--query_sample_rate" the tool asks you to always provide a sample rate. 4. Less decimals are printed for the estimated sample rate. NOTRY=True Review-Url: https://codereview.webrtc.org/2123773002 Cr-Commit-Position: refs/heads/master@{#13385} --- webrtc/tools/py_event_log_analyzer/README | 8 ++- .../tools/py_event_log_analyzer/pb_parse.py | 1 + .../py_event_log_analyzer/rtp_analyzer.py | 56 +++++++++++++++---- 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/webrtc/tools/py_event_log_analyzer/README b/webrtc/tools/py_event_log_analyzer/README index ed656ddef9..6c77136d04 100644 --- a/webrtc/tools/py_event_log_analyzer/README +++ b/webrtc/tools/py_event_log_analyzer/README @@ -12,12 +12,18 @@ is enough. After building, run the tool as follows: - ./out/my_build/rtp_analyzer.sh + ./out/my_build/rtp_analyzer.sh [options] where is a recorded RTC event log, which is stored in protobuf format. Such logs are generated in multiple ways, e.g. by Chrome through the chrome://webrtc-internals page. +Options: + -h, --help show this help message and exit + --dump_header_to_stdout + print header info to stdout; similar to rtp_analyze + --query_sample_rate always query user for real sample rate + The script has been tested to work in python versions 3.4.1 and 2.7.6, but should work in all python versions. diff --git a/webrtc/tools/py_event_log_analyzer/pb_parse.py b/webrtc/tools/py_event_log_analyzer/pb_parse.py index b1232f038e..b0ca2b3354 100644 --- a/webrtc/tools/py_event_log_analyzer/pb_parse.py +++ b/webrtc/tools/py_event_log_analyzer/pb_parse.py @@ -28,6 +28,7 @@ class DataPoint(object): (first2header_bytes, self.sequence_number, self.timestamp, self.ssrc) = header self.payload_type = first2header_bytes & 0b01111111 + self.marker_bit = (first2header_bytes & 0b10000000) >> 7 def parse_protobuf(file_path): diff --git a/webrtc/tools/py_event_log_analyzer/rtp_analyzer.py b/webrtc/tools/py_event_log_analyzer/rtp_analyzer.py index f859837e94..850dd43d39 100644 --- a/webrtc/tools/py_event_log_analyzer/rtp_analyzer.py +++ b/webrtc/tools/py_event_log_analyzer/rtp_analyzer.py @@ -12,6 +12,7 @@ from __future__ import division from __future__ import print_function import collections +import optparse import sys import matplotlib.pyplot as plt @@ -45,6 +46,15 @@ class RTPStatistics(object): self.bandwidth_kbps = None self.smooth_bw_kbps = None + def print_header_statistics(self): + print("{:>6}{:>11}{:>11}{:>6}{:>6}{:>3}{:>11}".format( + "SeqNo", "TimeStamp", "SendTime", "Size", "PT", "M", "SSRC")) + for point in self.data_points: + print("{:>6}{:>11}{:>11}{:>6}{:>6}{:>3}{:>11}".format( + point.sequence_number, point.timestamp, + int(point.arrival_timestamp_ms), point.size, point.payload_type, + point.marker_bit, "0x{:x}".format(point.ssrc))) + def print_ssrc_info(self, ssrc_id, ssrc): """Prints packet and size statistics for a given SSRC. @@ -116,9 +126,12 @@ class RTPStatistics(object): def print_sequence_number_statistics(self): seq_no_set = set(point.sequence_number for point in self.data_points) - print("Missing sequence numbers: {} out of {}".format( - max(seq_no_set) - min(seq_no_set) + 1 - len(seq_no_set), - len(seq_no_set) + missing_sequence_numbers = max(seq_no_set) - min(seq_no_set) + ( + 1 - len(seq_no_set)) + print("Missing sequence numbers: {} out of {} ({:.2f}%)".format( + missing_sequence_numbers, + len(seq_no_set), + 100 * missing_sequence_numbers / len(seq_no_set) )) print("Duplicated packets: {}".format(len(self.data_points) - len(seq_no_set))) @@ -126,7 +139,7 @@ class RTPStatistics(object): misc.count_reordered([point.sequence_number for point in self.data_points]))) - def estimate_frequency(self): + def estimate_frequency(self, always_query_sample_rate): """Estimates frequency and updates data. Guesses the most probable frequency by looking at changes in @@ -146,10 +159,11 @@ class RTPStatistics(object): if abs((freq_est - f) / f) < 0.05: freq = f - print("Estimated frequency: {}kHz".format(freq_est)) - if freq is None: - freq = int(misc.get_input( - "Frequency could not be guessed. Input frequency (in kHz)> ")) + print("Estimated frequency: {:.3f}kHz".format(freq_est)) + if freq is None or always_query_sample_rate: + if not always_query_sample_rate: + print ("Frequency could not be guessed.", end=" ") + freq = int(misc.get_input("Input frequency (in kHz)> ")) else: print("Guessed frequency: {}kHz".format(freq)) @@ -238,19 +252,37 @@ class RTPStatistics(object): def main(): - if len(sys.argv) < 2: - print("Usage: python rtp_analyzer.py ") + usage = "Usage: %prog [options] " + parser = optparse.OptionParser(usage=usage) + parser.add_option("--dump_header_to_stdout", + default=False, action="store_true", + help="print header info to stdout; similar to rtp_analyze") + parser.add_option("--query_sample_rate", + default=False, action="store_true", + help="always query user for real sample rate") + + (options, args) = parser.parse_args() + + if len(args) < 1: + parser.print_help() sys.exit(0) - data_points = pb_parse.parse_protobuf(sys.argv[1]) + data_points = pb_parse.parse_protobuf(args[0]) rtp_stats = RTPStatistics(data_points) + + if options.dump_header_to_stdout: + print("Printing header info to stdout.", file=sys.stderr) + rtp_stats.print_header_statistics() + sys.exit(0) + chosen_ssrc = rtp_stats.choose_ssrc() print("Chosen SSRC: 0X{:X}".format(chosen_ssrc)) rtp_stats.filter_ssrc(chosen_ssrc) + print("Statistics:") rtp_stats.print_sequence_number_statistics() - rtp_stats.estimate_frequency() + rtp_stats.estimate_frequency(options.query_sample_rate) rtp_stats.print_duration_statistics() rtp_stats.remove_reordered() rtp_stats.compute_bandwidth()