1#  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
2#
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
5#  tree. An additional intellectual property rights grant can be found
6#  in the file PATENTS.  All contributing project authors may
7#  be found in the AUTHORS file in the root of the source tree.
8
9#  To run this script please copy "out/<build_name>/pyproto/webrtc/rtc_tools/
10#  network_tester/network_tester_packet_pb2.py" next to this script.
11#  The you can run this script with:
12#  "python parse_packet_log.py -f packet_log.dat"
13#  for more information call:
14#  "python parse_packet_log.py --help"
15
16from optparse import OptionParser
17import struct
18
19import matplotlib.pyplot as plt
20
21import network_tester_packet_pb2
22
23def GetSize(file_to_parse):
24  data = file_to_parse.read(1)
25  if data == '':
26    return 0
27  return struct.unpack('<b', data)[0]
28
29
30def ParsePacketLog(packet_log_file_to_parse):
31  packets = []
32  with open(packet_log_file_to_parse, 'rb') as file_to_parse:
33    while True:
34      size = GetSize(file_to_parse)
35      if size == 0:
36        break
37      try:
38        packet = network_tester_packet_pb2.NetworkTesterPacket()
39        packet.ParseFromString(file_to_parse.read(size))
40        packets.append(packet)
41      except IOError:
42        break
43  return packets
44
45
46def GetTimeAxis(packets):
47  first_arrival_time = packets[0].arrival_timestamp
48  return [(packet.arrival_timestamp - first_arrival_time) / 1000000.0
49          for packet in packets]
50
51
52def CreateSendTimeDiffPlot(packets, plot):
53  first_send_time_diff = (
54      packets[0].arrival_timestamp - packets[0].send_timestamp)
55  y = [(packet.arrival_timestamp - packet.send_timestamp) - first_send_time_diff
56       for packet in packets]
57  plot.grid(True)
58  plot.set_title("SendTime difference [us]")
59  plot.plot(GetTimeAxis(packets), y)
60
61
62class MovingAverageBitrate(object):
63
64  def __init__(self):
65    self.packet_window = []
66    self.window_time = 1000000
67    self.bytes = 0
68    self.latest_packet_time = 0
69    self.send_interval = 0
70
71  def RemoveOldPackets(self):
72    for packet in self.packet_window:
73      if (self.latest_packet_time - packet.arrival_timestamp >
74          self.window_time):
75        self.bytes = self.bytes - packet.packet_size
76        self.packet_window.remove(packet)
77
78  def AddPacket(self, packet):
79    """This functions returns bits / second"""
80    self.send_interval = packet.arrival_timestamp - self.latest_packet_time
81    self.latest_packet_time = packet.arrival_timestamp
82    self.RemoveOldPackets()
83    self.packet_window.append(packet)
84    self.bytes = self.bytes + packet.packet_size
85    return self.bytes * 8
86
87
88def CreateReceiveBiratePlot(packets, plot):
89  bitrate = MovingAverageBitrate()
90  y = [bitrate.AddPacket(packet) for packet in packets]
91  plot.grid(True)
92  plot.set_title("Receive birate [bps]")
93  plot.plot(GetTimeAxis(packets), y)
94
95
96def CreatePacketlossPlot(packets, plot):
97  packets_look_up = {}
98  first_sequence_number = packets[0].sequence_number
99  last_sequence_number = packets[-1].sequence_number
100  for packet in packets:
101    packets_look_up[packet.sequence_number] = packet
102  y = []
103  x = []
104  first_arrival_time = 0
105  last_arrival_time = 0
106  last_arrival_time_diff = 0
107  for sequence_number in range(first_sequence_number, last_sequence_number + 1):
108    if sequence_number in packets_look_up:
109      y.append(0)
110      if first_arrival_time == 0:
111        first_arrival_time = packets_look_up[sequence_number].arrival_timestamp
112      x_time = (packets_look_up[sequence_number].arrival_timestamp -
113                first_arrival_time)
114      if last_arrival_time != 0:
115        last_arrival_time_diff = x_time - last_arrival_time
116      last_arrival_time = x_time
117      x.append(x_time / 1000000.0)
118    else:
119      if last_arrival_time != 0 and last_arrival_time_diff != 0:
120        x.append((last_arrival_time + last_arrival_time_diff) / 1000000.0)
121        y.append(1)
122  plot.grid(True)
123  plot.set_title("Lost packets [0/1]")
124  plot.plot(x, y)
125
126
127def main():
128  parser = OptionParser()
129  parser.add_option("-f",
130                    "--packet_log_file",
131                    dest="packet_log_file",
132                    help="packet_log file to parse")
133
134  options = parser.parse_args()[0]
135
136  packets = ParsePacketLog(options.packet_log_file)
137  f, plots = plt.subplots(3, sharex=True)
138  plt.xlabel('time [sec]')
139  CreateSendTimeDiffPlot(packets, plots[0])
140  CreateReceiveBiratePlot(packets, plots[1])
141  CreatePacketlossPlot(packets, plots[2])
142  f.subplots_adjust(hspace=0.3)
143  plt.show()
144
145
146if __name__ == "__main__":
147  main()
148