diff --git a/CMakeLists.txt b/CMakeLists.txt index 5773c560..89730395 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,6 +134,7 @@ add_library(base_objects OBJECT src/base/processing/LossEstimator.cpp src/base/processing/StepsGenerator.cpp src/base/processing/StepsLatencyEstimator.cpp + src/base/processing/MinMaxEstimator.cpp src/base/reports/Console.cpp src/base/reports/JsonPrinter.cpp src/base/reports/JsonReporter.cpp diff --git a/src/base/core/Config.hpp b/src/base/core/Config.hpp index 653269bd..c973d0ec 100644 --- a/src/base/core/Config.hpp +++ b/src/base/core/Config.hpp @@ -142,6 +142,12 @@ struct Config { // number of pre-allocated frames in frame pool size_t frame_pool_size { 128 }; + + // minimum latency time of a time window measurement in nanoseconds + unsigned int min_latency {0u}; + + // maximum latency time of a time window measurement in nanoseconds + unsigned int max_latency {static_cast(-1)}; // get warmup duration in samples size_t warmup_samples() const { diff --git a/src/base/core/Frame.cpp b/src/base/core/Frame.cpp index de3535c3..6648025e 100644 --- a/src/base/core/Frame.cpp +++ b/src/base/core/Frame.cpp @@ -126,4 +126,11 @@ nanoseconds_t Frame::hw_delay() const { return hw_delay_; } +bool Frame::has_impulse() const{ + return has_impulse_; +} + +void Frame::set_has_impulse(bool has_impulse){ + has_impulse_ = has_impulse; +} } // namespace signal_estimator diff --git a/src/base/core/Frame.hpp b/src/base/core/Frame.hpp index dce61ded..00089c8b 100644 --- a/src/base/core/Frame.hpp +++ b/src/base/core/Frame.hpp @@ -77,6 +77,12 @@ class Frame { // at the time when frame was captured or played nanoseconds_t hw_delay() const; + // get whether frame contains impulse + bool has_impulse() const; + + // record whether frame contains impulse + void set_has_impulse(bool has_impulse); + // index access const sample_t& operator[](const size_t index) const { assert(index < data_.size()); @@ -110,6 +116,7 @@ class Frame { nanoseconds_t sw_delay_ {}; nanoseconds_t hw_delay_ {}; + bool has_impulse_ {}; std::atomic refcount_ {}; }; diff --git a/src/base/processing/IEstimatorWrapper.hpp b/src/base/processing/IEstimatorWrapper.hpp new file mode 100644 index 00000000..bb047aa6 --- /dev/null +++ b/src/base/processing/IEstimatorWrapper.hpp @@ -0,0 +1,29 @@ +// Copyright (c) Signal Estimator authors +// Licensed under MIT + +#pragma once + +#include "core/Frame.hpp" +#include "processing/IEstimator.hpp" +#include + +namespace signal_estimator { + +// estimate and report some signal characteristic +class IEstimatorWrapper :public IEstimator { +protected: + std::unique_ptr m_Estimator; +public: + IEstimatorWrapper(std::unique_ptr estimator) : m_Estimator(std::move(estimator)){} + // called from output thread + void add_output(FramePtr frame) override { + m_Estimator->add_output(frame); + } + + // called from input thread + void add_input(FramePtr frame) override { + m_Estimator->add_input(frame); + } +}; + +} // namespace signal_estimator \ No newline at end of file diff --git a/src/base/processing/ImpulseGenerator.cpp b/src/base/processing/ImpulseGenerator.cpp index c8030ca1..9d7ecfb0 100644 --- a/src/base/processing/ImpulseGenerator.cpp +++ b/src/base/processing/ImpulseGenerator.cpp @@ -14,6 +14,7 @@ void ImpulseGenerator::generate(Frame& frame) { size_t i_frame = 0; +// TODO set flag for frame-> set_has_impulse do { for (; i_frame < frame.size() && counter_ < impulse_size_ && counter_ < impulse_interval_; diff --git a/src/base/processing/MinMaxEstimator.cpp b/src/base/processing/MinMaxEstimator.cpp new file mode 100644 index 00000000..ee6448aa --- /dev/null +++ b/src/base/processing/MinMaxEstimator.cpp @@ -0,0 +1,33 @@ + +#include "processing/MinMaxEstimator.hpp" + +namespace signal_estimator { + + // called from output thread +void MinMaxEstimator::add_output(FramePtr frame){ + if(frame->has_impulse()){ + impulse_started_.store(true); + impulse_time_.store(frame->sw_frame_time()); + }else{ + impulse_started_.store(false); + } + m_Estimator->add_output(frame); +}; + + // called from input thread +void MinMaxEstimator::add_input(FramePtr frame){ + if(impulse_started_.load() && + (frame->sw_frame_time() >= impulse_time_.load() + config_.min_latency) && + (frame->sw_frame_time() < impulse_time_.load() + config_.max_latency)){ + m_Estimator->add_input(frame); + } + else{ + for (size_t i = 0; i < frame->size(); i++){ + (frame->data())[i] = 0; + } + m_Estimator->add_input(frame); + } +}; + + +} // namespace signal_estimator \ No newline at end of file diff --git a/src/base/processing/MinMaxEstimator.hpp b/src/base/processing/MinMaxEstimator.hpp new file mode 100644 index 00000000..71094c96 --- /dev/null +++ b/src/base/processing/MinMaxEstimator.hpp @@ -0,0 +1,28 @@ +// Copyright (c) Signal Estimator authors +// Licensed under MIT + +#pragma once +#include "processing/IEstimatorWrapper.hpp" +#include "core/Config.hpp" + + +namespace signal_estimator { + +// estimate and report some signal characteristic +class MinMaxEstimator :public IEstimatorWrapper { +public: + MinMaxEstimator(const Config& config, std::unique_ptr estimator) + : IEstimatorWrapper(std::move(estimator)), + config_(config){} + // called from output thread + void add_output(FramePtr frame) override; + + // called from input thread + void add_input(FramePtr frame) override; +private: + std::atomic impulse_started_{}; + std::atomic impulse_time_{}; + const Config config_; +}; + +} // namespace signal_estimator \ No newline at end of file diff --git a/src/base/processing/StepsGenerator.cpp b/src/base/processing/StepsGenerator.cpp index 162c3395..c01f418f 100644 --- a/src/base/processing/StepsGenerator.cpp +++ b/src/base/processing/StepsGenerator.cpp @@ -15,6 +15,7 @@ StepsGenerator::StepsGenerator(const Config& config) , warmup_countdown_(config.output_info.period_count) { } +// TODO set flag for frame-> set_has_impulse void StepsGenerator::generate(Frame& frame) { std::fill_n(frame.data(), frame.size(), 0); diff --git a/src/base/run/Runner.cpp b/src/base/run/Runner.cpp index 2d1b4170..cdaca3ca 100644 --- a/src/base/run/Runner.cpp +++ b/src/base/run/Runner.cpp @@ -17,6 +17,7 @@ #include "processing/LossEstimator.hpp" #include "processing/StepsGenerator.hpp" #include "processing/StepsLatencyEstimator.hpp" +#include "processing/MinMaxEstimator.hpp" #include "reports/JsonReporter.hpp" #include "reports/TextReporter.hpp" @@ -141,12 +142,14 @@ bool Runner::start() { case Mode::LatencyStep: estimators_.emplace_back( - std::make_unique(config_, *reporters_[n])); + std::make_unique(config_, + std::make_unique(config_, *reporters_[n]))); break; case Mode::Losses: estimators_.emplace_back( - std::make_unique(config_, *reporters_[n])); + std::make_unique(config_, + std::make_unique(config_, *reporters_[n]))); break; case Mode::IOJitter: diff --git a/src/cli/Main.cpp b/src/cli/Main.cpp index c2e1dd08..ebae850d 100644 --- a/src/cli/Main.cpp +++ b/src/cli/Main.cpp @@ -55,6 +55,15 @@ int main(int argc, char** argv) { ->add_option("-w,--warmup", config.warmup_duration, "Warmup duration, seconds (zero for no warmup)") ->default_val(config.warmup_duration); + control_opts + ->add_option("--min-latency", config.min_latency, + "Minimum latency time window, microseconds (zero for no latency)") + ->default_val(config.min_latency); + + control_opts + ->add_option("--max-latency", config.max_latency, + "Maximum latency time window, microseconds (zero for no maximum)") + ->default_val(config.max_latency); auto io_opts = app.add_option_group("I/O options");