Skip to content

Commit

Permalink
chore: Rework FreqEstimator and LinkMeter configuration
Browse files Browse the repository at this point in the history
FreqEstimatorConfig and LinkMeterConfig are now part of
pipeline config.

LatencyConfig now does not contains settings for LinkMeter
(window length).

Instead, FreqEstimatorConfig and LinkMeterConfig both have
deduce_defaults() which set values based on latency profile.

This allows to pass custom settings to FreqEstimator and
LinkMeter in pipeline tests for adaptive latency.
  • Loading branch information
gavv committed Aug 2, 2024
1 parent f64b8bd commit 754654a
Show file tree
Hide file tree
Showing 19 changed files with 255 additions and 199 deletions.
3 changes: 2 additions & 1 deletion src/internal_modules/roc_audio/feedback_monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ FeedbackMonitor::FeedbackMonitor(IFrameWriter& writer,
ResamplerWriter* resampler,
const FeedbackConfig& feedback_config,
const LatencyConfig& latency_config,
const FreqEstimatorConfig& fe_config,
const SampleSpec& sample_spec,
dbgio::CsvDumper* dumper)
: tuner_(latency_config, sample_spec, dumper)
: tuner_(latency_config, fe_config, sample_spec, dumper)
, use_packetizer_(false)
, has_feedback_(false)
, last_feedback_ts_(0)
Expand Down
1 change: 1 addition & 0 deletions src/internal_modules/roc_audio/feedback_monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class FeedbackMonitor : public IFrameWriter, public core::NonCopyable<> {
ResamplerWriter* resampler,
const FeedbackConfig& feedback_config,
const LatencyConfig& latency_config,
const FreqEstimatorConfig& fe_config,
const SampleSpec& sample_spec,
dbgio::CsvDumper* dumper);

Expand Down
85 changes: 44 additions & 41 deletions src/internal_modules/roc_audio/freq_estimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,6 @@ namespace audio {

namespace {

// Make config from profile.
FreqEstimatorConfig make_config(FreqEstimatorProfile profile) {
FreqEstimatorConfig config;

switch (profile) {
case FreqEstimatorProfile_Responsive:
config.P = 1e-6;
config.I = 1e-10;
config.decimation_factor1 = fe_decim_factor_max;
config.decimation_factor2 = 0;
config.stable_criteria = 0.1;
break;

case FreqEstimatorProfile_Gradual:
config.P = 1e-6;
config.I = 5e-9;
config.decimation_factor1 = fe_decim_factor_max;
config.decimation_factor2 = fe_decim_factor_max;
config.stable_criteria = 0.05;
break;
}
config.stability_duration_criteria = 15 * core::Second;
config.control_action_saturation_cap = 1e-2;

return config;
}

// Calculate dot product of arrays IR of filter (coeff) and input array (samples).
//
// - coeff: Filter impulse response.
Expand All @@ -66,10 +39,52 @@ double dot_prod(const double* coeff,

} // namespace

FreqEstimator::FreqEstimator(FreqEstimatorProfile profile,
bool FreqEstimatorConfig::deduce_defaults(LatencyTunerProfile latency_profile) {
switch (latency_profile) {
case LatencyTunerProfile_Gradual:
if (P == 0 && I == 0) {
P = 1e-6;
I = 5e-9;
}
if (decimation_factor1 == 0 && decimation_factor2 == 0) {
decimation_factor1 = fe_decim_factor_max;
decimation_factor2 = fe_decim_factor_max;
}
if (stable_criteria == 0) {
stable_criteria = 0.05;
}
break;

case LatencyTunerProfile_Responsive:
if (P == 0 && I == 0) {
P = 1e-6;
I = 1e-10;
}
if (decimation_factor1 == 0 && decimation_factor2 == 0) {
decimation_factor1 = fe_decim_factor_max;
decimation_factor2 = 0;
}
if (stable_criteria == 0) {
stable_criteria = 0.1;
}
break;

case LatencyTunerProfile_Intact:
break;

default:
roc_log(LogError, "freq estimator: unexpected latency tuner profile %s",
latency_tuner_profile_to_str(latency_profile));
return false;
}

return true;
}

FreqEstimator::FreqEstimator(const FreqEstimatorConfig& config,
packet::stream_timestamp_t target_latency,
dbgio::CsvDumper* dumper)
: config_(make_config(profile))
: config_(config)
, target_(target_latency)
, dec1_ind_(0)
, dec2_ind_(0)
Expand Down Expand Up @@ -221,17 +236,5 @@ bool FreqEstimator::is_stable() const {
return stable_;
}

static const char* fe_profile_to_str(FreqEstimatorProfile profile) {
switch (profile) {
case FreqEstimatorProfile_Responsive:
return "responsive";

case FreqEstimatorProfile_Gradual:
return "gradual";
}

return "<invalid>";
}

} // namespace audio
} // namespace roc
31 changes: 14 additions & 17 deletions src/internal_modules/roc_audio/freq_estimator.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,23 @@
#define ROC_AUDIO_FREQ_ESTIMATOR_H_

#include "roc_audio/freq_estimator_decim.h"
#include "roc_audio/latency_config.h"
#include "roc_audio/sample.h"
#include "roc_core/attributes.h"
#include "roc_core/noncopyable.h"
#include "roc_dbgio/csv_dumper.h"
#include "roc_packet/units.h"

namespace roc {
namespace audio {

//! FreqEstimator parameters preset.
enum FreqEstimatorProfile {
//! Fast and responsive tuning.
//! Good for lower network latency and jitter.
FreqEstimatorProfile_Responsive,

//! Slow and smooth tuning.
//! Good for higher network latency and jitter.
FreqEstimatorProfile_Gradual
};

//! FreqEstimator tunable parameters.
struct FreqEstimatorConfig {
double P; //!< Proportional gain of PI-controller.
double I; //!< Integral gain of PI-controller.
//! Proportional gain of PI-controller.
double P;

//! Integral gain of PI-controller.
double I;

//! How much downsample input value (latency buffer size) on the first stage.
//! Must be less or equal to fe_decim_factor_max and must be greater than zero.
Expand All @@ -62,10 +56,13 @@ struct FreqEstimatorConfig {
, I(0)
, decimation_factor1(0)
, decimation_factor2(0)
, stable_criteria(0.1)
, stability_duration_criteria(0)
, control_action_saturation_cap(0) {
, stable_criteria(0)
, stability_duration_criteria(15 * core::Second)
, control_action_saturation_cap(1e-2) {
}

//! Automatically fill missing settings.
ROC_ATTR_NODISCARD bool deduce_defaults(LatencyTunerProfile latency_profile);
};

//! Evaluates sender's frequency to receiver's frequency ratio.
Expand All @@ -82,7 +79,7 @@ class FreqEstimator : public core::NonCopyable<> {
//! @b Parameters
//! - @p profile defines configuration preset.
//! - @p target_latency defines latency we want to archive.
FreqEstimator(FreqEstimatorProfile profile,
FreqEstimator(const FreqEstimatorConfig& config,
packet::stream_timestamp_t target_latency,
dbgio::CsvDumper* dumper);

Expand Down
14 changes: 0 additions & 14 deletions src/internal_modules/roc_audio/latency_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,16 +104,6 @@ core::nanoseconds_t deduce_stale_tolerance(const core::nanoseconds_t latency_tol
return std::max(latency_tolerance / 4, 10 * core::Millisecond);
}

size_t deduce_sliding_window_len(const LatencyTunerProfile tuner_profile) {
if (tuner_profile == audio::LatencyTunerProfile_Responsive) {
// Responsive profile requires faster reactions to changes
// of link characteristics.
return 10000;
} else {
return 30000;
}
}

bool validate_adaptive_latency(const core::nanoseconds_t target_latency,
const core::nanoseconds_t latency_tolerance,
const core::nanoseconds_t start_target_latency,
Expand Down Expand Up @@ -267,10 +257,6 @@ bool LatencyConfig::deduce_defaults(core::nanoseconds_t default_latency,
}
}

if (sliding_window_length == 0) {
sliding_window_length = deduce_sliding_window_len(tuner_profile);
}

return true;
}

Expand Down
10 changes: 2 additions & 8 deletions src/internal_modules/roc_audio/latency_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,6 @@ struct LatencyConfig {
//! For example, 0.01 allows freq_coeff values in range [0.99; 1.01].
float scaling_tolerance;

//! Number of packets we use to calculate sliding statistics.
//! @remarks
//! We calculate jitter statistics based on this last delivered packets.
size_t sliding_window_length;

//! Latency tuner decides to adjust target latency if
//! the current value >= estimated optimal latency *
//! latency_decrease_relative_threshold_.
Expand Down Expand Up @@ -182,7 +177,6 @@ struct LatencyConfig {
, stale_tolerance(0)
, scaling_interval(5 * core::Millisecond)
, scaling_tolerance(0.005f)
, sliding_window_length(0)
, latency_decrease_relative_threshold(1.7f)
, starting_timeout(5 * core::Second)
, cooldown_dec_timeout(5 * core::Second)
Expand All @@ -207,11 +201,11 @@ struct LatencyMetrics {
core::nanoseconds_t niq_stalling;

//! Estimated end-to-end latency.
//! An estimate of the time from recording a frame on sender to playing it
//! on receiver.
//! An estimate of time from recording a frame on sender to playing it on receiver.
core::nanoseconds_t e2e_latency;

//! Estimated FEC block duration.
//! Total duration of packets within one FEC block.
core::nanoseconds_t fec_block_duration;

LatencyMetrics()
Expand Down
7 changes: 4 additions & 3 deletions src/internal_modules/roc_audio/latency_monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,19 @@ LatencyMonitor::LatencyMonitor(IFrameReader& frame_reader,
const packet::ILinkMeter& link_meter,
const fec::BlockReader* fec_reader,
ResamplerReader* resampler,
const LatencyConfig& config,
const LatencyConfig& latency_config,
const FreqEstimatorConfig& fe_config,
const SampleSpec& packet_sample_spec,
const SampleSpec& frame_sample_spec,
dbgio::CsvDumper* dumper)
: tuner_(config, frame_sample_spec, dumper)
: tuner_(latency_config, fe_config, frame_sample_spec, dumper)
, frame_reader_(frame_reader)
, incoming_queue_(incoming_queue)
, depacketizer_(depacketizer)
, link_meter_(link_meter)
, fec_reader_(fec_reader)
, resampler_(resampler)
, enable_scaling_(config.tuner_profile != audio::LatencyTunerProfile_Intact)
, enable_scaling_(latency_config.tuner_profile != audio::LatencyTunerProfile_Intact)
, capture_ts_(0)
, packet_sample_spec_(packet_sample_spec)
, frame_sample_spec_(frame_sample_spec)
Expand Down
3 changes: 2 additions & 1 deletion src/internal_modules/roc_audio/latency_monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ class LatencyMonitor : public IFrameReader, public core::NonCopyable<> {
const packet::ILinkMeter& link_meter,
const fec::BlockReader* fec_reader,
ResamplerReader* resampler,
const LatencyConfig& config,
const LatencyConfig& latency_config,
const FreqEstimatorConfig& fe_config,
const SampleSpec& packet_sample_spec,
const SampleSpec& frame_sample_spec,
dbgio::CsvDumper* dumper);
Expand Down
Loading

0 comments on commit 754654a

Please sign in to comment.