From bc22c584355576de57920ce2ca20bf4260919b12 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 19 Jun 2017 15:49:13 +0200 Subject: [PATCH] module-spa: make separate monitor and node module Make it possible to load monitors and nodes separately by specifying the plugin and factory of the node/monitor to load. Add argument parsing for properties and configure them in the node when possible. --- Makefile | 7 ++ pipewire/client/array.h | 2 +- pipewire/daemon/pipewire.conf.in | 4 +- pipewire/modules/spa/meson.build | 24 ++--- pipewire/modules/spa/module-monitor.c | 64 ++++++++++++ pipewire/modules/spa/module-node.c | 140 ++++++++++++++++++++++++++ pipewire/modules/spa/module.c | 140 -------------------------- pipewire/server/module.c | 2 + 8 files changed, 229 insertions(+), 154 deletions(-) create mode 100644 pipewire/modules/spa/module-monitor.c create mode 100644 pipewire/modules/spa/module-node.c delete mode 100644 pipewire/modules/spa/module.c diff --git a/Makefile b/Makefile index 82f423741..d65f9a409 100644 --- a/Makefile +++ b/Makefile @@ -13,5 +13,12 @@ run: PIPEWIRE_CONFIG_FILE=build/pipewire/daemon/pipewire.conf \ build/pipewire/daemon/pipewire +monitor: + SPA_PLUGIN_DIR=build/spa/plugins \ + build/pipewire/tools/pipewire-monitor + dist: git archive --prefix=pipewire-0.1.0/ -o pipewire-0.1.0.tar.gz HEAD + +rpm: dist + rpmbuild -ta pipewire-0.1.0.tar.gz diff --git a/pipewire/client/array.h b/pipewire/client/array.h index 5c40f3738..1f7611618 100644 --- a/pipewire/client/array.h +++ b/pipewire/client/array.h @@ -44,7 +44,7 @@ struct pw_array { #define pw_array_get_len_s(a,s) ((a)->size / (s)) #define pw_array_get_unchecked_s(a,idx,s,t) SPA_MEMBER((a)->data,(idx)*(s),t) -#define pw_array_check_index_s(a,idx,s) ((idx) < pw_array_get_len(a,s)) +#define pw_array_check_index_s(a,idx,s) ((idx) < pw_array_get_len_s(a,s)) /** Get the number of items of type \a t in array \memberof pw_array */ #define pw_array_get_len(a,t) pw_array_get_len_s(a,sizeof(t)) diff --git a/pipewire/daemon/pipewire.conf.in b/pipewire/daemon/pipewire.conf.in index 2a4b8412b..fd8810225 100644 --- a/pipewire/daemon/pipewire.conf.in +++ b/pipewire/daemon/pipewire.conf.in @@ -1,7 +1,9 @@ #load-module libpipewire-module-protocol-dbus load-module libpipewire-module-protocol-native load-module libpipewire-module-suspend-on-idle -load-module libpipewire-module-spa --pattern snow +#load-module libpipewire-module-spa-monitor alsa/libspa-alsa alsa-monitor alsa +load-module libpipewire-module-spa-monitor v4l2/libspa-v4l2 v4l2-monitor v4l2 +#load-module libpipewire-module-spa-node videotestsrc/libspa-videotestsrc videotestsrc videotestsrc media.class=Video/Source Spa:POD:Object:Props:patternType=Spa:POD:Object:Props:patternType:snow load-module libpipewire-module-autolink #load-module libpipewire-module-mixer load-module libpipewire-module-client-node diff --git a/pipewire/modules/spa/meson.build b/pipewire/modules/spa/meson.build index cc75a4e75..bdada4b23 100644 --- a/pipewire/modules/spa/meson.build +++ b/pipewire/modules/spa/meson.build @@ -1,20 +1,20 @@ -pipewire_module_spa_headers = [ - 'spa-node.h', - 'spa-monitor.h', -] - -pipewire_module_spa_sources = [ - 'module.c', - 'spa-node.c', - 'spa-monitor.c', -] - pipewire_module_spa_c_args = [ '-DHAVE_CONFIG_H', '-D_GNU_SOURCE', ] -pipewire_module_spa = shared_library('pipewire-module-spa', pipewire_module_spa_sources, +pipewire_module_spa_monitor = shared_library('pipewire-module-spa-monitor', + [ 'module-monitor.c', 'spa-monitor.c' ], + c_args : pipewire_module_spa_c_args, + include_directories : [configinc, spa_inc], + link_with : spalib, + install : true, + install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')), + dependencies : [mathlib, dl_lib, pipewire_dep, pipewirecore_dep], +) + +pipewire_module_spa_node = shared_library('pipewire-module-spa-node', + [ 'module-node.c', 'spa-node.c' ], c_args : pipewire_module_spa_c_args, include_directories : [configinc, spa_inc], link_with : spalib, diff --git a/pipewire/modules/spa/module-monitor.c b/pipewire/modules/spa/module-monitor.c new file mode 100644 index 000000000..b1a5a4810 --- /dev/null +++ b/pipewire/modules/spa/module-monitor.c @@ -0,0 +1,64 @@ +/* PipeWire + * Copyright (C) 2016 Axis Communications + * @author Linus Svensson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +#include +#include +#include + +#include "spa-monitor.h" +#include "spa-node.h" + +bool pipewire__module_init(struct pw_module *module, const char *args) +{ + const char *dir; + char **argv; + int n_tokens; + + if (args == NULL) + goto wrong_arguments; + + argv = pw_split_strv(args, " \t", INT_MAX, &n_tokens); + if (n_tokens < 3) + goto not_enough_arguments; + + if ((dir = getenv("SPA_PLUGIN_DIR")) == NULL) + dir = PLUGINDIR; + + pw_spa_monitor_load(module->core, dir, argv[0], argv[1], argv[2]); + + pw_free_strv(argv); + + return true; + + not_enough_arguments: + pw_free_strv(argv); + wrong_arguments: + pw_log_error("usage: module-spa-monitor "); + return false; +} diff --git a/pipewire/modules/spa/module-node.c b/pipewire/modules/spa/module-node.c new file mode 100644 index 000000000..0113060c8 --- /dev/null +++ b/pipewire/modules/spa/module-node.c @@ -0,0 +1,140 @@ +/* PipeWire + * Copyright (C) 2016 Axis Communications + * @author Linus Svensson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +#include +#include +#include + +#include "spa-monitor.h" +#include "spa-node.h" + +static int +setup_props(struct pw_core *core, struct spa_node *spa_node, struct pw_properties *pw_props) +{ + int res; + struct spa_props *props; + void *state = NULL; + const char *key; + + if ((res = spa_node_get_props(spa_node, &props)) != SPA_RESULT_OK) { + pw_log_debug("spa_node_get_props failed: %d", res); + return SPA_RESULT_ERROR; + } + + while ((key = pw_properties_iterate(pw_props, &state))) { + struct spa_pod_prop *prop; + uint32_t id; + + if (!spa_type_is_a(key, SPA_TYPE_PROPS_BASE)) + continue; + + id = spa_type_map_get_id(core->type.map, key); + if (id == SPA_ID_INVALID) + continue; + + if ((prop = spa_pod_object_find_prop(&props->object, id))) { + const char *value = pw_properties_get(pw_props, key); + + pw_log_info("configure prop %s", key); + + switch(prop->body.value.type) { + case SPA_POD_TYPE_ID: + SPA_POD_VALUE(struct spa_pod_id, &prop->body.value) = + spa_type_map_get_id(core->type.map, value); + break; + case SPA_POD_TYPE_INT: + SPA_POD_VALUE(struct spa_pod_int, &prop->body.value) = atoi(value); + break; + case SPA_POD_TYPE_LONG: + SPA_POD_VALUE(struct spa_pod_long, &prop->body.value) = atoi(value); + break; + case SPA_POD_TYPE_FLOAT: + SPA_POD_VALUE(struct spa_pod_float, &prop->body.value) = atof(value); + break; + case SPA_POD_TYPE_DOUBLE: + SPA_POD_VALUE(struct spa_pod_double, &prop->body.value) = atof(value); + break; + case SPA_POD_TYPE_STRING: + break; + default: + break; + } + } + } + + if ((res = spa_node_set_props(spa_node, props)) != SPA_RESULT_OK) { + pw_log_debug("spa_node_set_props failed: %d", res); + return SPA_RESULT_ERROR; + } + + return SPA_RESULT_OK; +} + +bool pipewire__module_init(struct pw_module *module, const char *args) +{ + const char *dir; + struct pw_properties *props = NULL; + char **argv; + int i, n_tokens; + + if (args == NULL) + goto wrong_arguments; + + argv = pw_split_strv(args, " \t", INT_MAX, &n_tokens); + if (n_tokens < 3) + goto not_enough_arguments; + + if ((dir = getenv("SPA_PLUGIN_DIR")) == NULL) + dir = PLUGINDIR; + + props = pw_properties_new(NULL, NULL); + + for (i = 3; i < n_tokens; i++) { + char **prop; + int n_props; + + prop = pw_split_strv(argv[i], "=", INT_MAX, &n_props); + if (n_props >= 2) + pw_properties_set(props, prop[0], prop[1]); + + pw_free_strv(prop); + } + + pw_spa_node_load(module->core, dir, argv[0], argv[1], argv[2], props, setup_props); + + pw_free_strv(argv); + + return true; + + not_enough_arguments: + pw_free_strv(argv); + wrong_arguments: + pw_log_error("usage: module-spa-node [key=value ...]"); + return false; +} diff --git a/pipewire/modules/spa/module.c b/pipewire/modules/spa/module.c deleted file mode 100644 index 6bb2fd56c..000000000 --- a/pipewire/modules/spa/module.c +++ /dev/null @@ -1,140 +0,0 @@ -/* PipeWire - * Copyright (C) 2016 Axis Communications - * @author Linus Svensson - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#include - -#include -#include -#include - -#include "spa-monitor.h" -#include "spa-node.h" - -static int -setup_video_node(struct pw_core *core, struct spa_node *spa_node, struct pw_properties *pw_props) -{ - int res; - struct spa_props *props; - struct spa_pod_prop *prop; - const char *pattern, *pattern_type; - - /* Retrieve pattern property */ - pattern = pw_properties_get(pw_props, "pattern"); - if (strcmp(pattern, "smpte-snow") == 0) { - pattern_type = SPA_TYPE_PROPS__patternType ":smpte-snow"; - } else if (strcmp(pattern, "snow") == 0) { - pattern_type = SPA_TYPE_PROPS__patternType ":snow"; - } else { - pw_log_debug("Unrecognized pattern"); - return SPA_RESULT_ERROR; - } - - if ((res = spa_node_get_props(spa_node, &props)) != SPA_RESULT_OK) { - pw_log_debug("spa_node_get_props failed: %d", res); - return SPA_RESULT_ERROR; - } - - if ((prop = - spa_pod_object_find_prop(&props->object, - spa_type_map_get_id(core->type.map, - SPA_TYPE_PROPS__patternType)))) { - if (prop->body.value.type == SPA_POD_TYPE_ID) - SPA_POD_VALUE(struct spa_pod_id, &prop->body.value) = - spa_type_map_get_id(core->type.map, pattern_type); - } - - if ((res = spa_node_set_props(spa_node, props)) != SPA_RESULT_OK) { - pw_log_debug("spa_node_set_props failed: %d", res); - return SPA_RESULT_ERROR; - } - - return SPA_RESULT_OK; -} - -bool pipewire__module_init(struct pw_module *module, const char *args) -{ - const char *dir; - struct pw_properties *video_props = NULL, *audio_props = NULL; - - if (args != NULL) { - char **tmp_argv; - char **argv; - int n_tokens; - int opt = 0; - - tmp_argv = pw_split_strv(args, " \t", INT_MAX, &n_tokens); - - argv = malloc((n_tokens + 1) * sizeof(char *)); - /* getopt expects name of executable on the first place of argv */ - argv[0] = "videotestsrc"; - - for (int i = 1; i <= n_tokens; i++) { - argv[i] = tmp_argv[i - 1]; - } - - video_props = pw_properties_new("media.class", "Video/Source", NULL); - - static struct option long_options[] = { - {"filter", required_argument, 0, 'f'}, - {"pattern", required_argument, 0, 'p'}, - {"resolution", required_argument, 0, 'r'}, - {0, 0, 0, 0} - }; - - while ((opt = getopt_long(n_tokens + 1, argv, "p:r:f:", long_options, NULL)) != -1) { - switch (opt) { - case 'f': - pw_properties_set(video_props, "filter", optarg); - break; - case 'p': - pw_properties_set(video_props, "pattern", optarg); - break; - case 'r': - pw_properties_set(video_props, "resolution", optarg); - break; - default: - break; - } - } - free(argv); - pw_free_strv(tmp_argv); - } - if ((dir = getenv("SPA_PLUGIN_DIR")) == NULL) - dir = PLUGINDIR; - - pw_spa_monitor_load(module->core, dir, "alsa/libspa-alsa", "alsa-monitor", "alsa"); - - pw_spa_monitor_load(module->core, dir, "v4l2/libspa-v4l2", "v4l2-monitor", "v4l2"); - - audio_props = pw_properties_new("media.class", "Audio/Source", NULL); - pw_spa_node_load(module->core, dir, "audiotestsrc/libspa-audiotestsrc", - "audiotestsrc", "audiotestsrc", audio_props, NULL); - pw_spa_node_load(module->core, dir, "videotestsrc/libspa-videotestsrc", - "videotestsrc", "videotestsrc", video_props, setup_video_node); - - return true; -} diff --git a/pipewire/server/module.c b/pipewire/server/module.c index d9075ea25..12c7b4994 100644 --- a/pipewire/server/module.c +++ b/pipewire/server/module.c @@ -174,6 +174,8 @@ struct pw_module *pw_module_load(struct pw_core *core, this = &impl->this; this->core = core; + pw_signal_init(&this->destroy_signal); + if (!init_func(this, (char *) args)) goto init_failed;