pipewire: module-roc-{sink,source}: add rudimentary ROC_INTERFACE_AUDIO_CONTROL support

This commit is contained in:
Barnabás Pőcze 2023-11-23 16:44:17 +01:00
parent b19d0ffbc3
commit d88def09bd
6 changed files with 88 additions and 19 deletions

View file

@ -32,7 +32,9 @@ static const char *const pulse_module_options =
"sess_latency_msec=<target network latency in milliseconds> "
"local_ip=<local receiver ip> "
"local_source_port=<local receiver port for source packets> "
"local_repair_port=<local receiver port for repair packets> ";
"local_repair_port=<local receiver port for repair packets> "
"local_control_port=<local receiver port for control packets> "
;
#define NAME "roc-sink-input"
@ -162,6 +164,11 @@ static int module_roc_sink_input_prepare(struct module * const module)
pw_properties_set(props, "local_repair_port", NULL);
}
if ((str = pw_properties_get(props, "local_control_port")) != NULL) {
pw_properties_set(roc_props, "local.control.port", str);
pw_properties_set(props, "local_control_port", NULL);
}
if ((str = pw_properties_get(props, "sess_latency_msec")) != NULL) {
pw_properties_set(roc_props, "sess.latency.msec", str);
pw_properties_set(props, "sess_latency_msec", NULL);

View file

@ -30,7 +30,9 @@ static const char *const pulse_module_options =
"fec_code=<empty>|disable|rs8m|ldpc "
"remote_ip=<remote receiver ip> "
"remote_source_port=<remote receiver port for source packets> "
"remote_repair_port=<remote receiver port for repair packets> ";
"remote_repair_port=<remote receiver port for repair packets> "
"remote_control_port=<remote receiver port for control packets> "
;
#define NAME "roc-sink"
@ -119,6 +121,7 @@ static const char* const valid_args[] = {
"remote_ip",
"remote_source_port",
"remote_repair_port",
"remote_control_port",
NULL
};
static const struct spa_dict_item module_roc_sink_info[] = {
@ -177,6 +180,12 @@ static int module_roc_sink_prepare(struct module * const module)
pw_properties_set(roc_props, "remote.repair.port", str);
pw_properties_set(props, "remote_repair_port", NULL);
}
if ((str = pw_properties_get(props, "remote_control_port")) != NULL) {
pw_properties_set(roc_props, "remote.control.port", str);
pw_properties_set(props, "remote_control_port", NULL);
}
if ((str = pw_properties_get(props, "fec_code")) != NULL) {
pw_properties_set(roc_props, "fec.code", str);
pw_properties_set(props, "fec_code", NULL);

View file

@ -32,7 +32,9 @@ static const char *const pulse_module_options =
"sess_latency_msec=<target network latency in milliseconds> "
"local_ip=<local receiver ip> "
"local_source_port=<local receiver port for source packets> "
"local_repair_port=<local receiver port for repair packets> ";
"local_repair_port=<local receiver port for repair packets> "
"local_control_port=<local receiver port for control packets> "
;
#define NAME "roc-source"
@ -123,6 +125,7 @@ static const char* const valid_args[] = {
"local_ip",
"local_source_port",
"local_repair_port",
"local_control_port",
NULL
};
@ -179,6 +182,11 @@ static int module_roc_source_prepare(struct module * const module)
pw_properties_set(props, "local_repair_port", NULL);
}
if ((str = pw_properties_get(props, "local_control_port")) != NULL) {
pw_properties_set(roc_props, "local.control.port", str);
pw_properties_set(props, "local_control_port", NULL);
}
if ((str = pw_properties_get(props, "sess_latency_msec")) != NULL) {
pw_properties_set(roc_props, "sess.latency.msec", str);
pw_properties_set(props, "sess_latency_msec", NULL);

View file

@ -44,6 +44,7 @@
* - `remote.ip = <str>`: remote receiver ip
* - `remote.source.port = <str>`: remote receiver TCP/UDP port for source packets
* - `remote.repair.port = <str>`: remote receiver TCP/UDP port for receiver packets
* - `remote.control.port = <str>`: remote receiver TCP/UDP port for control packets
* - `fec.code = <str>`: Possible values: `disable`, `rs8m`, `ldpc`
*
* ## General options
@ -63,6 +64,7 @@
* remote.ip = 192.168.0.244
* remote.source.port = 10001
* remote.repair.port = 10002
* remote.control.port = 10003
* sink.name = "ROC Sink"
* sink.props = {
* node.name = "roc-sink"
@ -104,6 +106,9 @@ struct module_roc_sink_data {
char *remote_ip;
int remote_source_port;
int remote_repair_port;
roc_endpoint *remote_control_addr;
int remote_control_port;
};
static void stream_destroy(void *d)
@ -212,15 +217,12 @@ static void impl_destroy(struct module_roc_sink_data *data)
pw_properties_free(data->capture_props);
if (data->sender)
roc_sender_close(data->sender);
if (data->context)
roc_context_close(data->context);
spa_clear_ptr(data->sender, roc_sender_close);
spa_clear_ptr(data->context, roc_context_close);
if (data->remote_source_addr)
(void) roc_endpoint_deallocate(data->remote_source_addr);
if (data->remote_repair_addr)
(void) roc_endpoint_deallocate(data->remote_repair_addr);
spa_clear_ptr(data->remote_source_addr, roc_endpoint_deallocate);
spa_clear_ptr(data->remote_repair_addr, roc_endpoint_deallocate);
spa_clear_ptr(data->remote_control_addr, roc_endpoint_deallocate);
free(data->remote_ip);
free(data);
@ -309,6 +311,18 @@ static int roc_sink_setup(struct module_roc_sink_data *data)
}
}
res = pw_roc_create_endpoint(&data->remote_control_addr, PW_ROC_DEFAULT_CONTROL_PROTO, data->remote_ip, data->remote_control_port);
if (res < 0) {
pw_log_error("failed to create control endpoint: %s", spa_strerror(res));
return res;
}
if (roc_sender_connect(data->sender, ROC_SLOT_DEFAULT, ROC_INTERFACE_AUDIO_CONTROL,
data->remote_control_addr) != 0) {
pw_log_error("can't connect roc sender to remote control address");
return -EINVAL;
}
data->capture = pw_stream_new(data->core,
"roc-sink capture", data->capture_props);
data->capture_props = NULL;
@ -343,6 +357,7 @@ static const struct spa_dict_item module_roc_sink_info[] = {
"remote.ip=<remote receiver ip> "
"( remote.source.port=<remote receiver port for source packets> ) "
"( remote.repair.port=<remote receiver port for repair packets> ) "
"( remote.control.port=<remote receiver port for control packets> ) "
"( sink.props= { key=val ... } ) " },
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
};
@ -424,6 +439,13 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
} else {
data->remote_repair_port = PW_ROC_DEFAULT_REPAIR_PORT;
}
if ((str = pw_properties_get(props, "remote.control.port")) != NULL) {
data->remote_control_port = pw_properties_parse_int(str);
} else {
data->remote_control_port = PW_ROC_DEFAULT_CONTROL_PORT;
}
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

@ -44,6 +44,7 @@
* - `local.ip = <str>`: local sender ip
* - `local.source.port = <str>`: local receiver TCP/UDP port for source packets
* - `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`.
@ -68,6 +69,7 @@
* sess.latency.msec = 5000
* local.source.port = 10001
* local.repair.port = 10002
* local.control.port = 10003
* source.name = "ROC Source"
* source.props = {
* node.name = "roc-source"
@ -112,6 +114,9 @@ struct module_roc_source_data {
int local_source_port;
int local_repair_port;
int sess_latency_msec;
roc_endpoint *local_control_addr;
int local_control_port;
};
static void stream_destroy(void *d)
@ -221,15 +226,12 @@ static void impl_destroy(struct module_roc_source_data *data)
pw_properties_free(data->playback_props);
if (data->receiver)
roc_receiver_close(data->receiver);
if (data->context)
roc_context_close(data->context);
spa_clear_ptr(data->receiver, roc_receiver_close);
spa_clear_ptr(data->context, roc_context_close);
if (data->local_source_addr)
(void) roc_endpoint_deallocate(data->local_source_addr);
if (data->local_repair_addr)
(void) roc_endpoint_deallocate(data->local_repair_addr);
spa_clear_ptr(data->local_source_addr, roc_endpoint_deallocate);
spa_clear_ptr(data->local_repair_addr, roc_endpoint_deallocate);
spa_clear_ptr(data->local_control_addr, roc_endpoint_deallocate);
free(data->local_ip);
free(data);
@ -331,6 +333,18 @@ static int roc_source_setup(struct module_roc_source_data *data)
}
}
res = pw_roc_create_endpoint(&data->local_control_addr, PW_ROC_DEFAULT_CONTROL_PROTO, data->local_ip, data->local_control_port);
if (res < 0) {
pw_log_error("failed to create control endpoint: %s", spa_strerror(res));
return res;
}
if (roc_receiver_bind(data->receiver, ROC_SLOT_DEFAULT, ROC_INTERFACE_AUDIO_CONTROL,
data->local_control_addr) != 0) {
pw_log_error("can't connect roc receiver to local control address");
return -EINVAL;
}
data->playback = pw_stream_new(data->core,
"roc-source playback", data->playback_props);
data->playback_props = NULL;
@ -368,6 +382,7 @@ static const struct spa_dict_item module_roc_source_info[] = {
"( local.ip=<local receiver ip> ) "
"( local.source.port=<local receiver port for source packets> ) "
"( local.repair.port=<local receiver port for repair packets> ) "
"( local.control.port=<local receiver port for control packets> ) "
"( source.props= { key=value ... } ) " },
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
};
@ -446,6 +461,12 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
data->local_repair_port = PW_ROC_DEFAULT_REPAIR_PORT;
}
if ((str = pw_properties_get(props, "local.control.port")) != NULL) {
data->local_control_port = pw_properties_parse_int(str);
} else {
data->local_control_port = PW_ROC_DEFAULT_CONTROL_PORT;
}
if ((str = pw_properties_get(props, "sess.latency.msec")) != NULL) {
data->sess_latency_msec = pw_properties_parse_int(str);
} else {

View file

@ -9,8 +9,10 @@
#define PW_ROC_DEFAULT_IP "0.0.0.0"
#define PW_ROC_DEFAULT_SOURCE_PORT 10001
#define PW_ROC_DEFAULT_REPAIR_PORT 10002
#define PW_ROC_DEFAULT_CONTROL_PORT 10003
#define PW_ROC_DEFAULT_SESS_LATENCY 200
#define PW_ROC_DEFAULT_RATE 44100
#define PW_ROC_DEFAULT_CONTROL_PROTO ROC_PROTO_RTCP
static inline int pw_roc_parse_fec_encoding(roc_fec_encoding *out, const char *str)
{