OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 return true; | 50 return true; |
51 return std::find(desired_ssrc.begin(), desired_ssrc.end(), ssrc) != | 51 return std::find(desired_ssrc.begin(), desired_ssrc.end(), ssrc) != |
52 desired_ssrc.end(); | 52 desired_ssrc.end(); |
53 } | 53 } |
54 | 54 |
55 double AbsSendTimeToMicroseconds(int64_t abs_send_time) { | 55 double AbsSendTimeToMicroseconds(int64_t abs_send_time) { |
56 // The timestamp is a fixed point representation with 6 bits for seconds | 56 // The timestamp is a fixed point representation with 6 bits for seconds |
57 // and 18 bits for fractions of a second. Thus, we divide by 2^18 to get the | 57 // and 18 bits for fractions of a second. Thus, we divide by 2^18 to get the |
58 // time in seconds and then multiply by 1000000 to convert to microseconds. | 58 // time in seconds and then multiply by 1000000 to convert to microseconds. |
59 static constexpr double kTimestampToMicroSec = | 59 static constexpr double kTimestampToMicroSec = |
60 1000000.0 / static_cast<double>(1 << 18); | 60 1000000.0 / static_cast<double>(1ul << 18); |
61 return abs_send_time * kTimestampToMicroSec; | 61 return abs_send_time * kTimestampToMicroSec; |
62 } | 62 } |
63 | 63 |
64 // Computes the difference |later| - |earlier| where |later| and |earlier| | 64 // Computes the difference |later| - |earlier| where |later| and |earlier| |
65 // are counters that wrap at |modulus|. The difference is chosen to have the | 65 // are counters that wrap at |modulus|. The difference is chosen to have the |
66 // least absolute value. For example if |modulus| is 8, then the difference will | 66 // least absolute value. For example if |modulus| is 8, then the difference will |
67 // be chosen in the range [-3, 4]. If |modulus| is 9, then the difference will | 67 // be chosen in the range [-3, 4]. If |modulus| is 9, then the difference will |
68 // be in [-4, 4]. | 68 // be in [-4, 4]. |
69 int64_t WrappingDifference(uint32_t later, uint32_t earlier, int64_t modulus) { | 69 int64_t WrappingDifference(uint32_t later, uint32_t earlier, int64_t modulus) { |
70 RTC_DCHECK_LE(1, modulus); | 70 RTC_DCHECK_LE(1, modulus); |
(...skipping 20 matching lines...) Expand all Loading... |
91 extension_map->Register(webrtc::StringToRtpExtensionType(extension.uri), | 91 extension_map->Register(webrtc::StringToRtpExtensionType(extension.uri), |
92 extension.id); | 92 extension.id); |
93 } | 93 } |
94 } | 94 } |
95 | 95 |
96 constexpr float kLeftMargin = 0.01f; | 96 constexpr float kLeftMargin = 0.01f; |
97 constexpr float kRightMargin = 0.02f; | 97 constexpr float kRightMargin = 0.02f; |
98 constexpr float kBottomMargin = 0.02f; | 98 constexpr float kBottomMargin = 0.02f; |
99 constexpr float kTopMargin = 0.05f; | 99 constexpr float kTopMargin = 0.05f; |
100 | 100 |
| 101 class NetworkDelayDiff { |
| 102 public: |
| 103 class AbsSendTime { |
| 104 public: |
| 105 using DataType = LoggedRtpPacket; |
| 106 using ResultType = double; |
| 107 double operator()(const LoggedRtpPacket& old_packet, |
| 108 const LoggedRtpPacket& new_packet) { |
| 109 if (old_packet.header.extension.hasAbsoluteSendTime && |
| 110 new_packet.header.extension.hasAbsoluteSendTime) { |
| 111 int64_t send_time_diff = WrappingDifference( |
| 112 new_packet.header.extension.absoluteSendTime, |
| 113 old_packet.header.extension.absoluteSendTime, 1ul << 24); |
| 114 int64_t recv_time_diff = new_packet.timestamp - old_packet.timestamp; |
| 115 return static_cast<double>(recv_time_diff - |
| 116 AbsSendTimeToMicroseconds(send_time_diff)) / |
| 117 1000; |
| 118 } else { |
| 119 return 0; |
| 120 } |
| 121 } |
| 122 }; |
| 123 |
| 124 class CaptureTime { |
| 125 public: |
| 126 using DataType = LoggedRtpPacket; |
| 127 using ResultType = double; |
| 128 double operator()(const LoggedRtpPacket& old_packet, |
| 129 const LoggedRtpPacket& new_packet) { |
| 130 int64_t send_time_diff = WrappingDifference( |
| 131 new_packet.header.timestamp, old_packet.header.timestamp, 1ull << 32); |
| 132 int64_t recv_time_diff = new_packet.timestamp - old_packet.timestamp; |
| 133 |
| 134 const double kVideoSampleRate = 90000; |
| 135 // TODO(terelius): We treat all streams as video for now, even though |
| 136 // audio might be sampled at e.g. 16kHz, because it is really difficult to |
| 137 // figure out the true sampling rate of a stream. The effect is that the |
| 138 // delay will be scaled incorrectly for non-video streams. |
| 139 |
| 140 double delay_change = |
| 141 static_cast<double>(recv_time_diff) / 1000 - |
| 142 static_cast<double>(send_time_diff) / kVideoSampleRate * 1000; |
| 143 return delay_change; |
| 144 } |
| 145 }; |
| 146 }; |
| 147 |
| 148 template <typename Extractor> |
| 149 class Accumulated { |
| 150 public: |
| 151 using DataType = typename Extractor::DataType; |
| 152 using ResultType = typename Extractor::ResultType; |
| 153 ResultType operator()(const DataType& old_packet, |
| 154 const DataType& new_packet) { |
| 155 sum += extract(old_packet, new_packet); |
| 156 return sum; |
| 157 } |
| 158 |
| 159 private: |
| 160 Extractor extract; |
| 161 ResultType sum = 0; |
| 162 }; |
| 163 |
| 164 template <typename Extractor> |
| 165 void Pairwise(const std::vector<typename Extractor::DataType>& data, |
| 166 uint64_t begin_time, |
| 167 TimeSeries* result) { |
| 168 Extractor extract; |
| 169 for (size_t i = 1; i < data.size(); i++) { |
| 170 float x = static_cast<float>(data[i].timestamp - begin_time) / 1000000; |
| 171 float y = extract(data[i - 1], data[i]); |
| 172 result->points.emplace_back(x, y); |
| 173 } |
| 174 } |
| 175 |
101 } // namespace | 176 } // namespace |
102 | 177 |
103 EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log) | 178 EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log) |
104 : parsed_log_(log), window_duration_(250000), step_(10000) { | 179 : parsed_log_(log), window_duration_(250000), step_(10000) { |
105 uint64_t first_timestamp = std::numeric_limits<uint64_t>::max(); | 180 uint64_t first_timestamp = std::numeric_limits<uint64_t>::max(); |
106 uint64_t last_timestamp = std::numeric_limits<uint64_t>::min(); | 181 uint64_t last_timestamp = std::numeric_limits<uint64_t>::min(); |
107 | 182 |
108 // Maps a stream identifier consisting of ssrc and direction | 183 // Maps a stream identifier consisting of ssrc and direction |
109 // to the header extensions used by that stream, | 184 // to the header extensions used by that stream, |
110 std::map<StreamId, RtpHeaderExtensionMap> extension_maps; | 185 std::map<StreamId, RtpHeaderExtensionMap> extension_maps; |
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 | 514 |
440 plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); | 515 plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); |
441 plot->SetSuggestedYAxis(0, 1, "Difference since last packet", kBottomMargin, | 516 plot->SetSuggestedYAxis(0, 1, "Difference since last packet", kBottomMargin, |
442 kTopMargin); | 517 kTopMargin); |
443 plot->SetTitle("Sequence number"); | 518 plot->SetTitle("Sequence number"); |
444 } | 519 } |
445 | 520 |
446 void EventLogAnalyzer::CreateDelayChangeGraph(Plot* plot) { | 521 void EventLogAnalyzer::CreateDelayChangeGraph(Plot* plot) { |
447 for (auto& kv : rtp_packets_) { | 522 for (auto& kv : rtp_packets_) { |
448 StreamId stream_id = kv.first; | 523 StreamId stream_id = kv.first; |
| 524 const std::vector<LoggedRtpPacket>& packet_stream = kv.second; |
| 525 uint32_t ssrc = stream_id.GetSsrc(); |
449 // Filter on direction and SSRC. | 526 // Filter on direction and SSRC. |
450 if (stream_id.GetDirection() != kIncomingPacket || | 527 if (stream_id.GetDirection() != kIncomingPacket || |
451 !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_)) { | 528 !MatchingSsrc(ssrc, desired_ssrc_) || IsAudioSsrc(stream_id) || |
| 529 !IsVideoSsrc(stream_id) || IsRtxSsrc(stream_id)) { |
452 continue; | 530 continue; |
453 } | 531 } |
454 | 532 |
455 TimeSeries time_series; | 533 TimeSeries capture_time_data; |
456 time_series.label = SsrcToString(stream_id.GetSsrc()); | 534 capture_time_data.label = SsrcToString(ssrc) + " capture-time"; |
457 time_series.style = BAR_GRAPH; | 535 capture_time_data.style = BAR_GRAPH; |
458 const std::vector<LoggedRtpPacket>& packet_stream = kv.second; | 536 Pairwise<NetworkDelayDiff::CaptureTime>(packet_stream, begin_time_, |
459 int64_t last_abs_send_time = 0; | 537 &capture_time_data); |
460 int64_t last_timestamp = 0; | 538 plot->series_list_.push_back(std::move(capture_time_data)); |
461 for (const LoggedRtpPacket& packet : packet_stream) { | |
462 if (packet.header.extension.hasAbsoluteSendTime) { | |
463 int64_t send_time_diff = | |
464 WrappingDifference(packet.header.extension.absoluteSendTime, | |
465 last_abs_send_time, 1ul << 24); | |
466 int64_t recv_time_diff = packet.timestamp - last_timestamp; | |
467 | 539 |
468 last_abs_send_time = packet.header.extension.absoluteSendTime; | 540 TimeSeries send_time_data; |
469 last_timestamp = packet.timestamp; | 541 send_time_data.label = SsrcToString(ssrc) + " abs-send-time"; |
470 | 542 send_time_data.style = BAR_GRAPH; |
471 float x = static_cast<float>(packet.timestamp - begin_time_) / 1000000; | 543 Pairwise<NetworkDelayDiff::AbsSendTime>(packet_stream, begin_time_, |
472 double y = | 544 &send_time_data); |
473 static_cast<double>(recv_time_diff - | 545 plot->series_list_.push_back(std::move(send_time_data)); |
474 AbsSendTimeToMicroseconds(send_time_diff)) / | |
475 1000; | |
476 if (time_series.points.size() == 0) { | |
477 // There were no previously logged packets for this SSRC. | |
478 // Generate a point, but place it on the x-axis. | |
479 y = 0; | |
480 } | |
481 time_series.points.emplace_back(x, y); | |
482 } | |
483 } | |
484 // Add the data set to the plot. | |
485 plot->series_list_.push_back(std::move(time_series)); | |
486 } | 546 } |
487 | 547 |
488 plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); | 548 plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); |
489 plot->SetSuggestedYAxis(0, 1, "Latency change (ms)", kBottomMargin, | 549 plot->SetSuggestedYAxis(0, 1, "Latency change (ms)", kBottomMargin, |
490 kTopMargin); | 550 kTopMargin); |
491 plot->SetTitle("Network latency change between consecutive packets"); | 551 plot->SetTitle("Network latency change between consecutive packets"); |
492 } | 552 } |
493 | 553 |
494 void EventLogAnalyzer::CreateAccumulatedDelayChangeGraph(Plot* plot) { | 554 void EventLogAnalyzer::CreateAccumulatedDelayChangeGraph(Plot* plot) { |
495 for (auto& kv : rtp_packets_) { | 555 for (auto& kv : rtp_packets_) { |
496 StreamId stream_id = kv.first; | 556 StreamId stream_id = kv.first; |
| 557 const std::vector<LoggedRtpPacket>& packet_stream = kv.second; |
| 558 uint32_t ssrc = stream_id.GetSsrc(); |
497 // Filter on direction and SSRC. | 559 // Filter on direction and SSRC. |
498 if (stream_id.GetDirection() != kIncomingPacket || | 560 if (stream_id.GetDirection() != kIncomingPacket || |
499 !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_)) { | 561 !MatchingSsrc(ssrc, desired_ssrc_) || IsAudioSsrc(stream_id) || |
| 562 !IsVideoSsrc(stream_id) || IsRtxSsrc(stream_id)) { |
500 continue; | 563 continue; |
501 } | 564 } |
502 TimeSeries time_series; | |
503 time_series.label = SsrcToString(stream_id.GetSsrc()); | |
504 time_series.style = LINE_GRAPH; | |
505 const std::vector<LoggedRtpPacket>& packet_stream = kv.second; | |
506 int64_t last_abs_send_time = 0; | |
507 int64_t last_timestamp = 0; | |
508 double accumulated_delay_ms = 0; | |
509 for (const LoggedRtpPacket& packet : packet_stream) { | |
510 if (packet.header.extension.hasAbsoluteSendTime) { | |
511 int64_t send_time_diff = | |
512 WrappingDifference(packet.header.extension.absoluteSendTime, | |
513 last_abs_send_time, 1ul << 24); | |
514 int64_t recv_time_diff = packet.timestamp - last_timestamp; | |
515 | 565 |
516 last_abs_send_time = packet.header.extension.absoluteSendTime; | 566 TimeSeries capture_time_data; |
517 last_timestamp = packet.timestamp; | 567 capture_time_data.label = SsrcToString(ssrc) + " capture-time"; |
| 568 capture_time_data.style = LINE_GRAPH; |
| 569 Pairwise<Accumulated<NetworkDelayDiff::CaptureTime>>( |
| 570 packet_stream, begin_time_, &capture_time_data); |
| 571 plot->series_list_.push_back(std::move(capture_time_data)); |
518 | 572 |
519 float x = static_cast<float>(packet.timestamp - begin_time_) / 1000000; | 573 TimeSeries send_time_data; |
520 accumulated_delay_ms += | 574 send_time_data.label = SsrcToString(ssrc) + " abs-send-time"; |
521 static_cast<double>(recv_time_diff - | 575 send_time_data.style = LINE_GRAPH; |
522 AbsSendTimeToMicroseconds(send_time_diff)) / | 576 Pairwise<Accumulated<NetworkDelayDiff::AbsSendTime>>( |
523 1000; | 577 packet_stream, begin_time_, &send_time_data); |
524 if (time_series.points.size() == 0) { | 578 plot->series_list_.push_back(std::move(send_time_data)); |
525 // There were no previously logged packets for this SSRC. | |
526 // Generate a point, but place it on the x-axis. | |
527 accumulated_delay_ms = 0; | |
528 } | |
529 time_series.points.emplace_back(x, accumulated_delay_ms); | |
530 } | |
531 } | |
532 // Add the data set to the plot. | |
533 plot->series_list_.push_back(std::move(time_series)); | |
534 } | 579 } |
535 | 580 |
536 plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); | 581 plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); |
537 plot->SetSuggestedYAxis(0, 1, "Latency change (ms)", kBottomMargin, | 582 plot->SetSuggestedYAxis(0, 1, "Latency change (ms)", kBottomMargin, |
538 kTopMargin); | 583 kTopMargin); |
539 plot->SetTitle("Accumulated network latency change"); | 584 plot->SetTitle("Accumulated network latency change"); |
540 } | 585 } |
541 | 586 |
542 // Plot the fraction of packets lost (as perceived by the loss-based BWE). | 587 // Plot the fraction of packets lost (as perceived by the loss-based BWE). |
543 void EventLogAnalyzer::CreateFractionLossGraph(Plot* plot) { | 588 void EventLogAnalyzer::CreateFractionLossGraph(Plot* plot) { |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
899 point.y -= estimated_base_delay_ms; | 944 point.y -= estimated_base_delay_ms; |
900 // Add the data set to the plot. | 945 // Add the data set to the plot. |
901 plot->series_list_.push_back(std::move(time_series)); | 946 plot->series_list_.push_back(std::move(time_series)); |
902 | 947 |
903 plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); | 948 plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); |
904 plot->SetSuggestedYAxis(0, 10, "Delay (ms)", kBottomMargin, kTopMargin); | 949 plot->SetSuggestedYAxis(0, 10, "Delay (ms)", kBottomMargin, kTopMargin); |
905 plot->SetTitle("Network Delay Change."); | 950 plot->SetTitle("Network Delay Change."); |
906 } | 951 } |
907 } // namespace plotting | 952 } // namespace plotting |
908 } // namespace webrtc | 953 } // namespace webrtc |
OLD | NEW |