Reland: Add BWE plot to event log analyzer.
The plot is constructed by actually running the congestion controller with the logged rtp headers and rtcp feedback messages to reproduce the same behavior as in the real call. R=phoglund@webrtc.org, terelius@webrtc.org Review URL: https://codereview.webrtc.org/2193763002 . Cr-Commit-Position: refs/heads/master@{#13574}
This commit is contained in:
parent
3d9c71ad73
commit
13181035bc
@ -38,40 +38,6 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// No-op implementation is used if flag is not set, or in tests.
|
||||
class RtcEventLogNullImpl final : public RtcEventLog {
|
||||
public:
|
||||
bool StartLogging(const std::string& file_name,
|
||||
int64_t max_size_bytes) override {
|
||||
return false;
|
||||
}
|
||||
bool StartLogging(rtc::PlatformFile platform_file,
|
||||
int64_t max_size_bytes) override {
|
||||
// The platform_file is open and needs to be closed.
|
||||
if (!rtc::ClosePlatformFile(platform_file)) {
|
||||
LOG(LS_ERROR) << "Can't close file.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void StopLogging() override {}
|
||||
void LogVideoReceiveStreamConfig(
|
||||
const VideoReceiveStream::Config& config) override {}
|
||||
void LogVideoSendStreamConfig(
|
||||
const VideoSendStream::Config& config) override {}
|
||||
void LogRtpHeader(PacketDirection direction,
|
||||
MediaType media_type,
|
||||
const uint8_t* header,
|
||||
size_t packet_length) override {}
|
||||
void LogRtcpPacket(PacketDirection direction,
|
||||
MediaType media_type,
|
||||
const uint8_t* packet,
|
||||
size_t length) override {}
|
||||
void LogAudioPlayout(uint32_t ssrc) override {}
|
||||
void LogBwePacketLossEvent(int32_t bitrate,
|
||||
uint8_t fraction_loss,
|
||||
int32_t total_packets) override {}
|
||||
};
|
||||
|
||||
#ifdef ENABLE_RTC_EVENT_LOG
|
||||
|
||||
class RtcEventLogImpl final : public RtcEventLog {
|
||||
@ -454,6 +420,15 @@ bool RtcEventLog::ParseRtcEventLog(const std::string& file_name,
|
||||
|
||||
#endif // ENABLE_RTC_EVENT_LOG
|
||||
|
||||
bool RtcEventLogNullImpl::StartLogging(rtc::PlatformFile platform_file,
|
||||
int64_t max_size_bytes) {
|
||||
// The platform_file is open and needs to be closed.
|
||||
if (!rtc::ClosePlatformFile(platform_file)) {
|
||||
LOG(LS_ERROR) << "Can't close file.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// RtcEventLog member functions.
|
||||
std::unique_ptr<RtcEventLog> RtcEventLog::Create(const Clock* clock) {
|
||||
#ifdef ENABLE_RTC_EVENT_LOG
|
||||
|
||||
@ -109,6 +109,34 @@ class RtcEventLog {
|
||||
rtclog::EventStream* result);
|
||||
};
|
||||
|
||||
// No-op implementation is used if flag is not set, or in tests.
|
||||
class RtcEventLogNullImpl final : public RtcEventLog {
|
||||
public:
|
||||
bool StartLogging(const std::string& file_name,
|
||||
int64_t max_size_bytes) override {
|
||||
return false;
|
||||
}
|
||||
bool StartLogging(rtc::PlatformFile platform_file,
|
||||
int64_t max_size_bytes) override;
|
||||
void StopLogging() override {}
|
||||
void LogVideoReceiveStreamConfig(
|
||||
const VideoReceiveStream::Config& config) override {}
|
||||
void LogVideoSendStreamConfig(
|
||||
const VideoSendStream::Config& config) override {}
|
||||
void LogRtpHeader(PacketDirection direction,
|
||||
MediaType media_type,
|
||||
const uint8_t* header,
|
||||
size_t packet_length) override {}
|
||||
void LogRtcpPacket(PacketDirection direction,
|
||||
MediaType media_type,
|
||||
const uint8_t* packet,
|
||||
size_t length) override {}
|
||||
void LogAudioPlayout(uint32_t ssrc) override {}
|
||||
void LogBwePacketLossEvent(int32_t bitrate,
|
||||
uint8_t fraction_loss,
|
||||
int32_t total_packets) override {}
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_CALL_RTC_EVENT_LOG_H_
|
||||
|
||||
@ -304,7 +304,7 @@ void CongestionController::SignalNetworkState(NetworkState state) {
|
||||
|
||||
void CongestionController::OnSentPacket(const rtc::SentPacket& sent_packet) {
|
||||
transport_feedback_adapter_.OnSentPacket(sent_packet.packet_id,
|
||||
sent_packet.send_time_ms);
|
||||
sent_packet.send_time_ms);
|
||||
}
|
||||
|
||||
void CongestionController::OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) {
|
||||
|
||||
@ -114,6 +114,7 @@ webrtc_fuzzer_test("congestion_controller_feedback_fuzzer") {
|
||||
"congestion_controller_feedback_fuzzer.cc",
|
||||
]
|
||||
deps = [
|
||||
"../../:rtc_event_log",
|
||||
"../../modules/congestion_controller/",
|
||||
]
|
||||
}
|
||||
|
||||
@ -26,42 +26,13 @@ class NullBitrateObserver : public CongestionController::Observer,
|
||||
uint32_t bitrate) override {}
|
||||
};
|
||||
|
||||
class NullEventLog : public RtcEventLog {
|
||||
public:
|
||||
~NullEventLog() override {}
|
||||
bool StartLogging(const std::string& file_name,
|
||||
int64_t max_size_bytes) override {
|
||||
return true;
|
||||
}
|
||||
bool StartLogging(rtc::PlatformFile platform_file, int64_t max_size_bytes) {
|
||||
return true;
|
||||
}
|
||||
void StopLogging() override{};
|
||||
void LogVideoReceiveStreamConfig(
|
||||
const webrtc::VideoReceiveStream::Config& config) override {}
|
||||
void LogVideoSendStreamConfig(
|
||||
const webrtc::VideoSendStream::Config& config) override {}
|
||||
void LogRtpHeader(PacketDirection direction,
|
||||
MediaType media_type,
|
||||
const uint8_t* header,
|
||||
size_t packet_length) override {}
|
||||
void LogRtcpPacket(PacketDirection direction,
|
||||
MediaType media_type,
|
||||
const uint8_t* packet,
|
||||
size_t length) override {}
|
||||
void LogAudioPlayout(uint32_t ssrc) override {}
|
||||
void LogBwePacketLossEvent(int32_t bitrate,
|
||||
uint8_t fraction_loss,
|
||||
int32_t total_packets) override {}
|
||||
};
|
||||
|
||||
void FuzzOneInput(const uint8_t* data, size_t size) {
|
||||
size_t i = 0;
|
||||
if (size < sizeof(int64_t) + sizeof(uint8_t) + sizeof(uint32_t))
|
||||
return;
|
||||
SimulatedClock clock(data[i++]);
|
||||
NullBitrateObserver observer;
|
||||
NullEventLog event_log;
|
||||
RtcEventLogNullImpl event_log;
|
||||
CongestionController cc(&clock, &observer, &observer, &event_log);
|
||||
RemoteBitrateEstimator* rbe = cc.GetRemoteBitrateEstimator(true);
|
||||
RTPHeader header;
|
||||
|
||||
@ -173,6 +173,7 @@ source_set("agc_test_utils") {
|
||||
if (rtc_include_tests) {
|
||||
if (rtc_enable_protobuf) {
|
||||
executable("event_log_visualizer") {
|
||||
testonly = true
|
||||
sources = [
|
||||
"event_log_visualizer/analyzer.cc",
|
||||
"event_log_visualizer/analyzer.h",
|
||||
@ -193,9 +194,12 @@ if (rtc_include_tests) {
|
||||
|
||||
defines = [ "ENABLE_RTC_EVENT_LOG" ]
|
||||
deps = [
|
||||
"../:rtc_event_log",
|
||||
"../:rtc_event_log_parser",
|
||||
"../modules/congestion_controller:congestion_controller",
|
||||
"../modules/rtp_rtcp:rtp_rtcp",
|
||||
"../system_wrappers:system_wrappers_default",
|
||||
"../test:field_trial",
|
||||
"//third_party/gflags",
|
||||
]
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ include_rules = [
|
||||
"+webrtc/call",
|
||||
"+webrtc/common_video",
|
||||
"+webrtc/modules/audio_processing",
|
||||
"+webrtc/modules/congestion_controller",
|
||||
"+webrtc/modules/rtp_rtcp",
|
||||
"+webrtc/system_wrappers",
|
||||
"+webrtc/voice_engine",
|
||||
|
||||
@ -22,9 +22,12 @@
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/call.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/congestion_controller/include/congestion_controller.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
|
||||
#include "webrtc/video_receive_stream.h"
|
||||
#include "webrtc/video_send_stream.h"
|
||||
|
||||
@ -92,21 +95,15 @@ bool EventLogAnalyzer::StreamId::operator<(const StreamId& other) const {
|
||||
return true;
|
||||
}
|
||||
if (ssrc_ == other.ssrc_) {
|
||||
if (media_type_ < other.media_type_) {
|
||||
if (direction_ < other.direction_) {
|
||||
return true;
|
||||
}
|
||||
if (media_type_ == other.media_type_) {
|
||||
if (direction_ < other.direction_) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventLogAnalyzer::StreamId::operator==(const StreamId& other) const {
|
||||
return ssrc_ == other.ssrc_ && direction_ == other.direction_ &&
|
||||
media_type_ == other.media_type_;
|
||||
return ssrc_ == other.ssrc_ && direction_ == other.direction_;
|
||||
}
|
||||
|
||||
|
||||
@ -115,12 +112,11 @@ EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log)
|
||||
uint64_t first_timestamp = std::numeric_limits<uint64_t>::max();
|
||||
uint64_t last_timestamp = std::numeric_limits<uint64_t>::min();
|
||||
|
||||
// Maps a stream identifier consisting of ssrc, direction and MediaType
|
||||
// Maps a stream identifier consisting of ssrc and direction
|
||||
// to the header extensions used by that stream,
|
||||
std::map<StreamId, RtpHeaderExtensionMap> extension_maps;
|
||||
|
||||
PacketDirection direction;
|
||||
MediaType media_type;
|
||||
uint8_t header[IP_PACKET_SIZE];
|
||||
size_t header_length;
|
||||
size_t total_length;
|
||||
@ -140,8 +136,7 @@ EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log)
|
||||
case ParsedRtcEventLog::VIDEO_RECEIVER_CONFIG_EVENT: {
|
||||
VideoReceiveStream::Config config(nullptr);
|
||||
parsed_log_.GetVideoReceiveConfig(i, &config);
|
||||
StreamId stream(config.rtp.remote_ssrc, kIncomingPacket,
|
||||
MediaType::VIDEO);
|
||||
StreamId stream(config.rtp.remote_ssrc, kIncomingPacket);
|
||||
extension_maps[stream].Erase();
|
||||
for (size_t j = 0; j < config.rtp.extensions.size(); ++j) {
|
||||
const std::string& extension = config.rtp.extensions[j].uri;
|
||||
@ -155,7 +150,7 @@ EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log)
|
||||
VideoSendStream::Config config(nullptr);
|
||||
parsed_log_.GetVideoSendConfig(i, &config);
|
||||
for (auto ssrc : config.rtp.ssrcs) {
|
||||
StreamId stream(ssrc, kOutgoingPacket, MediaType::VIDEO);
|
||||
StreamId stream(ssrc, kOutgoingPacket);
|
||||
extension_maps[stream].Erase();
|
||||
for (size_t j = 0; j < config.rtp.extensions.size(); ++j) {
|
||||
const std::string& extension = config.rtp.extensions[j].uri;
|
||||
@ -177,13 +172,14 @@ EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log)
|
||||
break;
|
||||
}
|
||||
case ParsedRtcEventLog::RTP_EVENT: {
|
||||
MediaType media_type;
|
||||
parsed_log_.GetRtpHeader(i, &direction, &media_type, header,
|
||||
&header_length, &total_length);
|
||||
// Parse header to get SSRC.
|
||||
RtpUtility::RtpHeaderParser rtp_parser(header, header_length);
|
||||
RTPHeader parsed_header;
|
||||
rtp_parser.Parse(&parsed_header);
|
||||
StreamId stream(parsed_header.ssrc, direction, media_type);
|
||||
StreamId stream(parsed_header.ssrc, direction);
|
||||
// Look up the extension_map and parse it again to get the extensions.
|
||||
if (extension_maps.count(stream) == 1) {
|
||||
RtpHeaderExtensionMap* extension_map = &extension_maps[stream];
|
||||
@ -191,10 +187,45 @@ EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log)
|
||||
}
|
||||
uint64_t timestamp = parsed_log_.GetTimestamp(i);
|
||||
rtp_packets_[stream].push_back(
|
||||
LoggedRtpPacket(timestamp, parsed_header));
|
||||
LoggedRtpPacket(timestamp, parsed_header, total_length));
|
||||
break;
|
||||
}
|
||||
case ParsedRtcEventLog::RTCP_EVENT: {
|
||||
uint8_t packet[IP_PACKET_SIZE];
|
||||
MediaType media_type;
|
||||
parsed_log_.GetRtcpPacket(i, &direction, &media_type, packet,
|
||||
&total_length);
|
||||
|
||||
RtpUtility::RtpHeaderParser rtp_parser(packet, total_length);
|
||||
RTPHeader parsed_header;
|
||||
RTC_CHECK(rtp_parser.ParseRtcp(&parsed_header));
|
||||
uint32_t ssrc = parsed_header.ssrc;
|
||||
|
||||
RTCPUtility::RTCPParserV2 rtcp_parser(packet, total_length, true);
|
||||
RTC_CHECK(rtcp_parser.IsValid());
|
||||
|
||||
RTCPUtility::RTCPPacketTypes packet_type = rtcp_parser.Begin();
|
||||
while (packet_type != RTCPUtility::RTCPPacketTypes::kInvalid) {
|
||||
switch (packet_type) {
|
||||
case RTCPUtility::RTCPPacketTypes::kTransportFeedback: {
|
||||
// Currently feedback is logged twice, both for audio and video.
|
||||
// Only act on one of them.
|
||||
if (media_type == MediaType::VIDEO) {
|
||||
std::unique_ptr<rtcp::RtcpPacket> rtcp_packet(
|
||||
rtcp_parser.ReleaseRtcpPacket());
|
||||
StreamId stream(ssrc, direction);
|
||||
uint64_t timestamp = parsed_log_.GetTimestamp(i);
|
||||
rtcp_packets_[stream].push_back(LoggedRtcpPacket(
|
||||
timestamp, kRtcpTransportFeedback, std::move(rtcp_packet)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
rtcp_parser.Iterate();
|
||||
packet_type = rtcp_parser.PacketType();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ParsedRtcEventLog::LOG_START: {
|
||||
@ -232,6 +263,33 @@ EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log)
|
||||
end_time_ = last_timestamp;
|
||||
}
|
||||
|
||||
class BitrateObserver : public CongestionController::Observer,
|
||||
public RemoteBitrateObserver {
|
||||
public:
|
||||
BitrateObserver() : last_bitrate_bps_(0), bitrate_updated_(false) {}
|
||||
|
||||
void OnNetworkChanged(uint32_t bitrate_bps,
|
||||
uint8_t fraction_loss,
|
||||
int64_t rtt_ms) override {
|
||||
last_bitrate_bps_ = bitrate_bps;
|
||||
bitrate_updated_ = true;
|
||||
}
|
||||
|
||||
void OnReceiveBitrateChanged(const std::vector<uint32_t>& ssrcs,
|
||||
uint32_t bitrate) override {}
|
||||
|
||||
uint32_t last_bitrate_bps() const { return last_bitrate_bps_; }
|
||||
bool GetAndResetBitrateUpdated() {
|
||||
bool bitrate_updated = bitrate_updated_;
|
||||
bitrate_updated_ = false;
|
||||
return bitrate_updated;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t last_bitrate_bps_;
|
||||
bool bitrate_updated_;
|
||||
};
|
||||
|
||||
void EventLogAnalyzer::CreatePacketGraph(PacketDirection desired_direction,
|
||||
Plot* plot) {
|
||||
std::map<uint32_t, TimeSeries> time_series;
|
||||
@ -675,5 +733,113 @@ void EventLogAnalyzer::CreateStreamBitrateGraph(
|
||||
}
|
||||
}
|
||||
|
||||
void EventLogAnalyzer::CreateBweGraph(Plot* plot) {
|
||||
std::map<uint64_t, const LoggedRtpPacket*> outgoing_rtp;
|
||||
std::map<uint64_t, const LoggedRtcpPacket*> incoming_rtcp;
|
||||
|
||||
for (const auto& kv : rtp_packets_) {
|
||||
if (kv.first.GetDirection() == PacketDirection::kOutgoingPacket) {
|
||||
for (const LoggedRtpPacket& rtp_packet : kv.second)
|
||||
outgoing_rtp.insert(std::make_pair(rtp_packet.timestamp, &rtp_packet));
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& kv : rtcp_packets_) {
|
||||
if (kv.first.GetDirection() == PacketDirection::kIncomingPacket) {
|
||||
for (const LoggedRtcpPacket& rtcp_packet : kv.second)
|
||||
incoming_rtcp.insert(
|
||||
std::make_pair(rtcp_packet.timestamp, &rtcp_packet));
|
||||
}
|
||||
}
|
||||
|
||||
SimulatedClock clock(0);
|
||||
BitrateObserver observer;
|
||||
RtcEventLogNullImpl null_event_log;
|
||||
CongestionController cc(&clock, &observer, &observer, &null_event_log);
|
||||
// TODO(holmer): Log the call config and use that here instead.
|
||||
static const uint32_t kDefaultStartBitrateBps = 300000;
|
||||
cc.SetBweBitrates(0, kDefaultStartBitrateBps, -1);
|
||||
|
||||
TimeSeries time_series;
|
||||
time_series.label = "BWE";
|
||||
time_series.style = LINE_DOT_GRAPH;
|
||||
uint32_t max_y = 10;
|
||||
uint32_t min_y = 0;
|
||||
|
||||
auto rtp_iterator = outgoing_rtp.begin();
|
||||
auto rtcp_iterator = incoming_rtcp.begin();
|
||||
|
||||
auto NextRtpTime = [&]() {
|
||||
if (rtp_iterator != outgoing_rtp.end())
|
||||
return static_cast<int64_t>(rtp_iterator->first);
|
||||
return std::numeric_limits<int64_t>::max();
|
||||
};
|
||||
|
||||
auto NextRtcpTime = [&]() {
|
||||
if (rtcp_iterator != incoming_rtcp.end())
|
||||
return static_cast<int64_t>(rtcp_iterator->first);
|
||||
return std::numeric_limits<int64_t>::max();
|
||||
};
|
||||
|
||||
auto NextProcessTime = [&]() {
|
||||
if (rtcp_iterator != incoming_rtcp.end() ||
|
||||
rtp_iterator != outgoing_rtp.end()) {
|
||||
return clock.TimeInMicroseconds() +
|
||||
std::max<int64_t>(cc.TimeUntilNextProcess() * 1000, 0);
|
||||
}
|
||||
return std::numeric_limits<int64_t>::max();
|
||||
};
|
||||
|
||||
int64_t time_us = std::min(NextRtpTime(), NextRtcpTime());
|
||||
while (time_us != std::numeric_limits<int64_t>::max()) {
|
||||
clock.AdvanceTimeMicroseconds(time_us - clock.TimeInMicroseconds());
|
||||
if (clock.TimeInMicroseconds() >= NextRtcpTime()) {
|
||||
clock.AdvanceTimeMilliseconds(rtcp_iterator->first / 1000 -
|
||||
clock.TimeInMilliseconds());
|
||||
const LoggedRtcpPacket& rtcp = *rtcp_iterator->second;
|
||||
if (rtcp.type == kRtcpTransportFeedback) {
|
||||
cc.GetTransportFeedbackObserver()->OnTransportFeedback(
|
||||
*static_cast<rtcp::TransportFeedback*>(rtcp.packet.get()));
|
||||
}
|
||||
++rtcp_iterator;
|
||||
}
|
||||
if (clock.TimeInMicroseconds() >= NextRtpTime()) {
|
||||
clock.AdvanceTimeMilliseconds(rtp_iterator->first / 1000 -
|
||||
clock.TimeInMilliseconds());
|
||||
const LoggedRtpPacket& rtp = *rtp_iterator->second;
|
||||
if (rtp.header.extension.hasTransportSequenceNumber) {
|
||||
RTC_DCHECK(rtp.header.extension.hasTransportSequenceNumber);
|
||||
cc.GetTransportFeedbackObserver()->AddPacket(
|
||||
rtp.header.extension.transportSequenceNumber, rtp.total_length, 0);
|
||||
rtc::SentPacket sent_packet(
|
||||
rtp.header.extension.transportSequenceNumber, rtp.timestamp / 1000);
|
||||
cc.OnSentPacket(sent_packet);
|
||||
}
|
||||
++rtp_iterator;
|
||||
}
|
||||
if (clock.TimeInMicroseconds() >= NextProcessTime())
|
||||
cc.Process();
|
||||
if (observer.GetAndResetBitrateUpdated()) {
|
||||
uint32_t y = observer.last_bitrate_bps() / 1000;
|
||||
max_y = std::max(max_y, y);
|
||||
min_y = std::min(min_y, y);
|
||||
float x = static_cast<float>(clock.TimeInMicroseconds() - begin_time_) /
|
||||
1000000;
|
||||
time_series.points.emplace_back(x, y);
|
||||
}
|
||||
time_us = std::min({NextRtpTime(), NextRtcpTime(), NextProcessTime()});
|
||||
}
|
||||
// Add the data set to the plot.
|
||||
plot->series.push_back(std::move(time_series));
|
||||
|
||||
plot->xaxis_min = kDefaultXMin;
|
||||
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
|
||||
plot->xaxis_label = "Time (s)";
|
||||
plot->yaxis_min = min_y - (kYMargin - 1) / 2 * (max_y - min_y);
|
||||
plot->yaxis_max = max_y + (kYMargin - 1) / 2 * (max_y - min_y);
|
||||
plot->yaxis_label = "Bitrate (kbps)";
|
||||
plot->title = "BWE";
|
||||
}
|
||||
|
||||
} // namespace plotting
|
||||
} // namespace webrtc
|
||||
|
||||
@ -13,8 +13,12 @@
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "webrtc/call/rtc_event_log_parser.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
|
||||
#include "webrtc/tools/event_log_visualizer/plot_base.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -41,30 +45,41 @@ class EventLogAnalyzer {
|
||||
|
||||
void CreateStreamBitrateGraph(PacketDirection desired_direction, Plot* plot);
|
||||
|
||||
void CreateBweGraph(Plot* plot);
|
||||
|
||||
private:
|
||||
class StreamId {
|
||||
public:
|
||||
StreamId(uint32_t ssrc,
|
||||
webrtc::PacketDirection direction,
|
||||
webrtc::MediaType media_type)
|
||||
: ssrc_(ssrc), direction_(direction), media_type_(media_type) {}
|
||||
StreamId(uint32_t ssrc, webrtc::PacketDirection direction)
|
||||
: ssrc_(ssrc), direction_(direction) {}
|
||||
bool operator<(const StreamId& other) const;
|
||||
bool operator==(const StreamId& other) const;
|
||||
uint32_t GetSsrc() const { return ssrc_; }
|
||||
webrtc::PacketDirection GetDirection() const { return direction_; }
|
||||
webrtc::MediaType GetMediaType() const { return media_type_; }
|
||||
|
||||
private:
|
||||
uint32_t ssrc_;
|
||||
webrtc::PacketDirection direction_;
|
||||
webrtc::MediaType media_type_;
|
||||
};
|
||||
|
||||
struct LoggedRtpPacket {
|
||||
LoggedRtpPacket(uint64_t timestamp, RTPHeader header)
|
||||
: timestamp(timestamp), header(header) {}
|
||||
LoggedRtpPacket(uint64_t timestamp, RTPHeader header, size_t total_length)
|
||||
: timestamp(timestamp), header(header), total_length(total_length) {}
|
||||
uint64_t timestamp;
|
||||
RTPHeader header;
|
||||
size_t total_length;
|
||||
};
|
||||
|
||||
struct LoggedRtcpPacket {
|
||||
LoggedRtcpPacket(uint64_t timestamp,
|
||||
RTCPPacketType rtcp_type,
|
||||
std::unique_ptr<rtcp::RtcpPacket> rtcp_packet)
|
||||
: timestamp(timestamp),
|
||||
type(rtcp_type),
|
||||
packet(std::move(rtcp_packet)) {}
|
||||
uint64_t timestamp;
|
||||
RTCPPacketType type;
|
||||
std::unique_ptr<rtcp::RtcpPacket> packet;
|
||||
};
|
||||
|
||||
struct BwePacketLossEvent {
|
||||
@ -85,6 +100,8 @@ class EventLogAnalyzer {
|
||||
// if the stream has been configured.
|
||||
std::map<StreamId, std::vector<LoggedRtpPacket>> rtp_packets_;
|
||||
|
||||
std::map<StreamId, std::vector<LoggedRtcpPacket>> rtcp_packets_;
|
||||
|
||||
// A list of all updates from the send-side loss-based bandwidth estimator.
|
||||
std::vector<BwePacketLossEvent> bwe_loss_updates_;
|
||||
|
||||
|
||||
@ -43,6 +43,10 @@ DEFINE_bool(plot_total_bitrate,
|
||||
DEFINE_bool(plot_stream_bitrate,
|
||||
false,
|
||||
"Plot the bitrate used by each stream.");
|
||||
DEFINE_bool(plot_bwe,
|
||||
false,
|
||||
"Run the bandwidth estimator with the logged rtp and rtcp and plot "
|
||||
"the output.");
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::string program_name = argv[0];
|
||||
@ -132,6 +136,10 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAGS_plot_all || FLAGS_plot_bwe) {
|
||||
analyzer.CreateBweGraph(collection->append_new_plot());
|
||||
}
|
||||
|
||||
collection->draw();
|
||||
|
||||
return 0;
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
namespace webrtc {
|
||||
namespace plotting {
|
||||
|
||||
enum PlotStyle { LINE_GRAPH, BAR_GRAPH };
|
||||
enum PlotStyle { LINE_GRAPH, LINE_DOT_GRAPH, BAR_GRAPH };
|
||||
|
||||
struct TimeSeriesPoint {
|
||||
TimeSeriesPoint(float x, float y) : x(x), y(y) {}
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "webrtc/tools/event_log_visualizer/plot_python.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <memory>
|
||||
|
||||
namespace webrtc {
|
||||
namespace plotting {
|
||||
@ -58,6 +59,11 @@ void PythonPlot::draw() {
|
||||
} else if (series[i].style == LINE_GRAPH) {
|
||||
printf("plt.plot(x%zu, y%zu, color=rgb_colors[%zu], label=\'%s\')\n", i,
|
||||
i, i, series[i].label.c_str());
|
||||
} else if (series[i].style == LINE_DOT_GRAPH) {
|
||||
printf(
|
||||
"plt.plot(x%zu, y%zu, color=rgb_colors[%zu], label=\'%s\', "
|
||||
"marker='.')\n",
|
||||
i, i, i, series[i].label.c_str());
|
||||
} else {
|
||||
printf("raise Exception(\"Unknown graph type\")\n");
|
||||
}
|
||||
|
||||
@ -109,9 +109,12 @@
|
||||
'target_name': 'event_log_visualizer',
|
||||
'type': 'executable',
|
||||
'dependencies': [
|
||||
'<(webrtc_root)/webrtc.gyp:rtc_event_log',
|
||||
'<(webrtc_root)/webrtc.gyp:rtc_event_log_parser',
|
||||
'<(webrtc_root)/modules/modules.gyp:congestion_controller',
|
||||
'<(webrtc_root)/modules/modules.gyp:rtp_rtcp',
|
||||
'<(webrtc_root)/system_wrappers/system_wrappers.gyp:metrics_default',
|
||||
'<(webrtc_root)/test/test.gyp:field_trial',
|
||||
'<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
|
||||
],
|
||||
'sources': [
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user