mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-12 21:30:45 +01:00
Implement DelayVariationCalculator for events analysis.
This CL implements {,Logging}DelayVariationCalculator, whose purpose is to calculate simple inter-arrival metrics for a sequence of RTP frames. Uses could include RtcEventLog analysis and ad hoc testing. Want lgtm: asapersson Bug: webrtc:15213 Change-Id: I3f9d13a2c4fa66b6f1229c1b6fcd66a6911070de Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/306741 Commit-Queue: Rasmus Brandt <brandtr@webrtc.org> Reviewed-by: Åsa Persson <asapersson@webrtc.org> Reviewed-by: Jeremy Leconte <jleconte@webrtc.org> Cr-Commit-Position: refs/heads/main@{#40247}
This commit is contained in:
parent
f99e0f4aa0
commit
cde5354729
11 changed files with 594 additions and 0 deletions
|
@ -125,6 +125,7 @@ rtc_source_set("recordable_encoded_frame") {
|
|||
rtc_source_set("video_frame_type") {
|
||||
visibility = [ "*" ]
|
||||
sources = [ "video_frame_type.h" ]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
|
||||
}
|
||||
|
||||
rtc_source_set("render_resolution") {
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#ifndef API_VIDEO_VIDEO_FRAME_TYPE_H_
|
||||
#define API_VIDEO_VIDEO_FRAME_TYPE_H_
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
enum class VideoFrameType {
|
||||
|
@ -21,6 +23,20 @@ enum class VideoFrameType {
|
|||
kVideoFrameDelta = 4,
|
||||
};
|
||||
|
||||
inline constexpr absl::string_view VideoFrameTypeToString(
|
||||
VideoFrameType frame_type) {
|
||||
if (frame_type == VideoFrameType::kEmptyFrame) {
|
||||
return "empty";
|
||||
}
|
||||
if (frame_type == VideoFrameType::kVideoFrameKey) {
|
||||
return "key";
|
||||
}
|
||||
if (frame_type == VideoFrameType::kVideoFrameDelta) {
|
||||
return "delta";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_VIDEO_VIDEO_FRAME_TYPE_H_
|
||||
|
|
|
@ -754,6 +754,7 @@ if (rtc_include_tests) {
|
|||
"../rtc_base:rtc_task_queue",
|
||||
"../rtc_base/synchronization:mutex",
|
||||
"../rtc_base/system:file_wrapper",
|
||||
"jitter:jitter_unittests",
|
||||
"pc/e2e:e2e_unittests",
|
||||
"pc/e2e/analyzer/video:video_analyzer_unittests",
|
||||
"pc/e2e/analyzer/video/dvqa:dvqa_unittests",
|
||||
|
|
64
test/jitter/BUILD.gn
Normal file
64
test/jitter/BUILD.gn
Normal file
|
@ -0,0 +1,64 @@
|
|||
# Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
import("../../webrtc.gni")
|
||||
|
||||
rtc_library("delay_variation_calculator") {
|
||||
visibility = [ "*" ]
|
||||
sources = [
|
||||
"delay_variation_calculator.cc",
|
||||
"delay_variation_calculator.h",
|
||||
]
|
||||
deps = [
|
||||
"../../api/numerics",
|
||||
"../../api/test/metrics:metrics_logger",
|
||||
"../../api/units:data_size",
|
||||
"../../api/units:frequency",
|
||||
"../../api/units:time_delta",
|
||||
"../../api/units:timestamp",
|
||||
"../../api/video:video_frame_type",
|
||||
"../../rtc_base:logging",
|
||||
"../../rtc_base:rtc_numerics",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||
}
|
||||
|
||||
rtc_library("logging_delay_variation_calculator") {
|
||||
visibility = [ "*" ]
|
||||
sources = [
|
||||
"logging_delay_variation_calculator.cc",
|
||||
"logging_delay_variation_calculator.h",
|
||||
]
|
||||
deps = [
|
||||
":delay_variation_calculator",
|
||||
"../../api/test/metrics:global_metrics_logger_and_exporter",
|
||||
"../../api/units:data_size",
|
||||
"../../api/video:video_frame_type",
|
||||
"../../rtc_base:logging",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
|
||||
}
|
||||
|
||||
if (rtc_include_tests) {
|
||||
rtc_library("jitter_unittests") {
|
||||
testonly = true
|
||||
sources = [
|
||||
"delay_variation_calculator_unittest.cc",
|
||||
"logging_delay_variation_calculator_unittest.cc",
|
||||
]
|
||||
deps = [
|
||||
":delay_variation_calculator",
|
||||
":logging_delay_variation_calculator",
|
||||
"../../api/numerics",
|
||||
"../../api/test/metrics:metrics_logger",
|
||||
"../../api/units:timestamp",
|
||||
"../../system_wrappers",
|
||||
"../../test:test_support",
|
||||
]
|
||||
}
|
||||
}
|
1
test/jitter/OWNERS
Normal file
1
test/jitter/OWNERS
Normal file
|
@ -0,0 +1 @@
|
|||
brandtr@webrtc.org
|
130
test/jitter/delay_variation_calculator.cc
Normal file
130
test/jitter/delay_variation_calculator.cc
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "test/jitter/delay_variation_calculator.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/units/frequency.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
constexpr Frequency k90000Hz = Frequency::Hertz(90000);
|
||||
} // namespace
|
||||
|
||||
void DelayVariationCalculator::Insert(
|
||||
uint32_t rtp_timestamp,
|
||||
Timestamp arrival_time,
|
||||
DataSize size,
|
||||
absl::optional<int> spatial_layer,
|
||||
absl::optional<int> temporal_layer,
|
||||
absl::optional<VideoFrameType> frame_type) {
|
||||
Frame frame{.rtp_timestamp = rtp_timestamp,
|
||||
.unwrapped_rtp_timestamp = unwrapper_.Unwrap(rtp_timestamp),
|
||||
.arrival_time = arrival_time,
|
||||
.size = size,
|
||||
.spatial_layer = spatial_layer,
|
||||
.temporal_layer = temporal_layer,
|
||||
.frame_type = frame_type};
|
||||
// Using RTP timestamp as the time series sample identifier allows for
|
||||
// cross-correlating time series logged by different objects at different
|
||||
// arrival timestamps.
|
||||
Timestamp sample_time =
|
||||
Timestamp::Millis((frame.unwrapped_rtp_timestamp / k90000Hz).ms());
|
||||
MetadataT sample_metadata = BuildMetadata(frame);
|
||||
if (!prev_frame_) {
|
||||
InsertFirstFrame(frame, sample_time, sample_metadata);
|
||||
} else {
|
||||
InsertFrame(frame, sample_time, sample_metadata);
|
||||
}
|
||||
prev_frame_ = frame;
|
||||
}
|
||||
|
||||
void DelayVariationCalculator::InsertFirstFrame(const Frame& frame,
|
||||
Timestamp sample_time,
|
||||
MetadataT sample_metadata) {
|
||||
const auto s = [=](double sample_value) {
|
||||
return SamplesStatsCounter::StatsSample{.value = sample_value,
|
||||
.time = sample_time,
|
||||
.metadata = sample_metadata};
|
||||
};
|
||||
time_series_.rtp_timestamps.AddSample(
|
||||
s(static_cast<double>(frame.rtp_timestamp)));
|
||||
time_series_.arrival_times_ms.AddSample(s(frame.arrival_time.ms<double>()));
|
||||
time_series_.sizes_bytes.AddSample(s(frame.size.bytes<double>()));
|
||||
time_series_.inter_departure_times_ms.AddSample(s(0.0));
|
||||
time_series_.inter_arrival_times_ms.AddSample(s(0.0));
|
||||
time_series_.inter_delay_variations_ms.AddSample(s(0.0));
|
||||
time_series_.inter_size_variations_bytes.AddSample(s(0.0));
|
||||
}
|
||||
|
||||
void DelayVariationCalculator::InsertFrame(const Frame& frame,
|
||||
Timestamp sample_time,
|
||||
MetadataT sample_metadata) {
|
||||
int64_t inter_rtp_time =
|
||||
frame.unwrapped_rtp_timestamp - prev_frame_->unwrapped_rtp_timestamp;
|
||||
TimeDelta inter_departure_time = inter_rtp_time / k90000Hz;
|
||||
TimeDelta inter_arrival_time = frame.arrival_time - prev_frame_->arrival_time;
|
||||
TimeDelta inter_delay_variation = inter_arrival_time - inter_departure_time;
|
||||
double inter_size_variation_bytes =
|
||||
frame.size.bytes<double>() - prev_frame_->size.bytes<double>();
|
||||
const auto s = [=](double sample_value) {
|
||||
return SamplesStatsCounter::StatsSample{.value = sample_value,
|
||||
.time = sample_time,
|
||||
.metadata = sample_metadata};
|
||||
};
|
||||
const auto ms = [](const TimeDelta& td) { return td.ms<double>(); };
|
||||
time_series_.rtp_timestamps.AddSample(
|
||||
s(static_cast<double>(frame.rtp_timestamp)));
|
||||
time_series_.arrival_times_ms.AddSample(s(frame.arrival_time.ms<double>()));
|
||||
time_series_.sizes_bytes.AddSample(s(frame.size.bytes<double>()));
|
||||
time_series_.inter_departure_times_ms.AddSample(s(ms(inter_departure_time)));
|
||||
time_series_.inter_arrival_times_ms.AddSample(s(ms(inter_arrival_time)));
|
||||
time_series_.inter_delay_variations_ms.AddSample(
|
||||
s(ms(inter_delay_variation)));
|
||||
time_series_.inter_size_variations_bytes.AddSample(
|
||||
s(inter_size_variation_bytes));
|
||||
}
|
||||
|
||||
DelayVariationCalculator::MetadataT DelayVariationCalculator::BuildMetadata(
|
||||
const Frame& frame) {
|
||||
MetadataT metadata;
|
||||
if (prev_frame_) {
|
||||
if (prev_frame_->spatial_layer) {
|
||||
metadata["sl_prev"] = std::to_string(*prev_frame_->spatial_layer);
|
||||
}
|
||||
if (prev_frame_->temporal_layer) {
|
||||
metadata["tl_prev"] = std::to_string(*prev_frame_->temporal_layer);
|
||||
}
|
||||
if (prev_frame_->frame_type) {
|
||||
metadata["frame_type_prev"] =
|
||||
VideoFrameTypeToString(*prev_frame_->frame_type);
|
||||
}
|
||||
}
|
||||
if (frame.spatial_layer) {
|
||||
metadata["sl"] = std::to_string(*frame.spatial_layer);
|
||||
}
|
||||
if (frame.temporal_layer) {
|
||||
metadata["tl"] = std::to_string(*frame.temporal_layer);
|
||||
}
|
||||
if (frame.frame_type) {
|
||||
metadata["frame_type"] = VideoFrameTypeToString(*frame.frame_type);
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
94
test/jitter/delay_variation_calculator.h
Normal file
94
test/jitter/delay_variation_calculator.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef TEST_JITTER_DELAY_VARIATION_CALCULATOR_H_
|
||||
#define TEST_JITTER_DELAY_VARIATION_CALCULATOR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/numerics/samples_stats_counter.h"
|
||||
#include "api/test/metrics/metrics_logger.h"
|
||||
#include "api/units/data_size.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "api/video/video_frame_type.h"
|
||||
#include "rtc_base/numerics/sequence_number_unwrapper.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
// Helper class for calculating different delay variation statistics for "RTP
|
||||
// frame arrival events". One use case is gathering statistics from
|
||||
// RtcEventLogs. Another use case is online logging of data in test calls.
|
||||
class DelayVariationCalculator {
|
||||
public:
|
||||
struct TimeSeries {
|
||||
// Time series of RTP timestamps `t(n)` for each frame `n`.
|
||||
SamplesStatsCounter rtp_timestamps;
|
||||
// Time series of local arrival timestamps `r(n)` for each frame.
|
||||
SamplesStatsCounter arrival_times_ms;
|
||||
// Time series of sizes `s(n)` for each frame.
|
||||
SamplesStatsCounter sizes_bytes;
|
||||
// Time series of `d_t(n) = t(n) - t(n-1)` for each frame.
|
||||
SamplesStatsCounter inter_departure_times_ms;
|
||||
// Time series of `d_r(n) = r(n) - r(n-1)` for each frame.
|
||||
SamplesStatsCounter inter_arrival_times_ms;
|
||||
// Time series of `d_r(n) - d_t(n) = (r(n) - r(n-1)) - (t(n) - t(n-1))`
|
||||
// for each frame.
|
||||
SamplesStatsCounter inter_delay_variations_ms;
|
||||
// Time series of `s(n) - s(n-1)`, for each frame.
|
||||
SamplesStatsCounter inter_size_variations_bytes;
|
||||
};
|
||||
|
||||
DelayVariationCalculator() = default;
|
||||
~DelayVariationCalculator() = default;
|
||||
|
||||
void Insert(uint32_t rtp_timestamp,
|
||||
Timestamp arrival_time,
|
||||
DataSize size,
|
||||
absl::optional<int> spatial_layer = absl::nullopt,
|
||||
absl::optional<int> temporal_layer = absl::nullopt,
|
||||
absl::optional<VideoFrameType> frame_type = absl::nullopt);
|
||||
|
||||
const TimeSeries& time_series() const { return time_series_; }
|
||||
|
||||
private:
|
||||
struct Frame {
|
||||
uint32_t rtp_timestamp;
|
||||
int64_t unwrapped_rtp_timestamp;
|
||||
Timestamp arrival_time;
|
||||
DataSize size;
|
||||
absl::optional<int> spatial_layer;
|
||||
absl::optional<int> temporal_layer;
|
||||
absl::optional<VideoFrameType> frame_type;
|
||||
};
|
||||
using MetadataT = std::map<std::string, std::string>;
|
||||
|
||||
void InsertFirstFrame(const Frame& frame,
|
||||
Timestamp sample_time,
|
||||
MetadataT sample_metadata);
|
||||
void InsertFrame(const Frame& frame,
|
||||
Timestamp sample_time,
|
||||
MetadataT sample_metadata);
|
||||
|
||||
MetadataT BuildMetadata(const Frame& frame);
|
||||
|
||||
RtpTimestampUnwrapper unwrapper_;
|
||||
absl::optional<Frame> prev_frame_ = absl::nullopt;
|
||||
TimeSeries time_series_;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // TEST_JITTER_DELAY_VARIATION_CALCULATOR_H_
|
108
test/jitter/delay_variation_calculator_unittest.cc
Normal file
108
test/jitter/delay_variation_calculator_unittest.cc
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright 2023 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "test/jitter/delay_variation_calculator.h"
|
||||
|
||||
#include "api/numerics/samples_stats_counter.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "test/gmock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
MATCHER_P(HasLength, s, "") {
|
||||
bool c1 = arg.rtp_timestamps.NumSamples() == s;
|
||||
bool c2 = arg.arrival_times_ms.NumSamples() == s;
|
||||
bool c3 = arg.sizes_bytes.NumSamples() == s;
|
||||
bool c4 = arg.inter_departure_times_ms.NumSamples() == s;
|
||||
bool c5 = arg.inter_arrival_times_ms.NumSamples() == s;
|
||||
bool c6 = arg.inter_delay_variations_ms.NumSamples() == s;
|
||||
bool c7 = arg.inter_size_variations_bytes.NumSamples() == s;
|
||||
*result_listener << "c: " << c1 << c2 << c3 << c4 << c5 << c6 << c7;
|
||||
return c1 && c2 && c3 && c4 && c5 && c6 && c7;
|
||||
}
|
||||
|
||||
TEST(DelayVariationCalculatorTest, NoTimeSeriesWithoutFrame) {
|
||||
DelayVariationCalculator calc;
|
||||
|
||||
EXPECT_THAT(calc.time_series(), HasLength(0));
|
||||
}
|
||||
|
||||
TEST(DelayVariationCalculatorTest, PartialTimeSeriesWithOneFrame) {
|
||||
DelayVariationCalculator calc;
|
||||
|
||||
calc.Insert(3000, Timestamp::Millis(33), DataSize::Bytes(100));
|
||||
|
||||
DelayVariationCalculator::TimeSeries ts = calc.time_series();
|
||||
ASSERT_THAT(ts, HasLength(1));
|
||||
auto v0 = [](const SamplesStatsCounter& c) {
|
||||
return c.GetTimedSamples()[0].value;
|
||||
};
|
||||
EXPECT_EQ(v0(ts.rtp_timestamps), 3000);
|
||||
EXPECT_EQ(v0(ts.arrival_times_ms), 33);
|
||||
EXPECT_EQ(v0(ts.sizes_bytes), 100);
|
||||
EXPECT_EQ(v0(ts.inter_departure_times_ms), 0);
|
||||
EXPECT_EQ(v0(ts.inter_arrival_times_ms), 0);
|
||||
EXPECT_EQ(v0(ts.inter_delay_variations_ms), 0);
|
||||
EXPECT_EQ(v0(ts.inter_size_variations_bytes), 0);
|
||||
}
|
||||
|
||||
TEST(DelayVariationCalculatorTest, TimeSeriesWithTwoFrames) {
|
||||
DelayVariationCalculator calc;
|
||||
|
||||
calc.Insert(3000, Timestamp::Millis(33), DataSize::Bytes(100));
|
||||
calc.Insert(6000, Timestamp::Millis(66), DataSize::Bytes(100));
|
||||
|
||||
DelayVariationCalculator::TimeSeries ts = calc.time_series();
|
||||
ASSERT_THAT(ts, HasLength(2));
|
||||
auto v1 = [](const SamplesStatsCounter& c) {
|
||||
return c.GetTimedSamples()[1].value;
|
||||
};
|
||||
EXPECT_EQ(v1(ts.rtp_timestamps), 6000);
|
||||
EXPECT_EQ(v1(ts.arrival_times_ms), 66);
|
||||
EXPECT_EQ(v1(ts.sizes_bytes), 100);
|
||||
EXPECT_EQ(v1(ts.inter_departure_times_ms), 33.333);
|
||||
EXPECT_EQ(v1(ts.inter_arrival_times_ms), 33);
|
||||
EXPECT_EQ(v1(ts.inter_delay_variations_ms), -0.333);
|
||||
EXPECT_EQ(v1(ts.inter_size_variations_bytes), 0);
|
||||
}
|
||||
|
||||
TEST(DelayVariationCalculatorTest, MetadataRecordedForAllTimeSeriesAndFrames) {
|
||||
DelayVariationCalculator calc;
|
||||
|
||||
calc.Insert(3000, Timestamp::Millis(33), DataSize::Bytes(100), /*sl=*/0,
|
||||
/*tl=*/0, VideoFrameType::kVideoFrameKey);
|
||||
calc.Insert(6000, Timestamp::Millis(66), DataSize::Bytes(100), /*sl=*/0,
|
||||
/*tl=*/1, VideoFrameType::kVideoFrameDelta);
|
||||
|
||||
DelayVariationCalculator::TimeSeries ts = calc.time_series();
|
||||
ASSERT_THAT(ts, HasLength(2));
|
||||
auto v = [](const SamplesStatsCounter* c, int n, std::string key) {
|
||||
return c->GetTimedSamples()[n].metadata.at(key);
|
||||
};
|
||||
for (const auto* c :
|
||||
{&ts.rtp_timestamps, &ts.arrival_times_ms, &ts.sizes_bytes,
|
||||
&ts.inter_departure_times_ms, &ts.inter_arrival_times_ms,
|
||||
&ts.inter_delay_variations_ms, &ts.inter_size_variations_bytes}) {
|
||||
EXPECT_EQ(v(c, 0, "sl"), "0");
|
||||
EXPECT_EQ(v(c, 0, "tl"), "0");
|
||||
EXPECT_EQ(v(c, 0, "frame_type"), "key");
|
||||
EXPECT_EQ(v(c, 1, "sl_prev"), "0");
|
||||
EXPECT_EQ(v(c, 1, "tl_prev"), "0");
|
||||
EXPECT_EQ(v(c, 1, "frame_type_prev"), "key");
|
||||
EXPECT_EQ(v(c, 1, "sl"), "0");
|
||||
EXPECT_EQ(v(c, 1, "tl"), "1");
|
||||
EXPECT_EQ(v(c, 1, "frame_type"), "delta");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
70
test/jitter/logging_delay_variation_calculator.cc
Normal file
70
test/jitter/logging_delay_variation_calculator.cc
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "test/jitter/logging_delay_variation_calculator.h"
|
||||
|
||||
#include "api/test/metrics/global_metrics_logger_and_exporter.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
void LoggingDelayVariationCalculator::Insert(
|
||||
uint32_t rtp_timestamp,
|
||||
Timestamp arrival_time,
|
||||
DataSize size,
|
||||
absl::optional<int> spatial_layer,
|
||||
absl::optional<int> temporal_layer,
|
||||
absl::optional<VideoFrameType> frame_type) {
|
||||
calc_.Insert(rtp_timestamp, arrival_time, size, spatial_layer, temporal_layer,
|
||||
frame_type);
|
||||
}
|
||||
|
||||
void LoggingDelayVariationCalculator::LogMetrics() const {
|
||||
const DelayVariationCalculator::TimeSeries& time_series = calc_.time_series();
|
||||
|
||||
if (!time_series.rtp_timestamps.IsEmpty()) {
|
||||
logger_->LogMetric("rtp_timestamp", log_type_, time_series.rtp_timestamps,
|
||||
Unit::kUnitless, ImprovementDirection::kNeitherIsBetter);
|
||||
}
|
||||
if (!time_series.arrival_times_ms.IsEmpty()) {
|
||||
logger_->LogMetric("arrival_time", log_type_, time_series.arrival_times_ms,
|
||||
Unit::kMilliseconds,
|
||||
ImprovementDirection::kNeitherIsBetter);
|
||||
}
|
||||
if (!time_series.sizes_bytes.IsEmpty()) {
|
||||
logger_->LogMetric("size_bytes", log_type_, time_series.sizes_bytes,
|
||||
Unit::kBytes, ImprovementDirection::kNeitherIsBetter);
|
||||
}
|
||||
if (!time_series.inter_departure_times_ms.IsEmpty()) {
|
||||
logger_->LogMetric(
|
||||
"inter_departure_time", log_type_, time_series.inter_departure_times_ms,
|
||||
Unit::kMilliseconds, ImprovementDirection::kNeitherIsBetter);
|
||||
}
|
||||
if (!time_series.inter_arrival_times_ms.IsEmpty()) {
|
||||
logger_->LogMetric("inter_arrival_time", log_type_,
|
||||
time_series.inter_arrival_times_ms, Unit::kMilliseconds,
|
||||
ImprovementDirection::kNeitherIsBetter);
|
||||
}
|
||||
if (!time_series.inter_delay_variations_ms.IsEmpty()) {
|
||||
logger_->LogMetric("inter_delay_variation", log_type_,
|
||||
time_series.inter_delay_variations_ms,
|
||||
Unit::kMilliseconds,
|
||||
ImprovementDirection::kNeitherIsBetter);
|
||||
}
|
||||
if (!time_series.inter_size_variations_bytes.IsEmpty()) {
|
||||
logger_->LogMetric("inter_size_variation", log_type_,
|
||||
time_series.inter_size_variations_bytes, Unit::kBytes,
|
||||
ImprovementDirection::kNeitherIsBetter);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
53
test/jitter/logging_delay_variation_calculator.h
Normal file
53
test/jitter/logging_delay_variation_calculator.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef TEST_JITTER_LOGGING_DELAY_VARIATION_CALCULATOR_H_
|
||||
#define TEST_JITTER_LOGGING_DELAY_VARIATION_CALCULATOR_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/test/metrics/global_metrics_logger_and_exporter.h"
|
||||
#include "api/units/data_size.h"
|
||||
#include "test/jitter/delay_variation_calculator.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
// This class logs the results from a `DelayVariationCalculator`
|
||||
// to a metrics logger. For ease of integration, logging happens at
|
||||
// object destruction.
|
||||
class LoggingDelayVariationCalculator {
|
||||
public:
|
||||
LoggingDelayVariationCalculator(
|
||||
absl::string_view log_type,
|
||||
DefaultMetricsLogger* logger = GetGlobalMetricsLogger())
|
||||
: log_type_(log_type), logger_(logger) {}
|
||||
~LoggingDelayVariationCalculator() { LogMetrics(); }
|
||||
|
||||
void Insert(uint32_t rtp_timestamp,
|
||||
Timestamp arrival_time,
|
||||
DataSize size,
|
||||
absl::optional<int> spatial_layer = absl::nullopt,
|
||||
absl::optional<int> temporal_layer = absl::nullopt,
|
||||
absl::optional<VideoFrameType> frame_type = absl::nullopt);
|
||||
|
||||
private:
|
||||
void LogMetrics() const;
|
||||
|
||||
const std::string log_type_;
|
||||
DefaultMetricsLogger* const logger_;
|
||||
DelayVariationCalculator calc_;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // TEST_JITTER_LOGGING_DELAY_VARIATION_CALCULATOR_H_
|
56
test/jitter/logging_delay_variation_calculator_unittest.cc
Normal file
56
test/jitter/logging_delay_variation_calculator_unittest.cc
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2023 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "test/jitter/logging_delay_variation_calculator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "api/test/metrics/metrics_logger.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "system_wrappers/include/clock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
TEST(LoggingDelayVariationCalculator, TimeSeriesWithTwoFrames) {
|
||||
SimulatedClock clock(123456);
|
||||
DefaultMetricsLogger logger(&clock);
|
||||
{
|
||||
LoggingDelayVariationCalculator calc("TimeSeriesWithTwoFrames", &logger);
|
||||
calc.Insert(3000, Timestamp::Millis(33), DataSize::Bytes(100));
|
||||
calc.Insert(6000, Timestamp::Millis(66), DataSize::Bytes(100));
|
||||
// Metrics are logged when `calc` goes out of scope.
|
||||
}
|
||||
|
||||
std::vector<Metric> metrics = logger.GetCollectedMetrics();
|
||||
std::map<std::string, double> last_sample_by_metric_name;
|
||||
std::transform(metrics.begin(), metrics.end(),
|
||||
std::inserter(last_sample_by_metric_name,
|
||||
last_sample_by_metric_name.end()),
|
||||
[](const Metric& metric) {
|
||||
EXPECT_FALSE(metric.time_series.samples.empty());
|
||||
return std::make_pair(
|
||||
metric.name, metric.time_series.samples.back().value);
|
||||
});
|
||||
EXPECT_EQ(last_sample_by_metric_name["rtp_timestamp"], 6000.0);
|
||||
EXPECT_EQ(last_sample_by_metric_name["arrival_time"], 66.0);
|
||||
EXPECT_EQ(last_sample_by_metric_name["size_bytes"], 100.0);
|
||||
EXPECT_EQ(last_sample_by_metric_name["inter_departure_time"], 33.333);
|
||||
EXPECT_EQ(last_sample_by_metric_name["inter_arrival_time"], 33.0);
|
||||
EXPECT_EQ(last_sample_by_metric_name["inter_delay_variation"], -0.333);
|
||||
EXPECT_EQ(last_sample_by_metric_name["inter_size_variation"], 0.0);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
Loading…
Reference in a new issue