diff --git a/src/modules/meson.build b/src/modules/meson.build index 6b215f3a0..59f46ae13 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -693,7 +693,7 @@ pipewire_module_vban_recv = shared_library('pipewire-module-vban-recv', build_module_roc = roc_dep.found() if build_module_roc pipewire_module_roc_sink = shared_library('pipewire-module-roc-sink', - [ 'module-roc-sink.c' ], + [ 'module-roc-sink.c', 'module-roc/common.c'], include_directories : [configinc], install : true, install_dir : modules_install_dir, @@ -702,7 +702,7 @@ if build_module_roc ) pipewire_module_roc_source = shared_library('pipewire-module-roc-source', - [ 'module-roc-source.c' ], + [ 'module-roc-source.c', 'module-roc/common.c' ], include_directories : [configinc], install : true, install_dir : modules_install_dir, diff --git a/src/modules/module-roc-sink.c b/src/modules/module-roc-sink.c index 1cca69592..39ca2bce1 100644 --- a/src/modules/module-roc-sink.c +++ b/src/modules/module-roc-sink.c @@ -46,6 +46,9 @@ * - `remote.repair.port = `: remote receiver TCP/UDP port for receiver packets * - `remote.control.port = `: remote receiver TCP/UDP port for control packets * - `fec.code = `: Possible values: `disable`, `rs8m`, `ldpc` + * - `log.level = `: log level for roc-toolkit. Possible values: `DEFAULT`, + * `NONE`, `ERROR`, `INFO`, `DEBUG`, `TRACE`; `DEFAULT` follows the log + * level of the PipeWire context. * * ## General options * @@ -75,6 +78,7 @@ * node.name = "roc-sink" * } * audio.position = [ FL FR ] + * log.level = DEFAULT * } * } *] @@ -84,8 +88,9 @@ #define NAME "roc-sink" -PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); +PW_LOG_TOPIC(mod_topic, "mod." NAME); #define PW_LOG_TOPIC_DEFAULT mod_topic +PW_LOG_TOPIC_EXTERN(roc_log_topic); struct module_roc_sink_data { struct pw_impl_module *module; @@ -115,6 +120,8 @@ struct module_roc_sink_data { roc_endpoint *remote_control_addr; int remote_control_port; + + roc_log_level loglevel; }; static void stream_destroy(void *d) @@ -300,6 +307,8 @@ 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); + pw_roc_log_init(); + res = roc_sender_open(data->context, &sender_config, &data->sender); if (res) { pw_log_error("failed to create roc sender: %d", res); @@ -382,7 +391,8 @@ static const struct spa_dict_item module_roc_sink_info[] = { "( remote.repair.port= ) " "( remote.control.port= ) " "( audio.position= ) " - "( sink.props= { key=val ... } ) " }, + "( sink.props= { key=val ... } ) " + "( log.level=|DEFAULT|NONE|RROR|INFO|DEBUG|TRACE ) " }, { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, }; @@ -396,6 +406,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) int res = 0; PW_LOG_TOPIC_INIT(mod_topic); + PW_LOG_TOPIC_INIT(roc_log_topic); data = calloc(1, sizeof(struct module_roc_sink_data)); if (data == NULL) @@ -502,6 +513,14 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) pw_log_error("can't connect: %m"); goto out; } + if ((str = pw_properties_get(props, "log.level")) != NULL) { + const struct spa_log *log_conf = pw_log_get(); + const roc_log_level default_level = pw_roc_log_level_pw_2_roc(log_conf->level); + if (pw_roc_parse_log_level(&data->loglevel, str, default_level)) { + pw_log_error("Invalid log level %s, using default", str); + data->loglevel = default_level; + } + } pw_proxy_add_listener((struct pw_proxy*)data->core, &data->core_proxy_listener, diff --git a/src/modules/module-roc-source.c b/src/modules/module-roc-source.c index 6c67a037c..2173c6af1 100644 --- a/src/modules/module-roc-source.c +++ b/src/modules/module-roc-source.c @@ -56,6 +56,9 @@ * - `fec.code = `: Possible values: `default`, `disable`, `rs8m`, `ldpc` * * - `resampler.profile = `: Deprecated, use roc.resampler.profile + * - `log.level = `: log level for roc-toolkit. Possible values: `DEFAULT`, + * `NONE`, `ERROR`, `INFO`, `DEBUG`, `TRACE`; `DEFAULT` follows the log + * level of the PipeWire context. * * ## General options * @@ -89,6 +92,7 @@ * node.name = "roc-source" * } * audio.position = [ FL FR ] + * log.level = DEFAULT * } * } *] @@ -98,8 +102,9 @@ #define NAME "roc-source" -PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); +PW_LOG_TOPIC(mod_topic, "mod." NAME); #define PW_LOG_TOPIC_DEFAULT mod_topic +PW_LOG_TOPIC_EXTERN(roc_log_topic); struct module_roc_source_data { struct pw_impl_module *module; @@ -135,6 +140,8 @@ struct module_roc_source_data { roc_endpoint *local_control_addr; int local_control_port; + + roc_log_level loglevel; }; static void stream_destroy(void *d) @@ -333,6 +340,8 @@ static int roc_source_setup(struct module_roc_source_data *data) */ receiver_config.target_latency = (unsigned long long)data->sess_latency_msec * SPA_NSEC_PER_MSEC; + pw_roc_log_init(); + res = roc_receiver_open(data->context, &receiver_config, &data->receiver); if (res) { pw_log_error("failed to create roc receiver: %d", res); @@ -421,7 +430,8 @@ static const struct spa_dict_item module_roc_source_info[] = { "( local.repair.port= ) " "( local.control.port= ) " "( audio.position= ) " - "( source.props= { key=value ... } ) " }, + "( source.props= { key=value ... } ) " + "( log.level=|DEFAULT|NONE|RROR|INFO|DEBUG|TRACE ) " }, { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, }; @@ -557,6 +567,14 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) } else { data->fec_code = ROC_FEC_ENCODING_DEFAULT; } + if ((str = pw_properties_get(props, "log.level")) != NULL) { + const struct spa_log *log_conf = pw_log_get(); + const roc_log_level default_level = pw_roc_log_level_pw_2_roc(log_conf->level); + if (pw_roc_parse_log_level(&data->loglevel, str, default_level)) { + pw_log_error("Invalid log level %s, using default", str); + data->loglevel = default_level; + } + } data->core = pw_context_get_object(data->module_context, PW_TYPE_INTERFACE_Core); if (data->core == NULL) { diff --git a/src/modules/module-roc/common.c b/src/modules/module-roc/common.c new file mode 100644 index 000000000..244c203dd --- /dev/null +++ b/src/modules/module-roc/common.c @@ -0,0 +1,21 @@ +#include +#include + +#include "common.h" + +PW_LOG_TOPIC(roc_log_topic, "mod.roc.lib"); + +void pw_roc_log_init(void) +{ + roc_log_set_handler(pw_roc_log_handler, NULL); + roc_log_set_level(pw_roc_log_level_pw_2_roc(roc_log_topic->has_custom_level ? roc_log_topic->level : pw_log_level)); +} + +void pw_roc_log_handler(const roc_log_message *message, void *argument) +{ + const enum spa_log_level log_level = pw_roc_log_level_roc_2_pw(message->level); + if (SPA_UNLIKELY(pw_log_topic_enabled(log_level, roc_log_topic))) { + pw_log_logt(log_level, roc_log_topic, message->file, message->line, message->module, message->text, ""); + } +} + diff --git a/src/modules/module-roc/common.h b/src/modules/module-roc/common.h index 69153659e..c94ac69a8 100644 --- a/src/modules/module-roc/common.h +++ b/src/modules/module-roc/common.h @@ -3,8 +3,10 @@ #include #include +#include #include +#include #define PW_ROC_DEFAULT_IP "0.0.0.0" #define PW_ROC_DEFAULT_SOURCE_PORT 10001 @@ -18,6 +20,9 @@ #define PW_ROC_MULTITRACK_ENCODING_ID 100 #define PW_ROC_STEREO_POSITIONS "[ FL FR ]" +void pw_roc_log_init(void); +void pw_roc_log_handler(const roc_log_message *message, void *argument); + static inline int pw_roc_parse_fec_encoding(roc_fec_encoding *out, const char *str) { if (!str || !*str || spa_streq(str, "default")) @@ -132,4 +137,62 @@ static inline void pw_roc_fec_encoding_to_proto(roc_fec_encoding fec_code, roc_p } } +static inline roc_log_level pw_roc_log_level_pw_2_roc(const enum spa_log_level pw_log_level) +{ + switch (pw_log_level) { + case SPA_LOG_LEVEL_NONE: + return ROC_LOG_NONE; + case SPA_LOG_LEVEL_ERROR: + return ROC_LOG_ERROR; + case SPA_LOG_LEVEL_WARN: + return ROC_LOG_ERROR; + case SPA_LOG_LEVEL_INFO: + return ROC_LOG_INFO; + case SPA_LOG_LEVEL_DEBUG: + return ROC_LOG_DEBUG; + case SPA_LOG_LEVEL_TRACE: + return ROC_LOG_TRACE; + default: + return ROC_LOG_NONE; + } +} + +static inline enum spa_log_level pw_roc_log_level_roc_2_pw(const roc_log_level roc_log_level) +{ + switch (roc_log_level) { + case ROC_LOG_NONE: + return SPA_LOG_LEVEL_NONE; + case ROC_LOG_ERROR: + return SPA_LOG_LEVEL_ERROR; + case ROC_LOG_INFO: + return SPA_LOG_LEVEL_INFO; + case ROC_LOG_DEBUG: + return SPA_LOG_LEVEL_DEBUG; + case ROC_LOG_TRACE: + return SPA_LOG_LEVEL_TRACE; + default: + return SPA_LOG_LEVEL_NONE; + } +} + +static inline int pw_roc_parse_log_level(roc_log_level *loglevel, const char *str, + roc_log_level default_level) +{ + if (spa_streq(str, "DEFAULT")) + *loglevel = default_level; + else if (spa_streq(str, "NONE")) + *loglevel = ROC_LOG_NONE; + else if (spa_streq(str, "ERROR")) + *loglevel = ROC_LOG_ERROR; + else if (spa_streq(str, "INFO")) + *loglevel = ROC_LOG_INFO; + else if (spa_streq(str, "DEBUG")) + *loglevel = ROC_LOG_DEBUG; + else if (spa_streq(str, "TRACE")) + *loglevel = ROC_LOG_TRACE; + else + return -EINVAL; + return 0; +} + #endif /* MODULE_ROC_COMMON_H */