module-roc: add some more options

To configure the resampler backend and latency-tuner. This is mostly
to work around potential bugs in the ROC resampler backend.

See #4516
This commit is contained in:
Wim Taymans 2025-02-18 15:51:39 +01:00
parent 8cd8138cc8
commit 3270bd4552
2 changed files with 93 additions and 9 deletions

View file

@ -45,9 +45,16 @@
* - `local.repair.port = <str>`: local receiver TCP/UDP port for receiver packets
* - `local.control.port = <str>`: local receiver TCP/UDP port for control packets
* - `sess.latency.msec = <str>`: target network latency in milliseconds
* - `resampler.profile = <str>`: Possible values: `disable`, `high`,
* `medium`, `low`.
* - `fec.code = <str>`: Possible values: `disable`, `rs8m`, `ldpc`
* - `roc.resampler.backend = <str>`: Possible values: `default`, `builtin`,
* `speex`, `speexdec`.
* - `roc.resampler.profile = <str>`: Possible values: `default`, `high`,
* `medium`, `low`.
* - `roc.latency-tuner.backend = <str>`: Possible values: `default`, `niq`
* - `roc.latency-tuner.profile = <str>`: Possible values: `default`, `intact`,
* `responsive`, `gradual`
* - `fec.code = <str>`: Possible values: `default`, `disable`, `rs8m`, `ldpc`
*
* - `resampler.profile = <str>`: Deprecated, use roc.resampler.profile
*
* ## General options
*
@ -65,7 +72,10 @@
* { name = libpipewire-module-roc-source
* args = {
* local.ip = 0.0.0.0
* resampler.profile = medium
* #roc.resampler.backend = default
* roc.resampler.profile = medium
* #roc.latency-tuner.backend = default
* #roc.latency-tuner.profile = default
* fec.code = disable
* sess.latency.msec = 5000
* local.source.port = 10001
@ -109,6 +119,9 @@ struct module_roc_source_data {
roc_receiver *receiver;
roc_resampler_profile resampler_profile;
roc_resampler_backend resampler_backend;
roc_latency_tuner_backend latency_tuner_backend;
roc_latency_tuner_profile latency_tuner_profile;
roc_fec_encoding fec_code;
uint32_t rate;
char *local_ip;
@ -275,6 +288,9 @@ static int roc_source_setup(struct module_roc_source_data *data)
receiver_config.frame_encoding.channels = ROC_CHANNEL_LAYOUT_STEREO;
receiver_config.frame_encoding.format = ROC_FORMAT_PCM_FLOAT32;
receiver_config.resampler_profile = data->resampler_profile;
receiver_config.resampler_backend = data->resampler_backend;
receiver_config.latency_tuner_backend = data->latency_tuner_backend;
receiver_config.latency_tuner_profile = data->latency_tuner_profile;
info.rate = data->rate;
@ -377,7 +393,10 @@ static const struct spa_dict_item module_roc_source_info[] = {
{ PW_KEY_MODULE_AUTHOR, "Sanchayan Maity <sanchayan@asymptotic.io>" },
{ PW_KEY_MODULE_DESCRIPTION, "roc source" },
{ PW_KEY_MODULE_USAGE, "( source.name=<name for the source> ) "
"( resampler.profile=<empty>|disable|high|medium|low ) "
"( roc.resampler.backend=<empty>|default|builtin|speex|speexdec ) "
"( roc.resampler.profile=<empty>|default|high|medium|low ) "
"( roc.latency-tuner.backend=<empty>|default|niq ) "
"( roc.latency-tuner.profile=<empty>|default|intact|responsive|gradual ) "
"( fec.code=<empty>|disable|rs8m|ldpc ) "
"( sess.latency.msec=<target network latency in milliseconds> ) "
"( local.ip=<local receiver ip> ) "
@ -473,8 +492,16 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
} else {
data->sess_latency_msec = PW_ROC_DEFAULT_SESS_LATENCY;
}
if ((str = pw_properties_get(props, "resampler.profile")) != NULL) {
if ((str = pw_properties_get(props, "roc.resampler.backend")) != NULL) {
if (pw_roc_parse_resampler_backend(&data->resampler_backend, str)) {
pw_log_warn("Invalid resampler backend %s, using default", str);
data->resampler_backend = ROC_RESAMPLER_BACKEND_DEFAULT;
}
} else {
data->resampler_backend = ROC_RESAMPLER_BACKEND_DEFAULT;
}
if ((str = pw_properties_get(props, "roc.resampler.profile")) != NULL ||
(str = pw_properties_get(props, "resampler.profile")) != NULL) {
if (pw_roc_parse_resampler_profile(&data->resampler_profile, str)) {
pw_log_warn("Invalid resampler profile %s, using default", str);
data->resampler_profile = ROC_RESAMPLER_PROFILE_DEFAULT;
@ -482,6 +509,22 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
} else {
data->resampler_profile = ROC_RESAMPLER_PROFILE_DEFAULT;
}
if ((str = pw_properties_get(props, "roc.latency-tuner.backend")) != NULL) {
if (pw_roc_parse_latency_tuner_backend(&data->latency_tuner_backend, str)) {
pw_log_warn("Invalid latency-tuner backend %s, using default", str);
data->latency_tuner_backend = ROC_LATENCY_TUNER_BACKEND_DEFAULT;
}
} else {
data->latency_tuner_backend = ROC_LATENCY_TUNER_BACKEND_DEFAULT;
}
if ((str = pw_properties_get(props, "roc.latency-tuner.profile")) != NULL) {
if (pw_roc_parse_latency_tuner_profile(&data->latency_tuner_profile, str)) {
pw_log_warn("Invalid latency-tuner profile %s, using default", str);
data->latency_tuner_profile = ROC_LATENCY_TUNER_PROFILE_DEFAULT;
}
} else {
data->latency_tuner_profile = ROC_LATENCY_TUNER_PROFILE_DEFAULT;
}
if ((str = pw_properties_get(props, "fec.code")) != NULL) {
if (pw_roc_parse_fec_encoding(&data->fec_code, str)) {
pw_log_error("Invalid fec code %s, using default", str);

View file

@ -16,7 +16,7 @@
static inline int pw_roc_parse_fec_encoding(roc_fec_encoding *out, const char *str)
{
if (!str || !*str)
if (!str || !*str || spa_streq(str, "default"))
*out = ROC_FEC_ENCODING_DEFAULT;
else if (spa_streq(str, "disable"))
*out = ROC_FEC_ENCODING_DISABLE;
@ -31,7 +31,7 @@ static inline int pw_roc_parse_fec_encoding(roc_fec_encoding *out, const char *s
static inline int pw_roc_parse_resampler_profile(roc_resampler_profile *out, const char *str)
{
if (!str || !*str)
if (!str || !*str || spa_streq(str, "default"))
*out = ROC_RESAMPLER_PROFILE_DEFAULT;
else if (spa_streq(str, "high"))
*out = ROC_RESAMPLER_PROFILE_HIGH;
@ -44,6 +44,47 @@ static inline int pw_roc_parse_resampler_profile(roc_resampler_profile *out, con
return 0;
}
static inline int pw_roc_parse_resampler_backend(roc_resampler_backend *out, const char *str)
{
if (!str || !*str || spa_streq(str, "default"))
*out = ROC_RESAMPLER_BACKEND_DEFAULT;
else if (spa_streq(str, "builtin"))
*out = ROC_RESAMPLER_BACKEND_BUILTIN;
else if (spa_streq(str, "speex"))
*out = ROC_RESAMPLER_BACKEND_SPEEX;
else if (spa_streq(str, "speexdec"))
*out = ROC_RESAMPLER_BACKEND_SPEEXDEC;
else
return -EINVAL;
return 0;
}
static inline int pw_roc_parse_latency_tuner_backend(roc_latency_tuner_backend *out, const char *str)
{
if (!str || !*str || spa_streq(str, "default"))
*out = ROC_LATENCY_TUNER_BACKEND_DEFAULT;
else if (spa_streq(str, "niq"))
*out = ROC_LATENCY_TUNER_BACKEND_NIQ;
else
return -EINVAL;
return 0;
}
static inline int pw_roc_parse_latency_tuner_profile(roc_latency_tuner_profile *out, const char *str)
{
if (!str || !*str || spa_streq(str, "default"))
*out = ROC_LATENCY_TUNER_PROFILE_DEFAULT;
else if (spa_streq(str, "intact"))
*out = ROC_LATENCY_TUNER_PROFILE_INTACT;
else if (spa_streq(str, "responsive"))
*out = ROC_LATENCY_TUNER_PROFILE_RESPONSIVE;
else if (spa_streq(str, "gradual"))
*out = ROC_LATENCY_TUNER_PROFILE_GRADUAL;
else
return -EINVAL;
return 0;
}
static inline int pw_roc_create_endpoint(roc_endpoint **result, roc_protocol protocol, const char *ip, int port)
{
roc_endpoint *endpoint;