Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Side by Side Diff: webrtc/tools/py_event_log_analyzer/rtp_analyzer.py

Issue 2123773002: Changes in UI and minor extra functionality for rtp_analyzer. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/tools/py_event_log_analyzer/pb_parse.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. 1 # Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
2 # 2 #
3 # Use of this source code is governed by a BSD-style license 3 # Use of this source code is governed by a BSD-style license
4 # that can be found in the LICENSE file in the root of the source 4 # that can be found in the LICENSE file in the root of the source
5 # tree. An additional intellectual property rights grant can be found 5 # tree. An additional intellectual property rights grant can be found
6 # in the file PATENTS. All contributing project authors may 6 # in the file PATENTS. All contributing project authors may
7 # be found in the AUTHORS file in the root of the source tree. 7 # be found in the AUTHORS file in the root of the source tree.
8 8
9 """Displays statistics and plots graphs from RTC protobuf dump.""" 9 """Displays statistics and plots graphs from RTC protobuf dump."""
10 10
11 from __future__ import division 11 from __future__ import division
12 from __future__ import print_function 12 from __future__ import print_function
13 13
14 import collections 14 import collections
15 import optparse
15 import sys 16 import sys
16 17
17 import matplotlib.pyplot as plt 18 import matplotlib.pyplot as plt
18 import numpy 19 import numpy
19 20
20 import misc 21 import misc
21 import pb_parse 22 import pb_parse
22 23
23 24
24 class RTPStatistics(object): 25 class RTPStatistics(object):
(...skipping 13 matching lines...) Expand all
38 39
39 """ 40 """
40 41
41 self.data_points = data_points 42 self.data_points = data_points
42 self.ssrc_frequencies = misc.normalize_counter( 43 self.ssrc_frequencies = misc.normalize_counter(
43 collections.Counter([pt.ssrc for pt in self.data_points])) 44 collections.Counter([pt.ssrc for pt in self.data_points]))
44 self.ssrc_size_table = misc.ssrc_normalized_size_table(self.data_points) 45 self.ssrc_size_table = misc.ssrc_normalized_size_table(self.data_points)
45 self.bandwidth_kbps = None 46 self.bandwidth_kbps = None
46 self.smooth_bw_kbps = None 47 self.smooth_bw_kbps = None
47 48
49 def print_header_statistics(self):
50 print("{:>6}{:>11}{:>11}{:>6}{:>6}{:>3}{:>11}".format(
51 "SeqNo", "TimeStamp", "SendTime", "Size", "PT", "M", "SSRC"))
52 for point in self.data_points:
53 print("{:>6}{:>11}{:>11}{:>6}{:>6}{:>3}{:>11}".format(
54 point.sequence_number, point.timestamp,
55 int(point.arrival_timestamp_ms), point.size, point.payload_type,
56 point.marker_bit, "0x{:x}".format(point.ssrc)))
57
48 def print_ssrc_info(self, ssrc_id, ssrc): 58 def print_ssrc_info(self, ssrc_id, ssrc):
49 """Prints packet and size statistics for a given SSRC. 59 """Prints packet and size statistics for a given SSRC.
50 60
51 Args: 61 Args:
52 ssrc_id: textual identifier of SSRC printed beside statistics for it. 62 ssrc_id: textual identifier of SSRC printed beside statistics for it.
53 ssrc: SSRC by which to filter data and display statistics 63 ssrc: SSRC by which to filter data and display statistics
54 """ 64 """
55 filtered_ssrc = [point for point in self.data_points if point.ssrc 65 filtered_ssrc = [point for point in self.data_points if point.ssrc
56 == ssrc] 66 == ssrc]
57 payloads = misc.normalize_counter( 67 payloads = misc.normalize_counter(
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 unwrapped_timestamps = misc.unwrap([point.timestamp for point in 119 unwrapped_timestamps = misc.unwrap([point.timestamp for point in
110 self.data_points], 2**32 - 1) 120 self.data_points], 2**32 - 1)
111 121
112 for (data_point, timestamp) in zip(self.data_points, 122 for (data_point, timestamp) in zip(self.data_points,
113 unwrapped_timestamps): 123 unwrapped_timestamps):
114 data_point.timestamp = timestamp 124 data_point.timestamp = timestamp
115 125
116 def print_sequence_number_statistics(self): 126 def print_sequence_number_statistics(self):
117 seq_no_set = set(point.sequence_number for point in 127 seq_no_set = set(point.sequence_number for point in
118 self.data_points) 128 self.data_points)
119 print("Missing sequence numbers: {} out of {}".format( 129 missing_sequence_numbers = max(seq_no_set) - min(seq_no_set) + (
120 max(seq_no_set) - min(seq_no_set) + 1 - len(seq_no_set), 130 1 - len(seq_no_set))
121 len(seq_no_set) 131 print("Missing sequence numbers: {} out of {} ({:.2f}%)".format(
132 missing_sequence_numbers,
133 len(seq_no_set),
134 100 * missing_sequence_numbers / len(seq_no_set)
122 )) 135 ))
123 print("Duplicated packets: {}".format(len(self.data_points) - 136 print("Duplicated packets: {}".format(len(self.data_points) -
124 len(seq_no_set))) 137 len(seq_no_set)))
125 print("Reordered packets: {}".format( 138 print("Reordered packets: {}".format(
126 misc.count_reordered([point.sequence_number for point in 139 misc.count_reordered([point.sequence_number for point in
127 self.data_points]))) 140 self.data_points])))
128 141
129 def estimate_frequency(self): 142 def estimate_frequency(self, always_query_sample_rate):
130 """Estimates frequency and updates data. 143 """Estimates frequency and updates data.
131 144
132 Guesses the most probable frequency by looking at changes in 145 Guesses the most probable frequency by looking at changes in
133 timestamps (RFC 3550 section 5.1), calculates clock drifts and 146 timestamps (RFC 3550 section 5.1), calculates clock drifts and
134 sending time of packets. Updates `self.data_points` with changes 147 sending time of packets. Updates `self.data_points` with changes
135 in delay and send time. 148 in delay and send time.
136 """ 149 """
137 delta_timestamp = (self.data_points[-1].timestamp - 150 delta_timestamp = (self.data_points[-1].timestamp -
138 self.data_points[0].timestamp) 151 self.data_points[0].timestamp)
139 delta_arr_timestamp = float((self.data_points[-1].arrival_timestamp_ms - 152 delta_arr_timestamp = float((self.data_points[-1].arrival_timestamp_ms -
140 self.data_points[0].arrival_timestamp_ms)) 153 self.data_points[0].arrival_timestamp_ms))
141 freq_est = delta_timestamp / delta_arr_timestamp 154 freq_est = delta_timestamp / delta_arr_timestamp
142 155
143 freq_vec = [8, 16, 32, 48, 90] 156 freq_vec = [8, 16, 32, 48, 90]
144 freq = None 157 freq = None
145 for f in freq_vec: 158 for f in freq_vec:
146 if abs((freq_est - f) / f) < 0.05: 159 if abs((freq_est - f) / f) < 0.05:
147 freq = f 160 freq = f
148 161
149 print("Estimated frequency: {}kHz".format(freq_est)) 162 print("Estimated frequency: {:.3f}kHz".format(freq_est))
150 if freq is None: 163 if freq is None or always_query_sample_rate:
151 freq = int(misc.get_input( 164 if not always_query_sample_rate:
152 "Frequency could not be guessed. Input frequency (in kHz)> ")) 165 print ("Frequency could not be guessed.", end=" ")
166 freq = int(misc.get_input("Input frequency (in kHz)> "))
153 else: 167 else:
154 print("Guessed frequency: {}kHz".format(freq)) 168 print("Guessed frequency: {}kHz".format(freq))
155 169
156 for point in self.data_points: 170 for point in self.data_points:
157 point.real_send_time_ms = (point.timestamp - 171 point.real_send_time_ms = (point.timestamp -
158 self.data_points[0].timestamp) / freq 172 self.data_points[0].timestamp) / freq
159 point.delay = point.arrival_timestamp_ms -point.real_send_time_ms 173 point.delay = point.arrival_timestamp_ms -point.real_send_time_ms
160 174
161 def print_duration_statistics(self): 175 def print_duration_statistics(self):
162 """Prints delay, clock drift and bitrate statistics.""" 176 """Prints delay, clock drift and bitrate statistics."""
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 plt.plot([f.real_send_time_ms / 1000 for f in 245 plt.plot([f.real_send_time_ms / 1000 for f in
232 self.data_points][:len(self.smooth_bw_kbps)], 246 self.data_points][:len(self.smooth_bw_kbps)],
233 self.smooth_bw_kbps[:len(self.data_points)]) 247 self.smooth_bw_kbps[:len(self.data_points)])
234 plt.xlabel("Send time [s]") 248 plt.xlabel("Send time [s]")
235 plt.ylabel("Bandwidth [kbps]") 249 plt.ylabel("Bandwidth [kbps]")
236 250
237 plt.show() 251 plt.show()
238 252
239 253
240 def main(): 254 def main():
241 if len(sys.argv) < 2: 255 usage = "Usage: %prog [options] <filename of rtc event log>"
242 print("Usage: python rtp_analyzer.py <filename of rtc event log>") 256 parser = optparse.OptionParser(usage=usage)
257 parser.add_option("--dump_header_to_stdout",
258 default=False, action="store_true",
259 help="print header info to stdout; similar to rtp_analyze")
260 parser.add_option("--query_sample_rate",
261 default=False, action="store_true",
262 help="always query user for real sample rate")
263
264 (options, args) = parser.parse_args()
265
266 if len(args) < 1:
267 parser.print_help()
243 sys.exit(0) 268 sys.exit(0)
244 269
245 data_points = pb_parse.parse_protobuf(sys.argv[1]) 270 data_points = pb_parse.parse_protobuf(args[0])
246 rtp_stats = RTPStatistics(data_points) 271 rtp_stats = RTPStatistics(data_points)
272
273 if options.dump_header_to_stdout:
274 print("Printing header info to stdout.", file=sys.stderr)
275 rtp_stats.print_header_statistics()
276 sys.exit(0)
277
247 chosen_ssrc = rtp_stats.choose_ssrc() 278 chosen_ssrc = rtp_stats.choose_ssrc()
248 print("Chosen SSRC: 0X{:X}".format(chosen_ssrc)) 279 print("Chosen SSRC: 0X{:X}".format(chosen_ssrc))
249 280
250 rtp_stats.filter_ssrc(chosen_ssrc) 281 rtp_stats.filter_ssrc(chosen_ssrc)
282
251 print("Statistics:") 283 print("Statistics:")
252 rtp_stats.print_sequence_number_statistics() 284 rtp_stats.print_sequence_number_statistics()
253 rtp_stats.estimate_frequency() 285 rtp_stats.estimate_frequency(options.query_sample_rate)
254 rtp_stats.print_duration_statistics() 286 rtp_stats.print_duration_statistics()
255 rtp_stats.remove_reordered() 287 rtp_stats.remove_reordered()
256 rtp_stats.compute_bandwidth() 288 rtp_stats.compute_bandwidth()
257 rtp_stats.plot_statistics() 289 rtp_stats.plot_statistics()
258 290
259 if __name__ == "__main__": 291 if __name__ == "__main__":
260 main() 292 main()
OLDNEW
« no previous file with comments | « webrtc/tools/py_event_log_analyzer/pb_parse.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698