Estimate RTP clock frequency and plot capture-send delay.
Bug: webrtc:8450
Change-Id: Idea093854a644f3018a565168425583dc4783ce9
Reviewed-on: https://webrtc-review.googlesource.com/15480
Reviewed-by: Patrik Höglund <phoglund@webrtc.org>
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Commit-Queue: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20442}
diff --git a/rtc_tools/event_log_visualizer/analyzer.cc b/rtc_tools/event_log_visualizer/analyzer.cc
index 7043c68..efa9965 100644
--- a/rtc_tools/event_log_visualizer/analyzer.cc
+++ b/rtc_tools/event_log_visualizer/analyzer.cc
@@ -47,6 +47,7 @@
#include "rtc_base/checks.h"
#include "rtc_base/format_macros.h"
#include "rtc_base/logging.h"
+#include "rtc_base/numerics/sequence_number_util.h"
#include "rtc_base/ptr_util.h"
#include "rtc_base/rate_statistics.h"
@@ -596,6 +597,46 @@
return name.str();
}
+// This is much more reliable for outgoing streams than for incoming streams.
+rtc::Optional<uint32_t> EventLogAnalyzer::EstimateRtpClockFrequency(
+ const std::vector<LoggedRtpPacket>& packets) const {
+ RTC_CHECK(packets.size() >= 2);
+ uint64_t end_time_us = log_segments_.empty()
+ ? std::numeric_limits<uint64_t>::max()
+ : log_segments_.front().second;
+ SeqNumUnwrapper<uint32_t> unwrapper;
+ uint64_t first_rtp_timestamp = unwrapper.Unwrap(packets[0].header.timestamp);
+ uint64_t first_log_timestamp = packets[0].timestamp;
+ uint64_t last_rtp_timestamp = first_rtp_timestamp;
+ uint64_t last_log_timestamp = first_log_timestamp;
+ for (size_t i = 1; i < packets.size(); i++) {
+ if (packets[i].timestamp > end_time_us)
+ break;
+ last_rtp_timestamp = unwrapper.Unwrap(packets[i].header.timestamp);
+ last_log_timestamp = packets[i].timestamp;
+ }
+ if (last_log_timestamp - first_log_timestamp < 1000000) {
+ LOG(LS_WARNING)
+ << "Failed to estimate RTP clock frequency: Stream too short. ("
+ << packets.size() << " packets, "
+ << last_log_timestamp - first_log_timestamp << " us)";
+ return rtc::Optional<uint32_t>();
+ }
+ double duration =
+ static_cast<double>(last_log_timestamp - first_log_timestamp) / 1000000;
+ double estimated_frequency =
+ (last_rtp_timestamp - first_rtp_timestamp) / duration;
+ for (uint32_t f : {8000, 16000, 32000, 48000, 90000}) {
+ if (std::fabs(estimated_frequency - f) < 0.05 * f) {
+ return rtc::Optional<uint32_t>(f);
+ }
+ }
+ LOG(LS_WARNING) << "Failed to estimate RTP clock frequency: Estimate "
+ << estimated_frequency
+ << "not close to any stardard RTP frequency.";
+ return rtc::Optional<uint32_t>();
+}
+
void EventLogAnalyzer::CreatePacketGraph(PacketDirection desired_direction,
Plot* plot) {
for (auto& kv : rtp_packets_) {
@@ -1459,6 +1500,55 @@
return timestamps;
}
+void EventLogAnalyzer::CreatePacerDelayGraph(Plot* plot) {
+ for (const auto& kv : rtp_packets_) {
+ const std::vector<LoggedRtpPacket>& packets = kv.second;
+ StreamId stream_id = kv.first;
+
+ if (packets.size() < 2) {
+ LOG(LS_WARNING) << "Can't estimate a the RTP clock frequency or the "
+ "pacer delay with less than 2 packets in the stream";
+ continue;
+ }
+ rtc::Optional<uint32_t> estimated_frequency =
+ EstimateRtpClockFrequency(packets);
+ if (!estimated_frequency)
+ continue;
+ if (IsVideoSsrc(stream_id) && *estimated_frequency != 90000) {
+ LOG(LS_WARNING)
+ << "Video stream should use a 90 kHz clock but appears to use "
+ << *estimated_frequency / 1000 << ". Discarding.";
+ continue;
+ }
+
+ TimeSeries pacer_delay_series(
+ GetStreamName(stream_id) + "(" +
+ std::to_string(*estimated_frequency / 1000) + " kHz)",
+ LINE_DOT_GRAPH);
+ SeqNumUnwrapper<uint32_t> timestamp_unwrapper;
+ uint64_t first_capture_timestamp =
+ timestamp_unwrapper.Unwrap(packets.front().header.timestamp);
+ uint64_t first_send_timestamp = packets.front().timestamp;
+ for (LoggedRtpPacket packet : packets) {
+ double capture_time_ms = (static_cast<double>(timestamp_unwrapper.Unwrap(
+ packet.header.timestamp)) -
+ first_capture_timestamp) /
+ *estimated_frequency * 1000;
+ double send_time_ms =
+ static_cast<double>(packet.timestamp - first_send_timestamp) / 1000;
+ float x = static_cast<float>(packet.timestamp - begin_time_) / 1000000;
+ float y = send_time_ms - capture_time_ms;
+ pacer_delay_series.points.emplace_back(x, y);
+ }
+ plot->AppendTimeSeries(std::move(pacer_delay_series));
+ }
+
+ plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
+ plot->SetSuggestedYAxis(0, 10, "Pacer delay (ms)", kBottomMargin, kTopMargin);
+ plot->SetTitle(
+ "Delay from capture to send time. (First packet normalized to 0.)");
+}
+
void EventLogAnalyzer::CreateTimestampGraph(Plot* plot) {
for (const auto& kv : rtp_packets_) {
const std::vector<LoggedRtpPacket>& rtp_packets = kv.second;