roc: add fec_code option

Add fec_code option.
Fix resample.profile parsing.
This commit is contained in:
Wim Taymans 2022-04-25 16:20:55 +02:00
parent 1e244b4ebd
commit 09ea37cfdf
5 changed files with 152 additions and 78 deletions

View file

@ -121,7 +121,8 @@ struct module_roc_source_data {
roc_context *context;
roc_receiver *receiver;
char *resampler_profile;
roc_resampler_profile resampler_profile;
roc_fec_code fec_code;
char *local_ip;
int local_source_port;
int local_repair_port;
@ -137,25 +138,34 @@ static void stream_destroy(void *d)
static int roc_parse_resampler_profile(roc_resampler_profile *out, const char *str)
{
if (!str || !*str) {
if (!str || !*str)
*out = ROC_RESAMPLER_DEFAULT;
return 0;
} else if (spa_streq(str, "disable") == 0) {
else if (spa_streq(str, "disable"))
*out = ROC_RESAMPLER_DISABLE;
return 0;
} else if (spa_streq(str, "high") == 0) {
else if (spa_streq(str, "high"))
*out = ROC_RESAMPLER_HIGH;
return 0;
} else if (spa_streq(str, "medium") == 0) {
else if (spa_streq(str, "medium"))
*out = ROC_RESAMPLER_MEDIUM;
return 0;
} else if (spa_streq(str, "low") == 0) {
else if (spa_streq(str, "low"))
*out = ROC_RESAMPLER_LOW;
return 0;
} else {
pw_log_error("Invalid resampler profile: %s", str);
else
return -EINVAL;
}
return 0;
}
static int roc_parse_fec_code(roc_fec_code *out, const char *str)
{
if (!str || !*str)
*out = ROC_FEC_DEFAULT;
else if (spa_streq(str, "disable"))
*out = ROC_FEC_DISABLE;
else if (spa_streq(str, "rs8m"))
*out = ROC_FEC_RS8M;
else if (spa_streq(str, "ldpc"))
*out = ROC_FEC_LDPC_STAIRCASE;
else
return -EINVAL;
return 0;
}
static void playback_process(void *data)
@ -265,7 +275,6 @@ static void impl_destroy(struct module_roc_source_data *data)
roc_context_close(data->context);
free(data->local_ip);
free(data->resampler_profile);
free(data);
}
@ -291,6 +300,7 @@ static int roc_source_setup(struct module_roc_source_data *data)
uint32_t n_params;
uint8_t buffer[1024];
int res;
roc_protocol audio_proto, repair_proto;
if (roc_address_init(&data->local_addr, ROC_AF_AUTO, data->local_ip, 0)) {
pw_log_error("Invalid local IP address");
@ -309,19 +319,18 @@ static int roc_source_setup(struct module_roc_source_data *data)
return -EINVAL;
}
memset(&context_config, 0, sizeof(context_config));
spa_zero(context_config);
data->context = roc_context_open(&context_config);
if (!data->context) {
pw_log_error("Failed to create roc context");
return -EINVAL;
}
memset(&receiver_config, 0, sizeof(receiver_config));
spa_zero(receiver_config);
receiver_config.frame_sample_rate = 44100;
receiver_config.frame_channels = ROC_CHANNEL_SET_STEREO;
receiver_config.frame_encoding = ROC_FRAME_ENCODING_PCM_FLOAT;
receiver_config.resampler_profile = data->resampler_profile;
/* Fixed to be the same as ROC receiver config above */
info.rate = 44100;
@ -333,12 +342,6 @@ static int roc_source_setup(struct module_roc_source_data *data)
pw_properties_setf(data->playback_props, PW_KEY_NODE_RATE, "1/%d", info.rate);
if (roc_parse_resampler_profile(&receiver_config.resampler_profile,
data->resampler_profile)) {
pw_log_error("Invalid resampler profile");
return -EINVAL;
}
/*
* Note that target latency is in nano seconds.
*
@ -358,16 +361,33 @@ static int roc_source_setup(struct module_roc_source_data *data)
return -EINVAL;
}
if (roc_receiver_bind(data->receiver, ROC_PORT_AUDIO_SOURCE, ROC_PROTO_RTP_RS8M_SOURCE,
switch (data->fec_code) {
case ROC_FEC_DEFAULT:
case ROC_FEC_RS8M:
audio_proto = ROC_PROTO_RTP_RS8M_SOURCE;
repair_proto = ROC_PROTO_RS8M_REPAIR;
break;
case ROC_FEC_LDPC_STAIRCASE:
audio_proto = ROC_PROTO_RTP_LDPC_SOURCE;
repair_proto = ROC_PROTO_LDPC_REPAIR;
break;
default:
audio_proto = ROC_PROTO_RTP;
repair_proto = 0;
break;
}
if (roc_receiver_bind(data->receiver, ROC_PORT_AUDIO_SOURCE, audio_proto,
&data->local_source_addr) != 0) {
pw_log_error("can't connect roc receiver to local source address");
return -EINVAL;
}
if (roc_receiver_bind(data->receiver, ROC_PORT_AUDIO_REPAIR, ROC_PROTO_RS8M_REPAIR,
&data->local_repair_addr) != 0) {
pw_log_error("can't connect roc receiver to local repair address");
return -EINVAL;
if (repair_proto != 0) {
if (roc_receiver_bind(data->receiver, ROC_PORT_AUDIO_REPAIR, repair_proto,
&data->local_repair_addr) != 0) {
pw_log_error("can't connect roc receiver to local repair address");
return -EINVAL;
}
}
data->playback = pw_stream_new(data->core,
@ -402,6 +422,7 @@ static const struct spa_dict_item module_roc_source_info[] = {
{ PW_KEY_MODULE_DESCRIPTION, "roc source" },
{ PW_KEY_MODULE_USAGE, "source.name=<name for the source> "
"resampler.profile=<empty>|disable|high|medium|low "
"fec.code=<empty>|disable|rs8m|ldpc "
"sess.latency.msec=<target network latency in milliseconds> "
"local.ip=<local receiver ip> "
"local.source.port=<local receiver port for source packets> "
@ -417,8 +438,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
struct module_roc_source_data *data;
struct pw_properties *props = NULL, *playback_props = NULL;
const char *str;
char *local_ip = NULL, *resampler_profile = NULL;
int res = 0, local_repair_port, local_source_port, sess_latency_msec;
int res = 0;
PW_LOG_TOPIC_INIT(mod_topic);
@ -466,36 +486,50 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
pw_properties_set(playback_props, PW_KEY_NODE_NETWORK, "true");
if ((str = pw_properties_get(props, "local.ip")) != NULL) {
local_ip = strdup(str);
data->local_ip = strdup(str);
pw_properties_set(props, "local.ip", NULL);
} else {
local_ip = strdup(ROC_DEFAULT_IP);
data->local_ip = strdup(ROC_DEFAULT_IP);
}
if ((str = pw_properties_get(props, "local.source.port")) != NULL) {
local_source_port = pw_properties_parse_int(str);
data->local_source_port = pw_properties_parse_int(str);
pw_properties_set(props, "local.source.port", NULL);
} else {
local_source_port = ROC_DEFAULT_SOURCE_PORT;
data->local_source_port = ROC_DEFAULT_SOURCE_PORT;
}
if ((str = pw_properties_get(props, "local.repair.port")) != NULL) {
local_repair_port = pw_properties_parse_int(str);
data->local_repair_port = pw_properties_parse_int(str);
pw_properties_set(props, "local.repair.port", NULL);
} else {
local_repair_port = ROC_DEFAULT_REPAIR_PORT;
data->local_repair_port = ROC_DEFAULT_REPAIR_PORT;
}
if ((str = pw_properties_get(props, "sess.latency.msec")) != NULL) {
sess_latency_msec = pw_properties_parse_int(str);
data->sess_latency_msec = pw_properties_parse_int(str);
pw_properties_set(props, "sess.latency.msec", NULL);
} else {
sess_latency_msec = ROC_DEFAULT_SESS_LATENCY;
data->sess_latency_msec = ROC_DEFAULT_SESS_LATENCY;
}
if ((str = pw_properties_get(props, "resampler.profile")) != NULL) {
resampler_profile = strdup(str);
if (roc_parse_resampler_profile(&data->resampler_profile, str)) {
pw_log_warn("Invalid resampler profile %s, using default", str);
data->resampler_profile = ROC_RESAMPLER_DEFAULT;
}
pw_properties_set(props, "resampler.profile", NULL);
} else {
data->resampler_profile = ROC_RESAMPLER_DEFAULT;
}
if ((str = pw_properties_get(props, "fec.code")) != NULL) {
if (roc_parse_fec_code(&data->fec_code, str)) {
pw_log_error("Invalid fec code %s, using default", str);
data->fec_code = ROC_FEC_DEFAULT;
}
pw_properties_set(props, "fec.code", NULL);
} else {
data->fec_code = ROC_FEC_DEFAULT;
}
data->core = pw_context_get_object(data->module_context, PW_TYPE_INTERFACE_Core);
@ -521,12 +555,6 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
&data->core_listener,
&core_events, data);
data->local_ip = local_ip;
data->local_source_port = local_source_port;
data->local_repair_port = local_repair_port;
data->sess_latency_msec = sess_latency_msec;
data->resampler_profile = resampler_profile;
if ((res = roc_source_setup(data)) < 0)
goto out;