diff --git a/src/modules/meson.build b/src/modules/meson.build index 087c72371..815ee66b9 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -505,8 +505,8 @@ pipewire_module_raop_sink = shared_library('pipewire-module-raop-sink', endif summary({'raop-sink (requires OpenSSL)': build_module_raop}, bool_yn: true, section: 'Optional Modules') -roc_lib = cc.find_library('roc', has_headers: ['roc/config.h' ], required: get_option('roc')) -summary({'ROC': roc_lib.found()}, bool_yn: true, section: 'Streaming between daemons') +roc_dep = dependency('roc', required: get_option('roc')) +summary({'ROC': roc_dep.found()}, bool_yn: true, section: 'Streaming between daemons') pipewire_module_rtp_source = shared_library('pipewire-module-rtp-source', [ 'module-rtp-source.c' ], @@ -526,7 +526,7 @@ pipewire_module_rtp_sink = shared_library('pipewire-module-rtp-sink', dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep], ) -build_module_roc = roc_lib.found() +build_module_roc = roc_dep.found() if build_module_roc pipewire_module_roc_sink = shared_library('pipewire-module-roc-sink', [ 'module-roc-sink.c' ], @@ -534,7 +534,7 @@ pipewire_module_roc_sink = shared_library('pipewire-module-roc-sink', install : true, install_dir : modules_install_dir, install_rpath: modules_install_dir, - dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep, roc_lib], + dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep, roc_dep], ) pipewire_module_roc_source = shared_library('pipewire-module-roc-source', @@ -543,7 +543,7 @@ pipewire_module_roc_source = shared_library('pipewire-module-roc-source', install : true, install_dir : modules_install_dir, install_rpath: modules_install_dir, - dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep, roc_lib], + dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep, roc_dep], ) endif summary({'roc-sink': build_module_roc}, bool_yn: true, section: 'Optional Modules') diff --git a/src/modules/module-protocol-pulse/modules/module-roc-sink.c b/src/modules/module-protocol-pulse/modules/module-roc-sink.c index 22ff4dc83..c8e64a279 100644 --- a/src/modules/module-protocol-pulse/modules/module-roc-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-roc-sink.c @@ -116,7 +116,6 @@ static const struct spa_dict_item module_roc_sink_info[] = { { PW_KEY_MODULE_USAGE, "sink_name= " "sink_properties= " "fec_code=|disable|rs8m|ldpc " - "local_ip= " "remote_ip= " "remote_source_port= " "remote_repair_port= " }, @@ -163,11 +162,6 @@ static int module_roc_sink_prepare(struct module * const module) goto out; } - if ((str = pw_properties_get(props, "local_ip")) != NULL) { - pw_properties_set(roc_props, "local.ip", str); - pw_properties_set(props, "local_ip", NULL); - } - if ((str = pw_properties_get(props, "remote_source_port")) != NULL) { pw_properties_set(roc_props, "remote.source.port", str); pw_properties_set(props, "remote_source_port", NULL); diff --git a/src/modules/module-roc-sink.c b/src/modules/module-roc-sink.c index 324caa935..8f0d2e882 100644 --- a/src/modules/module-roc-sink.c +++ b/src/modules/module-roc-sink.c @@ -40,6 +40,8 @@ #include #include +#include "module-roc/common.h" + /** \page page_module_roc_sink PipeWire Module: ROC sink * * The `roc-sink` module creates a PipeWire sink that sends samples to @@ -52,7 +54,6 @@ * * - `sink.props = {}`: properties to be passed to the sink stream * - `sink.name = `: node.name of the sink - * - `local.ip = `: local sender ip * - `remote.ip = `: remote receiver ip * - `remote.source.port = `: remote receiver TCP/UDP port for source packets * - `remote.repair.port = `: remote receiver TCP/UDP port for receiver packets @@ -92,11 +93,6 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); #define PW_LOG_TOPIC_DEFAULT mod_topic -#define ROC_DEFAULT_IP "0.0.0.0" -#define ROC_DEFAULT_SOURCE_PORT 10001 -#define ROC_DEFAULT_REPAIR_PORT 10002 -#define ROC_DEFAULT_RATE 44100 - struct module_roc_sink_data { struct pw_impl_module *module; struct spa_hook module_listener; @@ -113,35 +109,18 @@ struct module_roc_sink_data { unsigned int do_disconnect:1; - roc_address local_addr; - roc_address remote_source_addr; - roc_address remote_repair_addr; + roc_endpoint *remote_source_addr; + roc_endpoint *remote_repair_addr; roc_context *context; roc_sender *sender; - roc_fec_code fec_code; + roc_fec_encoding fec_code; uint32_t rate; - char *local_ip; char *remote_ip; int remote_source_port; int remote_repair_port; }; -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 stream_destroy(void *d) { struct module_roc_sink_data *data = d; @@ -254,7 +233,11 @@ static void impl_destroy(struct module_roc_sink_data *data) if (data->context) roc_context_close(data->context); - free(data->local_ip); + 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); + free(data->remote_ip); free(data); } @@ -283,28 +266,11 @@ static int roc_sink_setup(struct module_roc_sink_data *data) 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"); - return -EINVAL; - } - - if (roc_address_init(&data->remote_source_addr, ROC_AF_AUTO, data->remote_ip, - data->remote_source_port)) { - pw_log_error("Invalid remote source address"); - return -EINVAL; - } - - if (roc_address_init(&data->remote_repair_addr, ROC_AF_AUTO, data->remote_ip, - data->remote_repair_port)) { - pw_log_error("Invalid remote repair address"); - return -EINVAL; - } - memset(&context_config, 0, sizeof(context_config)); - data->context = roc_context_open(&context_config); - if (!data->context) { - pw_log_error("Failed to create roc context"); + res = roc_context_open(&context_config, &data->context); + if (res) { + pw_log_error("failed to create roc context: %d", res); return -EINVAL; } @@ -313,7 +279,7 @@ static int roc_sink_setup(struct module_roc_sink_data *data) sender_config.frame_sample_rate = data->rate; sender_config.frame_channels = ROC_CHANNEL_SET_STEREO; sender_config.frame_encoding = ROC_FRAME_ENCODING_PCM_FLOAT; - sender_config.fec_code = data->fec_code; + sender_config.fec_encoding = data->fec_code; info.rate = data->rate; @@ -325,24 +291,19 @@ static int roc_sink_setup(struct module_roc_sink_data *data) pw_properties_setf(data->capture_props, PW_KEY_NODE_RATE, "1/%d", info.rate); - data->sender = roc_sender_open(data->context, &sender_config); - if (!data->sender) { - pw_log_error("Failed to create roc sender"); - return -EINVAL; - } - - if (roc_sender_bind(data->sender, &data->local_addr) != 0) { - pw_log_error("Failed to bind sender to local address"); + res = roc_sender_open(data->context, &sender_config, &data->sender); + if (res) { + pw_log_error("failed to create roc sender: %d", res); return -EINVAL; } switch (data->fec_code) { - case ROC_FEC_DEFAULT: - case ROC_FEC_RS8M: + case ROC_FEC_ENCODING_DEFAULT: + case ROC_FEC_ENCODING_RS8M: audio_proto = ROC_PROTO_RTP_RS8M_SOURCE; repair_proto = ROC_PROTO_RS8M_REPAIR; break; - case ROC_FEC_LDPC_STAIRCASE: + case ROC_FEC_ENCODING_LDPC_STAIRCASE: audio_proto = ROC_PROTO_RTP_LDPC_SOURCE; repair_proto = ROC_PROTO_LDPC_REPAIR; break; @@ -352,15 +313,27 @@ static int roc_sink_setup(struct module_roc_sink_data *data) break; } - if (roc_sender_connect(data->sender, ROC_PORT_AUDIO_SOURCE, audio_proto, - &data->remote_source_addr) != 0) { + res = pw_roc_create_endpoint(&data->remote_source_addr, audio_proto, data->remote_ip, data->remote_source_port); + if (res < 0) { + pw_log_warn("failed to create source endpoint: %s", spa_strerror(res)); + return res; + } + + if (roc_sender_connect(data->sender, ROC_SLOT_DEFAULT, ROC_INTERFACE_AUDIO_SOURCE, + data->remote_source_addr) != 0) { pw_log_error("can't connect roc sender to remote source address"); return -EINVAL; } if (repair_proto != 0) { - if (roc_sender_connect(data->sender, ROC_PORT_AUDIO_REPAIR, repair_proto, - &data->remote_repair_addr) != 0) { + res = pw_roc_create_endpoint(&data->remote_repair_addr, repair_proto, data->remote_ip, data->remote_repair_port); + if (res < 0) { + pw_log_error("failed to create repair endpoint: %s", spa_strerror(res)); + return res; + } + + if (roc_sender_connect(data->sender, ROC_SLOT_DEFAULT, ROC_INTERFACE_AUDIO_REPAIR, + data->remote_repair_addr) != 0) { pw_log_error("can't connect roc sender to remote repair address"); return -EINVAL; } @@ -463,7 +436,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) data->rate = pw_properties_get_uint32(capture_props, PW_KEY_AUDIO_RATE, data->rate); if (data->rate == 0) - data->rate = ROC_DEFAULT_RATE; + data->rate = PW_ROC_DEFAULT_RATE; if ((str = pw_properties_get(props, "remote.ip")) != NULL) { data->remote_ip = strdup(str); @@ -474,37 +447,31 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) goto out; } - if ((str = pw_properties_get(props, "local.ip")) != NULL) { - data->local_ip = strdup(str); - pw_properties_set(props, "local.ip", NULL); - } else { - data->local_ip = strdup(ROC_DEFAULT_IP); - } - if ((str = pw_properties_get(props, "remote.source.port")) != NULL) { data->remote_source_port = pw_properties_parse_int(str); pw_properties_set(props, "remote.source.port", NULL); } else { - data->remote_source_port = ROC_DEFAULT_SOURCE_PORT; + data->remote_source_port = PW_ROC_DEFAULT_SOURCE_PORT; } if ((str = pw_properties_get(props, "remote.repair.port")) != NULL) { data->remote_repair_port = pw_properties_parse_int(str); pw_properties_set(props, "remote.repair.port", NULL); } else { - data->remote_repair_port = ROC_DEFAULT_REPAIR_PORT; + data->remote_repair_port = PW_ROC_DEFAULT_REPAIR_PORT; } if ((str = pw_properties_get(props, "fec.code")) != NULL) { - if (roc_parse_fec_code(&data->fec_code, str)) { + if (pw_roc_parse_fec_encoding(&data->fec_code, str)) { pw_log_error("Invalid fec code %s, using default", str); - data->fec_code = ROC_FEC_DEFAULT; + data->fec_code = ROC_FEC_ENCODING_DEFAULT; } pw_log_info("using fec.code %s %d", str, data->fec_code); pw_properties_set(props, "fec.code", NULL); } else { - data->fec_code = ROC_FEC_DEFAULT; + data->fec_code = ROC_FEC_ENCODING_DEFAULT; } + data->core = pw_context_get_object(data->module_context, PW_TYPE_INTERFACE_Core); if (data->core == NULL) { str = pw_properties_get(props, PW_KEY_REMOTE_NAME); diff --git a/src/modules/module-roc-source.c b/src/modules/module-roc-source.c index 2085c292a..301ec77a4 100644 --- a/src/modules/module-roc-source.c +++ b/src/modules/module-roc-source.c @@ -40,6 +40,8 @@ #include #include +#include "module-roc/common.h" + /** \page page_module_roc_source PipeWire Module: ROC source * * The `roc-source` module creates a PipeWire source that receives samples @@ -95,12 +97,6 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); #define PW_LOG_TOPIC_DEFAULT mod_topic -#define ROC_DEFAULT_IP "0.0.0.0" -#define ROC_DEFAULT_SOURCE_PORT 10001 -#define ROC_DEFAULT_REPAIR_PORT 10002 -#define ROC_DEFAULT_SESS_LATENCY 200 -#define ROC_DEFAULT_RATE 44100 - struct module_roc_source_data { struct pw_impl_module *module; struct spa_hook module_listener; @@ -118,14 +114,13 @@ struct module_roc_source_data { unsigned int do_disconnect:1; uint32_t stride; - roc_address local_addr; - roc_address local_source_addr; - roc_address local_repair_addr; + roc_endpoint *local_source_addr; + roc_endpoint *local_repair_addr; roc_context *context; roc_receiver *receiver; roc_resampler_profile resampler_profile; - roc_fec_code fec_code; + roc_fec_encoding fec_code; uint32_t rate; char *local_ip; int local_source_port; @@ -140,38 +135,6 @@ static void stream_destroy(void *d) data->playback = NULL; } -static int roc_parse_resampler_profile(roc_resampler_profile *out, const char *str) -{ - if (!str || !*str) - *out = ROC_RESAMPLER_DEFAULT; - else if (spa_streq(str, "disable")) - *out = ROC_RESAMPLER_DISABLE; - else if (spa_streq(str, "high")) - *out = ROC_RESAMPLER_HIGH; - else if (spa_streq(str, "medium")) - *out = ROC_RESAMPLER_MEDIUM; - else if (spa_streq(str, "low")) - *out = ROC_RESAMPLER_LOW; - 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) { struct module_roc_source_data *impl = data; @@ -278,6 +241,11 @@ static void impl_destroy(struct module_roc_source_data *data) if (data->context) roc_context_close(data->context); + 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); + free(data->local_ip); free(data); } @@ -306,27 +274,10 @@ static int roc_source_setup(struct module_roc_source_data *data) 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"); - return -EINVAL; - } - - if (roc_address_init(&data->local_source_addr, ROC_AF_AUTO, data->local_ip, - data->local_source_port)) { - pw_log_error("Invalid local source address"); - return -EINVAL; - } - - if (roc_address_init(&data->local_repair_addr, ROC_AF_AUTO, data->local_ip, - data->local_repair_port)) { - pw_log_error("Invalid local repair address"); - return -EINVAL; - } - spa_zero(context_config); - data->context = roc_context_open(&context_config); - if (!data->context) { - pw_log_error("Failed to create roc context"); + res = roc_context_open(&context_config, &data->context); + if (res) { + pw_log_error("failed to create roc context: %d", res); return -EINVAL; } @@ -360,19 +311,19 @@ static int roc_source_setup(struct module_roc_source_data *data) */ receiver_config.target_latency = data->sess_latency_msec * 1000000; - data->receiver = roc_receiver_open(data->context, &receiver_config); - if (!data->receiver) { - pw_log_error("Failed to create roc receiver"); + res = roc_receiver_open(data->context, &receiver_config, &data->receiver); + if (res) { + pw_log_error("failed to create roc receiver: %d", res); return -EINVAL; } switch (data->fec_code) { - case ROC_FEC_DEFAULT: - case ROC_FEC_RS8M: + case ROC_FEC_ENCODING_DEFAULT: + case ROC_FEC_ENCODING_RS8M: audio_proto = ROC_PROTO_RTP_RS8M_SOURCE; repair_proto = ROC_PROTO_RS8M_REPAIR; break; - case ROC_FEC_LDPC_STAIRCASE: + case ROC_FEC_ENCODING_LDPC_STAIRCASE: audio_proto = ROC_PROTO_RTP_LDPC_SOURCE; repair_proto = ROC_PROTO_LDPC_REPAIR; break; @@ -382,14 +333,27 @@ static int roc_source_setup(struct module_roc_source_data *data) break; } - if (roc_receiver_bind(data->receiver, ROC_PORT_AUDIO_SOURCE, audio_proto, - &data->local_source_addr) != 0) { + res = pw_roc_create_endpoint(&data->local_source_addr, audio_proto, data->local_ip, data->local_source_port); + if (res < 0) { + pw_log_error("failed to create source endpoint: %s", spa_strerror(res)); + return res; + } + + if (roc_receiver_bind(data->receiver, ROC_SLOT_DEFAULT, ROC_INTERFACE_AUDIO_SOURCE, + data->local_source_addr) != 0) { pw_log_error("can't connect roc receiver to local source address"); return -EINVAL; } + if (repair_proto != 0) { - if (roc_receiver_bind(data->receiver, ROC_PORT_AUDIO_REPAIR, repair_proto, - &data->local_repair_addr) != 0) { + res = pw_roc_create_endpoint(&data->local_repair_addr, repair_proto, data->local_ip, data->local_repair_port); + if (res < 0) { + pw_log_error("failed to create repair endpoint: %s", spa_strerror(res)); + return res; + } + + if (roc_receiver_bind(data->receiver, ROC_SLOT_DEFAULT, ROC_INTERFACE_AUDIO_REPAIR, + data->local_repair_addr) != 0) { pw_log_error("can't connect roc receiver to local repair address"); return -EINVAL; } @@ -492,53 +456,53 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) data->rate = pw_properties_get_uint32(playback_props, PW_KEY_AUDIO_RATE, data->rate); if (data->rate == 0) - data->rate = ROC_DEFAULT_RATE; + data->rate = PW_ROC_DEFAULT_RATE; if ((str = pw_properties_get(props, "local.ip")) != NULL) { data->local_ip = strdup(str); pw_properties_set(props, "local.ip", NULL); } else { - data->local_ip = strdup(ROC_DEFAULT_IP); + data->local_ip = strdup(PW_ROC_DEFAULT_IP); } if ((str = pw_properties_get(props, "local.source.port")) != NULL) { data->local_source_port = pw_properties_parse_int(str); pw_properties_set(props, "local.source.port", NULL); } else { - data->local_source_port = ROC_DEFAULT_SOURCE_PORT; + data->local_source_port = PW_ROC_DEFAULT_SOURCE_PORT; } if ((str = pw_properties_get(props, "local.repair.port")) != NULL) { data->local_repair_port = pw_properties_parse_int(str); pw_properties_set(props, "local.repair.port", NULL); } else { - data->local_repair_port = ROC_DEFAULT_REPAIR_PORT; + data->local_repair_port = PW_ROC_DEFAULT_REPAIR_PORT; } if ((str = pw_properties_get(props, "sess.latency.msec")) != NULL) { data->sess_latency_msec = pw_properties_parse_int(str); pw_properties_set(props, "sess.latency.msec", NULL); } else { - data->sess_latency_msec = ROC_DEFAULT_SESS_LATENCY; + data->sess_latency_msec = PW_ROC_DEFAULT_SESS_LATENCY; } if ((str = pw_properties_get(props, "resampler.profile")) != NULL) { - if (roc_parse_resampler_profile(&data->resampler_profile, str)) { + 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_DEFAULT; + data->resampler_profile = ROC_RESAMPLER_PROFILE_DEFAULT; } pw_properties_set(props, "resampler.profile", NULL); } else { - data->resampler_profile = ROC_RESAMPLER_DEFAULT; + data->resampler_profile = ROC_RESAMPLER_PROFILE_DEFAULT; } if ((str = pw_properties_get(props, "fec.code")) != NULL) { - if (roc_parse_fec_code(&data->fec_code, str)) { + if (pw_roc_parse_fec_encoding(&data->fec_code, str)) { pw_log_error("Invalid fec code %s, using default", str); - data->fec_code = ROC_FEC_DEFAULT; + data->fec_code = ROC_FEC_ENCODING_DEFAULT; } pw_properties_set(props, "fec.code", NULL); } else { - data->fec_code = ROC_FEC_DEFAULT; + data->fec_code = ROC_FEC_ENCODING_DEFAULT; } data->core = pw_context_get_object(data->module_context, PW_TYPE_INTERFACE_Core); diff --git a/src/modules/module-roc/common.h b/src/modules/module-roc/common.h new file mode 100644 index 000000000..248c66ebd --- /dev/null +++ b/src/modules/module-roc/common.h @@ -0,0 +1,71 @@ +#ifndef MODULE_ROC_COMMON_H +#define MODULE_ROC_COMMON_H + +#include +#include + +#include + +#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_SESS_LATENCY 200 +#define PW_ROC_DEFAULT_RATE 44100 + +static inline int pw_roc_parse_fec_encoding(roc_fec_encoding *out, const char *str) +{ + if (!str || !*str) + *out = ROC_FEC_ENCODING_DEFAULT; + else if (spa_streq(str, "disable")) + *out = ROC_FEC_ENCODING_DISABLE; + else if (spa_streq(str, "rs8m")) + *out = ROC_FEC_ENCODING_RS8M; + else if (spa_streq(str, "ldpc")) + *out = ROC_FEC_ENCODING_LDPC_STAIRCASE; + else + return -EINVAL; + return 0; +} + +static inline int pw_roc_parse_resampler_profile(roc_resampler_profile *out, const char *str) +{ + if (!str || !*str) + *out = ROC_RESAMPLER_PROFILE_DEFAULT; + else if (spa_streq(str, "disable")) + *out = ROC_RESAMPLER_PROFILE_DISABLE; + else if (spa_streq(str, "high")) + *out = ROC_RESAMPLER_PROFILE_HIGH; + else if (spa_streq(str, "medium")) + *out = ROC_RESAMPLER_PROFILE_MEDIUM; + else if (spa_streq(str, "low")) + *out = ROC_RESAMPLER_PROFILE_LOW; + 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; + + if (roc_endpoint_allocate(&endpoint)) + return -ENOMEM; + + if (roc_endpoint_set_protocol(endpoint, protocol)) + goto out_error_free_ep; + + if (roc_endpoint_set_host(endpoint, ip)) + goto out_error_free_ep; + + if (roc_endpoint_set_port(endpoint, port)) + goto out_error_free_ep; + + *result = endpoint; + return 0; + +out_error_free_ep: + (void) roc_endpoint_deallocate(endpoint); + return -EINVAL; +} + +#endif /* MODULE_ROC_COMMON_H */