Skip to content

Commit

Permalink
roc-streaminggh-675 Rework pipeline configs
Browse files Browse the repository at this point in the history
- Replace LatencyMonitorConfig w/ LatencyConfig, which may be also
  used for FeedbackMonitor

- Move target_latency to LatencyConfig

- Use single deduce_defaults() method instead of multiple
  deduce_xxx() calls for each parameter

- Extract ResamplerConfig and move deducing default backend to it

- Invoke deduce_defaults() when constructing pipelines
  • Loading branch information
gavv committed Jan 26, 2024
1 parent b00d6d7 commit 3d88c20
Show file tree
Hide file tree
Showing 48 changed files with 714 additions and 538 deletions.
12 changes: 7 additions & 5 deletions src/internal_modules/roc_audio/builtin_resampler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,13 @@ BuiltinResampler::BuiltinResampler(core::IArena& arena,
return;
}

roc_log(LogDebug,
"builtin resampler: initializing: "
"window_interp=%lu window_size=%lu frame_size=%lu channels_num=%lu",
(unsigned long)window_interp_, (unsigned long)window_size_,
(unsigned long)frame_size_, (unsigned long)in_spec_.num_channels());
roc_log(
LogDebug,
"builtin resampler: initializing:"
" profile=%s window_interp=%lu window_size=%lu frame_size=%lu channels_num=%lu",
resampler_profile_to_str(profile), (unsigned long)window_interp_,
(unsigned long)window_size_, (unsigned long)frame_size_,
(unsigned long)in_spec_.num_channels());

valid_ = true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/internal_modules/roc_audio/builtin_resampler.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include "roc_audio/frame.h"
#include "roc_audio/iframe_reader.h"
#include "roc_audio/iresampler.h"
#include "roc_audio/resampler_profile.h"
#include "roc_audio/resampler_config.h"
#include "roc_audio/sample.h"
#include "roc_audio/sample_spec.h"
#include "roc_core/array.h"
Expand Down
24 changes: 24 additions & 0 deletions src/internal_modules/roc_audio/freq_estimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ FreqEstimatorConfig make_config(FreqEstimatorProfile profile) {
config.decimation_factor1 = fe_decim_factor_max;
config.decimation_factor2 = fe_decim_factor_max;
break;

case FreqEstimatorProfile_Default:
break;
}

return config;
Expand Down Expand Up @@ -153,8 +156,29 @@ double FreqEstimator::run_controller_(double current) {
return 1 + config_.P * error + config_.I * accum_;
}

const char* fe_input_to_str(FreqEstimatorInput input) {
switch (input) {
case FreqEstimatorInput_Disable:
return "disable";

case FreqEstimatorInput_Default:
return "default";

case FreqEstimatorInput_NiqLatency:
return "niq";

case FreqEstimatorInput_E2eLatency:
return "e2e";
}

return "<invalid>";
}

const char* fe_profile_to_str(FreqEstimatorProfile profile) {
switch (profile) {
case FreqEstimatorProfile_Default:
return "default";

case FreqEstimatorProfile_Responsive:
return "responsive";

Expand Down
21 changes: 21 additions & 0 deletions src/internal_modules/roc_audio/freq_estimator.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,26 @@
namespace roc {
namespace audio {

//! FreqEstimator input value.
enum FreqEstimatorInput {
//! Don't use FreqEstimator.
FreqEstimatorInput_Disable,

//! Use default input.
FreqEstimatorInput_Default,

//! Feed FreqEstimator with Network Incoming Queue length.
FreqEstimatorInput_NiqLatency,

//! Feed FreqEstimator with End-to-end latency.
FreqEstimatorInput_E2eLatency
};

//! FreqEstimator paremeter preset.
enum FreqEstimatorProfile {
//! Use default profile.
FreqEstimatorProfile_Default,

//! Fast and responsive tuning.
//! Good for lower network latency and jitter.
FreqEstimatorProfile_Responsive,
Expand Down Expand Up @@ -94,6 +112,9 @@ class FreqEstimator : public core::NonCopyable<> {
double coeff_; // Current frequency coefficient value.
};

//! Get string name of FreqEstimator input.
const char* fe_input_to_str(FreqEstimatorInput input);

//! Get string name of FreqEstimator profile.
const char* fe_profile_to_str(FreqEstimatorProfile profile);

Expand Down
50 changes: 50 additions & 0 deletions src/internal_modules/roc_audio/latency_config.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2024 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include "roc_audio/latency_config.h"

namespace roc {
namespace audio {

void LatencyConfig::deduce_defaults(bool is_receiver) {
if (fe_input == audio::FreqEstimatorInput_Default) {
// On receiver, by default adjust clock based on NIQ latency.
// On sender, by default do not adjust clock.
fe_input = is_receiver ? audio::FreqEstimatorInput_NiqLatency
: audio::FreqEstimatorInput_Disable;
}

if (fe_profile == audio::FreqEstimatorProfile_Default) {
fe_profile = target_latency < 30 * core::Millisecond
// Prefer responsive profile on low latencies, because gradual profile
// won't do it at all.
? audio::FreqEstimatorProfile_Responsive
// Prefer gradual profile for higher latencies, because it can handle
// higher network jitter.
: audio::FreqEstimatorProfile_Gradual;
}

if (latency_tolerance < 0) {
// This formula returns target_latency * N, where N starts with larger
// number and approaches 0.5 as target_latency grows.
// Examples:
// target=1ms -> tolerance=8ms (x8)
// target=10ms -> tolerance=20ms (x2)
// target=200ms -> tolerance=200ms (x1)
// target=2000ms -> tolerance=1444ms (x0.722)
const core::nanoseconds_t capped_latency =
std::max(target_latency, core::Millisecond);

latency_tolerance = core::nanoseconds_t(
capped_latency
* (std::log((200 * core::Millisecond) * 2) / std::log(capped_latency * 2)));
}
}

} // namespace audio
} // namespace roc
62 changes: 62 additions & 0 deletions src/internal_modules/roc_audio/latency_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2015 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

//! @file roc_audio/latency_config.h
//! @brief Latency config.

#ifndef ROC_AUDIO_LATENCY_CONFIG_H_
#define ROC_AUDIO_LATENCY_CONFIG_H_

#include "roc_audio/freq_estimator.h"
#include "roc_core/time.h"

namespace roc {
namespace audio {

//! Parameters for latency and feedback monitors.
struct LatencyConfig {
//! FreqEstimator input.
FreqEstimatorInput fe_input;

//! FreqEstimator profile.
FreqEstimatorProfile fe_profile;

//! FreqEstimator update interval, nanoseconds.
//! How often to run FreqEstimator and update Resampler scaling.
core::nanoseconds_t fe_update_interval;

//! Target latency, nanoseconds.
core::nanoseconds_t target_latency;

//! Maximum allowed deviation from target latency, nanoseconds.
//! If the latency goes out of bounds, the session is terminated.
core::nanoseconds_t latency_tolerance;

//! Maximum allowed deviation of freq_coeff from 1.0.
//! If the scaling goes out of bounds, it is trimmed.
//! For example, 0.01 allows freq_coeff values in range [0.99; 1.01].
float scaling_tolerance;

//! Initialize.
LatencyConfig(const core::nanoseconds_t default_target_latency)
: fe_input(FreqEstimatorInput_Default)
, fe_profile(FreqEstimatorProfile_Default)
, fe_update_interval(5 * core::Millisecond)
, target_latency(default_target_latency)
, latency_tolerance(-1)
, scaling_tolerance(0.005f) {
}

//! Automatically fill missing settings.
void deduce_defaults(bool is_receiver);
};

} // namespace audio
} // namespace roc

#endif // ROC_AUDIO_LATENCY_CONFIG_H_
24 changes: 12 additions & 12 deletions src/internal_modules/roc_audio/latency_monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ LatencyMonitor::LatencyMonitor(IFrameReader& frame_reader,
const packet::SortedQueue& incoming_queue,
const Depacketizer& depacketizer,
ResamplerReader* resampler,
const LatencyMonitorConfig& config,
core::nanoseconds_t target_latency,
const LatencyConfig& config,
const SampleSpec& input_sample_spec,
const SampleSpec& output_sample_spec)
: frame_reader_(frame_reader)
Expand All @@ -52,11 +51,12 @@ LatencyMonitor::LatencyMonitor(IFrameReader& frame_reader,
, e2e_latency_(0)
, has_niq_latency_(false)
, has_e2e_latency_(false)
, target_latency_(input_sample_spec.ns_2_stream_timestamp_delta(target_latency))
, target_latency_(
input_sample_spec.ns_2_stream_timestamp_delta(config.target_latency))
, min_latency_(input_sample_spec.ns_2_stream_timestamp_delta(
target_latency - config.latency_tolerance))
config.target_latency - config.latency_tolerance))
, max_latency_(input_sample_spec.ns_2_stream_timestamp_delta(
target_latency + config.latency_tolerance))
config.target_latency + config.latency_tolerance))
, max_scaling_delta_(config.scaling_tolerance)
, input_sample_spec_(input_sample_spec)
, output_sample_spec_(output_sample_spec)
Expand All @@ -67,27 +67,27 @@ LatencyMonitor::LatencyMonitor(IFrameReader& frame_reader,
"latency monitor: initializing:"
" target=%lu(%.3fms) min=%lu(%.3fms) max=%lu(%.3fms)"
" in_rate=%lu out_rate=%lu"
" fe_enable=%d fe_profile=%s fe_interval=%.3fms",
" fe_input=%s fe_profile=%s fe_interval=%.3fms",
(unsigned long)target_latency_,
timestamp_to_ms(input_sample_spec_, target_latency_), (unsigned long)min_latency_,
timestamp_to_ms(input_sample_spec_, min_latency_), (unsigned long)max_latency_,
timestamp_to_ms(input_sample_spec_, max_latency_),
(unsigned long)input_sample_spec_.sample_rate(),
(unsigned long)output_sample_spec_.sample_rate(), (int)config.fe_enable,
fe_profile_to_str(config.fe_profile),
(unsigned long)output_sample_spec_.sample_rate(),
fe_input_to_str(config.fe_input), fe_profile_to_str(config.fe_profile),
timestamp_to_ms(input_sample_spec_,
(packet::stream_timestamp_diff_t)update_interval_));

if (target_latency_ < min_latency_ || target_latency_ > max_latency_
|| target_latency <= 0) {
if (config.target_latency <= 0 || config.latency_tolerance <= 0
|| target_latency_ < min_latency_ || target_latency_ > max_latency_) {
roc_log(LogError,
"latency monitor: invalid config:"
" target_latency=%ldns latency_tolerance=%ldns",
(long)target_latency, (long)config.latency_tolerance);
(long)config.target_latency, (long)config.latency_tolerance);
return;
}

if (config.fe_enable) {
if (config.fe_input != audio::FreqEstimatorInput_Disable) {
if (config.fe_update_interval <= 0) {
roc_log(LogError, "latency monitor: invalid config: fe_update_interval=%ld",
(long)config.fe_update_interval);
Expand Down
62 changes: 2 additions & 60 deletions src/internal_modules/roc_audio/latency_monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "roc_audio/depacketizer.h"
#include "roc_audio/freq_estimator.h"
#include "roc_audio/iframe_reader.h"
#include "roc_audio/latency_config.h"
#include "roc_audio/resampler_reader.h"
#include "roc_audio/sample_spec.h"
#include "roc_core/attributes.h"
Expand All @@ -27,64 +28,6 @@
namespace roc {
namespace audio {

//! Parameters for latency monitor.
struct LatencyMonitorConfig {
//! Enable FreqEstimator.
bool fe_enable;

//! FreqEstimator profile.
FreqEstimatorProfile fe_profile;

//! FreqEstimator update interval, nanoseconds.
//! How often to run FreqEstimator and update Resampler scaling.
core::nanoseconds_t fe_update_interval;

//! Maximum allowed deviation from target latency, nanoseconds.
//! If the latency goes out of bounds, the session is terminated.
core::nanoseconds_t latency_tolerance;

//! Maximum allowed deviation of freq_coeff from 1.0.
//! If the scaling goes out of bounds, it is trimmed.
//! For example, 0.01 allows freq_coeff values in range [0.99; 1.01].
float scaling_tolerance;

LatencyMonitorConfig()
: fe_enable(true)
, fe_profile(FreqEstimatorProfile_Responsive)
, fe_update_interval(5 * core::Millisecond)
, latency_tolerance(0)
, scaling_tolerance(0.005f) {
}

//! Automatically deduce FreqEstimator profile from target latency.
void deduce_fe_profile(const core::nanoseconds_t target_latency) {
fe_profile = target_latency < 30 * core::Millisecond
// prefer responsive profile on low latencies, because gradual profile
// won't do it at all
? FreqEstimatorProfile_Responsive
// prefer gradual profile for higher latencies, because it can handle
// higher network jitter
: FreqEstimatorProfile_Gradual;
}

//! Automatically deduce latency_tolerance from target_latency.
void deduce_latency_tolerance(core::nanoseconds_t target_latency) {
// this formula returns target_latency * N, where N starts with larger
// number and approaches 0.5 as target_latency grows
// examples:
// target=1ms -> tolerance=8ms (x8)
// target=10ms -> tolerance=20ms (x2)
// target=200ms -> tolerance=200ms (x1)
// target=2000ms -> tolerance=1444ms (x0.722)
if (target_latency < core::Millisecond) {
target_latency = core::Millisecond;
}
latency_tolerance = core::nanoseconds_t(
target_latency
* (std::log((200 * core::Millisecond) * 2) / std::log(target_latency * 2)));
}
};

//! Metrics of latency monitor.
struct LatencyMonitorMetrics {
//! Estimated NIQ latency.
Expand Down Expand Up @@ -155,8 +98,7 @@ class LatencyMonitor : public IFrameReader, public core::NonCopyable<> {
const packet::SortedQueue& incoming_queue,
const Depacketizer& depacketizer,
ResamplerReader* resampler,
const LatencyMonitorConfig& config,
core::nanoseconds_t target_latency,
const LatencyConfig& config,
const SampleSpec& input_sample_spec,
const SampleSpec& output_sample_spec);

Expand Down
33 changes: 0 additions & 33 deletions src/internal_modules/roc_audio/resampler_backend.cpp

This file was deleted.

Loading

0 comments on commit 3d88c20

Please sign in to comment.