From 4e4fbabcc53a0d15ab961ec3637ae3862b695641 Mon Sep 17 00:00:00 2001 From: Victor Gaydov Date: Sat, 3 Aug 2024 03:48:33 +0400 Subject: [PATCH] gh-765: Port LatencyTuner & FreqEstimator to STS time & fix bugs - Use STS instead of system clock for timeouts. This allows to write fast pipeline tests not tied to real time. - Properly compare STS timestamps in LatencyEstimator. Old code was doing comparison without handling possible wrap in several places. - Adaptive latency fix: if new target is below minimum, but current target is above minimum, set target to the minimum instead of keeping target unmodified. --- .../roc_audio/freq_estimator.cpp | 40 +++-- .../roc_audio/freq_estimator.h | 32 ++-- .../roc_audio/latency_tuner.cpp | 142 +++++++++++------- .../roc_audio/latency_tuner.h | 16 +- src/internal_modules/roc_packet/units.h | 40 +++++ src/tests/roc_audio/test_freq_estimator.cpp | 16 +- 6 files changed, 189 insertions(+), 97 deletions(-) diff --git a/src/internal_modules/roc_audio/freq_estimator.cpp b/src/internal_modules/roc_audio/freq_estimator.cpp index 0b9ee04db..6c2702dc5 100644 --- a/src/internal_modules/roc_audio/freq_estimator.cpp +++ b/src/internal_modules/roc_audio/freq_estimator.cpp @@ -83,16 +83,20 @@ bool FreqEstimatorConfig::deduce_defaults(LatencyTunerProfile latency_profile) { FreqEstimator::FreqEstimator(const FreqEstimatorConfig& config, packet::stream_timestamp_t target_latency, + const SampleSpec& sample_spec, dbgio::CsvDumper* dumper) : config_(config) - , target_(target_latency) , dec1_ind_(0) , dec2_ind_(0) , samples_counter_(0) , accum_(0) + , target_(target_latency) , coeff_(1) , stable_(false) - , last_unstable_time_(core::timestamp(core::ClockMonotonic)) + , last_unstable_time_(0) + , stability_duration_criteria_( + sample_spec.ns_2_stream_timestamp_delta(config.stability_duration_criteria)) + , current_stream_pos_(0) , dumper_(dumper) { roc_log(LogDebug, "freq estimator: initializing: P=%e I=%e dc1=%lu dc2=%lu", config_.P, config_.I, (unsigned long)config_.decimation_factor1, @@ -125,8 +129,12 @@ float FreqEstimator::freq_coeff() const { return (float)coeff_; } +bool FreqEstimator::is_stable() const { + return stable_; +} + void FreqEstimator::update_current_latency(packet::stream_timestamp_t current_latency) { - double filtered; + double filtered = 0; if (run_decimators_(current_latency, filtered)) { if (dumper_) { @@ -136,6 +144,17 @@ void FreqEstimator::update_current_latency(packet::stream_timestamp_t current_la } } +void FreqEstimator::update_target_latency(packet::stream_timestamp_t target_latency) { + target_ = (double)target_latency; +} + +void FreqEstimator::update_stream_position(packet::stream_timestamp_t stream_position) { + roc_panic_if_msg(!packet::stream_timestamp_ge(stream_position, current_stream_pos_), + "freq estimator: expected monotonic stream position"); + + current_stream_pos_ = stream_position; +} + bool FreqEstimator::run_decimators_(packet::stream_timestamp_t current, double& filtered) { samples_counter_++; @@ -181,18 +200,17 @@ double FreqEstimator::run_controller_(double current) { " current latency error: %.0f", error); - const core::nanoseconds_t now = core::timestamp(core::ClockMonotonic); - if (std::abs(error) > target_ * config_.stable_criteria && stable_) { stable_ = false; accum_ = 0; - last_unstable_time_ = now; + last_unstable_time_ = current_stream_pos_; roc_log(LogDebug, "freq estimator:" " unstable, %0.f > %.0f / %0.f", config_.stable_criteria, error, target_); } else if (std::abs(error) < target_ * config_.stable_criteria && !stable_ - && now - last_unstable_time_ > config_.stability_duration_criteria) { + && packet::stream_timestamp_diff(current_stream_pos_, last_unstable_time_) + > stability_duration_criteria_) { stable_ = true; roc_log(LogDebug, "freq estimator:" @@ -228,13 +246,5 @@ void FreqEstimator::dump_(double filtered) { dumper_->write(e); } -void FreqEstimator::update_target_latency(packet::stream_timestamp_t target_latency) { - target_ = (double)target_latency; -} - -bool FreqEstimator::is_stable() const { - return stable_; -} - } // namespace audio } // namespace roc diff --git a/src/internal_modules/roc_audio/freq_estimator.h b/src/internal_modules/roc_audio/freq_estimator.h index 8d42df9c9..009294cca 100644 --- a/src/internal_modules/roc_audio/freq_estimator.h +++ b/src/internal_modules/roc_audio/freq_estimator.h @@ -15,6 +15,7 @@ #include "roc_audio/freq_estimator_decim.h" #include "roc_audio/latency_config.h" #include "roc_audio/sample.h" +#include "roc_audio/sample_spec.h" #include "roc_core/attributes.h" #include "roc_core/noncopyable.h" #include "roc_dbgio/csv_dumper.h" @@ -81,17 +82,12 @@ class FreqEstimator : public core::NonCopyable<> { //! - @p target_latency defines latency we want to archive. FreqEstimator(const FreqEstimatorConfig& config, packet::stream_timestamp_t target_latency, + const SampleSpec& sample_spec, dbgio::CsvDumper* dumper); - //! Get current frequency coefficient. + //! Get current frequency coefficient to be passed to resampler. float freq_coeff() const; - //! Compute new value of frequency coefficient. - void update_current_latency(packet::stream_timestamp_t current_latency); - - //! Update target latency. - void update_target_latency(packet::stream_timestamp_t target_latency); - //! Is FreqEstimator in stable state. //! @remarks //! If current_latency is in kept within certain limits around target_latency @@ -99,13 +95,21 @@ class FreqEstimator : public core::NonCopyable<> { //! The state affects internal regulator strategy and it effectiveness. bool is_stable() const; + //! Tell FreqEstimator what is the new target. + void update_target_latency(packet::stream_timestamp_t target_latency); + + //! Tell FreqEstimator what is the actual measured latency. + void update_current_latency(packet::stream_timestamp_t current_latency); + + //! Tell FreqEstimator what is the current stream offset. + void update_stream_position(packet::stream_timestamp_t stream_position); + private: bool run_decimators_(packet::stream_timestamp_t current, double& filtered); double run_controller_(double current); void dump_(double filtered); const FreqEstimatorConfig config_; - double target_; // Target latency. double dec1_casc_buff_[fe_decim_len]; size_t dec1_ind_; @@ -116,11 +120,17 @@ class FreqEstimator : public core::NonCopyable<> { size_t samples_counter_; // Input samples counter. double accum_; // Integrator value. - double coeff_; // Current frequency coefficient value. + double target_; // Target latency. + double coeff_; // Current frequency coefficient value. - bool stable_; // True if FreqEstimator has stabilized. + // True if FreqEstimator has stabilized. + bool stable_; // Last time when FreqEstimator was out of range. - core::nanoseconds_t last_unstable_time_; + packet::stream_timestamp_t last_unstable_time_; + // How long stabilization takes. + const packet::stream_timestamp_diff_t stability_duration_criteria_; + // Current time. + packet::stream_timestamp_t current_stream_pos_; dbgio::CsvDumper* dumper_; }; diff --git a/src/internal_modules/roc_audio/latency_tuner.cpp b/src/internal_modules/roc_audio/latency_tuner.cpp index bb6e660e9..b6abf68f7 100644 --- a/src/internal_modules/roc_audio/latency_tuner.cpp +++ b/src/internal_modules/roc_audio/latency_tuner.cpp @@ -38,10 +38,9 @@ LatencyTuner::LatencyTuner(const LatencyConfig& latency_config, const SampleSpec& sample_spec, dbgio::CsvDumper* dumper) : stream_pos_(0) - , scale_interval_( - sample_spec.ns_2_stream_timestamp_delta(latency_config.scaling_interval)) + , scale_interval_(sample_spec.ns_2_stream_timestamp(latency_config.scaling_interval)) , scale_pos_(0) - , report_interval_(sample_spec.ns_2_stream_timestamp_delta(LogInterval)) + , report_interval_(sample_spec.ns_2_stream_timestamp(LogInterval)) , report_pos_(0) , has_new_freq_coeff_(false) , freq_coeff_(0) @@ -69,9 +68,12 @@ LatencyTuner::LatencyTuner(const LatencyConfig& latency_config, sample_spec.ns_2_stream_timestamp_delta(latency_config.stale_tolerance)) , sample_spec_(sample_spec) , target_latency_state_(TL_STARTING) - , starting_timeout_(latency_config.starting_timeout) - , cooldown_dec_timeout_(latency_config.cooldown_dec_timeout) - , cooldown_inc_timeout_(latency_config.cooldown_inc_timeout) + , starting_timeout_( + sample_spec.ns_2_stream_timestamp_delta(latency_config.starting_timeout)) + , cooldown_dec_timeout_( + sample_spec.ns_2_stream_timestamp_delta(latency_config.cooldown_dec_timeout)) + , cooldown_inc_timeout_( + sample_spec.ns_2_stream_timestamp_delta(latency_config.cooldown_inc_timeout)) , max_jitter_overhead_(latency_config.max_jitter_overhead) , mean_jitter_overhead_(latency_config.mean_jitter_overhead) , last_target_latency_update_(0) @@ -155,7 +157,8 @@ LatencyTuner::LatencyTuner(const LatencyConfig& latency_config, if (enable_latency_adjustment_) { fe_.reset(new (fe_) FreqEstimator( - fe_config, (packet::stream_timestamp_t)cur_target_latency_, dumper_)); + fe_config, (packet::stream_timestamp_t)cur_target_latency_, sample_spec, + dumper_)); } } @@ -316,13 +319,14 @@ void LatencyTuner::compute_scaling_(packet::stream_timestamp_diff_t actual_laten actual_latency = 0; } - if (stream_pos_ < scale_pos_) { + if (packet::stream_timestamp_lt(stream_pos_, scale_pos_)) { return; } - while (stream_pos_ >= scale_pos_) { + while (packet::stream_timestamp_ge(stream_pos_, scale_pos_)) { + fe_->update_stream_position(stream_pos_); fe_->update_current_latency((packet::stream_timestamp_t)actual_latency); - scale_pos_ += (packet::stream_timestamp_t)scale_interval_; + scale_pos_ += scale_interval_; } has_new_freq_coeff_ = true; @@ -349,21 +353,15 @@ void LatencyTuner::compute_scaling_(packet::stream_timestamp_diff_t actual_laten void LatencyTuner::update_target_latency_(const core::nanoseconds_t max_jitter_ns, const core::nanoseconds_t mean_jitter_ns, const core::nanoseconds_t fec_block_ns) { - const core::nanoseconds_t now = core::timestamp(core::ClockMonotonic); - - if (last_target_latency_update_ == 0) { - last_target_latency_update_ = now; - } - // If there is no active timeout, check if evaluated target latency is // significantly smaller than the latency in action so that we could decrease it. - if (target_latency_state_ == TL_NONE) { + if (target_latency_state_ == TL_IDLE) { // Here we estimate what would be the perfect latency for this moment based on // jitter statistics. Later we'll use this value only for decision making if it // worth changing or we rather keep the current latency target untouched. const core::nanoseconds_t estimate = std::max( - std::max((core::nanoseconds_t)(max_jitter_ns * max_jitter_overhead_), - (core::nanoseconds_t)(mean_jitter_ns * mean_jitter_overhead_)), + std::max(core::nanoseconds_t(max_jitter_ns * max_jitter_overhead_), + core::nanoseconds_t(mean_jitter_ns * mean_jitter_overhead_)), fec_block_ns); const core::nanoseconds_t cur_tl_ns = @@ -371,35 +369,48 @@ void LatencyTuner::update_target_latency_(const core::nanoseconds_t max_jitter_n if (estimate < cur_tl_ns && estimate * lat_update_upper_thrsh_ < cur_tl_ns && fe_->is_stable()) { - try_decrease_latency_(estimate, now, cur_tl_ns); + try_decrease_latency_(estimate, cur_tl_ns); } else if (estimate > cur_tl_ns) { // If evaluated target latency is greater, than we must increase it. - try_increase_latency_(estimate, now, cur_tl_ns); + try_increase_latency_(estimate, cur_tl_ns); } } else if (target_latency_state_ == TL_COOLDOWN_AFTER_DEC - && now - last_target_latency_update_ > cooldown_dec_timeout_) { + && packet::stream_timestamp_diff(stream_pos_, last_target_latency_update_) + > cooldown_dec_timeout_) { // Waiting the timeout since the last decreasement. - target_latency_state_ = TL_NONE; + target_latency_state_ = TL_IDLE; } else if (target_latency_state_ == TL_STARTING - && now - last_target_latency_update_ > starting_timeout_) { + && packet::stream_timestamp_diff(stream_pos_, last_target_latency_update_) + > starting_timeout_) { // Waiting the timeout since the startup. - target_latency_state_ = TL_NONE; + target_latency_state_ = TL_IDLE; } else if (target_latency_state_ == TL_COOLDOWN_AFTER_INC - && now - last_target_latency_update_ > cooldown_inc_timeout_) { + && packet::stream_timestamp_diff(stream_pos_, last_target_latency_update_) + > cooldown_inc_timeout_) { // Waiting the timeout since the last increasement. - target_latency_state_ = TL_NONE; + target_latency_state_ = TL_IDLE; } } void LatencyTuner::try_increase_latency_(const core::nanoseconds_t estimate, - const core::nanoseconds_t now, const core::nanoseconds_t cur_tl_ns) { - const core::nanoseconds_t new_tl_ns = + core::nanoseconds_t new_tl_ns = (core::nanoseconds_t)(estimate * lat_update_inc_step_); packet::stream_timestamp_diff_t new_tl_ts = sample_spec_.ns_2_stream_timestamp_delta(new_tl_ns); + if (new_tl_ts >= max_target_latency_ && cur_target_latency_ == max_target_latency_) { + if (last_lat_limiter_.allow()) { + roc_log(LogDebug, + "latency tuner:" + " not increasing target latency higher than limit %ld(%.3fms)", + (long)max_target_latency_, + sample_spec_.stream_timestamp_delta_2_ms(max_target_latency_)); + } + return; + } + if (new_tl_ts > max_target_latency_) { if (last_lat_limiter_.allow()) { roc_log(LogDebug, @@ -420,6 +431,8 @@ void LatencyTuner::try_increase_latency_(const core::nanoseconds_t estimate, (double)max_target_latency_ / core::Millisecond); } } + new_tl_ns = sample_spec_.stream_timestamp_2_ns( + (packet::stream_timestamp_t)max_target_latency_); new_tl_ts = max_target_latency_; } @@ -439,22 +452,21 @@ void LatencyTuner::try_increase_latency_(const core::nanoseconds_t estimate, (double)new_tl_ns / core::Millisecond); cur_target_latency_ = new_tl_ts; - last_target_latency_update_ = now; + last_target_latency_update_ = stream_pos_; target_latency_state_ = TL_COOLDOWN_AFTER_INC; fe_->update_target_latency((packet::stream_timestamp_t)cur_target_latency_); } void LatencyTuner::try_decrease_latency_(const core::nanoseconds_t estimate, - const core::nanoseconds_t now, const core::nanoseconds_t cur_tl_ns) { - const core::nanoseconds_t new_tl_ns = + core::nanoseconds_t new_tl_ns = (core::nanoseconds_t)(cur_tl_ns * lat_update_dec_step_); - const packet::stream_timestamp_diff_t new_tl_ts = + packet::stream_timestamp_diff_t new_tl_ts = sample_spec_.ns_2_stream_timestamp_delta(new_tl_ns); - if (new_tl_ts < min_target_latency_) { + if (new_tl_ts <= min_target_latency_ && cur_target_latency_ == min_target_latency_) { if (last_lat_limiter_.allow()) { roc_log(LogDebug, "latency tuner:" @@ -462,37 +474,53 @@ void LatencyTuner::try_decrease_latency_(const core::nanoseconds_t estimate, (long)min_target_latency_, sample_spec_.stream_timestamp_delta_2_ms(min_target_latency_)); } - } else { - roc_log(LogNote, - "latency tuner:" - " decreasing target latency %ld(%.3fms) => %ld(%.3fms)", - (long)cur_target_latency_, (double)cur_tl_ns / core::Millisecond, - (long)new_tl_ts, (double)new_tl_ns / core::Millisecond); + return; + } - roc_log(LogDebug, - "latency tuner:" - " estimate %.3fms * %.3f = %.3fms," - " new_tl %.3fms * %f = %.3fms", - (double)estimate / core::Millisecond, (double)lat_update_upper_thrsh_, - (double)estimate * (double)lat_update_upper_thrsh_ / core::Millisecond, - (double)cur_tl_ns / core::Millisecond, (double)lat_update_dec_step_, - (double)new_tl_ns / core::Millisecond); - - cur_target_latency_ = new_tl_ts; - last_target_latency_update_ = now; - target_latency_state_ = TL_COOLDOWN_AFTER_DEC; - - fe_->update_target_latency((packet::stream_timestamp_t)cur_target_latency_); + if (new_tl_ts < min_target_latency_) { + if (last_lat_limiter_.allow()) { + roc_log(LogDebug, + "latency tuner:" + " capping target latency %ld(%.3fms)" + " as min limit is higher %ld(%.3fms)", + (long)new_tl_ts, (double)new_tl_ns / core::Millisecond, + (long)min_target_latency_, + sample_spec_.stream_timestamp_delta_2_ms(min_target_latency_)); + } + new_tl_ns = sample_spec_.stream_timestamp_2_ns( + (packet::stream_timestamp_t)min_target_latency_); + new_tl_ts = min_target_latency_; } + + roc_log(LogNote, + "latency tuner:" + " decreasing target latency %ld(%.3fms) => %ld(%.3fms)", + (long)cur_target_latency_, (double)cur_tl_ns / core::Millisecond, + (long)new_tl_ts, (double)new_tl_ns / core::Millisecond); + + roc_log(LogDebug, + "latency tuner:" + " estimate %.3fms * %.3f = %.3fms," + " new_tl %.3fms * %f = %.3fms", + (double)estimate / core::Millisecond, (double)lat_update_upper_thrsh_, + (double)estimate * (double)lat_update_upper_thrsh_ / core::Millisecond, + (double)cur_tl_ns / core::Millisecond, (double)lat_update_dec_step_, + (double)new_tl_ns / core::Millisecond); + + cur_target_latency_ = new_tl_ts; + last_target_latency_update_ = stream_pos_; + target_latency_state_ = TL_COOLDOWN_AFTER_DEC; + + fe_->update_target_latency((packet::stream_timestamp_t)cur_target_latency_); } void LatencyTuner::periodic_report_() { - if (stream_pos_ < report_pos_) { + if (packet::stream_timestamp_lt(stream_pos_, report_pos_)) { return; } - while (stream_pos_ >= report_pos_) { - report_pos_ += (packet::stream_timestamp_t)report_interval_; + while (packet::stream_timestamp_ge(stream_pos_, report_pos_)) { + report_pos_ += report_interval_; } roc_log(LogDebug, diff --git a/src/internal_modules/roc_audio/latency_tuner.h b/src/internal_modules/roc_audio/latency_tuner.h index 67adba8cf..e17e65afc 100644 --- a/src/internal_modules/roc_audio/latency_tuner.h +++ b/src/internal_modules/roc_audio/latency_tuner.h @@ -94,10 +94,8 @@ class LatencyTuner : public core::NonCopyable<> { core::nanoseconds_t mean_jitter_ns, core::nanoseconds_t fec_block_ns); void try_decrease_latency_(core::nanoseconds_t estimate, - core::nanoseconds_t now, core::nanoseconds_t cur_tl_ns); void try_increase_latency_(core::nanoseconds_t estimate, - core::nanoseconds_t now, core::nanoseconds_t cur_tl_ns); void periodic_report_(); @@ -107,10 +105,10 @@ class LatencyTuner : public core::NonCopyable<> { packet::stream_timestamp_t stream_pos_; - packet::stream_timestamp_diff_t scale_interval_; + packet::stream_timestamp_t scale_interval_; packet::stream_timestamp_t scale_pos_; - packet::stream_timestamp_diff_t report_interval_; + packet::stream_timestamp_t report_interval_; packet::stream_timestamp_t report_pos_; bool has_new_freq_coeff_; @@ -157,20 +155,20 @@ class LatencyTuner : public core::NonCopyable<> { const SampleSpec sample_spec_; enum TargetLatencyState { - TL_NONE, + TL_IDLE, TL_STARTING, TL_COOLDOWN_AFTER_INC, TL_COOLDOWN_AFTER_DEC } target_latency_state_; - const core::nanoseconds_t starting_timeout_; - const core::nanoseconds_t cooldown_dec_timeout_; - const core::nanoseconds_t cooldown_inc_timeout_; + const packet::stream_timestamp_diff_t starting_timeout_; + const packet::stream_timestamp_diff_t cooldown_dec_timeout_; + const packet::stream_timestamp_diff_t cooldown_inc_timeout_; const float max_jitter_overhead_; const float mean_jitter_overhead_; - core::nanoseconds_t last_target_latency_update_; + packet::stream_timestamp_t last_target_latency_update_; const float lat_update_upper_thrsh_; const float lat_update_dec_step_; const float lat_update_inc_step_; diff --git a/src/internal_modules/roc_packet/units.h b/src/internal_modules/roc_packet/units.h index 0ce71569c..2f35133f2 100644 --- a/src/internal_modules/roc_packet/units.h +++ b/src/internal_modules/roc_packet/units.h @@ -56,6 +56,16 @@ inline bool stream_timestamp_le(const stream_timestamp_t a, const stream_timesta return stream_timestamp_diff(a, b) <= 0; } +//! Check if `a` is after `b`, taking possible wrap into account. +inline bool stream_timestamp_gt(const stream_timestamp_t a, const stream_timestamp_t b) { + return stream_timestamp_diff(a, b) > 0; +} + +//! Check if `a` is after or equal to `b`, taking possible wrap into account. +inline bool stream_timestamp_ge(const stream_timestamp_t a, const stream_timestamp_t b) { + return stream_timestamp_diff(a, b) >= 0; +} + //! Convert nanoseconds to stream timestamp. stream_timestamp_t ns_2_stream_timestamp(core::nanoseconds_t ns, size_t sample_rate); @@ -97,6 +107,16 @@ inline bool seqnum_le(const seqnum_t a, const seqnum_t b) { return seqnum_diff(a, b) <= 0; } +//! Check if `a` is after `b`, taking possible wrap into account. +inline bool seqnum_gt(const seqnum_t a, const seqnum_t b) { + return seqnum_diff(a, b) > 0; +} + +//! Check if `a` is after or equal to `b`, taking possible wrap into account. +inline bool seqnum_ge(const seqnum_t a, const seqnum_t b) { + return seqnum_diff(a, b) >= 0; +} + //! Extended sequence number. //! @remarks //! Sequence number extended to 32 bits. @@ -122,6 +142,16 @@ inline bool ext_seqnum_le(const ext_seqnum_t a, const ext_seqnum_t b) { return ext_seqnum_diff(a, b) <= 0; } +//! Check if `a` is after `b`, taking possible wrap into account. +inline bool ext_seqnum_gt(const ext_seqnum_t a, const ext_seqnum_t b) { + return ext_seqnum_diff(a, b) > 0; +} + +//! Check if `a` is after or equal to `b`, taking possible wrap into account. +inline bool ext_seqnum_ge(const ext_seqnum_t a, const ext_seqnum_t b) { + return ext_seqnum_diff(a, b) >= 0; +} + //! FEC packet block number. //! @remarks //! Defines position of FEC packet block within stream. @@ -149,6 +179,16 @@ inline bool blknum_le(const blknum_t a, const blknum_t b) { return blknum_diff(a, b) <= 0; } +//! Check if `a` is after `b`, taking possible wrap into account. +inline bool blknum_gt(const blknum_t a, const blknum_t b) { + return blknum_diff(a, b) > 0; +} + +//! Check if `a` is after or equal to `b`, taking possible wrap into account. +inline bool blknum_ge(const blknum_t a, const blknum_t b) { + return blknum_diff(a, b) >= 0; +} + } // namespace packet } // namespace roc diff --git a/src/tests/roc_audio/test_freq_estimator.cpp b/src/tests/roc_audio/test_freq_estimator.cpp index 8df79d93b..4fe53e53d 100644 --- a/src/tests/roc_audio/test_freq_estimator.cpp +++ b/src/tests/roc_audio/test_freq_estimator.cpp @@ -18,10 +18,16 @@ namespace { enum { Target = 10000 }; +const double Epsilon = 0.0001; + const LatencyTunerProfile profile_list[] = { LatencyTunerProfile_Responsive, LatencyTunerProfile_Gradual }; -const double Epsilon = 0.0001; +const SampleSpec sample_spec(44100, + Sample_RawFormat, + ChanLayout_Surround, + ChanOrder_Smpte, + ChanMask_Surround_Mono); } // namespace @@ -32,7 +38,7 @@ TEST(freq_estimator, initial) { FreqEstimatorConfig config; CHECK(config.deduce_defaults(profile_list[p])); - FreqEstimator fe(config, Target, NULL); + FreqEstimator fe(config, Target, sample_spec, NULL); DOUBLES_EQUAL(1.0, (double)fe.freq_coeff(), Epsilon); } @@ -43,7 +49,7 @@ TEST(freq_estimator, aim_queue_size) { FreqEstimatorConfig config; CHECK(config.deduce_defaults(profile_list[p])); - FreqEstimator fe(config, Target, NULL); + FreqEstimator fe(config, Target, sample_spec, NULL); for (size_t n = 0; n < 1000; n++) { fe.update_current_latency(Target); @@ -58,7 +64,7 @@ TEST(freq_estimator, large_queue_size) { FreqEstimatorConfig config; CHECK(config.deduce_defaults(profile_list[p])); - FreqEstimator fe(config, Target, NULL); + FreqEstimator fe(config, Target, sample_spec, NULL); do { fe.update_current_latency(Target * 2); @@ -71,7 +77,7 @@ TEST(freq_estimator, small_queue_size) { FreqEstimatorConfig config; CHECK(config.deduce_defaults(profile_list[p])); - FreqEstimator fe(config, Target, NULL); + FreqEstimator fe(config, Target, sample_spec, NULL); do { fe.update_current_latency(Target / 2);